diff options
Diffstat (limited to 'gcc/ada/inline.adb')
-rw-r--r-- | gcc/ada/inline.adb | 215 |
1 files changed, 99 insertions, 116 deletions
diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb index 473553584dd..2fa6054a89a 100644 --- a/gcc/ada/inline.adb +++ b/gcc/ada/inline.adb @@ -70,15 +70,12 @@ package body Inline is ----------------------- -- For each call to an inlined subprogram, we make entries in a table - -- that stores caller and callee, and indicates a prerequisite from + -- that stores caller and callee, and indicates the call direction from -- one to the other. We also record the compilation unit that contains -- the callee. After analyzing the bodies of all such compilation units, - -- we produce a list of subprograms in topological order, for use by the - -- back-end. If P2 is a prerequisite of P1, then P1 calls P2, and for - -- proper inlining the back-end must analyze the body of P2 before that of - -- P1. The code below guarantees that the transitive closure of inlined - -- subprograms called from the main compilation unit is made available to - -- the code generator. + -- we compute the transitive closure of inlined subprograms called from + -- the main compilation unit and make it available to the code generator + -- in no particular order, thus allowing cycles in the call graph. Last_Inlined : Entity_Id := Empty; @@ -117,12 +114,11 @@ package body Inline is type Subp_Info is record Name : Entity_Id := Empty; + Next : Subp_Index := No_Subp; First_Succ : Succ_Index := No_Succ; - Count : Integer := 0; Listed : Boolean := False; Main_Call : Boolean := False; - Next : Subp_Index := No_Subp; - Next_Nopred : Subp_Index := No_Subp; + Processed : Boolean := False; end record; package Inlined is new Table.Table ( @@ -139,10 +135,11 @@ package body Inline is function Get_Code_Unit_Entity (E : Entity_Id) return Entity_Id; pragma Inline (Get_Code_Unit_Entity); - -- Return the entity node for the unit containing E + -- Return the entity node for the unit containing E. Always return + -- the spec for a package. - function Scope_In_Main_Unit (Scop : Entity_Id) return Boolean; - -- Return True if Scop is in the main unit or its spec + function In_Main_Unit_Or_Subunit (E : Entity_Id) return Boolean; + -- Return True if E is in the main unit or its spec or in a subunit procedure Add_Call (Called : Entity_Id; Caller : Entity_Id := Empty); -- Make two entries in Inlined table, for an inlined subprogram being @@ -166,9 +163,7 @@ package body Inline is -- example, an initialization procedure). procedure Add_Inlined_Subprogram (Index : Subp_Index); - -- Add subprogram to Inlined List once all of its predecessors have been - -- placed on the list. Decrement the count of all its successors, and - -- add them to list (recursively) if count drops to zero. + -- Add the subprogram to the list of inlined subprogram for the unit ------------------------------ -- Deferred Cleanup Actions -- @@ -203,29 +198,26 @@ package body Inline is if Present (Caller) then P2 := Add_Subp (Caller); - -- Add P2 to the list of successors of P1, if not already there. + -- Add P1 to the list of successors of P2, if not already there. -- Note that P2 may contain more than one call to P1, and only -- one needs to be recorded. - J := Inlined.Table (P1).First_Succ; + J := Inlined.Table (P2).First_Succ; while J /= No_Succ loop - if Successors.Table (J).Subp = P2 then + if Successors.Table (J).Subp = P1 then return; end if; J := Successors.Table (J).Next; end loop; - -- On exit, make a successor entry for P2 + -- On exit, make a successor entry for P1 Successors.Increment_Last; - Successors.Table (Successors.Last).Subp := P2; + Successors.Table (Successors.Last).Subp := P1; Successors.Table (Successors.Last).Next := - Inlined.Table (P1).First_Succ; - Inlined.Table (P1).First_Succ := Successors.Last; - - Inlined.Table (P2).Count := Inlined.Table (P2).Count + 1; - + Inlined.Table (P2).First_Succ; + Inlined.Table (P2).First_Succ := Successors.Last; else Inlined.Table (P1).Main_Call := True; end if; @@ -345,9 +337,11 @@ package body Inline is -- or other internally generated subprogram, because in that -- case the subprogram body appears in the same unit that -- declares the type, and that body is visible to the back end. + -- Do not inline it either if it is in the main unit. elsif not Is_Inlined (Pack) and then Comes_From_Source (E) + and then not In_Main_Unit_Or_Subunit (Pack) then Set_Is_Inlined (Pack); Inlined_Bodies.Increment_Last; @@ -365,8 +359,6 @@ package body Inline is procedure Add_Inlined_Subprogram (Index : Subp_Index) is E : constant Entity_Id := Inlined.Table (Index).Name; Pack : constant Entity_Id := Get_Code_Unit_Entity (E); - Succ : Succ_Index; - Subp : Subp_Index; function Back_End_Cannot_Inline (Subp : Entity_Id) return Boolean; -- There are various conditions under which back-end inlining cannot @@ -441,7 +433,7 @@ package body Inline is and then (Is_Inlined (Pack) or else Is_Generic_Instance (Pack) or else Is_Internal (E)) - and then not Scope_In_Main_Unit (E) + and then not In_Main_Unit_Or_Subunit (E) and then not Is_Nested (E) and then not Has_Initialized_Type (E) then @@ -460,27 +452,6 @@ package body Inline is end if; Inlined.Table (Index).Listed := True; - - -- Now add to the list those callers of the current subprogram that - -- are themselves called. They may appear on the graph as callers - -- of the current one, even if they are themselves not called, and - -- there is no point in including them in the list for the backend. - -- Furthermore, they might not even be public, in which case the - -- back-end cannot handle them at all. - - Succ := Inlined.Table (Index).First_Succ; - while Succ /= No_Succ loop - Subp := Successors.Table (Succ).Subp; - Inlined.Table (Subp).Count := Inlined.Table (Subp).Count - 1; - - if Inlined.Table (Subp).Count = 0 - and then Is_Called (Inlined.Table (Subp).Name) - then - Add_Inlined_Subprogram (Subp); - end if; - - Succ := Successors.Table (Succ).Next; - end loop; end Add_Inlined_Subprogram; ------------------------ @@ -545,12 +516,11 @@ package body Inline is begin Inlined.Increment_Last; Inlined.Table (Inlined.Last).Name := E; + Inlined.Table (Inlined.Last).Next := No_Subp; Inlined.Table (Inlined.Last).First_Succ := No_Succ; - Inlined.Table (Inlined.Last).Count := 0; Inlined.Table (Inlined.Last).Listed := False; Inlined.Table (Inlined.Last).Main_Call := False; - Inlined.Table (Inlined.Last).Next := No_Subp; - Inlined.Table (Inlined.Last).Next_Nopred := No_Subp; + Inlined.Table (Inlined.Last).Processed := False; end New_Entry; -- Start of processing for Add_Subp @@ -589,8 +559,20 @@ package body Inline is Comp_Unit : Node_Id; J : Int; Pack : Entity_Id; + Subp : Subp_Index; S : Succ_Index; + type Pending_Index is new Nat; + + package Pending_Inlined is new Table.Table ( + Table_Component_Type => Subp_Index, + Table_Index_Type => Pending_Index, + Table_Low_Bound => 1, + Table_Initial => Alloc.Inlined_Initial, + Table_Increment => Alloc.Inlined_Increment, + Table_Name => "Pending_Inlined"); + -- The workpile used to compute the transitive closure + function Is_Ancestor_Of_Main (U_Name : Entity_Id; Nam : Node_Id) return Boolean; @@ -757,64 +739,57 @@ package body Inline is -- as part of an inlined package, but are not themselves called. An -- accurate computation of just those subprograms that are needed -- requires that we perform a transitive closure over the call graph, - -- starting from calls in the main program. Here we do one step of - -- the inverse transitive closure, and reset the Is_Called flag on - -- subprograms all of whose callers are not. + -- starting from calls in the main program. for Index in Inlined.First .. Inlined.Last loop - S := Inlined.Table (Index).First_Succ; + if not Is_Called (Inlined.Table (Index).Name) then - if S /= No_Succ - and then not Inlined.Table (Index).Main_Call - then - Set_Is_Called (Inlined.Table (Index).Name, False); + -- This means that Add_Inlined_Body added the subprogram to the + -- table but wasn't able to handle its code unit. Do nothing. - while S /= No_Succ loop - if Is_Called - (Inlined.Table (Successors.Table (S).Subp).Name) - or else Inlined.Table (Successors.Table (S).Subp).Main_Call - then - Set_Is_Called (Inlined.Table (Index).Name); - exit; - end if; + Inlined.Table (Index).Processed := True; + + elsif Inlined.Table (Index).Main_Call then + Pending_Inlined.Increment_Last; + Pending_Inlined.Table (Pending_Inlined.Last) := Index; + Inlined.Table (Index).Processed := True; - S := Successors.Table (S).Next; - end loop; + else + Set_Is_Called (Inlined.Table (Index).Name, False); end if; end loop; - -- Now that the units are compiled, chain the subprograms within - -- that are called and inlined. Produce list of inlined subprograms - -- sorted in topological order. Start with all subprograms that - -- have no prerequisites, i.e. inlined subprograms that do not call - -- other inlined subprograms. + -- Iterate over the workpile until it is emptied, propagating the + -- Is_Called flag to the successors of the processed subprogram. - for Index in Inlined.First .. Inlined.Last loop + while Pending_Inlined.Last >= Pending_Inlined.First loop + Subp := Pending_Inlined.Table (Pending_Inlined.Last); + Pending_Inlined.Decrement_Last; - if Is_Called (Inlined.Table (Index).Name) - and then Inlined.Table (Index).Count = 0 - and then not Inlined.Table (Index).Listed - then - Add_Inlined_Subprogram (Index); - end if; + S := Inlined.Table (Subp).First_Succ; + + while S /= No_Succ loop + Subp := Successors.Table (S).Subp; + + if not Inlined.Table (Subp).Processed then + Set_Is_Called (Inlined.Table (Subp).Name); + Pending_Inlined.Increment_Last; + Pending_Inlined.Table (Pending_Inlined.Last) := Subp; + Inlined.Table (Subp).Processed := True; + end if; + + S := Successors.Table (S).Next; + end loop; end loop; - -- Because Add_Inlined_Subprogram treats recursively nodes that have - -- no prerequisites left, at the end of the loop all subprograms - -- must have been listed. If there are any unlisted subprograms - -- left, there must be some recursive chains that cannot be inlined. + -- Finally add the called subprograms to the list of inlined + -- subprograms for the unit. for Index in Inlined.First .. Inlined.Last loop if Is_Called (Inlined.Table (Index).Name) - and then Inlined.Table (Index).Count /= 0 - and then not Is_Predefined_File_Name - (Unit_File_Name - (Get_Source_Unit (Inlined.Table (Index).Name))) + and then not Inlined.Table (Index).Listed then - Error_Msg_N - ("& cannot be inlined?", Inlined.Table (Index).Name); - - -- A warning on the first one might be sufficient ??? + Add_Inlined_Subprogram (Index); end if; end loop; @@ -994,8 +969,14 @@ package body Inline is -------------------------- function Get_Code_Unit_Entity (E : Entity_Id) return Entity_Id is + Unit : Entity_Id := Cunit_Entity (Get_Code_Unit (E)); + begin - return Cunit_Entity (Get_Code_Unit (E)); + if Ekind (Unit) = E_Package_Body then + Unit := Spec_Entity (Unit); + end if; + + return Unit; end Get_Code_Unit_Entity; -------------------------- @@ -1027,6 +1008,28 @@ package body Inline is return False; end Has_Initialized_Type; + ----------------------------- + -- In_Main_Unit_Or_Subunit -- + ----------------------------- + + function In_Main_Unit_Or_Subunit (E : Entity_Id) return Boolean is + Comp : Node_Id := Cunit (Get_Code_Unit (E)); + + begin + -- Check whether the subprogram or package to inline is within the main + -- unit or its spec or within a subunit. In either case there are no + -- additional bodies to process. If the subprogram appears in a parent + -- of the current unit, the check on whether inlining is possible is + -- done in Analyze_Inlined_Bodies. + + while Nkind (Unit (Comp)) = N_Subunit loop + Comp := Library_Unit (Comp); + end loop; + + return Comp = Cunit (Main_Unit) + or else Comp = Library_Unit (Cunit (Main_Unit)); + end In_Main_Unit_Or_Subunit; + ---------------- -- Initialize -- ---------------- @@ -1061,7 +1064,6 @@ package body Inline is begin if Serious_Errors_Detected = 0 then - Expander_Active := (Operating_Mode = Opt.Generate_Code); Push_Scope (Standard_Standard); To_Clean := New_Elmt_List; @@ -1180,23 +1182,4 @@ package body Inline is end loop; end Remove_Dead_Instance; - ------------------------ - -- Scope_In_Main_Unit -- - ------------------------ - - function Scope_In_Main_Unit (Scop : Entity_Id) return Boolean is - Comp : constant Node_Id := Cunit (Get_Code_Unit (Scop)); - - begin - -- Check whether the scope of the subprogram to inline is within the - -- main unit or within its spec. In either case there are no additional - -- bodies to process. If the subprogram appears in a parent of the - -- current unit, the check on whether inlining is possible is done in - -- Analyze_Inlined_Bodies. - - return - Comp = Cunit (Main_Unit) - or else Comp = Library_Unit (Cunit (Main_Unit)); - end Scope_In_Main_Unit; - end Inline; |