| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- B I N D O . E L A B O R A T O R S -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2019-2022, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- |
| -- for more details. You should have received a copy of the GNU General -- |
| -- Public License distributed with GNAT; see file COPYING3. If not, go to -- |
| -- http://www.gnu.org/licenses for a complete copy of the license. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Butil; use Butil; |
| with Debug; use Debug; |
| with Output; use Output; |
| with Types; use Types; |
| |
| with Bindo.Augmentors; |
| use Bindo.Augmentors; |
| use Bindo.Augmentors.Library_Graph_Augmentors; |
| |
| with Bindo.Builders; |
| use Bindo.Builders; |
| use Bindo.Builders.Invocation_Graph_Builders; |
| use Bindo.Builders.Library_Graph_Builders; |
| |
| with Bindo.Diagnostics; |
| use Bindo.Diagnostics; |
| |
| with Bindo.Units; |
| use Bindo.Units; |
| |
| with Bindo.Validators; |
| use Bindo.Validators; |
| use Bindo.Validators.Elaboration_Order_Validators; |
| |
| with Bindo.Writers; |
| use Bindo.Writers; |
| use Bindo.Writers.ALI_Writers; |
| use Bindo.Writers.Dependency_Writers; |
| use Bindo.Writers.Elaboration_Order_Writers; |
| use Bindo.Writers.Invocation_Graph_Writers; |
| use Bindo.Writers.Library_Graph_Writers; |
| use Bindo.Writers.Phase_Writers; |
| use Bindo.Writers.Unit_Closure_Writers; |
| |
| with GNAT; use GNAT; |
| with GNAT.Graphs; use GNAT.Graphs; |
| |
| package body Bindo.Elaborators is |
| |
| -- The following type defines the advancement of the elaboration order |
| -- algorithm in terms of steps. |
| |
| type Elaboration_Order_Step is new Natural; |
| |
| Initial_Step : constant Elaboration_Order_Step := |
| Elaboration_Order_Step'First; |
| |
| ---------------------------------------------- |
| -- Invocation_And_Library_Graph_Elaborators -- |
| ---------------------------------------------- |
| |
| package body Invocation_And_Library_Graph_Elaborators is |
| |
| ----------------------- |
| -- Local subprograms -- |
| ----------------------- |
| |
| procedure Create_Component_Vertex_Sets |
| (G : Library_Graph; |
| Comp : Component_Id; |
| Elaborable_Vertices : out LGV_Sets.Membership_Set; |
| Waiting_Vertices : out LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step); |
| pragma Inline (Create_Component_Vertex_Sets); |
| -- Split all vertices of component Comp of library graph G as follows: |
| -- |
| -- * Elaborable vertices are added to set Elaborable_Vertices. |
| -- |
| -- * Vertices that are still waiting on their predecessors to be |
| -- elaborated are added to set Waiting_Vertices. |
| -- |
| -- Step is the current step in the elaboration order. |
| |
| procedure Create_Vertex_Sets |
| (G : Library_Graph; |
| Elaborable_Vertices : out LGV_Sets.Membership_Set; |
| Waiting_Vertices : out LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step); |
| pragma Inline (Create_Vertex_Sets); |
| -- Split all vertices of library graph G as follows: |
| -- |
| -- * Elaborable vertices are added to set Elaborable_Vertices. |
| -- |
| -- * Vertices that are still waiting on their predecessors to be |
| -- elaborated are added to set Waiting_Vertices. |
| -- |
| -- Step is the current step in the elaboration order. |
| |
| procedure Elaborate_Component |
| (G : Library_Graph; |
| Comp : Component_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Order : in out Unit_Id_Table; |
| Step : Elaboration_Order_Step); |
| pragma Inline (Elaborate_Component); |
| -- Elaborate as many vertices as possible that appear in component Comp |
| -- of library graph G. The sets contain vertices arranged as follows: |
| -- |
| -- * All_Elaborable_Vertices - all elaborable vertices in the library |
| -- graph. |
| -- |
| -- * All_Waiting_Vertices - all vertices in the library graph that are |
| -- waiting on predecessors to be elaborated. |
| -- |
| -- Order is the elaboration order. Step denotes the current step in the |
| -- elaboration order. |
| |
| procedure Elaborate_Library_Graph |
| (G : Library_Graph; |
| Order : out Unit_Id_Table; |
| Status : out Elaboration_Order_Status); |
| pragma Inline (Elaborate_Library_Graph); |
| -- Elaborate as many vertices as possible of library graph G. Order is |
| -- the elaboration order. Status is the condition of the elaboration |
| -- order. |
| |
| procedure Elaborate_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Order : in out Unit_Id_Table; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Elaborate_Vertex); |
| -- Elaborate vertex Vertex of library graph G by adding its unit to |
| -- elaboration order Order. The routine updates awaiting successors |
| -- where applicable. The sets contain vertices arranged as follows: |
| -- |
| -- * All_Elaborable_Vertices - all elaborable vertices in the library |
| -- graph. |
| -- |
| -- * All_Waiting_Vertices - all vertices in the library graph that are |
| -- waiting on predecessors to be elaborated. |
| -- |
| -- * Comp_Elaborable_Vertices - all elaborable vertices found in the |
| -- component of Vertex. |
| -- |
| -- * Comp_Waiting_Vertices - all vertices found in the component of |
| -- Vertex that are still waiting on predecessors to be elaborated. |
| -- |
| -- Order denotes the elaboration order. Step is the current step in the |
| -- elaboration order. Indent denotes the desired indentation level for |
| -- tracing. |
| |
| function Find_Best_Elaborable_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) return Library_Graph_Vertex_Id; |
| pragma Inline (Find_Best_Elaborable_Vertex); |
| -- Find the best vertex of library graph G from membership set S that |
| -- can be elaborated. Step is the current step in the elaboration order. |
| -- Indent is the desired indentation level for tracing. |
| |
| function Find_Best_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Is_Suitable_Vertex : LGV_Predicate_Ptr; |
| Compare_Vertices : LGV_Comparator_Ptr; |
| Initial_Best_Msg : String; |
| Subsequent_Best_Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| return Library_Graph_Vertex_Id; |
| pragma Inline (Find_Best_Vertex); |
| -- Find the best vertex of library graph G from membership set S which |
| -- satisfies predicate Is_Suitable_Vertex and is preferred by comparator |
| -- Compare_Vertices. Initial_Best_Msg is emitted on the first candidate |
| -- vertex. Subsequent_Best_Msg is emitted whenever a better vertex is |
| -- discovered. Step is the current step in the elaboration order. Indent |
| -- is the desired indentation level for tracing. |
| |
| function Find_Best_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) return Library_Graph_Vertex_Id; |
| pragma Inline (Find_Best_Weakly_Elaborable_Vertex); |
| -- Find the best vertex of library graph G from membership set S that |
| -- can be weakly elaborated. Step is the current step in the elaboration |
| -- order. Indent is the desired indentation level for tracing. |
| |
| function Has_Elaborable_Body |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean; |
| pragma Inline (Has_Elaborable_Body); |
| -- Determine whether vertex Vertex of library graph G has a body that is |
| -- elaborable. It is assumed that the vertex has been elaborated. |
| |
| procedure Insert_Elaborable_Successor |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Insert_Elaborable_Successor); |
| -- Add elaborable successor Vertex of library graph G to membership set |
| -- Elaborable_Vertices and remove it from both All_Waiting_Vertices and |
| -- Comp_Waiting_Vertices. Msg is a message emitted for tracing purposes. |
| -- Step is the current step in the elaboration order. Indent denotes the |
| -- desired indentation level for tracing. |
| |
| procedure Insert_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Set : LGV_Sets.Membership_Set; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Insert_Vertex); |
| -- Add vertex Vertex of library graph G to membership set Set. Msg is |
| -- a message emitted for tracing purposes. Step is the current step in |
| -- the elaboration order. Indent is the desired indentation level for |
| -- tracing. |
| |
| function Is_Better_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind; |
| pragma Inline (Is_Better_Elaborable_Vertex); |
| -- Determine whether vertex Vertex of library graph G is a better choice |
| -- for elaboration compared to vertex Compared_To. |
| |
| function Is_Better_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind; |
| pragma Inline (Is_Better_Weakly_Elaborable_Vertex); |
| -- Determine whether vertex Vertex of library graph G is a better choice |
| -- for weak elaboration compared to vertex Compared_To. |
| |
| function Is_Suitable_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean; |
| pragma Inline (Is_Suitable_Elaborable_Vertex); |
| -- Determine whether vertex Vertex of library graph G is suitable for |
| -- elaboration. |
| |
| function Is_Suitable_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean; |
| pragma Inline (Is_Suitable_Weakly_Elaborable_Vertex); |
| -- Determine whether vertex Vertex of library graph G is suitable for |
| -- weak elaboration. |
| |
| procedure Set_Unit_Elaboration_Positions (Order : Unit_Id_Table); |
| pragma Inline (Set_Unit_Elaboration_Positions); |
| -- Set the ALI.Units positions of all elaboration units in order Order |
| |
| procedure Trace_Component |
| (G : Library_Graph; |
| Comp : Component_Id; |
| Msg : String; |
| Step : Elaboration_Order_Step); |
| pragma Inline (Trace_Component); |
| -- Write elaboration-related information for component Comp of library |
| -- graph G to standard output, starting with message Msg. Step is the |
| -- current step in the elaboration order. |
| |
| procedure Trace_Step (Step : Elaboration_Order_Step); |
| pragma Inline (Trace_Step); |
| -- Write current step Step of the elaboration order to standard output |
| |
| procedure Trace_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Trace_Vertex); |
| -- Write elaboration-related information for vertex Vertex of library |
| -- graph G to standard output, starting with message Msg. Step is the |
| -- current step in the elaboration order. Indent denotes the desired |
| -- indentation level for tracing. |
| |
| procedure Trace_Vertices |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Set_Msg : String; |
| Vertex_Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Trace_Vertices); |
| -- Write the candidate vertices of library graph G present in membership |
| -- set Set to standard output, starting with message Set_Msg. Vertex_Msg |
| -- is the message emitted prior to each vertex. Step denotes the current |
| -- step in the elaboration order. Indent denotes the desired indentation |
| -- level for tracing. |
| |
| procedure Update_Successor |
| (G : Library_Graph; |
| Edge : Library_Graph_Edge_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Update_Successor); |
| -- Notify the successor of edge Edge of library graph G along with its |
| -- component that their predecessor has just been elaborated. This may |
| -- cause new vertices to become elaborable. The sets contain vertices |
| -- arranged as follows: |
| -- |
| -- * All_Elaborable_Vertices - all elaborable vertices in the library |
| -- graph. |
| -- |
| -- * All_Waiting_Vertices - all vertices in the library graph that are |
| -- waiting on predecessors to be elaborated. |
| -- |
| -- * Comp_Elaborable_Vertices - all elaborable vertices found in the |
| -- component of Vertex. |
| -- |
| -- * Comp_Waiting_Vertices - all vertices found in the component of |
| -- Vertex that are still waiting on predecessors to be elaborated. |
| -- |
| -- Step is the current step in the elaboration order. Indent denotes the |
| -- desired indentation level for tracing. |
| |
| procedure Update_Successors |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level); |
| pragma Inline (Update_Successors); |
| -- Notify all successors of vertex Vertex of library graph G along with |
| -- their components that their predecessor has just been elaborated. |
| -- This may cause new vertices to become elaborable. The sets contain |
| -- vertices arranged as follows: |
| -- |
| -- * All_Elaborable_Vertices - all elaborable vertices in the library |
| -- graph. |
| -- |
| -- * All_Waiting_Vertices - all vertices in the library graph that are |
| -- waiting on predecessors to be elaborated. |
| -- |
| -- * Comp_Elaborable_Vertices - all elaborable vertices found in the |
| -- component of Vertex. |
| -- |
| -- * Comp_Waiting_Vertices - all vertices found in the component of |
| -- Vertex that are still waiting on predecessors to be elaborated. |
| -- |
| -- Step is the current step in the elaboration order. Indent denotes the |
| -- desired indentation level for tracing. |
| |
| ---------------------------------- |
| -- Create_Component_Vertex_Sets -- |
| ---------------------------------- |
| |
| procedure Create_Component_Vertex_Sets |
| (G : Library_Graph; |
| Comp : Component_Id; |
| Elaborable_Vertices : out LGV_Sets.Membership_Set; |
| Waiting_Vertices : out LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step) |
| is |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Comp)); |
| |
| Num_Of_Vertices : constant Natural := |
| Number_Of_Component_Vertices (G, Comp); |
| |
| Iter : Component_Vertex_Iterator; |
| Vertex : Library_Graph_Vertex_Id; |
| |
| begin |
| Elaborable_Vertices := LGV_Sets.Create (Num_Of_Vertices); |
| Waiting_Vertices := LGV_Sets.Create (Num_Of_Vertices); |
| |
| Iter := Iterate_Component_Vertices (G, Comp); |
| while Has_Next (Iter) loop |
| Next (Iter, Vertex); |
| |
| -- Add the vertex to the proper set depending on whether it can be |
| -- elaborated. |
| |
| if Is_Elaborable_Vertex (G, Vertex) then |
| Insert_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Set => Elaborable_Vertices, |
| Msg => "add elaborable component vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| |
| else |
| Insert_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Set => Waiting_Vertices, |
| Msg => "add waiting component vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| end if; |
| end loop; |
| end Create_Component_Vertex_Sets; |
| |
| ------------------------ |
| -- Create_Vertex_Sets -- |
| ------------------------ |
| |
| procedure Create_Vertex_Sets |
| (G : Library_Graph; |
| Elaborable_Vertices : out LGV_Sets.Membership_Set; |
| Waiting_Vertices : out LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step) |
| is |
| pragma Assert (Present (G)); |
| |
| Num_Of_Vertices : constant Natural := Number_Of_Vertices (G); |
| |
| Iter : Library_Graphs.All_Vertex_Iterator; |
| Vertex : Library_Graph_Vertex_Id; |
| |
| begin |
| Elaborable_Vertices := LGV_Sets.Create (Num_Of_Vertices); |
| Waiting_Vertices := LGV_Sets.Create (Num_Of_Vertices); |
| |
| Iter := Iterate_All_Vertices (G); |
| while Has_Next (Iter) loop |
| Next (Iter, Vertex); |
| |
| -- Add the vertex to the proper set depending on whether it can be |
| -- elaborated. |
| |
| if Is_Elaborable_Vertex (G, Vertex) then |
| Insert_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Set => Elaborable_Vertices, |
| Msg => "add elaborable vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| |
| else |
| Insert_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Set => Waiting_Vertices, |
| Msg => "add waiting vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| end if; |
| end loop; |
| end Create_Vertex_Sets; |
| |
| ------------------------- |
| -- Elaborate_Component -- |
| ------------------------- |
| |
| procedure Elaborate_Component |
| (G : Library_Graph; |
| Comp : Component_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Order : in out Unit_Id_Table; |
| Step : Elaboration_Order_Step) |
| is |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Vertex : Library_Graph_Vertex_Id; |
| |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Comp)); |
| pragma Assert (LGV_Sets.Present (All_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (All_Waiting_Vertices)); |
| |
| Trace_Component |
| (G => G, |
| Comp => Comp, |
| Msg => "elaborating component", |
| Step => Step); |
| |
| -- Divide all vertices of the component into an elaborable and |
| -- waiting vertex set. |
| |
| Create_Component_Vertex_Sets |
| (G => G, |
| Comp => Comp, |
| Elaborable_Vertices => Comp_Elaborable_Vertices, |
| Waiting_Vertices => Comp_Waiting_Vertices, |
| Step => Step); |
| |
| loop |
| Trace_Vertices |
| (G => G, |
| Set => Comp_Elaborable_Vertices, |
| Set_Msg => "elaborable component vertices", |
| Vertex_Msg => "elaborable component vertex", |
| Step => Step, |
| Indent => Nested_Indentation); |
| |
| Trace_Vertices |
| (G => G, |
| Set => Comp_Waiting_Vertices, |
| Set_Msg => "waiting component vertices", |
| Vertex_Msg => "waiting component vertex", |
| Step => Step, |
| Indent => Nested_Indentation); |
| |
| Vertex := |
| Find_Best_Elaborable_Vertex |
| (G => G, |
| Set => Comp_Elaborable_Vertices, |
| Step => Step, |
| Indent => Nested_Indentation); |
| |
| -- The component lacks an elaborable vertex. This indicates that |
| -- either all vertices of the component have been elaborated or |
| -- the graph has a circularity. Locate the best weak vertex that |
| -- was compiled with the dynamic model to elaborate from the set |
| -- waiting vertices. This action assumes that certain invocations |
| -- will not take place at elaboration time. An order produced in |
| -- this fashion may fail an ABE check at run time. |
| |
| if not Present (Vertex) then |
| Vertex := |
| Find_Best_Weakly_Elaborable_Vertex |
| (G => G, |
| Set => Comp_Waiting_Vertices, |
| Step => Step, |
| Indent => Nested_Indentation); |
| end if; |
| |
| -- Stop the elaboration when either all vertices of the component |
| -- have been elaborated, or the graph contains a circularity. |
| |
| exit when not Present (Vertex); |
| |
| -- Try to elaborate as many vertices within the component as |
| -- possible. Each successful elaboration signals the appropriate |
| -- successors and components that they have one less predecessor |
| -- to wait on. |
| |
| Elaborate_Vertex |
| (G => G, |
| Vertex => Vertex, |
| All_Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Elaborable_Vertices => Comp_Elaborable_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Order => Order, |
| Step => Step, |
| Indent => Nested_Indentation); |
| end loop; |
| |
| LGV_Sets.Destroy (Comp_Elaborable_Vertices); |
| LGV_Sets.Destroy (Comp_Waiting_Vertices); |
| end Elaborate_Component; |
| |
| ----------------------------- |
| -- Elaborate_Library_Graph -- |
| ----------------------------- |
| |
| procedure Elaborate_Library_Graph |
| (G : Library_Graph; |
| Order : out Unit_Id_Table; |
| Status : out Elaboration_Order_Status) |
| is |
| Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Vertex : Library_Graph_Vertex_Id; |
| Waiting_Vertices : LGV_Sets.Membership_Set; |
| |
| begin |
| pragma Assert (Present (G)); |
| |
| Step := Initial_Step; |
| |
| -- Divide all vertices of the library graph into an elaborable and |
| -- waiting vertex set. |
| |
| Create_Vertex_Sets |
| (G => G, |
| Elaborable_Vertices => Elaborable_Vertices, |
| Waiting_Vertices => Waiting_Vertices, |
| Step => Step); |
| |
| loop |
| Step := Step + 1; |
| |
| Trace_Vertices |
| (G => G, |
| Set => Elaborable_Vertices, |
| Set_Msg => "elaborable vertices", |
| Vertex_Msg => "elaborable vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| |
| Trace_Vertices |
| (G => G, |
| Set => Waiting_Vertices, |
| Set_Msg => "waiting vertices", |
| Vertex_Msg => "waiting vertex", |
| Step => Step, |
| Indent => No_Indentation); |
| |
| Vertex := |
| Find_Best_Elaborable_Vertex |
| (G => G, |
| Set => Elaborable_Vertices, |
| Step => Step, |
| Indent => No_Indentation); |
| |
| -- The graph lacks an elaborable vertex. This indicates that |
| -- either all vertices have been elaborated or the graph has a |
| -- circularity. Find the best weak vertex that was compiled with |
| -- the dynamic model to elaborate from set of waiting vertices. |
| -- This action assumes that certain invocations will not take |
| -- place at elaboration time. An order produced in this fashion |
| -- may fail an ABE check at run time. |
| |
| if not Present (Vertex) then |
| Vertex := |
| Find_Best_Weakly_Elaborable_Vertex |
| (G => G, |
| Set => Waiting_Vertices, |
| Step => Step, |
| Indent => No_Indentation); |
| end if; |
| |
| -- Stop the elaboration when either all vertices of the graph have |
| -- been elaborated, or the graph contains a circularity. |
| |
| exit when not Present (Vertex); |
| |
| -- Elaborate the component of the vertex by trying to elaborate as |
| -- many vertices within the component as possible. Each successful |
| -- elaboration signals the appropriate successors and components |
| -- that they have one less predecessor to wait on. |
| |
| Elaborate_Component |
| (G => G, |
| Comp => Component (G, Vertex), |
| All_Elaborable_Vertices => Elaborable_Vertices, |
| All_Waiting_Vertices => Waiting_Vertices, |
| Order => Order, |
| Step => Step); |
| end loop; |
| |
| -- The graph contains an Elaborate_All circularity when at least one |
| -- edge subject to the related pragma appears in a component. |
| |
| if Has_Elaborate_All_Cycle (G) then |
| Status := Order_Has_Elaborate_All_Circularity; |
| |
| -- The graph contains a circularity when at least one vertex failed |
| -- to elaborate. |
| |
| elsif LGV_Sets.Size (Waiting_Vertices) /= 0 then |
| Status := Order_Has_Circularity; |
| |
| -- Otherwise the elaboration order is satisfactory |
| |
| else |
| Status := Order_OK; |
| end if; |
| |
| LGV_Sets.Destroy (Elaborable_Vertices); |
| LGV_Sets.Destroy (Waiting_Vertices); |
| end Elaborate_Library_Graph; |
| |
| --------------------- |
| -- Elaborate_Units -- |
| --------------------- |
| |
| procedure Elaborate_Units |
| (Order : out Unit_Id_Table; |
| Main_Lib_File : File_Name_Type) |
| is |
| pragma Unreferenced (Main_Lib_File); |
| |
| Inv_Graph : Invocation_Graph; |
| Lib_Graph : Library_Graph; |
| Status : Elaboration_Order_Status; |
| |
| begin |
| Start_Phase (Unit_Elaboration); |
| |
| -- Initialize all unit-related data structures and gather all units |
| -- that need elaboration. |
| |
| Initialize_Units; |
| Collect_Elaborable_Units; |
| |
| -- Create the library graph that captures the dependencies between |
| -- library items. |
| |
| Lib_Graph := Build_Library_Graph; |
| |
| -- Create the invocation graph that represents the flow of execution |
| |
| Inv_Graph := Build_Invocation_Graph (Lib_Graph); |
| |
| -- Traverse the invocation graph starting from elaboration code in |
| -- order to discover transitions of the execution flow from a unit |
| -- to a unit that result in extra edges within the library graph. |
| |
| Augment_Library_Graph (Inv_Graph); |
| |
| -- Create the component graph by collapsing all library items into |
| -- library units and traversing the library graph. |
| |
| Find_Components (Lib_Graph); |
| |
| -- Output the contents of the ALI tables and both graphs to standard |
| -- output now that they have been fully decorated. |
| |
| Write_ALI_Tables; |
| Write_Invocation_Graph (Inv_Graph); |
| Write_Library_Graph (Lib_Graph); |
| |
| -- Traverse the library graph to determine the elaboration order of |
| -- units. |
| |
| Elaborate_Library_Graph (Lib_Graph, Order, Status); |
| |
| -- The elaboration order is satisfactory |
| |
| if Status = Order_OK then |
| Validate_Elaboration_Order (Order); |
| |
| -- Set attribute Elab_Position of table ALI.Units for all units in |
| -- the elaboration order. |
| |
| Set_Unit_Elaboration_Positions (Order); |
| |
| -- Output the dependencies among units when switch -e (output |
| -- complete list of elaboration order dependencies) is active. |
| |
| Write_Dependencies (Lib_Graph); |
| |
| -- Output the elaboration order when switch -l (output chosen |
| -- elaboration order) is in effect. |
| |
| Write_Elaboration_Order (Order); |
| |
| -- Output the sources referenced in the closure of the order when |
| -- switch -R (list sources referenced in closure) is in effect. |
| |
| Write_Unit_Closure (Order); |
| |
| -- Otherwise the library graph contains at least one circularity |
| |
| else |
| Diagnose_Circularities (Inv_Graph); |
| end if; |
| |
| Destroy (Inv_Graph); |
| Destroy (Lib_Graph); |
| |
| -- Destroy all unit-related data structures |
| |
| Finalize_Units; |
| End_Phase (Unit_Elaboration); |
| |
| -- Halt the bind when there is no satisfactory elaboration order |
| |
| if Status /= Order_OK then |
| raise Unrecoverable_Error; |
| end if; |
| end Elaborate_Units; |
| |
| ---------------------- |
| -- Elaborate_Vertex -- |
| ---------------------- |
| |
| procedure Elaborate_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Order : in out Unit_Id_Table; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (Needs_Elaboration (G, Vertex)); |
| pragma Assert (LGV_Sets.Present (All_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (All_Waiting_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Waiting_Vertices)); |
| |
| Trace_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Msg => "elaborating vertex", |
| Step => Step, |
| Indent => Indent); |
| |
| -- Remove the vertex from both elaborable sets. This is needed when |
| -- the vertex is both an overall best candidate among all vertices, |
| -- and the best candidate within the component. |
| |
| LGV_Sets.Delete (All_Elaborable_Vertices, Vertex); |
| LGV_Sets.Delete (Comp_Elaborable_Vertices, Vertex); |
| |
| -- Remove the vertex from both waiting sets. This is needed when a |
| -- weakly elaborable vertex is both an overall best candidate among |
| -- all waiting vertices and the best waiting candidate within the |
| -- component. |
| |
| LGV_Sets.Delete (All_Waiting_Vertices, Vertex); |
| LGV_Sets.Delete (Comp_Waiting_Vertices, Vertex); |
| |
| -- Mark the vertex as elaborated in order to prevent further attempts |
| -- to re-elaborate it. |
| |
| Set_In_Elaboration_Order (G, Vertex); |
| |
| -- Add the unit represented by the vertex to the elaboration order |
| |
| Unit_Id_Tables.Append (Order, Unit (G, Vertex)); |
| |
| -- Notify all successors and their components that they have one |
| -- fewer predecessor to wait on. This may cause some successors to |
| -- be included in one of the sets. |
| |
| Update_Successors |
| (G => G, |
| Vertex => Vertex, |
| All_Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Elaborable_Vertices => Comp_Elaborable_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Step => Step, |
| Indent => Indent + Nested_Indentation); |
| |
| -- Elaborate an eligible completing body immediately after its spec. |
| -- This action satisfies the semantics of pragma Elaborate_Body. In |
| -- addition, it ensures that a body will not "drift" too far from its |
| -- spec in case invocation edges are removed from the library graph. |
| |
| if Has_Elaborable_Body (G, Vertex) then |
| Elaborate_Vertex |
| (G => G, |
| Vertex => Proper_Body (G, Vertex), |
| All_Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Elaborable_Vertices => Comp_Elaborable_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Order => Order, |
| Step => Step, |
| Indent => Indent); |
| end if; |
| end Elaborate_Vertex; |
| |
| --------------------------------- |
| -- Find_Best_Elaborable_Vertex -- |
| --------------------------------- |
| |
| function Find_Best_Elaborable_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) return Library_Graph_Vertex_Id |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (LGV_Sets.Present (Set)); |
| |
| return |
| Find_Best_Vertex |
| (G => G, |
| Set => Set, |
| Is_Suitable_Vertex => |
| Is_Suitable_Elaborable_Vertex'Access, |
| Compare_Vertices => |
| Is_Better_Elaborable_Vertex'Access, |
| Initial_Best_Msg => "initial best elaborable vertex", |
| Subsequent_Best_Msg => "better elaborable vertex", |
| Step => Step, |
| Indent => Indent); |
| end Find_Best_Elaborable_Vertex; |
| |
| ---------------------- |
| -- Find_Best_Vertex -- |
| ---------------------- |
| |
| function Find_Best_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Is_Suitable_Vertex : LGV_Predicate_Ptr; |
| Compare_Vertices : LGV_Comparator_Ptr; |
| Initial_Best_Msg : String; |
| Subsequent_Best_Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| return Library_Graph_Vertex_Id |
| is |
| Best_Vertex : Library_Graph_Vertex_Id; |
| Current_Vertex : Library_Graph_Vertex_Id; |
| Iter : LGV_Sets.Iterator; |
| |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (LGV_Sets.Present (Set)); |
| pragma Assert (Is_Suitable_Vertex /= null); |
| pragma Assert (Compare_Vertices /= null); |
| |
| -- Assume that there is no candidate |
| |
| Best_Vertex := No_Library_Graph_Vertex; |
| |
| -- Inspect all vertices in the set, looking for the best candidate |
| -- according to the comparator. |
| |
| Iter := LGV_Sets.Iterate (Set); |
| while LGV_Sets.Has_Next (Iter) loop |
| LGV_Sets.Next (Iter, Current_Vertex); |
| pragma Assert (Needs_Elaboration (G, Current_Vertex)); |
| |
| if Is_Suitable_Vertex.all (G, Current_Vertex) then |
| |
| -- A previous iteration already picked the best candidate. |
| -- Update the best candidate when the current vertex is a |
| -- better choice. |
| |
| if Present (Best_Vertex) then |
| if Compare_Vertices.all |
| (G => G, |
| Vertex => Current_Vertex, |
| Compared_To => Best_Vertex) = Higher_Precedence |
| then |
| Best_Vertex := Current_Vertex; |
| |
| Trace_Vertex |
| (G => G, |
| Vertex => Best_Vertex, |
| Msg => Subsequent_Best_Msg, |
| Step => Step, |
| Indent => Indent); |
| end if; |
| |
| -- Otherwise this is the first candidate |
| |
| else |
| Best_Vertex := Current_Vertex; |
| |
| Trace_Vertex |
| (G => G, |
| Vertex => Best_Vertex, |
| Msg => Initial_Best_Msg, |
| Step => Step, |
| Indent => Indent); |
| end if; |
| end if; |
| end loop; |
| |
| return Best_Vertex; |
| end Find_Best_Vertex; |
| |
| ---------------------------------------- |
| -- Find_Best_Weakly_Elaborable_Vertex -- |
| ---------------------------------------- |
| |
| function Find_Best_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) return Library_Graph_Vertex_Id |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (LGV_Sets.Present (Set)); |
| |
| return |
| Find_Best_Vertex |
| (G => G, |
| Set => Set, |
| Is_Suitable_Vertex => |
| Is_Suitable_Weakly_Elaborable_Vertex'Access, |
| Compare_Vertices => |
| Is_Better_Weakly_Elaborable_Vertex'Access, |
| Initial_Best_Msg => "initial best weakly elaborable vertex", |
| Subsequent_Best_Msg => "better weakly elaborable vertex", |
| Step => Step, |
| Indent => Indent); |
| end Find_Best_Weakly_Elaborable_Vertex; |
| |
| ------------------------- |
| -- Has_Elaborable_Body -- |
| ------------------------- |
| |
| function Has_Elaborable_Body |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| |
| -- The body of an already-elaborated spec subject to Elaborate_Body |
| -- is always elaborable. |
| |
| if Is_Spec_With_Elaborate_Body (G, Vertex) then |
| return True; |
| |
| elsif Is_Spec_With_Body (G, Vertex) then |
| return Is_Elaborable_Vertex (G, Proper_Body (G, Vertex)); |
| end if; |
| |
| return False; |
| end Has_Elaborable_Body; |
| |
| --------------------------------- |
| -- Insert_Elaborable_Successor -- |
| --------------------------------- |
| |
| procedure Insert_Elaborable_Successor |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (LGV_Sets.Present (Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (All_Waiting_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Waiting_Vertices)); |
| |
| Complement : constant Library_Graph_Vertex_Id := |
| Complementary_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Force_Complement => False); |
| |
| begin |
| -- Remove the successor from both waiting vertex sets because it may |
| -- be the best vertex to elaborate across the whole graph and within |
| -- its component. |
| |
| LGV_Sets.Delete (All_Waiting_Vertices, Vertex); |
| LGV_Sets.Delete (Comp_Waiting_Vertices, Vertex); |
| |
| Insert_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Set => Elaborable_Vertices, |
| Msg => Msg, |
| Step => Step, |
| Indent => Indent); |
| |
| if Present (Complement) then |
| |
| -- Remove the complement of the successor from both waiting vertex |
| -- sets because it may be the best vertex to elaborate across the |
| -- whole graph and within its component. |
| |
| LGV_Sets.Delete (All_Waiting_Vertices, Complement); |
| LGV_Sets.Delete (Comp_Waiting_Vertices, Complement); |
| |
| Insert_Vertex |
| (G => G, |
| Vertex => Complement, |
| Set => Elaborable_Vertices, |
| Msg => Msg, |
| Step => Step, |
| Indent => Indent); |
| end if; |
| end Insert_Elaborable_Successor; |
| |
| ------------------- |
| -- Insert_Vertex -- |
| ------------------- |
| |
| procedure Insert_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Set : LGV_Sets.Membership_Set; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (Needs_Elaboration (G, Vertex)); |
| pragma Assert (LGV_Sets.Present (Set)); |
| |
| -- Nothing to do when the vertex is already present in the set |
| |
| if LGV_Sets.Contains (Set, Vertex) then |
| return; |
| end if; |
| |
| Trace_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Msg => Msg, |
| Step => Step, |
| Indent => Indent); |
| |
| -- Add the vertex to the set |
| |
| LGV_Sets.Insert (Set, Vertex); |
| end Insert_Vertex; |
| |
| --------------------------------- |
| -- Is_Better_Elaborable_Vertex -- |
| --------------------------------- |
| |
| function Is_Better_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (Present (Compared_To)); |
| |
| -- Prefer a spec with Elaborate_Body over its corresponding body |
| |
| if Is_Elaborate_Body_Pair |
| (G => G, |
| Spec_Vertex => Vertex, |
| Body_Vertex => Compared_To) |
| then |
| return Higher_Precedence; |
| |
| elsif Is_Elaborate_Body_Pair |
| (G => G, |
| Spec_Vertex => Compared_To, |
| Body_Vertex => Vertex) |
| then |
| return Lower_Precedence; |
| |
| -- Prefer a predefined unit over a non-predefined unit |
| |
| elsif Is_Predefined_Unit (G, Vertex) |
| and then not Is_Predefined_Unit (G, Compared_To) |
| then |
| return Higher_Precedence; |
| |
| elsif not Is_Predefined_Unit (G, Vertex) |
| and then Is_Predefined_Unit (G, Compared_To) |
| then |
| return Lower_Precedence; |
| |
| -- Prefer an internal unit over a non-internal unit |
| |
| elsif Is_Internal_Unit (G, Vertex) |
| and then not Is_Internal_Unit (G, Compared_To) |
| then |
| return Higher_Precedence; |
| |
| elsif not Is_Internal_Unit (G, Vertex) |
| and then Is_Internal_Unit (G, Compared_To) |
| then |
| return Lower_Precedence; |
| |
| -- Prefer a preelaborated unit over a non-preelaborated unit |
| |
| elsif Is_Preelaborated_Unit (G, Vertex) |
| and then not Is_Preelaborated_Unit (G, Compared_To) |
| then |
| return Higher_Precedence; |
| |
| elsif not Is_Preelaborated_Unit (G, Vertex) |
| and then Is_Preelaborated_Unit (G, Compared_To) |
| then |
| return Lower_Precedence; |
| |
| -- Otherwise default to lexicographical order to ensure deterministic |
| -- behavior. |
| |
| elsif Uname_Less (Name (G, Vertex), Name (G, Compared_To)) then |
| return Higher_Precedence; |
| |
| else |
| return Lower_Precedence; |
| end if; |
| end Is_Better_Elaborable_Vertex; |
| |
| ---------------------------------------- |
| -- Is_Better_Weakly_Elaborable_Vertex -- |
| ---------------------------------------- |
| |
| function Is_Better_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind |
| is |
| Comp_Strong_Preds : Natural; |
| Comp_Weak_Preds : Natural; |
| Vertex_Strong_Preds : Natural; |
| Vertex_Weak_Preds : Natural; |
| |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (Present (Compared_To)); |
| |
| -- Obtain the number of pending predecessors for both candidates, |
| -- taking into account Elaborate_Body pairs. |
| |
| Pending_Predecessors_For_Elaboration |
| (G => G, |
| Vertex => Vertex, |
| Strong_Preds => Vertex_Strong_Preds, |
| Weak_Preds => Vertex_Weak_Preds); |
| |
| Pending_Predecessors_For_Elaboration |
| (G => G, |
| Vertex => Compared_To, |
| Strong_Preds => Comp_Strong_Preds, |
| Weak_Preds => Comp_Weak_Preds); |
| |
| -- Neither candidate should be waiting on strong predecessors, |
| -- otherwise the candidate cannot be weakly elaborated. |
| |
| pragma Assert (Vertex_Strong_Preds = 0); |
| pragma Assert (Comp_Strong_Preds = 0); |
| |
| -- Prefer a unit with fewer weak predecessors over a unit with more |
| -- weak predecessors. |
| |
| if Vertex_Weak_Preds < Comp_Weak_Preds then |
| return Higher_Precedence; |
| |
| elsif Vertex_Weak_Preds > Comp_Weak_Preds then |
| return Lower_Precedence; |
| |
| -- Otherwise default to lexicographical order to ensure deterministic |
| -- behavior. |
| |
| elsif Uname_Less (Name (G, Vertex), Name (G, Compared_To)) then |
| return Higher_Precedence; |
| |
| else |
| return Lower_Precedence; |
| end if; |
| end Is_Better_Weakly_Elaborable_Vertex; |
| |
| ----------------------------------- |
| -- Is_Suitable_Elaborable_Vertex -- |
| ----------------------------------- |
| |
| function Is_Suitable_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| |
| -- A vertex is suitable for elaboration as long it is not waiting on |
| -- any predecessors, ignoring the static or dynamic model. |
| |
| return Is_Elaborable_Vertex (G, Vertex); |
| end Is_Suitable_Elaborable_Vertex; |
| |
| ------------------------------------------ |
| -- Is_Suitable_Weakly_Elaborable_Vertex -- |
| ------------------------------------------ |
| |
| function Is_Suitable_Weakly_Elaborable_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id) return Boolean |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| |
| -- A vertex is suitable for weak elaboration when it is waiting on |
| -- weak predecessors only, and the unit it represents was compiled |
| -- using the dynamic model. |
| |
| return |
| Is_Dynamically_Elaborated (G, Vertex) |
| and then Is_Weakly_Elaborable_Vertex (G, Vertex); |
| end Is_Suitable_Weakly_Elaborable_Vertex; |
| |
| ------------------------------------ |
| -- Set_Unit_Elaboration_Positions -- |
| ------------------------------------ |
| |
| procedure Set_Unit_Elaboration_Positions (Order : Unit_Id_Table) is |
| U_Id : Unit_Id; |
| |
| begin |
| for Position in Unit_Id_Tables.First .. |
| Unit_Id_Tables.Last (Order) |
| loop |
| U_Id := Order.Table (Position); |
| |
| ALI.Units.Table (U_Id).Elab_Position := Position; |
| end loop; |
| end Set_Unit_Elaboration_Positions; |
| |
| --------------------- |
| -- Trace_Component -- |
| --------------------- |
| |
| procedure Trace_Component |
| (G : Library_Graph; |
| Comp : Component_Id; |
| Msg : String; |
| Step : Elaboration_Order_Step) |
| is |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Comp)); |
| |
| -- Nothing to do when switch -d_T (output elaboration order and cycle |
| -- detection trace information) is not in effect. |
| |
| if not Debug_Flag_Underscore_TT then |
| return; |
| end if; |
| |
| Trace_Step (Step); |
| Write_Str (Msg); |
| Write_Str (" (Comp_Id_"); |
| Write_Int (Int (Comp)); |
| Write_Str (")"); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Nested_Indentation); |
| Write_Str ("pending strong predecessors: "); |
| Write_Num (Int (Pending_Strong_Predecessors (G, Comp))); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Nested_Indentation); |
| Write_Str ("pending weak predecessors : "); |
| Write_Num (Int (Pending_Weak_Predecessors (G, Comp))); |
| Write_Eol; |
| end Trace_Component; |
| |
| ---------------- |
| -- Trace_Step -- |
| ---------------- |
| |
| procedure Trace_Step (Step : Elaboration_Order_Step) is |
| begin |
| -- Nothing to do when switch -d_T (output elaboration order and cycle |
| -- detection trace information) is not in effect. |
| |
| if not Debug_Flag_Underscore_TT then |
| return; |
| end if; |
| |
| Write_Num |
| (Val => Int (Step), |
| Val_Indent => Step_Column); |
| Write_Str (": "); |
| end Trace_Step; |
| |
| ------------------ |
| -- Trace_Vertex -- |
| ------------------ |
| |
| procedure Trace_Vertex |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| |
| Attr_Indent : constant Indentation_Level := |
| Indent + Nested_Indentation; |
| Comp : constant Component_Id := Component (G, Vertex); |
| |
| begin |
| -- Nothing to do when switch -d_T (output elaboration order and cycle |
| -- detection trace information) is not in effect. |
| |
| if not Debug_Flag_Underscore_TT then |
| return; |
| end if; |
| |
| Trace_Step (Step); |
| Indent_By (Indent); |
| Write_Str (Msg); |
| Write_Str (" (LGV_Id_"); |
| Write_Int (Int (Vertex)); |
| Write_Str (")"); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("name = "); |
| Write_Name (Name (G, Vertex)); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("Component (Comp_Id_"); |
| Write_Int (Int (Comp)); |
| Write_Str (")"); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("pending strong predecessors: "); |
| Write_Num (Int (Pending_Strong_Predecessors (G, Vertex))); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("pending weak predecessors : "); |
| Write_Num (Int (Pending_Weak_Predecessors (G, Vertex))); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("pending strong components : "); |
| Write_Num (Int (Pending_Strong_Predecessors (G, Comp))); |
| Write_Eol; |
| |
| Trace_Step (Step); |
| Indent_By (Attr_Indent); |
| Write_Str ("pending weak components : "); |
| Write_Num (Int (Pending_Weak_Predecessors (G, Comp))); |
| Write_Eol; |
| end Trace_Vertex; |
| |
| -------------------- |
| -- Trace_Vertices -- |
| -------------------- |
| |
| procedure Trace_Vertices |
| (G : Library_Graph; |
| Set : LGV_Sets.Membership_Set; |
| Set_Msg : String; |
| Vertex_Msg : String; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| Vertex_Indent : constant Indentation_Level := |
| Indent + Nested_Indentation; |
| |
| Iter : LGV_Sets.Iterator; |
| Vertex : Library_Graph_Vertex_Id; |
| |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (LGV_Sets.Present (Set)); |
| |
| -- Nothing to do when switch -d_T (output elaboration order and cycle |
| -- detection trace information) is not in effect. |
| |
| if not Debug_Flag_Underscore_TT then |
| return; |
| end if; |
| |
| Trace_Step (Step); |
| Indent_By (Indent); |
| Write_Str (Set_Msg); |
| Write_Str (": "); |
| Write_Int (Int (LGV_Sets.Size (Set))); |
| Write_Eol; |
| |
| Iter := LGV_Sets.Iterate (Set); |
| while LGV_Sets.Has_Next (Iter) loop |
| LGV_Sets.Next (Iter, Vertex); |
| |
| Trace_Vertex |
| (G => G, |
| Vertex => Vertex, |
| Msg => Vertex_Msg, |
| Step => Step, |
| Indent => Vertex_Indent); |
| end loop; |
| end Trace_Vertices; |
| |
| ---------------------- |
| -- Update_Successor -- |
| ---------------------- |
| |
| procedure Update_Successor |
| (G : Library_Graph; |
| Edge : Library_Graph_Edge_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Edge)); |
| pragma Assert (LGV_Sets.Present (All_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (All_Waiting_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Waiting_Vertices)); |
| |
| Pred : constant Library_Graph_Vertex_Id := Predecessor (G, Edge); |
| Succ : constant Library_Graph_Vertex_Id := Successor (G, Edge); |
| |
| pragma Assert (Needs_Elaboration (G, Pred)); |
| pragma Assert (Needs_Elaboration (G, Succ)); |
| |
| In_Different_Components : constant Boolean := |
| not In_Same_Component |
| (G => G, |
| Left => Pred, |
| Right => Succ); |
| |
| Succ_Comp : constant Component_Id := Component (G, Succ); |
| Vertex_Indent : constant Indentation_Level := |
| Indent + Nested_Indentation; |
| |
| Iter : Component_Vertex_Iterator; |
| Vertex : Library_Graph_Vertex_Id; |
| |
| begin |
| Trace_Vertex |
| (G => G, |
| Vertex => Succ, |
| Msg => "updating successor", |
| Step => Step, |
| Indent => Indent); |
| |
| -- Notify the successor that it has one less predecessor to wait on. |
| -- This effectively eliminates the edge that links the two. |
| |
| Decrement_Pending_Predecessors |
| (G => G, |
| Vertex => Succ, |
| Edge => Edge); |
| |
| -- The predecessor and successor reside in different components. |
| -- Notify the successor component it has one fewer components to |
| -- wait on. |
| |
| if In_Different_Components then |
| Decrement_Pending_Predecessors |
| (G => G, |
| Comp => Succ_Comp, |
| Edge => Edge); |
| end if; |
| |
| -- At this point the successor may become elaborable when its final |
| -- predecessor or final predecessor component has been elaborated. |
| |
| if Is_Elaborable_Vertex (G, Succ) then |
| |
| -- The predecessor and successor reside in different components. |
| -- The successor must not be added to the candidates of Pred's |
| -- component because this will mix units from the two components. |
| -- Instead, the successor is added to the set of all elaborable |
| -- vertices. |
| |
| if In_Different_Components then |
| Insert_Elaborable_Successor |
| (G => G, |
| Vertex => Succ, |
| Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Msg => "add elaborable successor", |
| Step => Step, |
| Indent => Vertex_Indent); |
| |
| -- Otherwise the predecessor and successor reside within the same |
| -- component. Pred's component gains another elaborable vertex. |
| |
| else |
| Insert_Elaborable_Successor |
| (G => G, |
| Vertex => Succ, |
| Elaborable_Vertices => Comp_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Msg => |
| "add elaborable component successor", |
| Step => Step, |
| Indent => Vertex_Indent); |
| end if; |
| end if; |
| |
| -- At this point the successor component may become elaborable when |
| -- its final predecessor component is elaborated. This in turn may |
| -- allow vertices of the successor component to be elaborated. |
| |
| if In_Different_Components |
| and then Is_Elaborable_Component (G, Succ_Comp) |
| then |
| Iter := Iterate_Component_Vertices (G, Succ_Comp); |
| while Has_Next (Iter) loop |
| Next (Iter, Vertex); |
| |
| if Is_Elaborable_Vertex (G, Vertex) then |
| Insert_Elaborable_Successor |
| (G => G, |
| Vertex => Vertex, |
| Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Msg => "add elaborable vertex", |
| Step => Step, |
| Indent => Vertex_Indent); |
| end if; |
| end loop; |
| end if; |
| end Update_Successor; |
| |
| ----------------------- |
| -- Update_Successors -- |
| ----------------------- |
| |
| procedure Update_Successors |
| (G : Library_Graph; |
| Vertex : Library_Graph_Vertex_Id; |
| All_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| All_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Comp_Elaborable_Vertices : LGV_Sets.Membership_Set; |
| Comp_Waiting_Vertices : LGV_Sets.Membership_Set; |
| Step : Elaboration_Order_Step; |
| Indent : Indentation_Level) |
| is |
| Edge : Library_Graph_Edge_Id; |
| Iter : Edges_To_Successors_Iterator; |
| |
| begin |
| pragma Assert (Present (G)); |
| pragma Assert (Present (Vertex)); |
| pragma Assert (Needs_Elaboration (G, Vertex)); |
| pragma Assert (LGV_Sets.Present (All_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (All_Waiting_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Elaborable_Vertices)); |
| pragma Assert (LGV_Sets.Present (Comp_Waiting_Vertices)); |
| |
| Iter := Iterate_Edges_To_Successors (G, Vertex); |
| while Has_Next (Iter) loop |
| Next (Iter, Edge); |
| pragma Assert (Predecessor (G, Edge) = Vertex); |
| |
| Update_Successor |
| (G => G, |
| Edge => Edge, |
| All_Elaborable_Vertices => All_Elaborable_Vertices, |
| All_Waiting_Vertices => All_Waiting_Vertices, |
| Comp_Elaborable_Vertices => Comp_Elaborable_Vertices, |
| Comp_Waiting_Vertices => Comp_Waiting_Vertices, |
| Step => Step, |
| Indent => Indent); |
| end loop; |
| end Update_Successors; |
| end Invocation_And_Library_Graph_Elaborators; |
| |
| end Bindo.Elaborators; |