Mercurial > hg > CbC > CbC_gcc
diff gcc/ada/bindo-graphs.adb @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/ada/bindo-graphs.adb Thu Feb 13 11:34:05 2020 +0900 @@ -0,0 +1,5714 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- B I N D O . G R A P H S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2019, 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 Ada.Unchecked_Deallocation; + +with Butil; use Butil; +with Debug; use Debug; +with Output; use Output; + +with Bindo.Writers; +use Bindo.Writers; +use Bindo.Writers.Phase_Writers; + +package body Bindo.Graphs is + + ----------------------- + -- Local subprograms -- + ----------------------- + + function Sequence_Next_Cycle return Library_Graph_Cycle_Id; + pragma Inline (Sequence_Next_Cycle); + -- Generate a new unique library graph cycle handle + + function Sequence_Next_Edge return Invocation_Graph_Edge_Id; + pragma Inline (Sequence_Next_Edge); + -- Generate a new unique invocation graph edge handle + + function Sequence_Next_Edge return Library_Graph_Edge_Id; + pragma Inline (Sequence_Next_Edge); + -- Generate a new unique library graph edge handle + + function Sequence_Next_Vertex return Invocation_Graph_Vertex_Id; + pragma Inline (Sequence_Next_Vertex); + -- Generate a new unique invocation graph vertex handle + + function Sequence_Next_Vertex return Library_Graph_Vertex_Id; + pragma Inline (Sequence_Next_Vertex); + -- Generate a new unique library graph vertex handle + + ----------------------------------- + -- Destroy_Invocation_Graph_Edge -- + ----------------------------------- + + procedure Destroy_Invocation_Graph_Edge + (Edge : in out Invocation_Graph_Edge_Id) + is + pragma Unreferenced (Edge); + begin + null; + end Destroy_Invocation_Graph_Edge; + + --------------------------------- + -- Destroy_Library_Graph_Cycle -- + --------------------------------- + + procedure Destroy_Library_Graph_Cycle + (Cycle : in out Library_Graph_Cycle_Id) + is + pragma Unreferenced (Cycle); + begin + null; + end Destroy_Library_Graph_Cycle; + + -------------------------------- + -- Destroy_Library_Graph_Edge -- + -------------------------------- + + procedure Destroy_Library_Graph_Edge + (Edge : in out Library_Graph_Edge_Id) + is + pragma Unreferenced (Edge); + begin + null; + end Destroy_Library_Graph_Edge; + + ---------------------------------- + -- Destroy_Library_Graph_Vertex -- + ---------------------------------- + + procedure Destroy_Library_Graph_Vertex + (Vertex : in out Library_Graph_Vertex_Id) + is + pragma Unreferenced (Vertex); + begin + null; + end Destroy_Library_Graph_Vertex; + + -------------------------------- + -- Hash_Invocation_Graph_Edge -- + -------------------------------- + + function Hash_Invocation_Graph_Edge + (Edge : Invocation_Graph_Edge_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (Edge)); + + return Bucket_Range_Type (Edge); + end Hash_Invocation_Graph_Edge; + + ---------------------------------- + -- Hash_Invocation_Graph_Vertex -- + ---------------------------------- + + function Hash_Invocation_Graph_Vertex + (Vertex : Invocation_Graph_Vertex_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (Vertex)); + + return Bucket_Range_Type (Vertex); + end Hash_Invocation_Graph_Vertex; + + ------------------------------ + -- Hash_Library_Graph_Cycle -- + ------------------------------ + + function Hash_Library_Graph_Cycle + (Cycle : Library_Graph_Cycle_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (Cycle)); + + return Bucket_Range_Type (Cycle); + end Hash_Library_Graph_Cycle; + + ----------------------------- + -- Hash_Library_Graph_Edge -- + ----------------------------- + + function Hash_Library_Graph_Edge + (Edge : Library_Graph_Edge_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (Edge)); + + return Bucket_Range_Type (Edge); + end Hash_Library_Graph_Edge; + + ------------------------------- + -- Hash_Library_Graph_Vertex -- + ------------------------------- + + function Hash_Library_Graph_Vertex + (Vertex : Library_Graph_Vertex_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (Vertex)); + + return Bucket_Range_Type (Vertex); + end Hash_Library_Graph_Vertex; + + ----------------------- + -- Invocation_Graphs -- + ----------------------- + + package body Invocation_Graphs is + + ----------------------- + -- Local subprograms -- + ----------------------- + + procedure Free is + new Ada.Unchecked_Deallocation + (Invocation_Graph_Attributes, Invocation_Graph); + + function Get_IGE_Attributes + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) + return Invocation_Graph_Edge_Attributes; + pragma Inline (Get_IGE_Attributes); + -- Obtain the attributes of edge Edge of invocation graph G + + function Get_IGV_Attributes + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) + return Invocation_Graph_Vertex_Attributes; + pragma Inline (Get_IGV_Attributes); + -- Obtain the attributes of vertex Vertex of invocation graph G + + procedure Increment_Invocation_Graph_Edge_Count + (G : Invocation_Graph; + Kind : Invocation_Kind); + pragma Inline (Increment_Invocation_Graph_Edge_Count); + -- Increment the number of edges of king Kind in invocation graph G by + -- one. + + function Is_Elaboration_Root + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Boolean; + pragma Inline (Is_Elaboration_Root); + -- Determine whether vertex Vertex of invocation graph denotes the + -- elaboration procedure of a spec or a body. + + function Is_Existing_Source_Target_Relation + (G : Invocation_Graph; + Rel : Source_Target_Relation) return Boolean; + pragma Inline (Is_Existing_Source_Target_Relation); + -- Determine whether a source vertex and a target vertex described by + -- relation Rel are already related in invocation graph G. + + procedure Save_Elaboration_Root + (G : Invocation_Graph; + Root : Invocation_Graph_Vertex_Id); + pragma Inline (Save_Elaboration_Root); + -- Save elaboration root Root of invocation graph G + + procedure Set_Corresponding_Vertex + (G : Invocation_Graph; + IS_Id : Invocation_Signature_Id; + Vertex : Invocation_Graph_Vertex_Id); + pragma Inline (Set_Corresponding_Vertex); + -- Associate vertex Vertex of invocation graph G with signature IS_Id + + procedure Set_Is_Existing_Source_Target_Relation + (G : Invocation_Graph; + Rel : Source_Target_Relation; + Val : Boolean := True); + pragma Inline (Set_Is_Existing_Source_Target_Relation); + -- Mark a source vertex and a target vertex described by relation Rel as + -- already related in invocation graph G depending on value Val. + + procedure Set_IGE_Attributes + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id; + Val : Invocation_Graph_Edge_Attributes); + pragma Inline (Set_IGE_Attributes); + -- Set the attributes of edge Edge of invocation graph G to value Val + + procedure Set_IGV_Attributes + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id; + Val : Invocation_Graph_Vertex_Attributes); + pragma Inline (Set_IGV_Attributes); + -- Set the attributes of vertex Vertex of invocation graph G to value + -- Val. + + -------------- + -- Add_Edge -- + -------------- + + procedure Add_Edge + (G : Invocation_Graph; + Source : Invocation_Graph_Vertex_Id; + Target : Invocation_Graph_Vertex_Id; + IR_Id : Invocation_Relation_Id) + is + pragma Assert (Present (G)); + pragma Assert (Present (Source)); + pragma Assert (Present (Target)); + pragma Assert (Present (IR_Id)); + + Rel : constant Source_Target_Relation := + (Source => Source, + Target => Target); + + Edge : Invocation_Graph_Edge_Id; + + begin + -- Nothing to do when the source and target are already related by an + -- edge. + + if Is_Existing_Source_Target_Relation (G, Rel) then + return; + end if; + + Edge := Sequence_Next_Edge; + + -- Add the edge to the underlying graph + + DG.Add_Edge + (G => G.Graph, + E => Edge, + Source => Source, + Destination => Target); + + -- Build and save the attributes of the edge + + Set_IGE_Attributes + (G => G, + Edge => Edge, + Val => (Relation => IR_Id)); + + -- Mark the source and target as related by the new edge. This + -- prevents all further attempts to link the same source and target. + + Set_Is_Existing_Source_Target_Relation (G, Rel); + + -- Update the edge statistics + + Increment_Invocation_Graph_Edge_Count (G, Kind (IR_Id)); + end Add_Edge; + + ---------------- + -- Add_Vertex -- + ---------------- + + procedure Add_Vertex + (G : Invocation_Graph; + IC_Id : Invocation_Construct_Id; + Body_Vertex : Library_Graph_Vertex_Id; + Spec_Vertex : Library_Graph_Vertex_Id) + is + pragma Assert (Present (G)); + pragma Assert (Present (IC_Id)); + pragma Assert (Present (Body_Vertex)); + pragma Assert (Present (Spec_Vertex)); + + Construct_Signature : constant Invocation_Signature_Id := + Signature (IC_Id); + Vertex : Invocation_Graph_Vertex_Id; + + begin + -- Nothing to do when the construct already has a vertex + + if Present (Corresponding_Vertex (G, Construct_Signature)) then + return; + end if; + + Vertex := Sequence_Next_Vertex; + + -- Add the vertex to the underlying graph + + DG.Add_Vertex (G.Graph, Vertex); + + -- Build and save the attributes of the vertex + + Set_IGV_Attributes + (G => G, + Vertex => Vertex, + Val => (Body_Vertex => Body_Vertex, + Construct => IC_Id, + Spec_Vertex => Spec_Vertex)); + + -- Associate the construct with its corresponding vertex + + Set_Corresponding_Vertex (G, Construct_Signature, Vertex); + + -- Save the vertex for later processing when it denotes a spec or + -- body elaboration procedure. + + if Is_Elaboration_Root (G, Vertex) then + Save_Elaboration_Root (G, Vertex); + end if; + end Add_Vertex; + + ----------------- + -- Body_Vertex -- + ----------------- + + function Body_Vertex + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_IGV_Attributes (G, Vertex).Body_Vertex; + end Body_Vertex; + + ------------ + -- Column -- + ------------ + + function Column + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Nat + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Column (Signature (Construct (G, Vertex))); + end Column; + + --------------- + -- Construct -- + --------------- + + function Construct + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Invocation_Construct_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_IGV_Attributes (G, Vertex).Construct; + end Construct; + + -------------------------- + -- Corresponding_Vertex -- + -------------------------- + + function Corresponding_Vertex + (G : Invocation_Graph; + IS_Id : Invocation_Signature_Id) return Invocation_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (IS_Id)); + + return Signature_Tables.Get (G.Signature_To_Vertex, IS_Id); + end Corresponding_Vertex; + + ------------ + -- Create -- + ------------ + + function Create + (Initial_Vertices : Positive; + Initial_Edges : Positive) return Invocation_Graph + is + G : constant Invocation_Graph := new Invocation_Graph_Attributes; + + begin + G.Edge_Attributes := IGE_Tables.Create (Initial_Edges); + G.Graph := + DG.Create + (Initial_Vertices => Initial_Vertices, + Initial_Edges => Initial_Edges); + G.Relations := Relation_Sets.Create (Initial_Edges); + G.Roots := IGV_Sets.Create (Initial_Vertices); + G.Signature_To_Vertex := Signature_Tables.Create (Initial_Vertices); + G.Vertex_Attributes := IGV_Tables.Create (Initial_Vertices); + + return G; + end Create; + + ------------- + -- Destroy -- + ------------- + + procedure Destroy (G : in out Invocation_Graph) is + begin + pragma Assert (Present (G)); + + IGE_Tables.Destroy (G.Edge_Attributes); + DG.Destroy (G.Graph); + Relation_Sets.Destroy (G.Relations); + IGV_Sets.Destroy (G.Roots); + Signature_Tables.Destroy (G.Signature_To_Vertex); + IGV_Tables.Destroy (G.Vertex_Attributes); + + Free (G); + end Destroy; + + ----------------------------------- + -- Destroy_Invocation_Graph_Edge -- + ----------------------------------- + + procedure Destroy_Invocation_Graph_Edge + (Edge : in out Invocation_Graph_Edge_Id) + is + pragma Unreferenced (Edge); + begin + null; + end Destroy_Invocation_Graph_Edge; + + ---------------------------------------------- + -- Destroy_Invocation_Graph_Edge_Attributes -- + ---------------------------------------------- + + procedure Destroy_Invocation_Graph_Edge_Attributes + (Attrs : in out Invocation_Graph_Edge_Attributes) + is + pragma Unreferenced (Attrs); + begin + null; + end Destroy_Invocation_Graph_Edge_Attributes; + + ------------------------------------- + -- Destroy_Invocation_Graph_Vertex -- + ------------------------------------- + + procedure Destroy_Invocation_Graph_Vertex + (Vertex : in out Invocation_Graph_Vertex_Id) + is + pragma Unreferenced (Vertex); + begin + null; + end Destroy_Invocation_Graph_Vertex; + + ------------------------------------------------ + -- Destroy_Invocation_Graph_Vertex_Attributes -- + ------------------------------------------------ + + procedure Destroy_Invocation_Graph_Vertex_Attributes + (Attrs : in out Invocation_Graph_Vertex_Attributes) + is + pragma Unreferenced (Attrs); + begin + null; + end Destroy_Invocation_Graph_Vertex_Attributes; + + ----------- + -- Extra -- + ----------- + + function Extra + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) return Name_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Extra (Relation (G, Edge)); + end Extra; + + ------------------------ + -- Get_IGE_Attributes -- + ------------------------ + + function Get_IGE_Attributes + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) + return Invocation_Graph_Edge_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return IGE_Tables.Get (G.Edge_Attributes, Edge); + end Get_IGE_Attributes; + + ------------------------ + -- Get_IGV_Attributes -- + ------------------------ + + function Get_IGV_Attributes + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) + return Invocation_Graph_Vertex_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return IGV_Tables.Get (G.Vertex_Attributes, Vertex); + end Get_IGV_Attributes; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : All_Edge_Iterator) return Boolean is + begin + return DG.Has_Next (DG.All_Edge_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : All_Vertex_Iterator) return Boolean is + begin + return DG.Has_Next (DG.All_Vertex_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Edges_To_Targets_Iterator) return Boolean is + begin + return DG.Has_Next (DG.Outgoing_Edge_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Elaboration_Root_Iterator) return Boolean is + begin + return IGV_Sets.Has_Next (IGV_Sets.Iterator (Iter)); + end Has_Next; + + ------------------------------- + -- Hash_Invocation_Signature -- + ------------------------------- + + function Hash_Invocation_Signature + (IS_Id : Invocation_Signature_Id) return Bucket_Range_Type + is + begin + pragma Assert (Present (IS_Id)); + + return Bucket_Range_Type (IS_Id); + end Hash_Invocation_Signature; + + --------------------------------- + -- Hash_Source_Target_Relation -- + --------------------------------- + + function Hash_Source_Target_Relation + (Rel : Source_Target_Relation) return Bucket_Range_Type + is + begin + pragma Assert (Present (Rel.Source)); + pragma Assert (Present (Rel.Target)); + + return + Hash_Two_Keys + (Bucket_Range_Type (Rel.Source), + Bucket_Range_Type (Rel.Target)); + end Hash_Source_Target_Relation; + + ------------------------------------------- + -- Increment_Invocation_Graph_Edge_Count -- + ------------------------------------------- + + procedure Increment_Invocation_Graph_Edge_Count + (G : Invocation_Graph; + Kind : Invocation_Kind) + is + pragma Assert (Present (G)); + + Count : Natural renames G.Counts (Kind); + + begin + Count := Count + 1; + end Increment_Invocation_Graph_Edge_Count; + + --------------------------------- + -- Invocation_Graph_Edge_Count -- + --------------------------------- + + function Invocation_Graph_Edge_Count + (G : Invocation_Graph; + Kind : Invocation_Kind) return Natural + is + begin + pragma Assert (Present (G)); + + return G.Counts (Kind); + end Invocation_Graph_Edge_Count; + + ------------------------- + -- Is_Elaboration_Root -- + ------------------------- + + function Is_Elaboration_Root + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Vertex_Kind : constant Invocation_Construct_Kind := + Kind (Construct (G, Vertex)); + + begin + return + Vertex_Kind = Elaborate_Body_Procedure + or else + Vertex_Kind = Elaborate_Spec_Procedure; + end Is_Elaboration_Root; + + ---------------------------------------- + -- Is_Existing_Source_Target_Relation -- + ---------------------------------------- + + function Is_Existing_Source_Target_Relation + (G : Invocation_Graph; + Rel : Source_Target_Relation) return Boolean + is + begin + pragma Assert (Present (G)); + + return Relation_Sets.Contains (G.Relations, Rel); + end Is_Existing_Source_Target_Relation; + + ----------------------- + -- Iterate_All_Edges -- + ----------------------- + + function Iterate_All_Edges + (G : Invocation_Graph) return All_Edge_Iterator + is + begin + pragma Assert (Present (G)); + + return All_Edge_Iterator (DG.Iterate_All_Edges (G.Graph)); + end Iterate_All_Edges; + + -------------------------- + -- Iterate_All_Vertices -- + -------------------------- + + function Iterate_All_Vertices + (G : Invocation_Graph) return All_Vertex_Iterator + is + begin + pragma Assert (Present (G)); + + return All_Vertex_Iterator (DG.Iterate_All_Vertices (G.Graph)); + end Iterate_All_Vertices; + + ------------------------------ + -- Iterate_Edges_To_Targets -- + ------------------------------ + + function Iterate_Edges_To_Targets + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Edges_To_Targets_Iterator + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return + Edges_To_Targets_Iterator + (DG.Iterate_Outgoing_Edges (G.Graph, Vertex)); + end Iterate_Edges_To_Targets; + + ------------------------------- + -- Iterate_Elaboration_Roots -- + ------------------------------- + + function Iterate_Elaboration_Roots + (G : Invocation_Graph) return Elaboration_Root_Iterator + is + begin + pragma Assert (Present (G)); + + return Elaboration_Root_Iterator (IGV_Sets.Iterate (G.Roots)); + end Iterate_Elaboration_Roots; + + ---------- + -- Kind -- + ---------- + + function Kind + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) return Invocation_Kind + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (Relation (G, Edge)); + end Kind; + + ---------- + -- Line -- + ---------- + + function Line + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Nat + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Line (Signature (Construct (G, Vertex))); + end Line; + + ---------- + -- Name -- + ---------- + + function Name + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Name_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Name (Signature (Construct (G, Vertex))); + end Name; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out All_Edge_Iterator; + Edge : out Invocation_Graph_Edge_Id) + is + begin + DG.Next (DG.All_Edge_Iterator (Iter), Edge); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out All_Vertex_Iterator; + Vertex : out Invocation_Graph_Vertex_Id) + is + begin + DG.Next (DG.All_Vertex_Iterator (Iter), Vertex); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Edges_To_Targets_Iterator; + Edge : out Invocation_Graph_Edge_Id) + is + begin + DG.Next (DG.Outgoing_Edge_Iterator (Iter), Edge); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Elaboration_Root_Iterator; + Root : out Invocation_Graph_Vertex_Id) + is + begin + IGV_Sets.Next (IGV_Sets.Iterator (Iter), Root); + end Next; + + --------------------- + -- Number_Of_Edges -- + --------------------- + + function Number_Of_Edges (G : Invocation_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Edges (G.Graph); + end Number_Of_Edges; + + -------------------------------- + -- Number_Of_Edges_To_Targets -- + -------------------------------- + + function Number_Of_Edges_To_Targets + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return DG.Number_Of_Outgoing_Edges (G.Graph, Vertex); + end Number_Of_Edges_To_Targets; + + --------------------------------- + -- Number_Of_Elaboration_Roots -- + --------------------------------- + + function Number_Of_Elaboration_Roots + (G : Invocation_Graph) return Natural + is + begin + pragma Assert (Present (G)); + + return IGV_Sets.Size (G.Roots); + end Number_Of_Elaboration_Roots; + + ------------------------ + -- Number_Of_Vertices -- + ------------------------ + + function Number_Of_Vertices (G : Invocation_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Vertices (G.Graph); + end Number_Of_Vertices; + + ------------- + -- Present -- + ------------- + + function Present (G : Invocation_Graph) return Boolean is + begin + return G /= Nil; + end Present; + + -------------- + -- Relation -- + -------------- + + function Relation + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) return Invocation_Relation_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Get_IGE_Attributes (G, Edge).Relation; + end Relation; + + --------------------------- + -- Save_Elaboration_Root -- + --------------------------- + + procedure Save_Elaboration_Root + (G : Invocation_Graph; + Root : Invocation_Graph_Vertex_Id) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Root)); + + IGV_Sets.Insert (G.Roots, Root); + end Save_Elaboration_Root; + + ------------------------------ + -- Set_Corresponding_Vertex -- + ------------------------------ + + procedure Set_Corresponding_Vertex + (G : Invocation_Graph; + IS_Id : Invocation_Signature_Id; + Vertex : Invocation_Graph_Vertex_Id) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (IS_Id)); + pragma Assert (Present (Vertex)); + + Signature_Tables.Put (G.Signature_To_Vertex, IS_Id, Vertex); + end Set_Corresponding_Vertex; + + -------------------------------------------- + -- Set_Is_Existing_Source_Target_Relation -- + -------------------------------------------- + + procedure Set_Is_Existing_Source_Target_Relation + (G : Invocation_Graph; + Rel : Source_Target_Relation; + Val : Boolean := True) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Rel.Source)); + pragma Assert (Present (Rel.Target)); + + if Val then + Relation_Sets.Insert (G.Relations, Rel); + else + Relation_Sets.Delete (G.Relations, Rel); + end if; + end Set_Is_Existing_Source_Target_Relation; + + ------------------------ + -- Set_IGE_Attributes -- + ------------------------ + + procedure Set_IGE_Attributes + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id; + Val : Invocation_Graph_Edge_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + IGE_Tables.Put (G.Edge_Attributes, Edge, Val); + end Set_IGE_Attributes; + + ------------------------ + -- Set_IGV_Attributes -- + ------------------------ + + procedure Set_IGV_Attributes + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id; + Val : Invocation_Graph_Vertex_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + IGV_Tables.Put (G.Vertex_Attributes, Vertex, Val); + end Set_IGV_Attributes; + + ----------------- + -- Spec_Vertex -- + ----------------- + + function Spec_Vertex + (G : Invocation_Graph; + Vertex : Invocation_Graph_Vertex_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_IGV_Attributes (G, Vertex).Spec_Vertex; + end Spec_Vertex; + + ------------ + -- Target -- + ------------ + + function Target + (G : Invocation_Graph; + Edge : Invocation_Graph_Edge_Id) return Invocation_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return DG.Destination_Vertex (G.Graph, Edge); + end Target; + end Invocation_Graphs; + + -------------------- + -- Library_Graphs -- + -------------------- + + package body Library_Graphs is + + ----------------------- + -- Local subprograms -- + ----------------------- + + procedure Add_Body_Before_Spec_Edge + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Edges : LGE_Lists.Doubly_Linked_List); + pragma Inline (Add_Body_Before_Spec_Edge); + -- Create a new edge in library graph G between vertex Vertex and its + -- corresponding spec or body, where the body is a predecessor and the + -- spec a successor. Add the edge to list Edges. + + procedure Add_Body_Before_Spec_Edges + (G : Library_Graph; + Edges : LGE_Lists.Doubly_Linked_List); + pragma Inline (Add_Body_Before_Spec_Edges); + -- Create new edges in library graph G for all vertices and their + -- corresponding specs or bodies, where the body is a predecessor + -- and the spec is a successor. Add all edges to list Edges. + + function Add_Edge_With_Return + (G : Library_Graph; + Pred : Library_Graph_Vertex_Id; + Succ : Library_Graph_Vertex_Id; + Kind : Library_Graph_Edge_Kind; + Activates_Task : Boolean) return Library_Graph_Edge_Id; + pragma Inline (Add_Edge_With_Return); + -- Create a new edge in library graph G with source vertex Pred and + -- destination vertex Succ, and return its handle. Kind denotes the + -- nature of the edge. Activates_Task should be set when the edge + -- involves a task activation. If Pred and Succ are already related, + -- no edge is created and No_Library_Graph_Edge is returned. + + function At_Least_One_Edge_Satisfies + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Predicate : LGE_Predicate_Ptr) return Boolean; + pragma Inline (At_Least_One_Edge_Satisfies); + -- Determine whether at least one edge of cycle Cycle of library graph G + -- satisfies predicate Predicate. + + function Copy_Cycle_Path + (Cycle_Path : LGE_Lists.Doubly_Linked_List) + return LGE_Lists.Doubly_Linked_List; + pragma Inline (Copy_Cycle_Path); + -- Create a deep copy of list Cycle_Path + + function Cycle_End_Vertices + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Elaborate_All_Active : Boolean) return LGV_Sets.Membership_Set; + pragma Inline (Cycle_End_Vertices); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Collect the vertices that terminate a cycle starting + -- from vertex Vertex of library graph G in a set. This is usually the + -- vertex itself, unless the vertex is part of an Elaborate_Body pair, + -- or flag Elaborate_All_Active is set. In that case the complementary + -- vertex is also added to the set. + + function Cycle_Kind_Of + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Cycle_Kind; + pragma Inline (Cycle_Kind_Of); + -- Determine the cycle kind of edge Edge of library graph G if the edge + -- participated in a circuit. + + function Cycle_Kind_Precedence + (Kind : Library_Graph_Cycle_Kind; + Compared_To : Library_Graph_Cycle_Kind) return Precedence_Kind; + pragma Inline (Cycle_Kind_Precedence); + -- Determine the precedence of cycle kind Kind compared to cycle kind + -- Compared_To. + + function Cycle_Path_Precedence + (G : Library_Graph; + Path : LGE_Lists.Doubly_Linked_List; + Compared_To : LGE_Lists.Doubly_Linked_List) return Precedence_Kind; + pragma Inline (Cycle_Path_Precedence); + -- Determine the precedence of cycle path Path of library graph G + -- compared to path Compared_To. + + function Cycle_Precedence + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Compared_To : Library_Graph_Cycle_Id) return Precedence_Kind; + pragma Inline (Cycle_Precedence); + -- Determine the precedence of cycle Cycle of library graph G compared + -- to cycle Compared_To. + + procedure Decrement_Library_Graph_Edge_Count + (G : Library_Graph; + Kind : Library_Graph_Edge_Kind); + pragma Inline (Decrement_Library_Graph_Edge_Count); + -- Decrement the number of edges of kind King in library graph G by one + + procedure Delete_Body_Before_Spec_Edges + (G : Library_Graph; + Edges : LGE_Lists.Doubly_Linked_List); + pragma Inline (Delete_Body_Before_Spec_Edges); + -- Delete all edges in list Edges from library graph G, that link spec + -- and bodies, where the body acts as the predecessor and the spec as a + -- successor. + + procedure Delete_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id); + pragma Inline (Delete_Edge); + -- Delete edge Edge from library graph G + + function Edge_Precedence + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Compared_To : Library_Graph_Edge_Id) return Precedence_Kind; + pragma Inline (Edge_Precedence); + -- Determine the precedence of edge Edge of library graph G compared to + -- edge Compared_To. + + procedure Find_Cycles_From_Successor + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + End_Vertices : LGV_Sets.Membership_Set; + Deleted_Vertices : LGV_Sets.Membership_Set; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path_Stack : LGE_Lists.Doubly_Linked_List; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List; + Cycle_Count : in out Natural; + Cycle_Limit : Natural; + Elaborate_All_Active : Boolean; + Has_Cycle : out Boolean; + Indent : Indentation_Level); + pragma Inline (Find_Cycles_From_Successor); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Find all cycles from the successor indicated by edge + -- Edge of library graph G. If at least one cycle exists, set Has_Cycle + -- to True. The remaining parameters are as follows: + -- + -- * End vertices is the set of vertices that terminate a potential + -- cycle. + -- + -- * Deleted vertices is the set of vertices that have been expanded + -- during previous depth-first searches and should not be visited + -- for the rest of the algorithm. + -- + -- * Most_Significant_Edge is the current highest-precedence edge on + -- the path of the potential cycle. + -- + -- * Invocation_Edge_Count is the number of invocation edges on the + -- path of the potential cycle. + -- + -- * Cycle_Path_Stack is the path of the potential cycle. + -- + -- * Visited_Set is the set of vertices that have been visited during + -- the current depth-first search. + -- + -- * Visited_Stack maintains the vertices of Visited_Set in a stack + -- for later unvisiting. + -- + -- * Cycle_Count is the number of cycles discovered so far. + -- + -- * Cycle_Limit is the upper bound of the number of cycles to be + -- discovered. + -- + -- * Elaborate_All_Active should be set when the component currently + -- being examined for cycles contains an Elaborate_All edge. + -- + -- * Indent in the desired indentation level for tracing. + + procedure Find_Cycles_From_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + End_Vertices : LGV_Sets.Membership_Set; + Deleted_Vertices : LGV_Sets.Membership_Set; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path_Stack : LGE_Lists.Doubly_Linked_List; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List; + Cycle_Count : in out Natural; + Cycle_Limit : Natural; + Elaborate_All_Active : Boolean; + Is_Start_Vertex : Boolean; + Has_Cycle : out Boolean; + Indent : Indentation_Level); + pragma Inline (Find_Cycles_From_Vertex); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Find all cycles from vertex Vertex of library graph + -- G. If at least one cycle exists, set Has_Cycle to True. The remaining + -- parameters are as follows: + -- + -- * End_Vertices is the set of vertices that terminate a potential + -- cycle. + -- + -- * Deleted_Vertices is the set of vertices that have been expanded + -- during previous depth-first searches and should not be visited + -- for the rest of the algorithm. + -- + -- * Most_Significant_Edge is the current highest-precedence edge on + -- the path of the potential cycle. + -- + -- * Invocation_Edge_Count is the number of invocation edges on the + -- path of the potential cycle. + -- + -- * Cycle_Path_Stack is the path of the potential cycle. + -- + -- * Visited_Set is the set of vertices that have been visited during + -- the current depth-first search. + -- + -- * Visited_Stack maintains the vertices of Visited_Set in a stack + -- for later unvisiting. + -- + -- * Cycle_Count is the number of cycles discovered so far. + -- + -- * Cycle_Limit is the upper bound of the number of cycles to be + -- discovered. + -- + -- * Elaborate_All_Active should be set when the component currently + -- being examined for cycles contains an Elaborate_All edge. + -- + -- * Indent in the desired indentation level for tracing. + + procedure Find_Cycles_In_Component + (G : Library_Graph; + Comp : Component_Id; + Cycle_Count : in out Natural; + Cycle_Limit : Natural); + pragma Inline (Find_Cycles_In_Component); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Find all cycles in component Comp of library graph + -- G. The remaining parameters are as follows: + -- + -- * Cycle_Count is the number of cycles discovered so far. + -- + -- * Cycle_Limit is the upper bound of the number of cycles to be + -- discovered. + + function Find_First_Lower_Precedence_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Id; + pragma Inline (Find_First_Lower_Precedence_Cycle); + -- Inspect the list of cycles of library graph G and return the first + -- cycle whose precedence is lower than that of cycle Cycle. If there + -- is no such cycle, return No_Library_Graph_Cycle. + + procedure Free is + new Ada.Unchecked_Deallocation + (Library_Graph_Attributes, Library_Graph); + + function Get_Component_Attributes + (G : Library_Graph; + Comp : Component_Id) return Component_Attributes; + pragma Inline (Get_Component_Attributes); + -- Obtain the attributes of component Comp of library graph G + + function Get_LGC_Attributes + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Attributes; + pragma Inline (Get_LGC_Attributes); + -- Obtain the attributes of cycle Cycle of library graph G + + function Get_LGE_Attributes + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) + return Library_Graph_Edge_Attributes; + pragma Inline (Get_LGE_Attributes); + -- Obtain the attributes of edge Edge of library graph G + + function Get_LGV_Attributes + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) + return Library_Graph_Vertex_Attributes; + pragma Inline (Get_LGV_Attributes); + -- Obtain the attributes of vertex Edge of library graph G + + function Has_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean; + pragma Inline (Has_Elaborate_Body); + -- Determine whether vertex Vertex of library graph G is subject to + -- pragma Elaborate_Body. + + function Has_Elaborate_All_Edge + (G : Library_Graph; + Comp : Component_Id) return Boolean; + pragma Inline (Has_Elaborate_All_Edge); + -- Determine whether component Comp of library graph G contains an + -- Elaborate_All edge that links two vertices in the same component. + + function Has_Elaborate_All_Edge + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean; + pragma Inline (Has_Elaborate_All_Edge); + -- Determine whether vertex Vertex of library graph G contains an + -- Elaborate_All edge to a successor where both the vertex and the + -- successor reside in the same component. + + function Highest_Precedence_Edge + (G : Library_Graph; + Left : Library_Graph_Edge_Id; + Right : Library_Graph_Edge_Id) return Library_Graph_Edge_Id; + pragma Inline (Highest_Precedence_Edge); + -- Return the edge with highest precedence among edges Left and Right of + -- library graph G. + + procedure Increment_Library_Graph_Edge_Count + (G : Library_Graph; + Kind : Library_Graph_Edge_Kind); + pragma Inline (Increment_Library_Graph_Edge_Count); + -- Increment the number of edges of king Kind in library graph G by one + + procedure Increment_Pending_Predecessors + (G : Library_Graph; + Comp : Component_Id; + Edge : Library_Graph_Edge_Id); + pragma Inline (Increment_Pending_Predecessors); + -- Increment the number of pending predecessors component Comp which was + -- reached via edge Edge of library graph G must wait on before it can + -- be elaborated by one. + + procedure Increment_Pending_Predecessors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Edge : Library_Graph_Edge_Id); + pragma Inline (Increment_Pending_Predecessors); + -- Increment the number of pending predecessors vertex Vertex which was + -- reached via edge Edge of library graph G must wait on before it can + -- be elaborated by one. + + procedure Initialize_Components (G : Library_Graph); + pragma Inline (Initialize_Components); + -- Initialize on the initial call or re-initialize on subsequent calls + -- all components of library graph G. + + function Is_Cycle_Initiating_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cycle_Initiating_Edge); + -- Determine whether edge Edge of library graph G starts a cycle + + function Is_Cyclic_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle. + + function Is_Cyclic_Elaborate_All_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Elaborate_All_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and has a predecessor that is subject to pragma Elaborate_All. + + function Is_Cyclic_Elaborate_Body_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Elaborate_Body_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and has a successor that is either a spec subject to pragma + -- Elaborate_Body, or a body that completes such a spec. + + function Is_Cyclic_Elaborate_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Elaborate_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and has a predecessor that is subject to pragma Elaborate. + + function Is_Cyclic_Forced_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Forced_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and came from the forced-elaboration-order file. + + function Is_Cyclic_Invocation_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_Invocation_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and came from the traversal of the invocation graph. + + function Is_Cyclic_With_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Cyclic_With_Edge); + -- Determine whether edge Edge of library graph G participates in a + -- cycle and is the result of a with dependency between its successor + -- and predecessor. + + function Is_Recorded_Edge + (G : Library_Graph; + Rel : Predecessor_Successor_Relation) return Boolean; + pragma Inline (Is_Recorded_Edge); + -- Determine whether a predecessor vertex and a successor vertex + -- described by relation Rel are already linked in library graph G. + + function Is_Static_Successor_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Is_Static_Successor_Edge); + -- Determine whether the successor of invocation edge Edge represents a + -- unit that was compiled with the static model. + + function Is_Vertex_With_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean; + pragma Inline (Is_Vertex_With_Elaborate_Body); + -- Determine whether vertex Vertex of library graph G denotes a spec + -- subject to pragma Elaborate_Body or the completing body of such a + -- spec. + + function Links_Vertices_In_Same_Component + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean; + pragma Inline (Links_Vertices_In_Same_Component); + -- Determine whether edge Edge of library graph G links a predecessor + -- and successor that reside in the same component. + + function Maximum_Invocation_Edge_Count + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Count : Natural) return Natural; + pragma Inline (Maximum_Invocation_Edge_Count); + -- Determine whether edge Edge of library graph G is an invocation edge, + -- and if it is return Count + 1, otherwise return Count. + + procedure Normalize_Cycle_Path + (Cycle_Path : LGE_Lists.Doubly_Linked_List; + Most_Significant_Edge : Library_Graph_Edge_Id); + pragma Inline (Normalize_Cycle_Path); + -- Normalize cycle path Path by rotating it until its starting edge is + -- Sig_Edge. + + procedure Order_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id); + pragma Inline (Order_Cycle); + -- Insert cycle Cycle in library graph G and sort it based on its + -- precedence relative to all recorded cycles. + + function Path + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return LGE_Lists.Doubly_Linked_List; + pragma Inline (Path); + -- Obtain the path of edges which comprises cycle Cycle of library + -- graph G. + + procedure Record_Cycle + (G : Library_Graph; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path : LGE_Lists.Doubly_Linked_List; + Indent : Indentation_Level); + pragma Inline (Record_Cycle); + -- Normalize a cycle described by its path Cycle_Path and add it to + -- library graph G. Most_Significant_Edge denotes the edge with the + -- highest significance along the cycle path. Invocation_Edge_Count + -- is the number of invocation edges along the cycle path. Indent is + -- the desired indentation level for tracing. + + procedure Set_Component_Attributes + (G : Library_Graph; + Comp : Component_Id; + Val : Component_Attributes); + pragma Inline (Set_Component_Attributes); + -- Set the attributes of component Comp of library graph G to value Val + + procedure Set_Corresponding_Vertex + (G : Library_Graph; + U_Id : Unit_Id; + Val : Library_Graph_Vertex_Id); + pragma Inline (Set_Corresponding_Vertex); + -- Associate vertex Val of library graph G with unit U_Id + + procedure Set_Is_Recorded_Edge + (G : Library_Graph; + Rel : Predecessor_Successor_Relation; + Val : Boolean := True); + pragma Inline (Set_Is_Recorded_Edge); + -- Mark a predecessor vertex and a successor vertex described by + -- relation Rel as already linked depending on value Val. + + procedure Set_LGC_Attributes + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Val : Library_Graph_Cycle_Attributes); + pragma Inline (Set_LGC_Attributes); + -- Set the attributes of cycle Cycle of library graph G to value Val + + procedure Set_LGE_Attributes + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Val : Library_Graph_Edge_Attributes); + pragma Inline (Set_LGE_Attributes); + -- Set the attributes of edge Edge of library graph G to value Val + + procedure Set_LGV_Attributes + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Val : Library_Graph_Vertex_Attributes); + pragma Inline (Set_LGV_Attributes); + -- Set the attributes of vertex Vertex of library graph G to value Val + + procedure Trace_Component + (G : Library_Graph; + Comp : Component_Id; + Indent : Indentation_Level); + pragma Inline (Trace_Component); + -- Write the contents of component Comp of library graph G to standard + -- output. Indent is the desired indentation level for tracing. + + procedure Trace_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Indent : Indentation_Level); + pragma Inline (Trace_Cycle); + -- Write the contents of cycle Cycle of library graph G to standard + -- output. Indent is the desired indentation level for tracing. + + procedure Trace_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Indent : Indentation_Level); + pragma Inline (Trace_Edge); + -- Write the contents of edge Edge of library graph G to standard + -- output. Indent is the desired indentation level for tracing. + + procedure Trace_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Indent : Indentation_Level); + pragma Inline (Trace_Vertex); + -- Write the contents of vertex Vertex of library graph G to standard + -- output. Indent is the desired indentation level for tracing. + + procedure Unvisit + (Vertex : Library_Graph_Vertex_Id; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List); + pragma Inline (Unvisit); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Unwind the Visited_Stack by removing the top vertex + -- from set Visited_Set until vertex Vertex is reached, inclusive. + + procedure Update_Pending_Predecessors + (Strong_Predecessors : in out Natural; + Weak_Predecessors : in out Natural; + Update_Weak : Boolean; + Value : Integer); + pragma Inline (Update_Pending_Predecessors); + -- Update the number of pending strong or weak predecessors denoted by + -- Strong_Predecessors and Weak_Predecessors respectively depending on + -- flag Update_Weak by adding value Value. + + procedure Update_Pending_Predecessors_Of_Components (G : Library_Graph); + pragma Inline (Update_Pending_Predecessors_Of_Components); + -- Update the number of pending predecessors all components of library + -- graph G must wait on before they can be elaborated. + + procedure Update_Pending_Predecessors_Of_Components + (G : Library_Graph; + Edge : Library_Graph_Edge_Id); + pragma Inline (Update_Pending_Predecessors_Of_Components); + -- Update the number of pending predecessors the component of edge + -- LGE_Is's successor vertex of library graph G must wait on before + -- it can be elaborated. + + function Vertex_Precedence + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind; + pragma Inline (Vertex_Precedence); + -- Determine the precedence of vertex Vertex of library graph G compared + -- to vertex Compared_To. + + procedure Visit + (Vertex : Library_Graph_Vertex_Id; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List); + pragma Inline (Visit); + -- Part of Tarjan's enumeration of the elementary circuits of a directed + -- graph algorithm. Push vertex Vertex on the Visited_Stack and add it + -- to set Visited_Set. + + -------------------- + -- Activates_Task -- + -------------------- + + function Activates_Task + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Kind (G, Edge) = Invocation_Edge + and then Get_LGE_Attributes (G, Edge).Activates_Task; + end Activates_Task; + + ------------------------------- + -- Add_Body_Before_Spec_Edge -- + ------------------------------- + + procedure Add_Body_Before_Spec_Edge + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Edges : LGE_Lists.Doubly_Linked_List) + is + Edge : Library_Graph_Edge_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + pragma Assert (LGE_Lists.Present (Edges)); + + -- A vertex requires a special Body_Before_Spec edge to its + -- Corresponding_Item when it either denotes a + -- + -- * Body that completes a previous spec + -- + -- * Spec with a completing body + -- + -- The edge creates an intentional circularity between the spec and + -- body in order to emulate a library unit, and guarantees that both + -- will appear in the same component. + -- + -- Due to the structure of the library graph, either the spec or + -- the body may be visited first, yet Corresponding_Item will still + -- attempt to create the Body_Before_Spec edge. This is OK because + -- successor and predecessor are kept consistent in both cases, and + -- Add_Edge_With_Return will prevent the creation of the second edge. + + -- Assume that no Body_Before_Spec is necessary + + Edge := No_Library_Graph_Edge; + + -- A body that completes a previous spec + + if Is_Body_With_Spec (G, Vertex) then + Edge := + Add_Edge_With_Return + (G => G, + Pred => Vertex, + Succ => Corresponding_Item (G, Vertex), + Kind => Body_Before_Spec_Edge, + Activates_Task => False); + + -- A spec with a completing body + + elsif Is_Spec_With_Body (G, Vertex) then + Edge := + Add_Edge_With_Return + (G => G, + Pred => Corresponding_Item (G, Vertex), + Succ => Vertex, + Kind => Body_Before_Spec_Edge, + Activates_Task => False); + end if; + + if Present (Edge) then + LGE_Lists.Append (Edges, Edge); + end if; + end Add_Body_Before_Spec_Edge; + + -------------------------------- + -- Add_Body_Before_Spec_Edges -- + -------------------------------- + + procedure Add_Body_Before_Spec_Edges + (G : Library_Graph; + Edges : LGE_Lists.Doubly_Linked_List) + is + Iter : Elaborable_Units_Iterator; + U_Id : Unit_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (LGE_Lists.Present (Edges)); + + Iter := Iterate_Elaborable_Units; + while Has_Next (Iter) loop + Next (Iter, U_Id); + + Add_Body_Before_Spec_Edge + (G => G, + Vertex => Corresponding_Vertex (G, U_Id), + Edges => Edges); + end loop; + end Add_Body_Before_Spec_Edges; + + -------------- + -- Add_Edge -- + -------------- + + procedure Add_Edge + (G : Library_Graph; + Pred : Library_Graph_Vertex_Id; + Succ : Library_Graph_Vertex_Id; + Kind : Library_Graph_Edge_Kind; + Activates_Task : Boolean) + is + Edge : Library_Graph_Edge_Id; + pragma Unreferenced (Edge); + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Pred)); + pragma Assert (Present (Succ)); + pragma Assert (Kind /= No_Edge); + pragma Assert (not Activates_Task or else Kind = Invocation_Edge); + + Edge := + Add_Edge_With_Return + (G => G, + Pred => Pred, + Succ => Succ, + Kind => Kind, + Activates_Task => Activates_Task); + end Add_Edge; + + -------------------------- + -- Add_Edge_With_Return -- + -------------------------- + + function Add_Edge_With_Return + (G : Library_Graph; + Pred : Library_Graph_Vertex_Id; + Succ : Library_Graph_Vertex_Id; + Kind : Library_Graph_Edge_Kind; + Activates_Task : Boolean) return Library_Graph_Edge_Id + is + pragma Assert (Present (G)); + pragma Assert (Present (Pred)); + pragma Assert (Present (Succ)); + pragma Assert (Kind /= No_Edge); + + Rel : constant Predecessor_Successor_Relation := + (Predecessor => Pred, + Successor => Succ); + + Edge : Library_Graph_Edge_Id; + + begin + -- Nothing to do when the predecessor and successor are already + -- related by an edge. + + if Is_Recorded_Edge (G, Rel) then + return No_Library_Graph_Edge; + end if; + + Edge := Sequence_Next_Edge; + + -- Add the edge to the underlying graph. Note that the predecessor + -- is the source of the edge because it will later need to notify + -- all its successors that it has been elaborated. + + DG.Add_Edge + (G => G.Graph, + E => Edge, + Source => Pred, + Destination => Succ); + + -- Construct and save the attributes of the edge + + Set_LGE_Attributes + (G => G, + Edge => Edge, + Val => + (Activates_Task => Activates_Task, + Kind => Kind)); + + -- Mark the predecessor and successor as related by the new edge. + -- This prevents all further attempts to link the same predecessor + -- and successor. + + Set_Is_Recorded_Edge (G, Rel); + + -- Update the number of pending predecessors the successor must wait + -- on before it is elaborated. + + Increment_Pending_Predecessors + (G => G, + Vertex => Succ, + Edge => Edge); + + -- Update the edge statistics + + Increment_Library_Graph_Edge_Count (G, Kind); + + return Edge; + end Add_Edge_With_Return; + + ---------------- + -- Add_Vertex -- + ---------------- + + procedure Add_Vertex + (G : Library_Graph; + U_Id : Unit_Id) + is + Vertex : Library_Graph_Vertex_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (U_Id)); + + -- Nothing to do when the unit already has a vertex + + if Present (Corresponding_Vertex (G, U_Id)) then + return; + end if; + + Vertex := Sequence_Next_Vertex; + + -- Add the vertex to the underlying graph + + DG.Add_Vertex (G.Graph, Vertex); + + -- Construct and save the attributes of the vertex + + Set_LGV_Attributes + (G => G, + Vertex => Vertex, + Val => + (Corresponding_Item => No_Library_Graph_Vertex, + In_Elaboration_Order => False, + Pending_Strong_Predecessors => 0, + Pending_Weak_Predecessors => 0, + Unit => U_Id)); + + -- Associate the unit with its corresponding vertex + + Set_Corresponding_Vertex (G, U_Id, Vertex); + end Add_Vertex; + + --------------------------------- + -- At_Least_One_Edge_Satisfies -- + --------------------------------- + + function At_Least_One_Edge_Satisfies + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Predicate : LGE_Predicate_Ptr) return Boolean + is + Edge : Library_Graph_Edge_Id; + Iter : Edges_Of_Cycle_Iterator; + Satisfied : Boolean; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + pragma Assert (Predicate /= null); + + -- Assume that the predicate cannot be satisfied + + Satisfied := False; + + -- IMPORTANT: + -- + -- * The iteration must run to completion in order to unlock the + -- edges of the cycle. + + Iter := Iterate_Edges_Of_Cycle (G, Cycle); + while Has_Next (Iter) loop + Next (Iter, Edge); + + Satisfied := Satisfied or else Predicate.all (G, Edge); + end loop; + + return Satisfied; + end At_Least_One_Edge_Satisfies; + + -------------------------- + -- Complementary_Vertex -- + -------------------------- + + function Complementary_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Force_Complement : Boolean) return Library_Graph_Vertex_Id + is + Complement : Library_Graph_Vertex_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + -- Assume that there is no complementary vertex + + Complement := No_Library_Graph_Vertex; + + -- The caller requests the complement explicitly + + if Force_Complement then + Complement := Corresponding_Item (G, Vertex); + + -- The vertex is a completing body of a spec subject to pragma + -- Elaborate_Body. The complementary vertex is the spec. + + elsif Is_Body_Of_Spec_With_Elaborate_Body (G, Vertex) then + Complement := Proper_Spec (G, Vertex); + + -- The vertex is a spec subject to pragma Elaborate_Body. The + -- complementary vertex is the body. + + elsif Is_Spec_With_Elaborate_Body (G, Vertex) then + Complement := Proper_Body (G, Vertex); + end if; + + return Complement; + end Complementary_Vertex; + + --------------- + -- Component -- + --------------- + + function Component + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Component_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return DG.Component (G.Graph, Vertex); + end Component; + + --------------------------------- + -- Contains_Elaborate_All_Edge -- + --------------------------------- + + function Contains_Elaborate_All_Edge + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return + At_Least_One_Edge_Satisfies + (G => G, + Cycle => Cycle, + Predicate => Is_Elaborate_All_Edge'Access); + end Contains_Elaborate_All_Edge; + + ------------------------------------ + -- Contains_Static_Successor_Edge -- + ------------------------------------ + + function Contains_Static_Successor_Edge + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return + At_Least_One_Edge_Satisfies + (G => G, + Cycle => Cycle, + Predicate => Is_Static_Successor_Edge'Access); + end Contains_Static_Successor_Edge; + + ------------------------------ + -- Contains_Task_Activation -- + ------------------------------ + + function Contains_Task_Activation + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return + At_Least_One_Edge_Satisfies + (G => G, + Cycle => Cycle, + Predicate => Activates_Task'Access); + end Contains_Task_Activation; + + --------------------- + -- Copy_Cycle_Path -- + --------------------- + + function Copy_Cycle_Path + (Cycle_Path : LGE_Lists.Doubly_Linked_List) + return LGE_Lists.Doubly_Linked_List + is + Edge : Library_Graph_Edge_Id; + Iter : LGE_Lists.Iterator; + Path : LGE_Lists.Doubly_Linked_List; + + begin + pragma Assert (LGE_Lists.Present (Cycle_Path)); + + Path := LGE_Lists.Create; + Iter := LGE_Lists.Iterate (Cycle_Path); + while LGE_Lists.Has_Next (Iter) loop + LGE_Lists.Next (Iter, Edge); + + LGE_Lists.Append (Path, Edge); + end loop; + + return Path; + end Copy_Cycle_Path; + + ------------------------ + -- Corresponding_Item -- + ------------------------ + + function Corresponding_Item + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_LGV_Attributes (G, Vertex).Corresponding_Item; + end Corresponding_Item; + + -------------------------- + -- Corresponding_Vertex -- + -------------------------- + + function Corresponding_Vertex + (G : Library_Graph; + U_Id : Unit_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (U_Id)); + + return Unit_Tables.Get (G.Unit_To_Vertex, U_Id); + end Corresponding_Vertex; + + ------------ + -- Create -- + ------------ + + function Create + (Initial_Vertices : Positive; + Initial_Edges : Positive) return Library_Graph + is + G : constant Library_Graph := new Library_Graph_Attributes; + + begin + G.Component_Attributes := Component_Tables.Create (Initial_Vertices); + G.Cycle_Attributes := LGC_Tables.Create (Initial_Vertices); + G.Cycles := LGC_Lists.Create; + G.Edge_Attributes := LGE_Tables.Create (Initial_Edges); + G.Graph := + DG.Create + (Initial_Vertices => Initial_Vertices, + Initial_Edges => Initial_Edges); + G.Recorded_Edges := RE_Sets.Create (Initial_Edges); + G.Unit_To_Vertex := Unit_Tables.Create (Initial_Vertices); + G.Vertex_Attributes := LGV_Tables.Create (Initial_Vertices); + + return G; + end Create; + + ------------------------ + -- Cycle_End_Vertices -- + ------------------------ + + function Cycle_End_Vertices + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Elaborate_All_Active : Boolean) return LGV_Sets.Membership_Set + is + Complement : Library_Graph_Vertex_Id; + End_Vertices : LGV_Sets.Membership_Set := LGV_Sets.Nil; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + End_Vertices := LGV_Sets.Create (2); + + -- The input vertex always terminates a cycle path + + LGV_Sets.Insert (End_Vertices, Vertex); + + -- Add the complementary vertex to the set of cycle terminating + -- vertices when either Elaborate_All is in effect, or the input + -- vertex is part of an Elaborat_Body pair. + + if Elaborate_All_Active + or else Is_Vertex_With_Elaborate_Body (G, Vertex) + then + Complement := + Complementary_Vertex + (G => G, + Vertex => Vertex, + Force_Complement => Elaborate_All_Active); + + if Present (Complement) then + LGV_Sets.Insert (End_Vertices, Complement); + end if; + end if; + + return End_Vertices; + end Cycle_End_Vertices; + + ------------------- + -- Cycle_Kind_Of -- + ------------------- + + function Cycle_Kind_Of + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Cycle_Kind + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + begin + if Is_Cyclic_Elaborate_All_Edge (G, Edge) then + return Elaborate_All_Cycle; + + elsif Is_Cyclic_Elaborate_Body_Edge (G, Edge) then + return Elaborate_Body_Cycle; + + elsif Is_Cyclic_Elaborate_Edge (G, Edge) then + return Elaborate_Cycle; + + elsif Is_Cyclic_Forced_Edge (G, Edge) then + return Forced_Cycle; + + elsif Is_Cyclic_Invocation_Edge (G, Edge) then + return Invocation_Cycle; + + else + return No_Cycle_Kind; + end if; + end Cycle_Kind_Of; + + --------------------------- + -- Cycle_Kind_Precedence -- + --------------------------- + + function Cycle_Kind_Precedence + (Kind : Library_Graph_Cycle_Kind; + Compared_To : Library_Graph_Cycle_Kind) return Precedence_Kind + is + Comp_Pos : constant Integer := + Library_Graph_Cycle_Kind'Pos (Compared_To); + Kind_Pos : constant Integer := Library_Graph_Cycle_Kind'Pos (Kind); + + begin + -- A lower ordinal indicates a higher precedence + + if Kind_Pos < Comp_Pos then + return Higher_Precedence; + + elsif Kind_Pos > Comp_Pos then + return Lower_Precedence; + + else + return Equal_Precedence; + end if; + end Cycle_Kind_Precedence; + + --------------------------- + -- Cycle_Path_Precedence -- + --------------------------- + + function Cycle_Path_Precedence + (G : Library_Graph; + Path : LGE_Lists.Doubly_Linked_List; + Compared_To : LGE_Lists.Doubly_Linked_List) return Precedence_Kind + is + procedure Next_Available + (Iter : in out LGE_Lists.Iterator; + Edge : out Library_Graph_Edge_Id); + pragma Inline (Next_Available); + -- Obtain the next edge available through iterator Iter, or return + -- No_Library_Graph_Edge if the iterator has been exhausted. + + -------------------- + -- Next_Available -- + -------------------- + + procedure Next_Available + (Iter : in out LGE_Lists.Iterator; + Edge : out Library_Graph_Edge_Id) + is + begin + -- Assume that the iterator has been exhausted + + Edge := No_Library_Graph_Edge; + + if LGE_Lists.Has_Next (Iter) then + LGE_Lists.Next (Iter, Edge); + end if; + end Next_Available; + + -- Local variables + + Comp_Edge : Library_Graph_Edge_Id; + Comp_Iter : LGE_Lists.Iterator; + Path_Edge : Library_Graph_Edge_Id; + Path_Iter : LGE_Lists.Iterator; + Prec : Precedence_Kind; + + -- Start of processing for Cycle_Path_Precedence + + begin + pragma Assert (Present (G)); + pragma Assert (LGE_Lists.Present (Path)); + pragma Assert (LGE_Lists.Present (Compared_To)); + + -- Assume that the paths have equal precedence + + Prec := Equal_Precedence; + + Comp_Iter := LGE_Lists.Iterate (Compared_To); + Path_Iter := LGE_Lists.Iterate (Path); + + Next_Available (Comp_Iter, Comp_Edge); + Next_Available (Path_Iter, Path_Edge); + + -- IMPORTANT: + -- + -- * The iteration must run to completion in order to unlock the + -- edges of both paths. + + while Present (Comp_Edge) or else Present (Path_Edge) loop + if Prec = Equal_Precedence + and then Present (Comp_Edge) + and then Present (Path_Edge) + then + Prec := + Edge_Precedence + (G => G, + Edge => Path_Edge, + Compared_To => Comp_Edge); + end if; + + Next_Available (Comp_Iter, Comp_Edge); + Next_Available (Path_Iter, Path_Edge); + end loop; + + return Prec; + end Cycle_Path_Precedence; + + ---------------------- + -- Cycle_Precedence -- + ---------------------- + + function Cycle_Precedence + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Compared_To : Library_Graph_Cycle_Id) return Precedence_Kind + is + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + pragma Assert (Present (Compared_To)); + + Comp_Invs : constant Natural := + Invocation_Edge_Count (G, Compared_To); + Comp_Len : constant Natural := Length (G, Compared_To); + Cycle_Invs : constant Natural := Invocation_Edge_Count (G, Cycle); + Cycle_Len : constant Natural := Length (G, Cycle); + Kind_Prec : constant Precedence_Kind := + Cycle_Kind_Precedence + (Kind => Kind (G, Cycle), + Compared_To => Kind (G, Compared_To)); + + begin + -- Prefer a cycle with higher precedence based on its kind + + if Kind_Prec = Higher_Precedence + or else + Kind_Prec = Lower_Precedence + then + return Kind_Prec; + + -- Prefer a shorter cycle + + elsif Cycle_Len < Comp_Len then + return Higher_Precedence; + + elsif Cycle_Len > Comp_Len then + return Lower_Precedence; + + -- Prefer a cycle wih fewer invocation edges + + elsif Cycle_Invs < Comp_Invs then + return Higher_Precedence; + + elsif Cycle_Invs > Comp_Invs then + return Lower_Precedence; + + -- Prefer a cycle with a higher path precedence + + else + return + Cycle_Path_Precedence + (G => G, + Path => Path (G, Cycle), + Compared_To => Path (G, Compared_To)); + end if; + end Cycle_Precedence; + + ---------------------------------------- + -- Decrement_Library_Graph_Edge_Count -- + ---------------------------------------- + + procedure Decrement_Library_Graph_Edge_Count + (G : Library_Graph; + Kind : Library_Graph_Edge_Kind) + is + pragma Assert (Present (G)); + + Count : Natural renames G.Counts (Kind); + + begin + Count := Count - 1; + end Decrement_Library_Graph_Edge_Count; + + ------------------------------------ + -- Decrement_Pending_Predecessors -- + ------------------------------------ + + procedure Decrement_Pending_Predecessors + (G : Library_Graph; + Comp : Component_Id; + Edge : Library_Graph_Edge_Id) + is + Attrs : Component_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + Attrs := Get_Component_Attributes (G, Comp); + + Update_Pending_Predecessors + (Strong_Predecessors => Attrs.Pending_Strong_Predecessors, + Weak_Predecessors => Attrs.Pending_Weak_Predecessors, + Update_Weak => Is_Invocation_Edge (G, Edge), + Value => -1); + + Set_Component_Attributes (G, Comp, Attrs); + end Decrement_Pending_Predecessors; + + ------------------------------------ + -- Decrement_Pending_Predecessors -- + ------------------------------------ + + procedure Decrement_Pending_Predecessors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Edge : Library_Graph_Edge_Id) + is + Attrs : Library_Graph_Vertex_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Attrs := Get_LGV_Attributes (G, Vertex); + + Update_Pending_Predecessors + (Strong_Predecessors => Attrs.Pending_Strong_Predecessors, + Weak_Predecessors => Attrs.Pending_Weak_Predecessors, + Update_Weak => Is_Invocation_Edge (G, Edge), + Value => -1); + + Set_LGV_Attributes (G, Vertex, Attrs); + end Decrement_Pending_Predecessors; + + ----------------------------------- + -- Delete_Body_Before_Spec_Edges -- + ----------------------------------- + + procedure Delete_Body_Before_Spec_Edges + (G : Library_Graph; + Edges : LGE_Lists.Doubly_Linked_List) + is + Edge : Library_Graph_Edge_Id; + Iter : LGE_Lists.Iterator; + + begin + pragma Assert (Present (G)); + pragma Assert (LGE_Lists.Present (Edges)); + + Iter := LGE_Lists.Iterate (Edges); + while LGE_Lists.Has_Next (Iter) loop + LGE_Lists.Next (Iter, Edge); + pragma Assert (Kind (G, Edge) = Body_Before_Spec_Edge); + + Delete_Edge (G, Edge); + end loop; + end Delete_Body_Before_Spec_Edges; + + ----------------- + -- Delete_Edge -- + ----------------- + + procedure Delete_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + Pred : constant Library_Graph_Vertex_Id := Predecessor (G, Edge); + Succ : constant Library_Graph_Vertex_Id := Successor (G, Edge); + Rel : constant Predecessor_Successor_Relation := + (Predecessor => Pred, + Successor => Succ); + + begin + -- Update the edge statistics + + Decrement_Library_Graph_Edge_Count (G, Kind (G, Edge)); + + -- Update the number of pending predecessors the successor must wait + -- on before it is elaborated. + + Decrement_Pending_Predecessors + (G => G, + Vertex => Succ, + Edge => Edge); + + -- Delete the link between the predecessor and successor. This allows + -- for further attempts to link the same predecessor and successor. + + RE_Sets.Delete (G.Recorded_Edges, Rel); + + -- Delete the attributes of the edge + + LGE_Tables.Delete (G.Edge_Attributes, Edge); + + -- Delete the edge from the underlying graph + + DG.Delete_Edge (G.Graph, Edge); + end Delete_Edge; + + ------------- + -- Destroy -- + ------------- + + procedure Destroy (G : in out Library_Graph) is + begin + pragma Assert (Present (G)); + + Component_Tables.Destroy (G.Component_Attributes); + LGC_Tables.Destroy (G.Cycle_Attributes); + LGC_Lists.Destroy (G.Cycles); + LGE_Tables.Destroy (G.Edge_Attributes); + DG.Destroy (G.Graph); + RE_Sets.Destroy (G.Recorded_Edges); + Unit_Tables.Destroy (G.Unit_To_Vertex); + LGV_Tables.Destroy (G.Vertex_Attributes); + + Free (G); + end Destroy; + + ---------------------------------- + -- Destroy_Component_Attributes -- + ---------------------------------- + + procedure Destroy_Component_Attributes + (Attrs : in out Component_Attributes) + is + pragma Unreferenced (Attrs); + begin + null; + end Destroy_Component_Attributes; + + -------------------------------------------- + -- Destroy_Library_Graph_Cycle_Attributes -- + -------------------------------------------- + + procedure Destroy_Library_Graph_Cycle_Attributes + (Attrs : in out Library_Graph_Cycle_Attributes) + is + begin + LGE_Lists.Destroy (Attrs.Path); + end Destroy_Library_Graph_Cycle_Attributes; + + ------------------------------------------- + -- Destroy_Library_Graph_Edge_Attributes -- + ------------------------------------------- + + procedure Destroy_Library_Graph_Edge_Attributes + (Attrs : in out Library_Graph_Edge_Attributes) + is + pragma Unreferenced (Attrs); + begin + null; + end Destroy_Library_Graph_Edge_Attributes; + + --------------------------------------------- + -- Destroy_Library_Graph_Vertex_Attributes -- + --------------------------------------------- + + procedure Destroy_Library_Graph_Vertex_Attributes + (Attrs : in out Library_Graph_Vertex_Attributes) + is + pragma Unreferenced (Attrs); + begin + null; + end Destroy_Library_Graph_Vertex_Attributes; + + --------------------- + -- Edge_Precedence -- + --------------------- + + function Edge_Precedence + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Compared_To : Library_Graph_Edge_Id) return Precedence_Kind + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + pragma Assert (Present (Compared_To)); + + Comp_Succ : constant Library_Graph_Vertex_Id := + Successor (G, Compared_To); + Edge_Succ : constant Library_Graph_Vertex_Id := + Successor (G, Edge); + Kind_Prec : constant Precedence_Kind := + Cycle_Kind_Precedence + (Kind => Cycle_Kind_Of (G, Edge), + Compared_To => Cycle_Kind_Of (G, Compared_To)); + Succ_Prec : constant Precedence_Kind := + Vertex_Precedence + (G => G, + Vertex => Edge_Succ, + Compared_To => Comp_Succ); + + begin + -- Prefer an edge with a higher cycle kind precedence + + if Kind_Prec = Higher_Precedence + or else + Kind_Prec = Lower_Precedence + then + return Kind_Prec; + + -- Prefer an edge whose successor has a higher precedence + + elsif Comp_Succ /= Edge_Succ + and then (Succ_Prec = Higher_Precedence + or else + Succ_Prec = Lower_Precedence) + then + return Succ_Prec; + + -- Prefer an edge whose predecessor has a higher precedence + + else + return + Vertex_Precedence + (G => G, + Vertex => Predecessor (G, Edge), + Compared_To => Predecessor (G, Compared_To)); + end if; + end Edge_Precedence; + + --------------- + -- File_Name -- + --------------- + + function File_Name + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return File_Name_Type + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return File_Name (Unit (G, Vertex)); + end File_Name; + + --------------------- + -- Find_Components -- + --------------------- + + procedure Find_Components (G : Library_Graph) is + Edges : LGE_Lists.Doubly_Linked_List; + + begin + pragma Assert (Present (G)); + + Start_Phase (Component_Discovery); + + -- Initialize or reinitialize the components of the graph + + Initialize_Components (G); + + -- Create a set of special edges that link a predecessor body with a + -- successor spec. This is an illegal dependency, however using such + -- edges eliminates the need to create yet another graph, where both + -- spec and body are collapsed into a single vertex. + + Edges := LGE_Lists.Create; + Add_Body_Before_Spec_Edges (G, Edges); + + DG.Find_Components (G.Graph); + + -- Remove the special edges that link a predecessor body with a + -- successor spec because they cause unresolvable circularities. + + Delete_Body_Before_Spec_Edges (G, Edges); + LGE_Lists.Destroy (Edges); + + -- Update the number of predecessors various components must wait on + -- before they can be elaborated. + + Update_Pending_Predecessors_Of_Components (G); + End_Phase (Component_Discovery); + end Find_Components; + + ----------------- + -- Find_Cycles -- + ----------------- + + procedure Find_Cycles (G : Library_Graph) is + All_Cycle_Limit : constant Natural := 64; + -- The performance of Tarjan's algorithm may degrate to exponential + -- when pragma Elaborate_All is in effect, or some vertex is part of + -- an Elaborate_Body pair. In this case the algorithm discovers all + -- combinations of edges that close a circuit starting and ending on + -- some start vertex while going through different vertices. Use a + -- limit on the total number of cycles within a component to guard + -- against such degradation. + + Comp : Component_Id; + Cycle_Count : Natural; + Iter : Component_Iterator; + + begin + pragma Assert (Present (G)); + + Start_Phase (Cycle_Discovery); + + -- The cycles of graph G are discovered using Tarjan's enumeration + -- of the elementary circuits of a directed-graph algorithm. Do not + -- modify this code unless you intimately understand the algorithm. + -- + -- The logic of the algorithm is split among the following routines: + -- + -- Cycle_End_Vertices + -- Find_Cycles_From_Successor + -- Find_Cycles_From_Vertex + -- Find_Cycles_In_Component + -- Unvisit + -- Visit + -- + -- The original algorithm has been significantly modified in order to + -- + -- * Accommodate the semantics of Elaborate_All and Elaborate_Body. + -- + -- * Capture cycle paths as edges rather than vertices. + -- + -- * Take advantage of graph components. + + -- Assume that the graph does not contain a cycle + + Cycle_Count := 0; + + -- Run the modified version of the algorithm on each component of the + -- graph. + + Iter := Iterate_Components (G); + while Has_Next (Iter) loop + Next (Iter, Comp); + + Find_Cycles_In_Component + (G => G, + Comp => Comp, + Cycle_Count => Cycle_Count, + Cycle_Limit => All_Cycle_Limit); + end loop; + + End_Phase (Cycle_Discovery); + end Find_Cycles; + + -------------------------------- + -- Find_Cycles_From_Successor -- + -------------------------------- + + procedure Find_Cycles_From_Successor + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + End_Vertices : LGV_Sets.Membership_Set; + Deleted_Vertices : LGV_Sets.Membership_Set; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path_Stack : LGE_Lists.Doubly_Linked_List; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List; + Cycle_Count : in out Natural; + Cycle_Limit : Natural; + Elaborate_All_Active : Boolean; + Has_Cycle : out Boolean; + Indent : Indentation_Level) + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + pragma Assert (LGV_Sets.Present (End_Vertices)); + pragma Assert (LGV_Sets.Present (Deleted_Vertices)); + pragma Assert (LGE_Lists.Present (Cycle_Path_Stack)); + pragma Assert (LGV_Sets.Present (Visited_Set)); + pragma Assert (LGV_Lists.Present (Visited_Stack)); + + Succ : constant Library_Graph_Vertex_Id := Successor (G, Edge); + Succ_Indent : constant Indentation_Level := + Indent + Nested_Indentation; + + begin + -- Assume that the successor reached via the edge does not result in + -- a cycle. + + Has_Cycle := False; + + -- Nothing to do when the edge connects two vertices residing in two + -- different components. + + if not Is_Cyclic_Edge (G, Edge) then + return; + end if; + + Trace_Edge (G, Edge, Indent); + + -- The modified version does not place vertices on the "point stack", + -- but instead collects the edges comprising the cycle. Prepare the + -- edge for backtracking. + + LGE_Lists.Prepend (Cycle_Path_Stack, Edge); + + Find_Cycles_From_Vertex + (G => G, + Vertex => Succ, + End_Vertices => End_Vertices, + Deleted_Vertices => Deleted_Vertices, + Most_Significant_Edge => Most_Significant_Edge, + Invocation_Edge_Count => Invocation_Edge_Count, + Cycle_Path_Stack => Cycle_Path_Stack, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack, + Cycle_Count => Cycle_Count, + Cycle_Limit => Cycle_Limit, + Elaborate_All_Active => Elaborate_All_Active, + Is_Start_Vertex => False, + Has_Cycle => Has_Cycle, + Indent => Succ_Indent); + + -- The modified version does not place vertices on the "point stack", + -- but instead collects the edges comprising the cycle. Backtrack the + -- edge. + + LGE_Lists.Delete_First (Cycle_Path_Stack); + end Find_Cycles_From_Successor; + + ----------------------------- + -- Find_Cycles_From_Vertex -- + ----------------------------- + + procedure Find_Cycles_From_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + End_Vertices : LGV_Sets.Membership_Set; + Deleted_Vertices : LGV_Sets.Membership_Set; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path_Stack : LGE_Lists.Doubly_Linked_List; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List; + Cycle_Count : in out Natural; + Cycle_Limit : Natural; + Elaborate_All_Active : Boolean; + Is_Start_Vertex : Boolean; + Has_Cycle : out Boolean; + Indent : Indentation_Level) + is + Edge_Indent : constant Indentation_Level := + Indent + Nested_Indentation; + + Complement : Library_Graph_Vertex_Id; + Edge : Library_Graph_Edge_Id; + Iter : Edges_To_Successors_Iterator; + + Complement_Has_Cycle : Boolean; + -- This flag is set when either Elaborate_All is in effect or the + -- current vertex is part of an Elaborate_Body pair, and visiting + -- the "complementary" vertex resulted in a cycle. + + Successor_Has_Cycle : Boolean; + -- This flag is set when visiting at least one successor of the + -- current vertex resulted in a cycle. + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + pragma Assert (LGV_Sets.Present (End_Vertices)); + pragma Assert (LGV_Sets.Present (Deleted_Vertices)); + pragma Assert (LGE_Lists.Present (Cycle_Path_Stack)); + pragma Assert (LGV_Sets.Present (Visited_Set)); + pragma Assert (LGV_Lists.Present (Visited_Stack)); + + -- Assume that the vertex does not close a circuit + + Has_Cycle := False; + + -- Nothing to do when the limit on the number of saved cycles has + -- been reached. This protects against a combinatorial explosion + -- in components with Elaborate_All cycles. + + if Cycle_Count >= Cycle_Limit then + return; + + -- The vertex closes the circuit, thus resulting in a cycle. Save + -- the cycle for later diagnostics. The initial invocation of the + -- routine always ignores the starting vertex, to prevent a spurious + -- self-cycle. + + elsif not Is_Start_Vertex + and then LGV_Sets.Contains (End_Vertices, Vertex) + then + Trace_Vertex (G, Vertex, Indent); + + Record_Cycle + (G => G, + Most_Significant_Edge => Most_Significant_Edge, + Invocation_Edge_Count => Invocation_Edge_Count, + Cycle_Path => Cycle_Path_Stack, + Indent => Indent); + + Has_Cycle := True; + Cycle_Count := Cycle_Count + 1; + return; + + -- Nothing to do when the vertex has already been deleted. This + -- indicates that all available cycles involving the vertex have + -- been discovered, and the vertex cannot contribute further to + -- the depth-first search. + + elsif LGV_Sets.Contains (Deleted_Vertices, Vertex) then + return; + + -- Nothing to do when the vertex has already been visited. This + -- indicates that the depth-first search initiated from some start + -- vertex already encountered this vertex, and the visited stack has + -- not been unrolled yet. + + elsif LGV_Sets.Contains (Visited_Set, Vertex) then + return; + end if; + + Trace_Vertex (G, Vertex, Indent); + + -- Mark the vertex as visited + + Visit + (Vertex => Vertex, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack); + + -- Extend the depth-first search via all the edges to successors + + Iter := Iterate_Edges_To_Successors (G, Vertex); + while Has_Next (Iter) loop + Next (Iter, Edge); + + Find_Cycles_From_Successor + (G => G, + Edge => Edge, + End_Vertices => End_Vertices, + Deleted_Vertices => Deleted_Vertices, + + -- The edge may be more important than the most important edge + -- up to this point, thus "upgrading" the nature of the cycle, + -- and shifting its point of normalization. + + Most_Significant_Edge => + Highest_Precedence_Edge + (G => G, + Left => Edge, + Right => Most_Significant_Edge), + + -- The edge may be an invocation edge, in which case the count + -- of invocation edges increases by one. + + Invocation_Edge_Count => + Maximum_Invocation_Edge_Count + (G => G, + Edge => Edge, + Count => Invocation_Edge_Count), + + Cycle_Path_Stack => Cycle_Path_Stack, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack, + Cycle_Count => Cycle_Count, + Cycle_Limit => Cycle_Limit, + Elaborate_All_Active => Elaborate_All_Active, + Has_Cycle => Successor_Has_Cycle, + Indent => Edge_Indent); + + Has_Cycle := Has_Cycle or Successor_Has_Cycle; + end loop; + + -- Visit the complementary vertex of the current vertex when pragma + -- Elaborate_All is in effect, or the current vertex is part of an + -- Elaborate_Body pair. + + if Elaborate_All_Active + or else Is_Vertex_With_Elaborate_Body (G, Vertex) + then + Complement := + Complementary_Vertex + (G => G, + Vertex => Vertex, + Force_Complement => Elaborate_All_Active); + + if Present (Complement) then + Find_Cycles_From_Vertex + (G => G, + Vertex => Complement, + End_Vertices => End_Vertices, + Deleted_Vertices => Deleted_Vertices, + Most_Significant_Edge => Most_Significant_Edge, + Invocation_Edge_Count => Invocation_Edge_Count, + Cycle_Path_Stack => Cycle_Path_Stack, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack, + Cycle_Count => Cycle_Count, + Cycle_Limit => Cycle_Limit, + Elaborate_All_Active => Elaborate_All_Active, + Is_Start_Vertex => Is_Start_Vertex, + Has_Cycle => Complement_Has_Cycle, + Indent => Indent); + + Has_Cycle := Has_Cycle or Complement_Has_Cycle; + end if; + end if; + + -- The original algorithm clears the "marked stack" in two places: + -- + -- * When the depth-first search starting from the current vertex + -- discovers at least one cycle, and + -- + -- * When the depth-first search initiated from a start vertex + -- completes. + -- + -- The modified version handles both cases in one place. + + if Has_Cycle or else Is_Start_Vertex then + Unvisit + (Vertex => Vertex, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack); + end if; + + -- Delete a start vertex from the graph once its depth-first search + -- completes. This action preserves the invariant where a cycle is + -- not rediscovered "later" in some permuted form. + + if Is_Start_Vertex then + LGV_Sets.Insert (Deleted_Vertices, Vertex); + end if; + end Find_Cycles_From_Vertex; + + ------------------------------ + -- Find_Cycles_In_Component -- + ------------------------------ + + procedure Find_Cycles_In_Component + (G : Library_Graph; + Comp : Component_Id; + Cycle_Count : in out Natural; + Cycle_Limit : Natural) + is + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + Num_Of_Vertices : constant Natural := + Number_Of_Component_Vertices (G, Comp); + + Elaborate_All_Active : constant Boolean := + Has_Elaborate_All_Edge (G, Comp); + -- The presence of an Elaborate_All edge within a component causes + -- all spec-body pairs to be treated as one vertex. + + Has_Cycle : Boolean; + Iter : Component_Vertex_Iterator; + Vertex : Library_Graph_Vertex_Id; + + Cycle_Path_Stack : LGE_Lists.Doubly_Linked_List := LGE_Lists.Nil; + -- The "point stack" of Tarjan's algorithm. The original maintains + -- a stack of vertices, however for diagnostic purposes using edges + -- is preferable. + + Deleted_Vertices : LGV_Sets.Membership_Set := LGV_Sets.Nil; + -- The original algorithm alters the graph by deleting vertices with + -- lower ordinals compared to some starting vertex. Since the graph + -- must remain intact for diagnostic purposes, vertices are instead + -- inserted in this set and treated as "deleted". + + End_Vertices : LGV_Sets.Membership_Set := LGV_Sets.Nil; + -- The original algorithm uses a single vertex to indicate the start + -- and end vertex of a cycle. The semantics of pragmas Elaborate_All + -- and Elaborate_Body increase this number by one. The end vertices + -- are added to this set and treated as "cycle-terminating". + + Visited_Set : LGV_Sets.Membership_Set := LGV_Sets.Nil; + -- The "mark" array of Tarjan's algorithm. Since the original visits + -- all vertices in increasing ordinal number 1 .. N, the array offers + -- a one-to-one mapping between a vertex and its "marked" state. The + -- modified version however visits vertices within components, where + -- their ordinals are not contiguous. Vertices are added to this set + -- and treated as "marked". + + Visited_Stack : LGV_Lists.Doubly_Linked_List := LGV_Lists.Nil; + -- The "marked stack" of Tarjan's algorithm + + begin + Trace_Component (G, Comp, No_Indentation); + + -- Initialize all component-level data structures + + Cycle_Path_Stack := LGE_Lists.Create; + Deleted_Vertices := LGV_Sets.Create (Num_Of_Vertices); + Visited_Set := LGV_Sets.Create (Num_Of_Vertices); + Visited_Stack := LGV_Lists.Create; + + -- The modified version does not use ordinals to visit vertices in + -- 1 .. N fashion. To preserve the invariant of the original, this + -- version deletes a vertex after its depth-first search completes. + -- The timing of the deletion is sound because all cycles through + -- that vertex have already been discovered, thus the vertex cannot + -- contribute to any cycles discovered "later" in the algorithm. + + Iter := Iterate_Component_Vertices (G, Comp); + while Has_Next (Iter) loop + Next (Iter, Vertex); + + -- Construct the set of vertices (at most 2) that terminates a + -- potential cycle that starts from the current vertex. + + End_Vertices := + Cycle_End_Vertices + (G => G, + Vertex => Vertex, + Elaborate_All_Active => Elaborate_All_Active); + + -- The modified version maintains two additional attributes while + -- performing the depth-first search: + -- + -- * The most significant edge of the current potential cycle. + -- + -- * The number of invocation edges encountered along the path + -- of the current potential cycle. + -- + -- Both attributes are used in the heuristic that determines the + -- importance of cycles. + + Find_Cycles_From_Vertex + (G => G, + Vertex => Vertex, + End_Vertices => End_Vertices, + Deleted_Vertices => Deleted_Vertices, + Most_Significant_Edge => No_Library_Graph_Edge, + Invocation_Edge_Count => 0, + Cycle_Path_Stack => Cycle_Path_Stack, + Visited_Set => Visited_Set, + Visited_Stack => Visited_Stack, + Cycle_Count => Cycle_Count, + Cycle_Limit => Cycle_Limit, + Elaborate_All_Active => Elaborate_All_Active, + Is_Start_Vertex => True, + Has_Cycle => Has_Cycle, + Indent => Nested_Indentation); + + -- Destroy the cycle-terminating vertices because a new set must + -- be constructed for the next vertex. + + LGV_Sets.Destroy (End_Vertices); + end loop; + + -- Destroy all component-level data structures + + LGE_Lists.Destroy (Cycle_Path_Stack); + LGV_Sets.Destroy (Deleted_Vertices); + LGV_Sets.Destroy (Visited_Set); + LGV_Lists.Destroy (Visited_Stack); + end Find_Cycles_In_Component; + + --------------------------------------- + -- Find_First_Lower_Precedence_Cycle -- + --------------------------------------- + + function Find_First_Lower_Precedence_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Id + is + Current_Cycle : Library_Graph_Cycle_Id; + Iter : All_Cycle_Iterator; + Lesser_Cycle : Library_Graph_Cycle_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + -- Assume that there is no lesser cycle + + Lesser_Cycle := No_Library_Graph_Cycle; + + -- Find a cycle with a slightly lower precedence than the input + -- cycle. + -- + -- IMPORTANT: + -- + -- * The iterator must run to completion in order to unlock the + -- list of all cycles. + + Iter := Iterate_All_Cycles (G); + while Has_Next (Iter) loop + Next (Iter, Current_Cycle); + + if not Present (Lesser_Cycle) + and then Cycle_Precedence + (G => G, + Cycle => Cycle, + Compared_To => Current_Cycle) = Higher_Precedence + then + Lesser_Cycle := Current_Cycle; + end if; + end loop; + + return Lesser_Cycle; + end Find_First_Lower_Precedence_Cycle; + + ------------------------------ + -- Get_Component_Attributes -- + ------------------------------ + + function Get_Component_Attributes + (G : Library_Graph; + Comp : Component_Id) return Component_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + return Component_Tables.Get (G.Component_Attributes, Comp); + end Get_Component_Attributes; + + ------------------------ + -- Get_LGC_Attributes -- + ------------------------ + + function Get_LGC_Attributes + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return LGC_Tables.Get (G.Cycle_Attributes, Cycle); + end Get_LGC_Attributes; + + ------------------------ + -- Get_LGE_Attributes -- + ------------------------ + + function Get_LGE_Attributes + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Edge_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return LGE_Tables.Get (G.Edge_Attributes, Edge); + end Get_LGE_Attributes; + + ------------------------ + -- Get_LGV_Attributes -- + ------------------------ + + function Get_LGV_Attributes + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) + return Library_Graph_Vertex_Attributes + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return LGV_Tables.Get (G.Vertex_Attributes, Vertex); + end Get_LGV_Attributes; + + ----------------------------- + -- Has_Elaborate_All_Cycle -- + ----------------------------- + + function Has_Elaborate_All_Cycle (G : Library_Graph) return Boolean is + Edge : Library_Graph_Edge_Id; + Iter : All_Edge_Iterator; + Seen : Boolean; + + begin + pragma Assert (Present (G)); + + -- Assume that no cyclic Elaborate_All edge has been seen + + Seen := False; + + -- IMPORTANT: + -- + -- * The iteration must run to completion in order to unlock the + -- graph. + + Iter := Iterate_All_Edges (G); + while Has_Next (Iter) loop + Next (Iter, Edge); + + if not Seen and then Is_Cyclic_Elaborate_All_Edge (G, Edge) then + Seen := True; + end if; + end loop; + + return Seen; + end Has_Elaborate_All_Cycle; + + ---------------------------- + -- Has_Elaborate_All_Edge -- + ---------------------------- + + function Has_Elaborate_All_Edge + (G : Library_Graph; + Comp : Component_Id) return Boolean + is + Has_Edge : Boolean; + Iter : Component_Vertex_Iterator; + Vertex : Library_Graph_Vertex_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + -- Assume that there is no Elaborate_All edge + + Has_Edge := False; + + -- IMPORTANT: + -- + -- * The iteration must run to completion in order to unlock the + -- component vertices. + + Iter := Iterate_Component_Vertices (G, Comp); + while Has_Next (Iter) loop + Next (Iter, Vertex); + + Has_Edge := Has_Edge or else Has_Elaborate_All_Edge (G, Vertex); + end loop; + + return Has_Edge; + end Has_Elaborate_All_Edge; + + ---------------------------- + -- Has_Elaborate_All_Edge -- + ---------------------------- + + function Has_Elaborate_All_Edge + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + Edge : Library_Graph_Edge_Id; + Has_Edge : Boolean; + Iter : Edges_To_Successors_Iterator; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + -- Assume that there is no Elaborate_All edge + + Has_Edge := False; + + -- IMPORTANT: + -- + -- * The iteration must run to completion in order to unlock the + -- edges to successors. + + Iter := Iterate_Edges_To_Successors (G, Vertex); + while Has_Next (Iter) loop + Next (Iter, Edge); + + Has_Edge := + Has_Edge or else Is_Cyclic_Elaborate_All_Edge (G, Edge); + end loop; + + return Has_Edge; + end Has_Elaborate_All_Edge; + + ------------------------ + -- Has_Elaborate_Body -- + ------------------------ + + function Has_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + -- Treat the spec and body as decoupled when switch -d_b (ignore the + -- effects of pragma Elaborate_Body) is in effect. + + return U_Rec.Elaborate_Body and not Debug_Flag_Underscore_B; + end Has_Elaborate_Body; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : All_Cycle_Iterator) return Boolean is + begin + return LGC_Lists.Has_Next (LGC_Lists.Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : All_Edge_Iterator) return Boolean is + begin + return DG.Has_Next (DG.All_Edge_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : All_Vertex_Iterator) return Boolean is + begin + return DG.Has_Next (DG.All_Vertex_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Component_Iterator) return Boolean is + begin + return DG.Has_Next (DG.Component_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Component_Vertex_Iterator) return Boolean is + begin + return DG.Has_Next (DG.Component_Vertex_Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Edges_Of_Cycle_Iterator) return Boolean is + begin + return LGE_Lists.Has_Next (LGE_Lists.Iterator (Iter)); + end Has_Next; + + -------------- + -- Has_Next -- + -------------- + + function Has_Next (Iter : Edges_To_Successors_Iterator) return Boolean is + begin + return DG.Has_Next (DG.Outgoing_Edge_Iterator (Iter)); + end Has_Next; + + ----------------------------- + -- Has_No_Elaboration_Code -- + ----------------------------- + + function Has_No_Elaboration_Code + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Has_No_Elaboration_Code (Unit (G, Vertex)); + end Has_No_Elaboration_Code; + + ----------------------------------------- + -- Hash_Library_Graph_Cycle_Attributes -- + ----------------------------------------- + + function Hash_Library_Graph_Cycle_Attributes + (Attrs : Library_Graph_Cycle_Attributes) return Bucket_Range_Type + is + Edge : Library_Graph_Edge_Id; + Hash : Bucket_Range_Type; + Iter : LGE_Lists.Iterator; + + begin + pragma Assert (LGE_Lists.Present (Attrs.Path)); + + -- The hash is obtained in the following manner: + -- + -- (((edge1 * 31) + edge2) * 31) + edgeN + + Hash := 0; + Iter := LGE_Lists.Iterate (Attrs.Path); + while LGE_Lists.Has_Next (Iter) loop + LGE_Lists.Next (Iter, Edge); + + Hash := (Hash * 31) + Bucket_Range_Type (Edge); + end loop; + + return Hash; + end Hash_Library_Graph_Cycle_Attributes; + + ----------------------------------------- + -- Hash_Predecessor_Successor_Relation -- + ----------------------------------------- + + function Hash_Predecessor_Successor_Relation + (Rel : Predecessor_Successor_Relation) return Bucket_Range_Type + is + begin + pragma Assert (Present (Rel.Predecessor)); + pragma Assert (Present (Rel.Successor)); + + return + Hash_Two_Keys + (Bucket_Range_Type (Rel.Predecessor), + Bucket_Range_Type (Rel.Successor)); + end Hash_Predecessor_Successor_Relation; + + ------------------------------ + -- Highest_Precedence_Cycle -- + ------------------------------ + + function Highest_Precedence_Cycle + (G : Library_Graph) return Library_Graph_Cycle_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (LGC_Lists.Present (G.Cycles)); + + if LGC_Lists.Is_Empty (G.Cycles) then + return No_Library_Graph_Cycle; + + -- The highest precedence cycle is always the first in the list of + -- all cycles. + + else + return LGC_Lists.First (G.Cycles); + end if; + end Highest_Precedence_Cycle; + + ----------------------------- + -- Highest_Precedence_Edge -- + ----------------------------- + + function Highest_Precedence_Edge + (G : Library_Graph; + Left : Library_Graph_Edge_Id; + Right : Library_Graph_Edge_Id) return Library_Graph_Edge_Id + is + Edge_Prec : Precedence_Kind; + + begin + pragma Assert (Present (G)); + + -- Both edges are available, pick the one with highest precedence + + if Present (Left) and then Present (Right) then + Edge_Prec := + Edge_Precedence + (G => G, + Edge => Left, + Compared_To => Right); + + if Edge_Prec = Higher_Precedence then + return Left; + + -- The precedence rules for edges are such that no two edges can + -- ever have the same precedence. + + else + pragma Assert (Edge_Prec = Lower_Precedence); + return Right; + end if; + + -- Otherwise at least one edge must be present + + elsif Present (Left) then + return Left; + + else + pragma Assert (Present (Right)); + + return Right; + end if; + end Highest_Precedence_Edge; + + -------------------------- + -- In_Elaboration_Order -- + -------------------------- + + function In_Elaboration_Order + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_LGV_Attributes (G, Vertex).In_Elaboration_Order; + end In_Elaboration_Order; + + ----------------------- + -- In_Same_Component -- + ----------------------- + + function In_Same_Component + (G : Library_Graph; + Left : Library_Graph_Vertex_Id; + Right : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Left)); + pragma Assert (Present (Right)); + + return Component (G, Left) = Component (G, Right); + end In_Same_Component; + + ---------------------------------------- + -- Increment_Library_Graph_Edge_Count -- + ---------------------------------------- + + procedure Increment_Library_Graph_Edge_Count + (G : Library_Graph; + Kind : Library_Graph_Edge_Kind) + is + pragma Assert (Present (G)); + + Count : Natural renames G.Counts (Kind); + + begin + Count := Count + 1; + end Increment_Library_Graph_Edge_Count; + + ------------------------------------ + -- Increment_Pending_Predecessors -- + ------------------------------------ + + procedure Increment_Pending_Predecessors + (G : Library_Graph; + Comp : Component_Id; + Edge : Library_Graph_Edge_Id) + is + Attrs : Component_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + Attrs := Get_Component_Attributes (G, Comp); + + Update_Pending_Predecessors + (Strong_Predecessors => Attrs.Pending_Strong_Predecessors, + Weak_Predecessors => Attrs.Pending_Weak_Predecessors, + Update_Weak => Is_Invocation_Edge (G, Edge), + Value => 1); + + Set_Component_Attributes (G, Comp, Attrs); + end Increment_Pending_Predecessors; + + ------------------------------------ + -- Increment_Pending_Predecessors -- + ------------------------------------ + + procedure Increment_Pending_Predecessors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Edge : Library_Graph_Edge_Id) + is + Attrs : Library_Graph_Vertex_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Attrs := Get_LGV_Attributes (G, Vertex); + + Update_Pending_Predecessors + (Strong_Predecessors => Attrs.Pending_Strong_Predecessors, + Weak_Predecessors => Attrs.Pending_Weak_Predecessors, + Update_Weak => Is_Invocation_Edge (G, Edge), + Value => 1); + + Set_LGV_Attributes (G, Vertex, Attrs); + end Increment_Pending_Predecessors; + + --------------------------- + -- Initialize_Components -- + --------------------------- + + procedure Initialize_Components (G : Library_Graph) is + begin + pragma Assert (Present (G)); + + -- The graph already contains a set of components. Reinitialize + -- them in order to accommodate the new set of components about to + -- be computed. + + if Number_Of_Components (G) > 0 then + Component_Tables.Destroy (G.Component_Attributes); + + G.Component_Attributes := + Component_Tables.Create (Number_Of_Vertices (G)); + end if; + end Initialize_Components; + + --------------------------- + -- Invocation_Edge_Count -- + --------------------------- + + function Invocation_Edge_Count + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return Get_LGC_Attributes (G, Cycle).Invocation_Edge_Count; + end Invocation_Edge_Count; + + ------------------------------- + -- Invocation_Graph_Encoding -- + ------------------------------- + + function Invocation_Graph_Encoding + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) + return Invocation_Graph_Encoding_Kind + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Invocation_Graph_Encoding (Unit (G, Vertex)); + end Invocation_Graph_Encoding; + + ------------- + -- Is_Body -- + ------------- + + function Is_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + return U_Rec.Utype = Is_Body or else U_Rec.Utype = Is_Body_Only; + end Is_Body; + + ----------------------------------------- + -- Is_Body_Of_Spec_With_Elaborate_Body -- + ----------------------------------------- + + function Is_Body_Of_Spec_With_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + if Is_Body_With_Spec (G, Vertex) then + return + Is_Spec_With_Elaborate_Body + (G => G, + Vertex => Proper_Spec (G, Vertex)); + end if; + + return False; + end Is_Body_Of_Spec_With_Elaborate_Body; + + ----------------------- + -- Is_Body_With_Spec -- + ----------------------- + + function Is_Body_With_Spec + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + return U_Rec.Utype = Is_Body; + end Is_Body_With_Spec; + + ------------------------------ + -- Is_Cycle_Initiating_Edge -- + ------------------------------ + + function Is_Cycle_Initiating_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Cyclic_Elaborate_All_Edge (G, Edge) + or else Is_Cyclic_Elaborate_Body_Edge (G, Edge) + or else Is_Cyclic_Elaborate_Edge (G, Edge) + or else Is_Cyclic_Forced_Edge (G, Edge) + or else Is_Cyclic_Invocation_Edge (G, Edge); + end Is_Cycle_Initiating_Edge; + + -------------------- + -- Is_Cyclic_Edge -- + -------------------- + + function Is_Cyclic_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Cycle_Initiating_Edge (G, Edge) + or else Is_Cyclic_With_Edge (G, Edge); + end Is_Cyclic_Edge; + + ---------------------------------- + -- Is_Cyclic_Elaborate_All_Edge -- + ---------------------------------- + + function Is_Cyclic_Elaborate_All_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Elaborate_All_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge); + end Is_Cyclic_Elaborate_All_Edge; + + ----------------------------------- + -- Is_Cyclic_Elaborate_Body_Edge -- + ----------------------------------- + + function Is_Cyclic_Elaborate_Body_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Elaborate_Body_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge); + end Is_Cyclic_Elaborate_Body_Edge; + + ------------------------------ + -- Is_Cyclic_Elaborate_Edge -- + ------------------------------ + + function Is_Cyclic_Elaborate_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Elaborate_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge); + end Is_Cyclic_Elaborate_Edge; + + --------------------------- + -- Is_Cyclic_Forced_Edge -- + --------------------------- + + function Is_Cyclic_Forced_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Forced_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge); + end Is_Cyclic_Forced_Edge; + + ------------------------------- + -- Is_Cyclic_Invocation_Edge -- + ------------------------------- + + function Is_Cyclic_Invocation_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Invocation_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge); + end Is_Cyclic_Invocation_Edge; + + ------------------------- + -- Is_Cyclic_With_Edge -- + ------------------------- + + function Is_Cyclic_With_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + -- Ignore Elaborate_Body edges because they also appear as with + -- edges, but have special successors. + + return + Is_With_Edge (G, Edge) + and then Links_Vertices_In_Same_Component (G, Edge) + and then not Is_Elaborate_Body_Edge (G, Edge); + end Is_Cyclic_With_Edge; + + ------------------------------- + -- Is_Dynamically_Elaborated -- + ------------------------------- + + function Is_Dynamically_Elaborated + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Is_Dynamically_Elaborated (Unit (G, Vertex)); + end Is_Dynamically_Elaborated; + + ----------------------------- + -- Is_Elaborable_Component -- + ----------------------------- + + function Is_Elaborable_Component + (G : Library_Graph; + Comp : Component_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + -- A component is elaborable when: + -- + -- * It is not waiting on strong predecessors, and + -- * It is not waiting on weak predecessors + + return + Pending_Strong_Predecessors (G, Comp) = 0 + and then Pending_Weak_Predecessors (G, Comp) = 0; + end Is_Elaborable_Component; + + -------------------------- + -- Is_Elaborable_Vertex -- + -------------------------- + + function Is_Elaborable_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Complement : constant Library_Graph_Vertex_Id := + Complementary_Vertex + (G => G, + Vertex => Vertex, + Force_Complement => False); + + Strong_Preds : Natural; + Weak_Preds : Natural; + + begin + -- A vertex is elaborable when: + -- + -- * It has not been elaborated yet, and + -- * The complement vertex of an Elaborate_Body pair has not been + -- elaborated yet, and + -- * It resides within an elaborable component, and + -- * It is not waiting on strong predecessors, and + -- * It is not waiting on weak predecessors + + if In_Elaboration_Order (G, Vertex) then + return False; + + elsif Present (Complement) + and then In_Elaboration_Order (G, Complement) + then + return False; + + elsif not Is_Elaborable_Component (G, Component (G, Vertex)) then + return False; + end if; + + Pending_Predecessors_For_Elaboration + (G => G, + Vertex => Vertex, + Strong_Preds => Strong_Preds, + Weak_Preds => Weak_Preds); + + return Strong_Preds = 0 and then Weak_Preds = 0; + end Is_Elaborable_Vertex; + + --------------------------- + -- Is_Elaborate_All_Edge -- + --------------------------- + + function Is_Elaborate_All_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = Elaborate_All_Edge; + end Is_Elaborate_All_Edge; + + ---------------------------- + -- Is_Elaborate_Body_Edge -- + ---------------------------- + + function Is_Elaborate_Body_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Kind (G, Edge) = With_Edge + and then Is_Vertex_With_Elaborate_Body (G, Successor (G, Edge)); + end Is_Elaborate_Body_Edge; + + ----------------------- + -- Is_Elaborate_Edge -- + ----------------------- + + function Is_Elaborate_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = Elaborate_Edge; + end Is_Elaborate_Edge; + + ---------------------------- + -- Is_Elaborate_Body_Pair -- + ---------------------------- + + function Is_Elaborate_Body_Pair + (G : Library_Graph; + Spec_Vertex : Library_Graph_Vertex_Id; + Body_Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Spec_Vertex)); + pragma Assert (Present (Body_Vertex)); + + return + Is_Spec_With_Elaborate_Body (G, Spec_Vertex) + and then Is_Body_Of_Spec_With_Elaborate_Body (G, Body_Vertex) + and then Proper_Body (G, Spec_Vertex) = Body_Vertex; + end Is_Elaborate_Body_Pair; + + -------------------- + -- Is_Forced_Edge -- + -------------------- + + function Is_Forced_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = Forced_Edge; + end Is_Forced_Edge; + + ---------------------- + -- Is_Internal_Unit -- + ---------------------- + + function Is_Internal_Unit + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Is_Internal_Unit (Unit (G, Vertex)); + end Is_Internal_Unit; + + ------------------------ + -- Is_Invocation_Edge -- + ------------------------ + + function Is_Invocation_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = Invocation_Edge; + end Is_Invocation_Edge; + + ------------------------ + -- Is_Predefined_Unit -- + ------------------------ + + function Is_Predefined_Unit + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Is_Predefined_Unit (Unit (G, Vertex)); + end Is_Predefined_Unit; + + --------------------------- + -- Is_Preelaborated_Unit -- + --------------------------- + + function Is_Preelaborated_Unit + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + return U_Rec.Preelab or else U_Rec.Pure; + end Is_Preelaborated_Unit; + + ---------------------- + -- Is_Recorded_Edge -- + ---------------------- + + function Is_Recorded_Edge + (G : Library_Graph; + Rel : Predecessor_Successor_Relation) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Rel.Predecessor)); + pragma Assert (Present (Rel.Successor)); + + return RE_Sets.Contains (G.Recorded_Edges, Rel); + end Is_Recorded_Edge; + + ------------- + -- Is_Spec -- + ------------- + + function Is_Spec + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + return U_Rec.Utype = Is_Spec or else U_Rec.Utype = Is_Spec_Only; + end Is_Spec; + + ------------------------------ + -- Is_Spec_Before_Body_Edge -- + ------------------------------ + + function Is_Spec_Before_Body_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = Spec_Before_Body_Edge; + end Is_Spec_Before_Body_Edge; + + ----------------------- + -- Is_Spec_With_Body -- + ----------------------- + + function Is_Spec_With_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + U_Id : constant Unit_Id := Unit (G, Vertex); + U_Rec : Unit_Record renames ALI.Units.Table (U_Id); + + begin + return U_Rec.Utype = Is_Spec; + end Is_Spec_With_Body; + + --------------------------------- + -- Is_Spec_With_Elaborate_Body -- + --------------------------------- + + function Is_Spec_With_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return + Is_Spec_With_Body (G, Vertex) + and then Has_Elaborate_Body (G, Vertex); + end Is_Spec_With_Elaborate_Body; + + ------------------------------ + -- Is_Static_Successor_Edge -- + ------------------------------ + + function Is_Static_Successor_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return + Is_Invocation_Edge (G, Edge) + and then not Is_Dynamically_Elaborated (G, Successor (G, Edge)); + end Is_Static_Successor_Edge; + + ----------------------------------- + -- Is_Vertex_With_Elaborate_Body -- + ----------------------------------- + + function Is_Vertex_With_Elaborate_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return + Is_Spec_With_Elaborate_Body (G, Vertex) + or else + Is_Body_Of_Spec_With_Elaborate_Body (G, Vertex); + end Is_Vertex_With_Elaborate_Body; + + --------------------------------- + -- Is_Weakly_Elaborable_Vertex -- + ---------------------------------- + + function Is_Weakly_Elaborable_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Complement : constant Library_Graph_Vertex_Id := + Complementary_Vertex + (G => G, + Vertex => Vertex, + Force_Complement => False); + + Strong_Preds : Natural; + Weak_Preds : Natural; + + begin + -- A vertex is weakly elaborable when: + -- + -- * It has not been elaborated yet, and + -- * The complement vertex of an Elaborate_Body pair has not been + -- elaborated yet, and + -- * It resides within an elaborable component, and + -- * It is not waiting on strong predecessors, and + -- * It is waiting on at least one weak predecessor + + if In_Elaboration_Order (G, Vertex) then + return False; + + elsif Present (Complement) + and then In_Elaboration_Order (G, Complement) + then + return False; + + elsif not Is_Elaborable_Component (G, Component (G, Vertex)) then + return False; + end if; + + Pending_Predecessors_For_Elaboration + (G => G, + Vertex => Vertex, + Strong_Preds => Strong_Preds, + Weak_Preds => Weak_Preds); + + return Strong_Preds = 0 and then Weak_Preds >= 1; + end Is_Weakly_Elaborable_Vertex; + + ------------------ + -- Is_With_Edge -- + ------------------ + + function Is_With_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Kind (G, Edge) = With_Edge; + end Is_With_Edge; + + ------------------------ + -- Iterate_All_Cycles -- + ------------------------ + + function Iterate_All_Cycles + (G : Library_Graph) return All_Cycle_Iterator + is + begin + pragma Assert (Present (G)); + + return All_Cycle_Iterator (LGC_Lists.Iterate (G.Cycles)); + end Iterate_All_Cycles; + + ----------------------- + -- Iterate_All_Edges -- + ----------------------- + + function Iterate_All_Edges + (G : Library_Graph) return All_Edge_Iterator + is + begin + pragma Assert (Present (G)); + + return All_Edge_Iterator (DG.Iterate_All_Edges (G.Graph)); + end Iterate_All_Edges; + + -------------------------- + -- Iterate_All_Vertices -- + -------------------------- + + function Iterate_All_Vertices + (G : Library_Graph) return All_Vertex_Iterator + is + begin + pragma Assert (Present (G)); + + return All_Vertex_Iterator (DG.Iterate_All_Vertices (G.Graph)); + end Iterate_All_Vertices; + + ------------------------ + -- Iterate_Components -- + ------------------------ + + function Iterate_Components + (G : Library_Graph) return Component_Iterator + is + begin + pragma Assert (Present (G)); + + return Component_Iterator (DG.Iterate_Components (G.Graph)); + end Iterate_Components; + + -------------------------------- + -- Iterate_Component_Vertices -- + -------------------------------- + + function Iterate_Component_Vertices + (G : Library_Graph; + Comp : Component_Id) return Component_Vertex_Iterator + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + return + Component_Vertex_Iterator + (DG.Iterate_Component_Vertices (G.Graph, Comp)); + end Iterate_Component_Vertices; + + ---------------------------- + -- Iterate_Edges_Of_Cycle -- + ---------------------------- + + function Iterate_Edges_Of_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Edges_Of_Cycle_Iterator + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return Edges_Of_Cycle_Iterator (LGE_Lists.Iterate (Path (G, Cycle))); + end Iterate_Edges_Of_Cycle; + + --------------------------------- + -- Iterate_Edges_To_Successors -- + --------------------------------- + + function Iterate_Edges_To_Successors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Edges_To_Successors_Iterator + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return + Edges_To_Successors_Iterator + (DG.Iterate_Outgoing_Edges (G.Graph, Vertex)); + end Iterate_Edges_To_Successors; + + ---------- + -- Kind -- + ---------- + + function Kind + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Kind + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return Get_LGC_Attributes (G, Cycle).Kind; + end Kind; + + ---------- + -- Kind -- + ---------- + + function Kind + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Edge_Kind + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return Get_LGE_Attributes (G, Edge).Kind; + end Kind; + + ------------ + -- Length -- + ------------ + + function Length + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return LGE_Lists.Size (Path (G, Cycle)); + end Length; + + ------------------------------ + -- Library_Graph_Edge_Count -- + ------------------------------ + + function Library_Graph_Edge_Count + (G : Library_Graph; + Kind : Library_Graph_Edge_Kind) return Natural + is + begin + pragma Assert (Present (G)); + + return G.Counts (Kind); + end Library_Graph_Edge_Count; + + -------------------------------------- + -- Links_Vertices_In_Same_Component -- + -------------------------------------- + + function Links_Vertices_In_Same_Component + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + -- An edge is part of a cycle when both the successor and predecessor + -- reside in the same component. + + return + In_Same_Component + (G => G, + Left => Predecessor (G, Edge), + Right => Successor (G, Edge)); + end Links_Vertices_In_Same_Component; + + ----------------------------------- + -- Maximum_Invocation_Edge_Count -- + ----------------------------------- + + function Maximum_Invocation_Edge_Count + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Count : Natural) return Natural + is + New_Count : Natural; + + begin + pragma Assert (Present (G)); + + New_Count := Count; + + if Present (Edge) and then Is_Invocation_Edge (G, Edge) then + New_Count := New_Count + 1; + end if; + + return New_Count; + end Maximum_Invocation_Edge_Count; + + ---------- + -- Name -- + ---------- + + function Name + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Unit_Name_Type + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Name (Unit (G, Vertex)); + end Name; + + ----------------------- + -- Needs_Elaboration -- + ----------------------- + + function Needs_Elaboration + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Boolean + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Needs_Elaboration (Unit (G, Vertex)); + end Needs_Elaboration; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out All_Cycle_Iterator; + Cycle : out Library_Graph_Cycle_Id) + is + begin + LGC_Lists.Next (LGC_Lists.Iterator (Iter), Cycle); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out All_Edge_Iterator; + Edge : out Library_Graph_Edge_Id) + is + begin + DG.Next (DG.All_Edge_Iterator (Iter), Edge); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out All_Vertex_Iterator; + Vertex : out Library_Graph_Vertex_Id) + is + begin + DG.Next (DG.All_Vertex_Iterator (Iter), Vertex); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Edges_Of_Cycle_Iterator; + Edge : out Library_Graph_Edge_Id) + is + begin + LGE_Lists.Next (LGE_Lists.Iterator (Iter), Edge); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Component_Iterator; + Comp : out Component_Id) + is + begin + DG.Next (DG.Component_Iterator (Iter), Comp); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Edges_To_Successors_Iterator; + Edge : out Library_Graph_Edge_Id) + is + begin + DG.Next (DG.Outgoing_Edge_Iterator (Iter), Edge); + end Next; + + ---------- + -- Next -- + ---------- + + procedure Next + (Iter : in out Component_Vertex_Iterator; + Vertex : out Library_Graph_Vertex_Id) + is + begin + DG.Next (DG.Component_Vertex_Iterator (Iter), Vertex); + end Next; + + -------------------------- + -- Normalize_Cycle_Path -- + -------------------------- + + procedure Normalize_Cycle_Path + (Cycle_Path : LGE_Lists.Doubly_Linked_List; + Most_Significant_Edge : Library_Graph_Edge_Id) + is + Edge : Library_Graph_Edge_Id; + + begin + pragma Assert (LGE_Lists.Present (Cycle_Path)); + pragma Assert (Present (Most_Significant_Edge)); + + -- Perform at most |Cycle_Path| rotations in case the cycle is + -- malformed and the significant edge does not appear within. + + for Rotation in 1 .. LGE_Lists.Size (Cycle_Path) loop + Edge := LGE_Lists.First (Cycle_Path); + + -- The cycle is already rotated such that the most significant + -- edge is first. + + if Edge = Most_Significant_Edge then + return; + + -- Otherwise rotate the cycle by relocating the current edge from + -- the start to the end of the path. This preserves the order of + -- the path. + + else + LGE_Lists.Delete_First (Cycle_Path); + LGE_Lists.Append (Cycle_Path, Edge); + end if; + end loop; + + pragma Assert (False); + end Normalize_Cycle_Path; + + ---------------------------------- + -- Number_Of_Component_Vertices -- + ---------------------------------- + + function Number_Of_Component_Vertices + (G : Library_Graph; + Comp : Component_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + return DG.Number_Of_Component_Vertices (G.Graph, Comp); + end Number_Of_Component_Vertices; + + -------------------------- + -- Number_Of_Components -- + -------------------------- + + function Number_Of_Components (G : Library_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Components (G.Graph); + end Number_Of_Components; + + ---------------------- + -- Number_Of_Cycles -- + ---------------------- + + function Number_Of_Cycles (G : Library_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return LGC_Lists.Size (G.Cycles); + end Number_Of_Cycles; + + --------------------- + -- Number_Of_Edges -- + --------------------- + + function Number_Of_Edges (G : Library_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Edges (G.Graph); + end Number_Of_Edges; + + ----------------------------------- + -- Number_Of_Edges_To_Successors -- + ----------------------------------- + + function Number_Of_Edges_To_Successors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Natural + is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Outgoing_Edges (G.Graph, Vertex); + end Number_Of_Edges_To_Successors; + + ------------------------ + -- Number_Of_Vertices -- + ------------------------ + + function Number_Of_Vertices (G : Library_Graph) return Natural is + begin + pragma Assert (Present (G)); + + return DG.Number_Of_Vertices (G.Graph); + end Number_Of_Vertices; + + ----------------- + -- Order_Cycle -- + ----------------- + + procedure Order_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) + is + Lesser_Cycle : Library_Graph_Cycle_Id; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + pragma Assert (LGC_Lists.Present (G.Cycles)); + + -- The input cycle is the first to be inserted + + if LGC_Lists.Is_Empty (G.Cycles) then + LGC_Lists.Prepend (G.Cycles, Cycle); + + -- Otherwise the list of all cycles contains at least one cycle. + -- Insert the input cycle based on its precedence. + + else + Lesser_Cycle := Find_First_Lower_Precedence_Cycle (G, Cycle); + + -- The list contains at least one cycle, and the input cycle has a + -- higher precedence compared to some cycle in the list. + + if Present (Lesser_Cycle) then + LGC_Lists.Insert_Before + (L => G.Cycles, + Before => Lesser_Cycle, + Elem => Cycle); + + -- Otherwise the input cycle has the lowest precedence among all + -- cycles. + + else + LGC_Lists.Append (G.Cycles, Cycle); + end if; + end if; + end Order_Cycle; + + ---------- + -- Path -- + ---------- + + function Path + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id) return LGE_Lists.Doubly_Linked_List + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + return Get_LGC_Attributes (G, Cycle).Path; + end Path; + + ------------------------------------------ + -- Pending_Predecessors_For_Elaboration -- + ------------------------------------------ + + procedure Pending_Predecessors_For_Elaboration + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Strong_Preds : out Natural; + Weak_Preds : out Natural) + is + Complement : Library_Graph_Vertex_Id; + Spec_Vertex : Library_Graph_Vertex_Id; + Total_Strong_Preds : Natural; + Total_Weak_Preds : Natural; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Total_Strong_Preds := Pending_Strong_Predecessors (G, Vertex); + Total_Weak_Preds := Pending_Weak_Predecessors (G, Vertex); + + -- Assume that there is no complementary vertex that needs to be + -- examined. + + Complement := No_Library_Graph_Vertex; + Spec_Vertex := No_Library_Graph_Vertex; + + if Is_Body_Of_Spec_With_Elaborate_Body (G, Vertex) then + Complement := Proper_Spec (G, Vertex); + Spec_Vertex := Complement; + + elsif Is_Spec_With_Elaborate_Body (G, Vertex) then + Complement := Proper_Body (G, Vertex); + Spec_Vertex := Vertex; + end if; + + -- The vertex is part of an Elaborate_Body pair. Take into account + -- the strong and weak predecessors of the complementary vertex. + + if Present (Complement) then + Total_Strong_Preds := + Pending_Strong_Predecessors (G, Complement) + Total_Strong_Preds; + Total_Weak_Preds := + Pending_Weak_Predecessors (G, Complement) + Total_Weak_Preds; + + -- The body of an Elaborate_Body pair is the successor of a strong + -- edge where the predecessor is the spec. This edge must not be + -- considered for elaboration purposes because the pair is treated + -- as one vertex. Account for the edge only when the spec has not + -- been elaborated yet. + + if not In_Elaboration_Order (G, Spec_Vertex) then + Total_Strong_Preds := Total_Strong_Preds - 1; + end if; + end if; + + Strong_Preds := Total_Strong_Preds; + Weak_Preds := Total_Weak_Preds; + end Pending_Predecessors_For_Elaboration; + + --------------------------------- + -- Pending_Strong_Predecessors -- + --------------------------------- + + function Pending_Strong_Predecessors + (G : Library_Graph; + Comp : Component_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + return Get_Component_Attributes (G, Comp).Pending_Strong_Predecessors; + end Pending_Strong_Predecessors; + + --------------------------------- + -- Pending_Strong_Predecessors -- + --------------------------------- + + function Pending_Strong_Predecessors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_LGV_Attributes (G, Vertex).Pending_Strong_Predecessors; + end Pending_Strong_Predecessors; + + ------------------------------- + -- Pending_Weak_Predecessors -- + ------------------------------- + + function Pending_Weak_Predecessors + (G : Library_Graph; + Comp : Component_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + return Get_Component_Attributes (G, Comp).Pending_Weak_Predecessors; + end Pending_Weak_Predecessors; + + ------------------------------- + -- Pending_Weak_Predecessors -- + ------------------------------- + + function Pending_Weak_Predecessors + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Natural + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_LGV_Attributes (G, Vertex).Pending_Weak_Predecessors; + end Pending_Weak_Predecessors; + + ----------------- + -- Predecessor -- + ----------------- + + function Predecessor + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return DG.Source_Vertex (G.Graph, Edge); + end Predecessor; + + ------------- + -- Present -- + ------------- + + function Present (G : Library_Graph) return Boolean is + begin + return G /= Nil; + end Present; + + ----------------- + -- Proper_Body -- + ----------------- + + function Proper_Body + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + -- When the vertex denotes a spec with a completing body, return the + -- body. + + if Is_Spec_With_Body (G, Vertex) then + return Corresponding_Item (G, Vertex); + + -- Otherwise the vertex must be a body + + else + pragma Assert (Is_Body (G, Vertex)); + return Vertex; + end if; + end Proper_Body; + + ----------------- + -- Proper_Spec -- + ----------------- + + function Proper_Spec + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + -- When the vertex denotes a body that completes a spec, return the + -- spec. + + if Is_Body_With_Spec (G, Vertex) then + return Corresponding_Item (G, Vertex); + + -- Otherwise the vertex must denote a spec + + else + pragma Assert (Is_Spec (G, Vertex)); + return Vertex; + end if; + end Proper_Spec; + + ------------------ + -- Record_Cycle -- + ------------------ + + procedure Record_Cycle + (G : Library_Graph; + Most_Significant_Edge : Library_Graph_Edge_Id; + Invocation_Edge_Count : Natural; + Cycle_Path : LGE_Lists.Doubly_Linked_List; + Indent : Indentation_Level) + is + Cycle : Library_Graph_Cycle_Id; + Path : LGE_Lists.Doubly_Linked_List; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Most_Significant_Edge)); + pragma Assert (LGE_Lists.Present (Cycle_Path)); + + -- Replicate the path of the cycle in order to avoid sharing lists + + Path := Copy_Cycle_Path (Cycle_Path); + + -- Normalize the path of the cycle such that its most significant + -- edge is the first in the list of edges. + + Normalize_Cycle_Path + (Cycle_Path => Path, + Most_Significant_Edge => Most_Significant_Edge); + + -- Save the cycle for diagnostic purposes. Its kind is determined by + -- its most significant edge. + + Cycle := Sequence_Next_Cycle; + + Set_LGC_Attributes + (G => G, + Cycle => Cycle, + Val => + (Invocation_Edge_Count => Invocation_Edge_Count, + Kind => + Cycle_Kind_Of + (G => G, + Edge => Most_Significant_Edge), + Path => Path)); + + Trace_Cycle (G, Cycle, Indent); + + -- Order the cycle based on its precedence relative to previously + -- discovered cycles. + + Order_Cycle (G, Cycle); + end Record_Cycle; + + ----------------------------------------- + -- Same_Library_Graph_Cycle_Attributes -- + ----------------------------------------- + + function Same_Library_Graph_Cycle_Attributes + (Left : Library_Graph_Cycle_Attributes; + Right : Library_Graph_Cycle_Attributes) return Boolean + is + begin + -- Two cycles are the same when + -- + -- * They are of the same kind + -- * They have the same number of invocation edges in their paths + -- * Their paths are the same length + -- * The edges comprising their paths are the same + + return + Left.Invocation_Edge_Count = Right.Invocation_Edge_Count + and then Left.Kind = Right.Kind + and then LGE_Lists.Equal (Left.Path, Right.Path); + end Same_Library_Graph_Cycle_Attributes; + + ------------------------------ + -- Set_Component_Attributes -- + ------------------------------ + + procedure Set_Component_Attributes + (G : Library_Graph; + Comp : Component_Id; + Val : Component_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + Component_Tables.Put (G.Component_Attributes, Comp, Val); + end Set_Component_Attributes; + + ---------------------------- + -- Set_Corresponding_Item -- + ---------------------------- + + procedure Set_Corresponding_Item + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Val : Library_Graph_Vertex_Id) + is + Attrs : Library_Graph_Vertex_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Attrs := Get_LGV_Attributes (G, Vertex); + Attrs.Corresponding_Item := Val; + Set_LGV_Attributes (G, Vertex, Attrs); + end Set_Corresponding_Item; + + ------------------------------ + -- Set_Corresponding_Vertex -- + ------------------------------ + + procedure Set_Corresponding_Vertex + (G : Library_Graph; + U_Id : Unit_Id; + Val : Library_Graph_Vertex_Id) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (U_Id)); + + Unit_Tables.Put (G.Unit_To_Vertex, U_Id, Val); + end Set_Corresponding_Vertex; + + ------------------------------ + -- Set_In_Elaboration_Order -- + ------------------------------ + + procedure Set_In_Elaboration_Order + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Val : Boolean := True) + is + Attrs : Library_Graph_Vertex_Attributes; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + Attrs := Get_LGV_Attributes (G, Vertex); + Attrs.In_Elaboration_Order := Val; + Set_LGV_Attributes (G, Vertex, Attrs); + end Set_In_Elaboration_Order; + + -------------------------- + -- Set_Is_Recorded_Edge -- + -------------------------- + + procedure Set_Is_Recorded_Edge + (G : Library_Graph; + Rel : Predecessor_Successor_Relation; + Val : Boolean := True) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Rel.Predecessor)); + pragma Assert (Present (Rel.Successor)); + + if Val then + RE_Sets.Insert (G.Recorded_Edges, Rel); + else + RE_Sets.Delete (G.Recorded_Edges, Rel); + end if; + end Set_Is_Recorded_Edge; + + ------------------------ + -- Set_LGC_Attributes -- + ------------------------ + + procedure Set_LGC_Attributes + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Val : Library_Graph_Cycle_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + LGC_Tables.Put (G.Cycle_Attributes, Cycle, Val); + end Set_LGC_Attributes; + + ------------------------ + -- Set_LGE_Attributes -- + ------------------------ + + procedure Set_LGE_Attributes + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Val : Library_Graph_Edge_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + LGE_Tables.Put (G.Edge_Attributes, Edge, Val); + end Set_LGE_Attributes; + + ------------------------ + -- Set_LGV_Attributes -- + ------------------------ + + procedure Set_LGV_Attributes + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Val : Library_Graph_Vertex_Attributes) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + LGV_Tables.Put (G.Vertex_Attributes, Vertex, Val); + end Set_LGV_Attributes; + + --------------- + -- Successor -- + --------------- + + function Successor + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) return Library_Graph_Vertex_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + return DG.Destination_Vertex (G.Graph, Edge); + end Successor; + + --------------------- + -- Trace_Component -- + --------------------- + + procedure Trace_Component + (G : Library_Graph; + Comp : Component_Id; + Indent : Indentation_Level) + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Comp)); + + -- Nothing to do when switch -d_t (output cycle-detection trace + -- information) is not in effect. + + if not Debug_Flag_Underscore_T then + return; + end if; + + Write_Eol; + Indent_By (Indent); + Write_Str ("component (Comp_"); + Write_Int (Int (Comp)); + Write_Str (")"); + Write_Eol; + end Trace_Component; + + ----------------- + -- Trace_Cycle -- + ----------------- + + procedure Trace_Cycle + (G : Library_Graph; + Cycle : Library_Graph_Cycle_Id; + Indent : Indentation_Level) + is + Attr_Indent : constant Indentation_Level := + Indent + Nested_Indentation; + Edge_Indent : constant Indentation_Level := + Attr_Indent + Nested_Indentation; + + Edge : Library_Graph_Edge_Id; + Iter : Edges_Of_Cycle_Iterator; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Cycle)); + + -- Nothing to do when switch -d_t (output cycle-detection trace + -- information) is not in effect. + + if not Debug_Flag_Underscore_T then + return; + end if; + + Indent_By (Indent); + Write_Str ("cycle (LGC_Id_"); + Write_Int (Int (Cycle)); + Write_Str (")"); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("kind = "); + Write_Str (Kind (G, Cycle)'Img); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("invocation edges = "); + Write_Int (Int (Invocation_Edge_Count (G, Cycle))); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("length: "); + Write_Int (Int (Length (G, Cycle))); + Write_Eol; + + Iter := Iterate_Edges_Of_Cycle (G, Cycle); + while Has_Next (Iter) loop + Next (Iter, Edge); + + Indent_By (Edge_Indent); + Write_Str ("library graph edge (LGE_Id_"); + Write_Int (Int (Edge)); + Write_Str (")"); + Write_Eol; + end loop; + end Trace_Cycle; + + ---------------- + -- Trace_Edge -- + ---------------- + + procedure Trace_Edge + (G : Library_Graph; + Edge : Library_Graph_Edge_Id; + Indent : Indentation_Level) + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + Attr_Indent : constant Indentation_Level := + Indent + Nested_Indentation; + + Pred : constant Library_Graph_Vertex_Id := Predecessor (G, Edge); + Succ : constant Library_Graph_Vertex_Id := Successor (G, Edge); + + begin + -- Nothing to do when switch -d_t (output cycle-detection trace + -- information) is not in effect. + + if not Debug_Flag_Underscore_T then + return; + end if; + + Indent_By (Indent); + Write_Str ("library graph edge (LGE_Id_"); + Write_Int (Int (Edge)); + Write_Str (")"); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("kind = "); + Write_Str (Kind (G, Edge)'Img); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("Predecessor (LGV_Id_"); + Write_Int (Int (Pred)); + Write_Str (") name = "); + Write_Name (Name (G, Pred)); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("Successor (LGV_Id_"); + Write_Int (Int (Succ)); + Write_Str (") name = "); + Write_Name (Name (G, Succ)); + Write_Eol; + end Trace_Edge; + + ------------------ + -- Trace_Vertex -- + ------------------ + + procedure Trace_Vertex + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id; + Indent : Indentation_Level) + is + Attr_Indent : constant Indentation_Level := + Indent + Nested_Indentation; + + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + -- Nothing to do when switch -d_t (output cycle-detection trace + -- information) is not in effect. + + if not Debug_Flag_Underscore_T then + return; + end if; + + Indent_By (Indent); + Write_Str ("library graph vertex (LGV_Id_"); + Write_Int (Int (Vertex)); + Write_Str (")"); + Write_Eol; + + Indent_By (Attr_Indent); + Write_Str ("Unit (U_Id_"); + Write_Int (Int (Unit (G, Vertex))); + Write_Str (") name = "); + Write_Name (Name (G, Vertex)); + Write_Eol; + end Trace_Vertex; + + ---------- + -- Unit -- + ---------- + + function Unit + (G : Library_Graph; + Vertex : Library_Graph_Vertex_Id) return Unit_Id + is + begin + pragma Assert (Present (G)); + pragma Assert (Present (Vertex)); + + return Get_LGV_Attributes (G, Vertex).Unit; + end Unit; + + ------------- + -- Unvisit -- + ------------- + + procedure Unvisit + (Vertex : Library_Graph_Vertex_Id; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List) + is + Current_Vertex : Library_Graph_Vertex_Id; + + begin + pragma Assert (Present (Vertex)); + pragma Assert (LGV_Sets.Present (Visited_Set)); + pragma Assert (LGV_Lists.Present (Visited_Stack)); + + while not LGV_Lists.Is_Empty (Visited_Stack) loop + Current_Vertex := LGV_Lists.First (Visited_Stack); + + LGV_Lists.Delete_First (Visited_Stack); + LGV_Sets.Delete (Visited_Set, Current_Vertex); + + exit when Current_Vertex = Vertex; + end loop; + end Unvisit; + + --------------------------------- + -- Update_Pending_Predecessors -- + --------------------------------- + + procedure Update_Pending_Predecessors + (Strong_Predecessors : in out Natural; + Weak_Predecessors : in out Natural; + Update_Weak : Boolean; + Value : Integer) + is + begin + if Update_Weak then + Weak_Predecessors := Weak_Predecessors + Value; + else + Strong_Predecessors := Strong_Predecessors + Value; + end if; + end Update_Pending_Predecessors; + + ----------------------------------------------- + -- Update_Pending_Predecessors_Of_Components -- + ----------------------------------------------- + + procedure Update_Pending_Predecessors_Of_Components + (G : Library_Graph) + is + Edge : Library_Graph_Edge_Id; + Iter : All_Edge_Iterator; + + begin + pragma Assert (Present (G)); + + Iter := Iterate_All_Edges (G); + while Has_Next (Iter) loop + Next (Iter, Edge); + + Update_Pending_Predecessors_Of_Components (G, Edge); + end loop; + end Update_Pending_Predecessors_Of_Components; + + ----------------------------------------------- + -- Update_Pending_Predecessors_Of_Components -- + ----------------------------------------------- + + procedure Update_Pending_Predecessors_Of_Components + (G : Library_Graph; + Edge : Library_Graph_Edge_Id) + is + pragma Assert (Present (G)); + pragma Assert (Present (Edge)); + + Pred_Comp : constant Component_Id := + Component (G, Predecessor (G, Edge)); + Succ_Comp : constant Component_Id := + Component (G, Successor (G, Edge)); + + pragma Assert (Present (Pred_Comp)); + pragma Assert (Present (Succ_Comp)); + + begin + -- The edge links a successor and a predecessor coming from two + -- different SCCs. This indicates that the SCC of the successor + -- must wait on another predecessor until it can be elaborated. + + if Pred_Comp /= Succ_Comp then + Increment_Pending_Predecessors + (G => G, + Comp => Succ_Comp, + Edge => Edge); + end if; + end Update_Pending_Predecessors_Of_Components; + + ----------------------- + -- Vertex_Precedence -- + ----------------------- + + function Vertex_Precedence + (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)); + + -- Use lexicographical order to determine precedence and ensure + -- deterministic behavior. + + if Uname_Less (Name (G, Vertex), Name (G, Compared_To)) then + return Higher_Precedence; + else + return Lower_Precedence; + end if; + end Vertex_Precedence; + + ----------- + -- Visit -- + ----------- + + procedure Visit + (Vertex : Library_Graph_Vertex_Id; + Visited_Set : LGV_Sets.Membership_Set; + Visited_Stack : LGV_Lists.Doubly_Linked_List) + is + begin + pragma Assert (Present (Vertex)); + pragma Assert (LGV_Sets.Present (Visited_Set)); + pragma Assert (LGV_Lists.Present (Visited_Stack)); + + LGV_Sets.Insert (Visited_Set, Vertex); + LGV_Lists.Prepend (Visited_Stack, Vertex); + end Visit; + end Library_Graphs; + + ------------- + -- Present -- + ------------- + + function Present (Edge : Invocation_Graph_Edge_Id) return Boolean is + begin + return Edge /= No_Invocation_Graph_Edge; + end Present; + + ------------- + -- Present -- + ------------- + + function Present (Vertex : Invocation_Graph_Vertex_Id) return Boolean is + begin + return Vertex /= No_Invocation_Graph_Vertex; + end Present; + + ------------- + -- Present -- + ------------- + + function Present (Cycle : Library_Graph_Cycle_Id) return Boolean is + begin + return Cycle /= No_Library_Graph_Cycle; + end Present; + + ------------- + -- Present -- + ------------- + + function Present (Edge : Library_Graph_Edge_Id) return Boolean is + begin + return Edge /= No_Library_Graph_Edge; + end Present; + + ------------- + -- Present -- + ------------- + + function Present (Vertex : Library_Graph_Vertex_Id) return Boolean is + begin + return Vertex /= No_Library_Graph_Vertex; + end Present; + + -------------------------- + -- Sequence_Next_Edge -- + -------------------------- + + IGE_Sequencer : Invocation_Graph_Edge_Id := First_Invocation_Graph_Edge; + -- The counter for invocation graph edges. Do not directly manipulate its + -- value. + + function Sequence_Next_Edge return Invocation_Graph_Edge_Id is + Edge : constant Invocation_Graph_Edge_Id := IGE_Sequencer; + + begin + IGE_Sequencer := IGE_Sequencer + 1; + return Edge; + end Sequence_Next_Edge; + + -------------------------- + -- Sequence_Next_Vertex -- + -------------------------- + + IGV_Sequencer : Invocation_Graph_Vertex_Id := First_Invocation_Graph_Vertex; + -- The counter for invocation graph vertices. Do not directly manipulate + -- its value. + + function Sequence_Next_Vertex return Invocation_Graph_Vertex_Id is + Vertex : constant Invocation_Graph_Vertex_Id := IGV_Sequencer; + + begin + IGV_Sequencer := IGV_Sequencer + 1; + return Vertex; + end Sequence_Next_Vertex; + + -------------------------- + -- Sequence_Next_Cycle -- + -------------------------- + + LGC_Sequencer : Library_Graph_Cycle_Id := First_Library_Graph_Cycle; + -- The counter for library graph cycles. Do not directly manipulate its + -- value. + + function Sequence_Next_Cycle return Library_Graph_Cycle_Id is + Cycle : constant Library_Graph_Cycle_Id := LGC_Sequencer; + + begin + LGC_Sequencer := LGC_Sequencer + 1; + return Cycle; + end Sequence_Next_Cycle; + + -------------------------- + -- Sequence_Next_Edge -- + -------------------------- + + LGE_Sequencer : Library_Graph_Edge_Id := First_Library_Graph_Edge; + -- The counter for library graph edges. Do not directly manipulate its + -- value. + + function Sequence_Next_Edge return Library_Graph_Edge_Id is + Edge : constant Library_Graph_Edge_Id := LGE_Sequencer; + + begin + LGE_Sequencer := LGE_Sequencer + 1; + return Edge; + end Sequence_Next_Edge; + + -------------------------- + -- Sequence_Next_Vertex -- + -------------------------- + + LGV_Sequencer : Library_Graph_Vertex_Id := First_Library_Graph_Vertex; + -- The counter for library graph vertices. Do not directly manipulate its + -- value. + + function Sequence_Next_Vertex return Library_Graph_Vertex_Id is + Vertex : constant Library_Graph_Vertex_Id := LGV_Sequencer; + + begin + LGV_Sequencer := LGV_Sequencer + 1; + return Vertex; + end Sequence_Next_Vertex; + +end Bindo.Graphs;