home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / inline.adb < prev    next >
Text File  |  1996-09-28  |  19KB  |  545 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                               I N L I N E                                --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.4 $                              --
  10. --                                                                          --
  11. --        Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved        --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. with Atree;    use Atree;
  26. with Einfo;    use Einfo;
  27. with Errout;   use Errout;
  28. with Expander; use Expander;
  29. with Lib;      use Lib;
  30. with Output;   use Output;
  31. with Sem_Ch8;  use Sem_Ch8;
  32. with Sem_Ch10; use Sem_Ch10;
  33. with Sem_Ch12; use Sem_Ch12;
  34. with Sem_Util; use Sem_Util;
  35. with Sinfo;    use Sinfo;
  36. with Stand;    use Stand;
  37. with Uname;    use Uname;
  38.  
  39. package body Inline is
  40.  
  41.    -----------------------
  42.    -- Inline Processing --
  43.    -----------------------
  44.  
  45.    --  For each call to an inlined subprogram, we make entries in a table
  46.    --  that stores caller and callee, and indicates a prerequisite from
  47.    --  one to the other. We also record the compilation unit that contains
  48.    --  the callee. After analyzing the bodies of all such compilation units,
  49.    --  we produce a list of subprograms in  topological order, for use by the
  50.    --  back-end. If P2 is a prerequisite of P1, then P1 calls P2, and for
  51.    --  proper inlining the back-end must analyze the body of P2 before that of
  52.    --  P1. The code below guarantees that the transitive closure of inlined
  53.    --  subprograms called from the main compilation unit is made available to
  54.    --  the code generator.
  55.  
  56.    Last_Inlined : Entity_Id := Empty;
  57.    Last_No_Pred : Entity_Id := Empty;
  58.  
  59.    --  For each entry in the table we keep a list of successors in topological
  60.    --  order, i.e. callers of the current subprogram.
  61.  
  62.    type Subp_Index is new Nat;
  63.    No_Subp : constant Subp_Index := 0;
  64.  
  65.    --  The subprogram entities are hashed into the Inlined table.
  66.  
  67.    Num_Hash_Headers : constant := 512;
  68.  
  69.    Hash_Headers : array (Subp_Index range 0 .. Num_Hash_Headers - 1)
  70.                                                           of Subp_Index;
  71.  
  72.    type Succ_Index is new Nat;
  73.    No_Succ : constant Succ_Index := 0;
  74.  
  75.    type Succ_Info is record
  76.       Subp : Subp_Index;
  77.       Next : Succ_Index;
  78.    end record;
  79.  
  80.    --  The following table stores list elements for the successor lists.
  81.    --  These lists cannot be chained directly through entries in the Inlined
  82.    --  table, because a given subprogram can appear in several such lists.
  83.  
  84.    package Successors is new Table (
  85.       Table_Component_Type => Succ_Info,
  86.       Table_Index_Type     => Succ_Index,
  87.       Table_Low_Bound      => 1,
  88.       Table_Initial        => 2000,
  89.       Table_Increment      => 20,
  90.       Table_Name           => "Successors");
  91.  
  92.    type Subp_Info is record
  93.       Name        : Entity_Id  := Empty;
  94.       First_Succ  : Succ_Index := No_Succ;
  95.       Count       : Integer    := 0;
  96.       Listed      : Boolean    := False;
  97.       Main_Call  : Boolean    := False;
  98.       Next        : Subp_Index := No_Subp;
  99.       Next_Nopred : Subp_Index := No_Subp;
  100.    end record;
  101.  
  102.    package Inlined is new Table (
  103.       Table_Component_Type => Subp_Info,
  104.       Table_Index_Type     => Subp_Index,
  105.       Table_Low_Bound      => 1,
  106.       Table_Initial        => 1000,
  107.       Table_Increment      => 20,
  108.       Table_Name           => "Inline_Table");
  109.  
  110.    -----------------------
  111.    -- Local Subprograms --
  112.    -----------------------
  113.  
  114.    function Scope_In_Main_Unit (Scop : Entity_Id) return Boolean;
  115.    --  Return True if Scop is in the main unit or its spec.
  116.  
  117.    procedure Add_Call (Called : Entity_Id; Caller : Entity_Id := Empty);
  118.    --  Make two entries in Inlined table, for an inlined subprogram being
  119.    --  called, and for the inlined subprogram that contains the call. If
  120.    --  the call is in the main compilation unit, Caller is Empty.
  121.  
  122.    function Add_Subp (E : Entity_Id) return Subp_Index;
  123.    --  Make entry in Inlined table for subprogram E, or return table index
  124.    --  that already holds E.
  125.  
  126.    procedure New_No_Pred (Index : Subp_Index);
  127.    --  Add subprogram to Inlined List once all of its predecessors have been
  128.    --  placed on the list. Decrement the count of all its successors, and
  129.    --  add them to list (recursively) if count drops to zero.
  130.  
  131.    ------------------------
  132.    -- Instantiate_Bodies --
  133.    ------------------------
  134.  
  135.    --  Generic bodies contain all the non-local references, so an
  136.    --  instantiation does not need any more context than Standard
  137.    --  itself, even if the instantiation appears in an inner scope.
  138.    --  Generic associations have verified that the contract model is
  139.    --  satisfied, so that any error that may occur in the analysis of
  140.    --  the body is an internal error.
  141.  
  142.    procedure Instantiate_Bodies is
  143.       J    : Int;
  144.       Decl : Node_Id;
  145.       Inst : Node_Id;
  146.  
  147.    begin
  148.       if Errors_Detected = 0 then
  149.          Expander_Active := True;
  150.          New_Scope (Standard_Standard);
  151.  
  152.          --  A body instantiation may generate additional instantiations, so
  153.          --  the following loop must scan to the end of a possibly expanding
  154.          --  set (that's why we can't simply use a FOR loop here).
  155.  
  156.          J := 0;
  157.  
  158.          while J <= Pending_Instantiations.Last
  159.            and then Errors_Detected = 0
  160.          loop
  161.             Decl := Pending_Instantiations.Table (J).Act_Decl;
  162.             Inst := Pending_Instantiations.Table (J).Inst_Node;
  163.  
  164.             if Nkind (Decl) = N_Package_Declaration then
  165.                Instantiate_Package_Body (Inst, Decl);
  166.             else
  167.                Instantiate_Subprogram_Body (Inst, Decl);
  168.             end if;
  169.  
  170.             J := J + 1;
  171.          end loop;
  172.  
  173.          --  Reset the table of instantiations. Additional instantiations
  174.          --  may be added through inlining, when additional bodies are
  175.          --  analyzed.
  176.  
  177.          Pending_Instantiations.Init;
  178.          Pop_Scope;
  179.       end if;
  180.    end Instantiate_Bodies;
  181.  
  182.    ----------------------
  183.    -- Add_Inlined_Body --
  184.    ----------------------
  185.  
  186.    procedure Add_Inlined_Body (N : Node_Id; E : Entity_Id) is
  187.       Pack : Entity_Id;
  188.       Comp_Unit : Node_Id;
  189.  
  190.       function Must_Inline return Boolean;
  191.       --  Inlining is only done if the call statement N is in the main unit,
  192.       --  or within the body of another inlined subprogram.
  193.  
  194.       function Must_Inline return Boolean is
  195.          Scop : Entity_Id := Current_Scope;
  196.          Comp : Node_Id;
  197.  
  198.       begin
  199.          while Scope (Scop) /= Standard_Standard
  200.            and then not Is_Child_Unit (Scop)
  201.          loop
  202.             if Is_Overloadable (Scop)
  203.               and then Is_Inlined (Scop)
  204.             then
  205.                Add_Call (E, Scop);
  206.                return True;
  207.             end if;
  208.  
  209.             Scop := Scope (Scop);
  210.          end loop;
  211.  
  212.          --  Call is not within an inlined body. Check whether it is in
  213.          --  main unit.
  214.  
  215.          Comp := Parent (Scop);
  216.  
  217.          while Nkind (Comp) /= N_Compilation_Unit loop
  218.             Comp := Parent (Comp);
  219.          end loop;
  220.  
  221.          if (Comp = Cunit (Main_Unit)
  222.            or else Comp = Library_Unit (Cunit (Main_Unit)))
  223.          then
  224.             Add_Call (E);
  225.             return True;
  226.          else
  227.             return False;
  228.          end if;
  229.       end Must_Inline;
  230.  
  231.    begin
  232.       --  Find unit containing E, and add to list of inlined bodies if needed.
  233.       --  If the body is already present, no need to load any other unit. This
  234.       --  is the case for an initialization procedure, which appears in the
  235.       --  package declaration that contains the type. It is also the case if
  236.       --  the body has already been analyzed.
  237.  
  238.       if not Is_Abstract (E) then
  239.          Pack := Scope (E);
  240.  
  241.          if Must_Inline
  242.            and then Ekind (Pack) = E_Package
  243.          then
  244.             Set_Is_Called (E);
  245.             Comp_Unit := Parent (Pack);
  246.  
  247.             if not Is_Inlined (Pack)
  248.               and then not Has_Completion (E)
  249.               and then not Scope_In_Main_Unit (Pack)
  250.             then
  251.                Set_Is_Inlined (Pack);
  252.                Inlined_Bodies.Increment_Last;
  253.                Inlined_Bodies.Table (Inlined_Bodies.Last) := Pack;
  254.             end if;
  255.          end if;
  256.       end if;
  257.    end Add_Inlined_Body;
  258.  
  259.    ----------------------------
  260.    -- Analyze_Inlined_Bodies --
  261.    ----------------------------
  262.  
  263.    procedure Analyze_Inlined_Bodies is
  264.       Comp_Unit : Node_Id;
  265.       J         : Int;
  266.       Pack      : Entity_Id;
  267.       S         : Succ_Index;
  268.    begin
  269.       J := 0;
  270.  
  271.       if Errors_Detected = 0 then
  272.          New_Scope (Standard_Standard);
  273.  
  274.          while J <= Inlined_Bodies.Last
  275.            and then Errors_Detected = 0
  276.          loop
  277.             Pack := Inlined_Bodies.Table (J);
  278.  
  279.             while Present (Pack)
  280.               and then Scope (Pack) /= Standard_Standard
  281.               and then not Is_Child_Unit (Pack)
  282.             loop
  283.                Pack := Scope (Pack);
  284.             end loop;
  285.  
  286.             Comp_Unit := Parent (Pack);
  287.  
  288.             while Present (Comp_Unit)
  289.               and then Nkind (Comp_Unit) /= N_Compilation_Unit
  290.             loop
  291.                Comp_Unit := Parent (Comp_Unit);
  292.             end loop;
  293.  
  294.             if Present (Comp_Unit)
  295.               and then Comp_Unit /= Cunit (Main_Unit)
  296.              and then Body_Required (Comp_Unit)
  297.               and then not
  298.                 Is_Loaded (Get_Body_Name (Get_Unit_Name (Unit (Comp_Unit))))
  299.             then
  300.                Load_Needed_Body (Comp_Unit);
  301.             end if;
  302.  
  303.             J := J + 1;
  304.          end loop;
  305.  
  306.          --  The analysis of required bodies may have produced additional
  307.          --  generic instantiations. To obtain further inlining, we perform
  308.          --  another round of generic body instantiations. Establishing a
  309.          --  fully recursive loop between inlining and generic instantiations
  310.          --  is unlikely to yield more than this one additional pass.
  311.  
  312.          Instantiate_Bodies;
  313.  
  314.          --  The list of inlined subprograms is an overestimate, because
  315.          --  it includes inlined functions called from functions that are
  316.          --  compiled as part of an inlined package, but are not themselves
  317.          --  called. An accurate computation of just those subprograms that
  318.          --  are needed requires that we perform a transitive closure over
  319.          --  the call graph, starting from calls in the main program. Here
  320.          --  we do one step of the inverse transitive closure, and reset
  321.          --  the Is_Called flag on subprograms all of whose callers are not.
  322.  
  323.          for Index in Inlined.First .. Inlined.Last loop
  324.             S := Inlined.Table (Index).First_Succ;
  325.  
  326.             if S /= No_Succ
  327.               and then not Inlined.Table (Index).Main_Call
  328.             then
  329.                Set_Is_Called (Inlined.Table (Index).Name, False);
  330.  
  331.                while S /= No_Succ loop
  332.  
  333.                   if Is_Called
  334.                     (Inlined.Table (Successors.Table (S).Subp).Name)
  335.                    or else Inlined.Table (Successors.Table (S).Subp).Main_Call
  336.                   then
  337.                      Set_Is_Called (Inlined.Table (Index).Name);
  338.                      exit;
  339.                   end if;
  340.  
  341.                   S := Successors.Table (S).Next;
  342.                end loop;
  343.             end if;
  344.          end loop;
  345.  
  346.          --  Now that the units are compiled, chain the subprograms within
  347.          --  that are called and inlined. Produce list of inlined subprograms
  348.          --  sorted in  topological order. Start with all subprograms that
  349.          --  have no prerequisites, i.e. inlined subprograms that do not call
  350.          --  other inlined subprograms.
  351.  
  352.          for Index in Inlined.First .. Inlined.Last loop
  353.  
  354.             if Is_Called (Inlined.Table (Index).Name)
  355.               and then Inlined.Table (Index).Count = 0
  356.               and then not Inlined.Table (Index).Listed
  357.             then
  358.                New_No_Pred (Index);
  359.             end if;
  360.          end loop;
  361.  
  362.          --  Because New_No_Pred treats recursively nodes that have no
  363.          --  prerequisites left, at the end of the loop all subprograms
  364.          --  must have been listed. If there are any unlisted subprograms
  365.          --  left, there must be some recursive chains that cannot be inlined.
  366.  
  367.          for Index in Inlined.First .. Inlined.Last loop
  368.             if Is_Called (Inlined.Table (Index).Name)
  369.               and then Inlined.Table (Index).Count /= 0
  370.             then
  371.                Error_Msg_N
  372.                  ("cannot be inlined?", Inlined.Table (Index).Name);
  373.                --  A warning on the first one might be sufficient.
  374.             end if;
  375.          end loop;
  376.  
  377.          Pop_Scope;
  378.       end if;
  379.    end Analyze_Inlined_Bodies;
  380.  
  381.    -------------------------
  382.    --  Scope_In_Main_Unit --
  383.    -------------------------
  384.  
  385.    function Scope_In_Main_Unit (Scop : Entity_Id) return Boolean is
  386.       Comp : Node_Id;
  387.       S : Entity_Id := Scop;
  388.    begin
  389.       while Scope (S) /= Standard_Standard
  390.         and then not Is_Child_Unit (S)
  391.       loop
  392.          S := Scope (S);
  393.       end loop;
  394.  
  395.       Comp := Parent (S);
  396.  
  397.       while Present (Comp)
  398.         and then Nkind (Comp) /= N_Compilation_Unit
  399.       loop
  400.          Comp := Parent (Comp);
  401.       end loop;
  402.  
  403.       return (Comp = Cunit (Main_Unit)
  404.            or else Comp = Library_Unit (Cunit (Main_Unit)));
  405.    end Scope_In_Main_Unit;
  406.  
  407.    ---------------
  408.    --  Add_Call --
  409.    ---------------
  410.  
  411.    procedure Add_Call (Called : Entity_Id; Caller : Entity_Id := Empty) is
  412.       P1 : Subp_Index := Add_Subp (Called);
  413.       P2 : Subp_Index;
  414.       J  : Succ_Index;
  415.    begin
  416.       if Present (Caller) then
  417.          P2 := Add_Subp (Caller);
  418.  
  419.          --  Add P2 to the list of successors of P1, if not already there.
  420.          --  Note that P2 may contain more than one call to P1, and only
  421.          --  one needs to be recorded.
  422.  
  423.          J := Inlined.Table (P1).First_Succ;
  424.  
  425.          while J /= No_Succ loop
  426.  
  427.             if Successors.Table (J).Subp = P2 then
  428.                return;
  429.             end if;
  430.  
  431.             J := Successors.Table (J).Next;
  432.          end loop;
  433.  
  434.          --  On exit, make a successor entry for P2.
  435.  
  436.          Successors.Increment_Last;
  437.          Successors.Table (Successors.Last).Subp := P2;
  438.          Successors.Table (Successors.Last).Next :=
  439.                              Inlined.Table (P1).First_Succ;
  440.          Inlined.Table (P1).First_Succ := Successors.Last;
  441.  
  442.          Inlined.Table (P2).Count := Inlined.Table (P2).Count + 1;
  443.  
  444.       else
  445.          Inlined.Table (P1).Main_Call := True;
  446.       end if;
  447.    end Add_Call;
  448.  
  449.    ---------------
  450.    --  Add_Subp --
  451.    ---------------
  452.  
  453.    function Add_Subp (E : Entity_Id) return Subp_Index is
  454.       Index : Subp_Index := Subp_Index (E) mod Num_Hash_Headers;
  455.       J     : Subp_Index;
  456.  
  457.       procedure New_Entry;
  458.       --  Initialize entry in Inlined table.
  459.  
  460.       procedure New_Entry is
  461.       begin
  462.          Inlined.Increment_Last;
  463.          Inlined.Table (Inlined.Last).Name        := E;
  464.          Inlined.Table (Inlined.Last).First_Succ  := No_Succ;
  465.          Inlined.Table (Inlined.Last).Count       := 0;
  466.          Inlined.Table (Inlined.Last).Listed      := False;
  467.          Inlined.Table (Inlined.Last).Next        := No_Subp;
  468.          Inlined.Table (Inlined.Last).Next_Nopred := No_Subp;
  469.       end New_Entry;
  470.  
  471.    begin
  472.       if Hash_Headers (Index) = No_Subp then
  473.          New_Entry;
  474.          Hash_Headers (Index) := Inlined.Last;
  475.          return Inlined.Last;
  476.  
  477.       else
  478.          J := Hash_Headers (Index);
  479.  
  480.          while J /= No_Subp loop
  481.  
  482.             if Inlined.Table (J).Name = E then
  483.                return J;
  484.             else
  485.                Index := J;
  486.                J := Inlined.Table (J).Next;
  487.             end if;
  488.          end loop;
  489.  
  490.          --  On exit, subprogram was not found. Enter in table. Index is
  491.          --  the current last entry on the hash chain.
  492.  
  493.          New_Entry;
  494.          Inlined.Table (Index).Next := Inlined.Last;
  495.          return Inlined.Last;
  496.       end if;
  497.    end Add_Subp;
  498.  
  499.    -----------------
  500.    -- New_No_Pred --
  501.    -----------------
  502.  
  503.    procedure New_No_Pred (Index : Subp_Index) is
  504.       E    : constant Entity_Id := Inlined.Table (Index).Name;
  505.       Succ : Succ_Index;
  506.       Subp : Subp_Index;
  507.  
  508.    begin
  509.       --  Insert the current subprogram in the  list of inlined subprograms.
  510.  
  511.       if not Scope_In_Main_Unit (Scope (E)) then
  512.          if No (Last_Inlined) then
  513.             Set_First_Inlined_Subprogram (Cunit (Main_Unit), E);
  514.          else
  515.             Set_Next_Inlined_Subprogram (Last_Inlined, E);
  516.          end if;
  517.       end if;
  518.  
  519.       Last_Inlined := E;
  520.       Inlined.Table (Index).Listed := True;
  521.  
  522.       --  Write_Entity_Info (E, "");
  523.       --  Write_Eol;
  524.  
  525.       Succ := Inlined.Table (Index).First_Succ;
  526.  
  527.       while Succ /= No_Succ loop
  528.          Subp := Successors.Table (Succ).Subp;
  529.          Inlined.Table (Subp).Count := Inlined.Table (Subp).Count - 1;
  530.  
  531.          if Inlined.Table (Subp).Count = 0 then
  532.             New_No_Pred (Subp);
  533.          end if;
  534.  
  535.          Succ := Successors.Table (Succ).Next;
  536.       end loop;
  537.  
  538.    end New_No_Pred;
  539.  
  540. begin
  541.    for J in Hash_Headers'Range loop
  542.       Hash_Headers (J) := No_Subp;
  543.    end loop;
  544. end Inline;
  545.