[Ada] Further cleanup in inlining machinery
diff mbox series

Message ID 20190819083858.GA33339@adacore.com
State New
Headers show
Series
  • [Ada] Further cleanup in inlining machinery
Related show

Commit Message

Pierre-Marie de Rodat Aug. 19, 2019, 8:38 a.m. UTC
This gets rid of a small issue in the inlining machinery: under very
peculiar circumstances, it would add a pending instantiation for the
body of a generic package at the point of call to an inlined subprogram
of the instance.  That's theoritically problematic because the saved
context is that of the call and not that of the instance in this case,
although the strict conditions ensure that this doesn't make a real
difference in practice.

Now that the machinery can perform the pending instantiations on demand,
we can optimistically add more of them when the instantiations are
analyzed and thus remove the problematic handling at the point of call.

No functional changes.

Tested on x86_64-pc-linux-gnu, committed on trunk

2019-08-19  Eric Botcazou  <ebotcazou@adacore.com>

gcc/ada/

	* inline.adb (Add_Inlined_Body): Do not add pending
	instantiations.
	* sem_ch12.adb (Needs_Body_Instantiated): New predicate.
	(Analyze_Package_Instantiation): Use it to decide whether to add
	a pending instantiation for the body of the package.

Patch
diff mbox series

--- gcc/ada/inline.adb
+++ gcc/ada/inline.adb
@@ -510,7 +510,6 @@  package body Inline is
 
       Inst      : Entity_Id;
       Inst_Decl : Node_Id;
-      Inst_Node : Node_Id;
       Level     : Inline_Level_Type;
 
    --  Start of processing for Add_Inlined_Body
@@ -609,48 +608,24 @@  package body Inline is
                  and then Is_Generic_Instance (Inst)
                  and then not Is_Called (Inst)
                then
-                  --  Do not add a pending instantiation if the body exits
-                  --  already, or if the instance is a compilation unit, or
-                  --  the instance node is missing.
-
                   Inst_Decl := Unit_Declaration_Node (Inst);
+
+                  --  Do not inline the instance if the body already exists,
+                  --  or if the instance is a compilation unit, or else if
+                  --  the instance node is simply missing.
+
                   if Present (Corresponding_Body (Inst_Decl))
                     or else Nkind (Parent (Inst_Decl)) = N_Compilation_Unit
                     or else No (Next (Inst_Decl))
                   then
                      Set_Is_Called (Inst);
-
                   else
-                     --  If the inlined call itself appears within an instance,
-                     --  ensure that the enclosing instance body is available.
-                     --  This is necessary because Sem_Ch12.Might_Inline_Subp
-                     --  does not recurse into nested instantiations.
-
-                     if not Is_Inlined (Inst) and then In_Instance then
-                        Set_Is_Inlined (Inst);
-
-                        --  The instantiation node usually follows the package
-                        --  declaration for the instance. If the generic unit
-                        --  has aspect specifications, they are transformed
-                        --  into pragmas in the instance, and the instance node
-                        --  appears after them.
-
-                        Inst_Node := Next (Inst_Decl);
-
-                        while Nkind (Inst_Node) /= N_Package_Instantiation loop
-                           Inst_Node := Next (Inst_Node);
-                        end loop;
-
-                        Add_Pending_Instantiation (Inst_Node, Inst_Decl);
-                     end if;
-
                      Add_Inlined_Instance (Inst);
                   end if;
                end if;
             end if;
 
-            --  If the unit containing E is an instance, then the instance body
-            --  will be analyzed in any case, see Sem_Ch12.Might_Inline_Subp.
+            --  If the unit containing E is an instance, nothing more to do
 
             if Is_Generic_Instance (Pack) then
                null;

--- gcc/ada/sem_ch12.adb
+++ gcc/ada/sem_ch12.adb
@@ -240,6 +240,10 @@  package body Sem_Ch12 is
    --  circularity is detected, and used to abandon compilation after the
    --  messages have been posted.
 
+   Circularity_Detected : Boolean := False;
+   --  It should really be reset upon encountering a new main unit, but in
+   --  practice we do not use multiple main units so this is not critical.
+
    -----------------------------------------
    -- Implementation of Generic Contracts --
    -----------------------------------------
@@ -352,10 +356,6 @@  package body Sem_Ch12 is
 
    --    Instantiate_Subprogram_Contract
 
-   Circularity_Detected : Boolean := False;
-   --  This should really be reset on encountering a new main unit, but in
-   --  practice we are not using multiple main units so it is not critical.
-
    --------------------------------------------------
    -- Formal packages and partial parameterization --
    --------------------------------------------------
@@ -380,23 +380,23 @@  package body Sem_Ch12 is
    --  the generic package, and a set of declarations that map the actuals
    --  into local renamings, just as we do for bona fide instantiations. For
    --  defaulted parameters and formals with a box, we copy directly the
-   --  declarations of the formal into this local package. The result is a
-   --  a package whose visible declarations may include generic formals. This
+   --  declarations of the formals into this local package. The result is a
+   --  package whose visible declarations may include generic formals. This
    --  package is only used for type checking and visibility analysis, and
-   --  never reaches the back-end, so it can freely violate the placement
+   --  never reaches the back end, so it can freely violate the placement
    --  rules for generic formal declarations.
 
    --  The list of declarations (renamings and copies of formals) is built
    --  by Analyze_Associations, just as for regular instantiations.
 
    --  At the point of instantiation, conformance checking must be applied only
-   --  to those parameters that were specified in the formal. We perform this
+   --  to those parameters that were specified in the formals. We perform this
    --  checking by creating another internal instantiation, this one including
    --  only the renamings and the formals (the rest of the package spec is not
    --  relevant to conformance checking). We can then traverse two lists: the
    --  list of actuals in the instance that corresponds to the formal package,
    --  and the list of actuals produced for this bogus instantiation. We apply
-   --  the conformance rules to those actuals that are not defaulted (i.e.
+   --  the conformance rules to those actuals that are not defaulted, i.e.
    --  which still appear as generic formals.
 
    --  When we compile an instance body we must make the right parameters
@@ -3849,12 +3849,17 @@  package body Sem_Ch12 is
       --  Only relevant when back-end inlining is not enabled.
 
       function Might_Inline_Subp (Gen_Unit : Entity_Id) return Boolean;
-      --  If inlining is active and the generic contains inlined subprograms,
-      --  we either instantiate the body when front-end inlining is enabled,
-      --  or we add a pending instantiation when back-end inlining is enabled.
-      --  In the former case, this may cause superfluous instantiations, but
-      --  in either case we need to perform the instantiation of the body in
-      --  the context of the instance and not in that of the point of inlining.
+      --  Return True if inlining is active and Gen_Unit contains inlined
+      --  subprograms. In this case, we may either instantiate the body when
+      --  front-end inlining is enabled, or add a pending instantiation when
+      --  back-end inlining is enabled. In the former case, this may cause
+      --  superfluous instantiations, but in either case we need to perform
+      --  the instantiation of the body in the context of the instance and
+      --  not in that of the point of inlining.
+
+      function Needs_Body_Instantiated (Gen_Unit : Entity_Id) return Boolean;
+      --  Return True if Gen_Unit needs to have its body instantiated in the
+      --  context of N. This in particular excludes generic contexts.
 
       -----------------------
       -- Might_Inline_Subp --
@@ -3892,6 +3897,52 @@  package body Sem_Ch12 is
          return False;
       end Might_Inline_Subp;
 
+      -------------------------------
+      --  Needs_Body_Instantiated  --
+      -------------------------------
+
+      function Needs_Body_Instantiated (Gen_Unit : Entity_Id) return Boolean is
+      begin
+         --  No need to instantiate bodies in generic units
+
+         if Is_Generic_Unit (Cunit_Entity (Main_Unit)) then
+            return False;
+         end if;
+
+         --  If the instantiation is in the main unit, then the body is needed
+
+         if Is_In_Main_Unit (N) then
+            return True;
+         end if;
+
+         --  If not, then again no need to instantiate bodies in generic units
+
+         if Is_Generic_Unit (Cunit_Entity (Get_Code_Unit (N))) then
+            return False;
+         end if;
+
+         --  Here we have a special handling for back-end inlining: if the
+         --  instantiation is not a compilation unit, then we want to have
+         --  its body instantiated. The reason is that Might_Inline_Subp
+         --  does not catch all the cases (since it does not recurse into
+         --  nested packages) so this avoids the need to patch things up
+         --  at a later stage. Moreover the instantiations that are not
+         --  compilation units are only performed on demand when back-end
+         --  inlining is enabled, so this causes very little extra work.
+
+         if Nkind (Parent (N)) /= N_Compilation_Unit
+           and then Inline_Processing_Required
+           and then Back_End_Inlining
+         then
+            return True;
+         end if;
+
+         --  We want to have the bodies instantiated in non-main units if
+         --  they might contribute inlined subprograms.
+
+         return Might_Inline_Subp (Gen_Unit);
+      end Needs_Body_Instantiated;
+
       --  Local declarations
 
       Gen_Id         : constant Node_Id    := Name (N);
@@ -4256,9 +4307,7 @@  package body Sem_Ch12 is
          end if;
 
          --  Save the instantiation node for a subsequent instantiation of the
-         --  body if there is one and the main unit is not generic, and either
-         --  we are generating code for this main unit, or the instantiation
-         --  contains inlined subprograms and is not done in a generic unit.
+         --  body if there is one and it needs to be instantiated here.
 
          --  We instantiate the body only if we are generating code, or if we
          --  are generating cross-reference information, or if we are building
@@ -4354,12 +4403,7 @@  package body Sem_Ch12 is
               (Unit_Requires_Body (Gen_Unit)
                 or else Enclosing_Body_Present
                 or else Present (Corresponding_Body (Gen_Decl)))
-               and then not Is_Generic_Unit (Cunit_Entity (Main_Unit))
-               and then (Is_In_Main_Unit (N)
-                          or else (Might_Inline_Subp (Gen_Unit)
-                                    and then
-                                   not Is_Generic_Unit
-                                         (Cunit_Entity (Get_Code_Unit (N)))))
+               and then Needs_Body_Instantiated (Gen_Unit)
                and then not Is_Actual_Pack
                and then not Inline_Now
                and then (Operating_Mode = Generate_Code