1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- B I N D O . A U G M E N T O R S --
9 -- Copyright (C) 2019-2023, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Debug
; use Debug
;
27 with Output
; use Output
;
28 with Types
; use Types
;
32 use Bindo
.Writers
.Phase_Writers
;
34 package body Bindo
.Augmentors
is
36 ------------------------------
37 -- Library_Graph_Augmentors --
38 ------------------------------
40 package body Library_Graph_Augmentors
is
46 Longest_Path
: Natural := 0;
47 -- The length of the longest path found during the traversal of the
50 Total_Visited
: Natural := 0;
51 -- The number of visited invocation graph vertices during the process
54 -----------------------
55 -- Local subprograms --
56 -----------------------
58 procedure Visit_Elaboration_Root
59 (Inv_Graph
: Invocation_Graph
;
60 Root
: Invocation_Graph_Vertex_Id
);
61 pragma Inline
(Visit_Elaboration_Root
);
62 -- Start a DFS traversal from elaboration root Root to:
64 -- * Detect transitions between units.
66 -- * Create invocation edges for each such transition where the
69 procedure Visit_Elaboration_Roots
(Inv_Graph
: Invocation_Graph
);
70 pragma Inline
(Visit_Elaboration_Roots
);
71 -- Start a DFS traversal from all elaboration roots to:
73 -- * Detect transitions between units.
75 -- * Create invocation edges for each such transition where the
76 -- successor is the current root.
78 procedure Visit_Vertex
79 (Inv_Graph
: Invocation_Graph
;
80 Invoker
: Invocation_Graph_Vertex_Id
;
81 Last_Vertex
: Library_Graph_Vertex_Id
;
82 Root_Vertex
: Library_Graph_Vertex_Id
;
83 Visited_Invokers
: IGV_Sets
.Membership_Set
;
84 Activates_Task
: Boolean;
85 Internal_Controlled_Action
: Boolean;
87 pragma Inline
(Visit_Vertex
);
88 -- Visit invocation graph vertex Invoker to:
90 -- * Detect a transition from the last library graph vertex denoted by
91 -- Last_Vertex to the library graph vertex of Invoker.
93 -- * Create an invocation edge in library graph Lib_Graph to reflect
94 -- the transition, where the predecessor is the library graph vertex
95 -- or Invoker, and the successor is Root_Vertex.
97 -- * Visit the neighbours of Invoker.
99 -- Flag Internal_Controlled_Action should be set when the DFS traversal
100 -- visited an internal controlled invocation edge. Path is the length of
103 procedure Write_Statistics
;
104 pragma Inline
(Write_Statistics
);
105 -- Write the statistical information of the augmentation to standard
108 ---------------------------
109 -- Augment_Library_Graph --
110 ---------------------------
112 procedure Augment_Library_Graph
(Inv_Graph
: Invocation_Graph
) is
113 Lib_Graph
: constant Library_Graph
:= Get_Lib_Graph
(Inv_Graph
);
115 pragma Assert
(Present
(Lib_Graph
));
117 -- Nothing to do when there is no invocation graph
119 if not Present
(Inv_Graph
) then
123 Start_Phase
(Library_Graph_Augmentation
);
125 -- Prepare the statistics data
130 Visit_Elaboration_Roots
(Inv_Graph
);
133 End_Phase
(Library_Graph_Augmentation
);
134 end Augment_Library_Graph
;
136 ----------------------------
137 -- Visit_Elaboration_Root --
138 ----------------------------
140 procedure Visit_Elaboration_Root
141 (Inv_Graph
: Invocation_Graph
;
142 Root
: Invocation_Graph_Vertex_Id
)
144 Lib_Graph
: constant Library_Graph
:= Get_Lib_Graph
(Inv_Graph
);
145 pragma Assert
(Present
(Inv_Graph
));
146 pragma Assert
(Present
(Lib_Graph
));
147 pragma Assert
(Present
(Root
));
149 Root_Vertex
: constant Library_Graph_Vertex_Id
:=
150 Body_Vertex
(Inv_Graph
, Root
);
152 Visited
: IGV_Sets
.Membership_Set
;
155 -- Nothing to do when the unit where the elaboration root resides
156 -- lacks elaboration code. This implies that any invocation edges
157 -- going out of the unit are unwanted. This behavior emulates the
158 -- old elaboration order mechanism.
160 if Has_No_Elaboration_Code
(Lib_Graph
, Root_Vertex
) then
164 -- Prepare the global data
166 Visited
:= IGV_Sets
.Create
(Number_Of_Vertices
(Inv_Graph
));
169 (Inv_Graph
=> Inv_Graph
,
171 Last_Vertex
=> Root_Vertex
,
172 Root_Vertex
=> Root_Vertex
,
173 Visited_Invokers
=> Visited
,
174 Activates_Task
=> False,
175 Internal_Controlled_Action
=> False,
178 IGV_Sets
.Destroy
(Visited
);
179 end Visit_Elaboration_Root
;
181 -----------------------------
182 -- Visit_Elaboration_Roots --
183 -----------------------------
185 procedure Visit_Elaboration_Roots
(Inv_Graph
: Invocation_Graph
) is
186 Lib_Graph
: constant Library_Graph
:= Get_Lib_Graph
(Inv_Graph
);
187 pragma Assert
(Present
(Inv_Graph
));
188 pragma Assert
(Present
(Lib_Graph
));
190 Iter
: Elaboration_Root_Iterator
;
191 Root
: Invocation_Graph_Vertex_Id
;
194 Iter
:= Iterate_Elaboration_Roots
(Inv_Graph
);
195 while Has_Next
(Iter
) loop
198 Visit_Elaboration_Root
(Inv_Graph
=> Inv_Graph
, Root
=> Root
);
200 end Visit_Elaboration_Roots
;
206 procedure Visit_Vertex
207 (Inv_Graph
: Invocation_Graph
;
208 Invoker
: Invocation_Graph_Vertex_Id
;
209 Last_Vertex
: Library_Graph_Vertex_Id
;
210 Root_Vertex
: Library_Graph_Vertex_Id
;
211 Visited_Invokers
: IGV_Sets
.Membership_Set
;
212 Activates_Task
: Boolean;
213 Internal_Controlled_Action
: Boolean;
216 Lib_Graph
: constant Library_Graph
:= Get_Lib_Graph
(Inv_Graph
);
218 New_Path
: constant Natural := Path
+ 1;
220 Edge
: Invocation_Graph_Edge_Id
;
221 Edge_Kind
: Invocation_Kind
;
222 Invoker_Vertex
: Library_Graph_Vertex_Id
;
223 Iter
: Edges_To_Targets_Iterator
;
226 pragma Assert
(Present
(Inv_Graph
));
227 pragma Assert
(Present
(Lib_Graph
));
228 pragma Assert
(Present
(Invoker
));
229 pragma Assert
(Present
(Last_Vertex
));
230 pragma Assert
(Present
(Root_Vertex
));
231 pragma Assert
(IGV_Sets
.Present
(Visited_Invokers
));
233 -- Nothing to do when the current invocation graph vertex has already
236 if IGV_Sets
.Contains
(Visited_Invokers
, Invoker
) then
240 IGV_Sets
.Insert
(Visited_Invokers
, Invoker
);
242 -- Update the statistics
244 Longest_Path
:= Natural'Max (Longest_Path
, New_Path
);
245 Total_Visited
:= Total_Visited
+ 1;
247 -- The library graph vertex of the current invocation graph vertex
248 -- differs from that of the previous invocation graph vertex. This
249 -- indicates that elaboration is transitioning from one unit to
250 -- another. Add a library graph edge to capture this dependency.
252 Invoker_Vertex
:= Body_Vertex
(Inv_Graph
, Invoker
);
253 pragma Assert
(Present
(Invoker_Vertex
));
255 if Invoker_Vertex
/= Last_Vertex
then
257 -- The path ultimately reaches back into the unit where the root
258 -- resides, resulting in a self dependency. In most cases this is
259 -- a valid circularity, except when the path went through one of
260 -- the Deep_xxx finalization-related routines. Do not create a
261 -- library graph edge because the circularity is the result of
262 -- expansion and thus spurious.
264 if Invoker_Vertex
= Root_Vertex
265 and then Internal_Controlled_Action
269 -- Otherwise create the library graph edge, even if this results
270 -- in a self dependency.
275 Pred
=> Invoker_Vertex
,
277 Kind
=> Invocation_Edge
,
278 Activates_Task
=> Activates_Task
);
282 -- Extend the DFS traversal to all targets of the invocation graph
285 Iter
:= Iterate_Edges_To_Targets
(Inv_Graph
, Invoker
);
286 while Has_Next
(Iter
) loop
288 Edge_Kind
:= Kind
(Inv_Graph
, Edge
);
291 (Inv_Graph
=> Inv_Graph
,
292 Invoker
=> Target
(Inv_Graph
, Edge
),
293 Last_Vertex
=> Invoker_Vertex
,
294 Root_Vertex
=> Root_Vertex
,
295 Visited_Invokers
=> Visited_Invokers
,
298 or else Edge_Kind
= Task_Activation
,
299 Internal_Controlled_Action
=>
300 Internal_Controlled_Action
301 or else Edge_Kind
in Internal_Controlled_Invocation_Kind
,
306 ----------------------
307 -- Write_Statistics --
308 ----------------------
310 procedure Write_Statistics
is
312 -- Nothing to do when switch -d_L (output library item graph) is not
315 if not Debug_Flag_Underscore_LL
then
319 Write_Str
("Library Graph Augmentation");
323 Write_Str
("Vertices visited : ");
324 Write_Num
(Int
(Total_Visited
));
327 Write_Str
("Longest path length: ");
328 Write_Num
(Int
(Longest_Path
));
332 Write_Str
("Library Graph Augmentation end");
335 end Write_Statistics
;
336 end Library_Graph_Augmentors
;
338 end Bindo
.Augmentors
;