annotate gcc/ada/exp_unst.ads @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 ------------------------------------------------------------------------------
kono
parents:
diff changeset
2 -- --
kono
parents:
diff changeset
3 -- GNAT COMPILER COMPONENTS --
kono
parents:
diff changeset
4 -- --
kono
parents:
diff changeset
5 -- E X P _ U N S T --
kono
parents:
diff changeset
6 -- --
kono
parents:
diff changeset
7 -- S p e c --
kono
parents:
diff changeset
8 -- --
kono
parents:
diff changeset
9 -- Copyright (C) 2014-2017, Free Software Foundation, Inc. --
kono
parents:
diff changeset
10 -- --
kono
parents:
diff changeset
11 -- GNAT is free software; you can redistribute it and/or modify it under --
kono
parents:
diff changeset
12 -- terms of the GNU General Public License as published by the Free Soft- --
kono
parents:
diff changeset
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
kono
parents:
diff changeset
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
kono
parents:
diff changeset
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
kono
parents:
diff changeset
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
kono
parents:
diff changeset
17 -- for more details. You should have received a copy of the GNU General --
kono
parents:
diff changeset
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
kono
parents:
diff changeset
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
kono
parents:
diff changeset
20 -- --
kono
parents:
diff changeset
21 -- GNAT was originally developed by the GNAT team at New York University. --
kono
parents:
diff changeset
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
kono
parents:
diff changeset
23 -- --
kono
parents:
diff changeset
24 ------------------------------------------------------------------------------
kono
parents:
diff changeset
25
kono
parents:
diff changeset
26 -- Expand routines for unnesting subprograms
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 with Table;
kono
parents:
diff changeset
29 with Types; use Types;
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 package Exp_Unst is
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 -- -----------------
kono
parents:
diff changeset
34 -- -- The Problem --
kono
parents:
diff changeset
35 -- -----------------
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 -- Normally, nested subprograms in the source result in corresponding
kono
parents:
diff changeset
38 -- nested subprograms in the resulting tree. We then expect the back end
kono
parents:
diff changeset
39 -- to handle such nested subprograms, including all cases of uplevel
kono
parents:
diff changeset
40 -- references. For example, the GCC back end can do this relatively easily
kono
parents:
diff changeset
41 -- since GNU C (as an extension) allows nested functions with uplevel
kono
parents:
diff changeset
42 -- references, and implements an appropriate static chain approach to
kono
parents:
diff changeset
43 -- dealing with such uplevel references.
kono
parents:
diff changeset
44
kono
parents:
diff changeset
45 -- However, we also want to be able to interface with back ends that do
kono
parents:
diff changeset
46 -- not easily handle such uplevel references. One example is the back end
kono
parents:
diff changeset
47 -- that translates the tree into standard C source code. In the future,
kono
parents:
diff changeset
48 -- other back ends might need the same capability (e.g. a back end that
kono
parents:
diff changeset
49 -- generated LLVM intermediate code).
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 -- We could imagine simply handling such references in the appropriate
kono
parents:
diff changeset
52 -- back end. For example the back end that generates C could recognize
kono
parents:
diff changeset
53 -- nested subprograms and rig up some way of translating them, e.g. by
kono
parents:
diff changeset
54 -- making a static-link source level visible.
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 -- Rather than take that approach, we prefer to do a semantics-preserving
kono
parents:
diff changeset
57 -- transformation on the GNAT tree, that eliminates the problem before we
kono
parents:
diff changeset
58 -- hand the tree over to the back end. There are two reasons for preferring
kono
parents:
diff changeset
59 -- this approach:
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 -- First: the work needs only to be done once for all affected back ends
kono
parents:
diff changeset
62 -- and we can remain within the semantics of the tree. The front end is
kono
parents:
diff changeset
63 -- full of tree transformations, so we have all the infrastructure for
kono
parents:
diff changeset
64 -- doing transformations of this type.
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 -- Second: given that the transformation will be semantics-preserving,
kono
parents:
diff changeset
67 -- we can still used the standard GCC back end to build code from it.
kono
parents:
diff changeset
68 -- This means we can easily run our full test suite to verify that the
kono
parents:
diff changeset
69 -- transformations are indeed semantics preserving. It is a lot more
kono
parents:
diff changeset
70 -- work to thoroughly test the output of specialized back ends.
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 -- Looking at the problem, we have three situations to deal with. Note
kono
parents:
diff changeset
73 -- that in these examples, we use all lower case, since that is the way
kono
parents:
diff changeset
74 -- the internal tree is cased.
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 -- First, cases where there are no uplevel references, for example
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 -- procedure case1 is
kono
parents:
diff changeset
79 -- function max (m, n : Integer) return integer is
kono
parents:
diff changeset
80 -- begin
kono
parents:
diff changeset
81 -- return integer'max (m, n);
kono
parents:
diff changeset
82 -- end max;
kono
parents:
diff changeset
83 -- ...
kono
parents:
diff changeset
84 -- end case1;
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 -- Second, cases where there are explicit uplevel references.
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 -- procedure case2 (b : integer) is
kono
parents:
diff changeset
89 -- procedure Inner (bb : integer);
kono
parents:
diff changeset
90 --
kono
parents:
diff changeset
91 -- procedure inner2 is
kono
parents:
diff changeset
92 -- begin
kono
parents:
diff changeset
93 -- inner(5);
kono
parents:
diff changeset
94 -- end;
kono
parents:
diff changeset
95 --
kono
parents:
diff changeset
96 -- x : integer := 77;
kono
parents:
diff changeset
97 -- y : constant integer := 15 * 16;
kono
parents:
diff changeset
98 -- rv : integer := 10;
kono
parents:
diff changeset
99 --
kono
parents:
diff changeset
100 -- procedure inner (bb : integer) is
kono
parents:
diff changeset
101 -- begin
kono
parents:
diff changeset
102 -- x := rv + y + bb + b;
kono
parents:
diff changeset
103 -- end;
kono
parents:
diff changeset
104 --
kono
parents:
diff changeset
105 -- begin
kono
parents:
diff changeset
106 -- inner2;
kono
parents:
diff changeset
107 -- end case2;
kono
parents:
diff changeset
108
kono
parents:
diff changeset
109 -- In this second example, B, X, RV are uplevel referenced. Y is not
kono
parents:
diff changeset
110 -- considered as an uplevel reference since it is a static constant
kono
parents:
diff changeset
111 -- where references are replaced by the value at compile time.
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 -- Third, cases where there are implicit uplevel references via types
kono
parents:
diff changeset
114 -- whose bounds depend on locally declared constants or variables:
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 -- function case3 (x, y : integer) return boolean is
kono
parents:
diff changeset
117 -- subtype dynam is integer range x .. y + 3;
kono
parents:
diff changeset
118 -- subtype static is integer range 42 .. 73;
kono
parents:
diff changeset
119 -- xx : dynam := y;
kono
parents:
diff changeset
120 --
kono
parents:
diff changeset
121 -- type darr is array (dynam) of Integer;
kono
parents:
diff changeset
122 -- type darec is record
kono
parents:
diff changeset
123 -- A : darr;
kono
parents:
diff changeset
124 -- B : integer;
kono
parents:
diff changeset
125 -- end record;
kono
parents:
diff changeset
126 -- darecv : darec;
kono
parents:
diff changeset
127 --
kono
parents:
diff changeset
128 -- function inner (b : integer) return boolean is
kono
parents:
diff changeset
129 -- begin
kono
parents:
diff changeset
130 -- return b in dynam and then darecv.b in static;
kono
parents:
diff changeset
131 -- end inner;
kono
parents:
diff changeset
132 --
kono
parents:
diff changeset
133 -- begin
kono
parents:
diff changeset
134 -- return inner (42) and then inner (xx * 3 - y * 2);
kono
parents:
diff changeset
135 -- end case3;
kono
parents:
diff changeset
136 --
kono
parents:
diff changeset
137 -- In this third example, the membership test implicitly references the
kono
parents:
diff changeset
138 -- the bounds of Dynam, which both involve uplevel references.
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 -- ------------------
kono
parents:
diff changeset
141 -- -- The Solution --
kono
parents:
diff changeset
142 -- ------------------
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 -- Looking at the three cases above, the first case poses no problem at
kono
parents:
diff changeset
145 -- all. Indeed the subprogram could have been declared at the outer level
kono
parents:
diff changeset
146 -- (perhaps changing the name). But this style is quite common as a way
kono
parents:
diff changeset
147 -- of limiting the scope of a local procedure called only within the outer
kono
parents:
diff changeset
148 -- procedure. We could move it to the outer level (with a name change if
kono
parents:
diff changeset
149 -- needed), but we don't bother. We leave it nested, and the back end just
kono
parents:
diff changeset
150 -- translates it as though it were not nested.
kono
parents:
diff changeset
151
kono
parents:
diff changeset
152 -- In general we leave nested procedures nested, rather than trying to move
kono
parents:
diff changeset
153 -- them to the outer level (the back end may do that, e.g. as part of the
kono
parents:
diff changeset
154 -- translation to C, but we don't do it in the tree itself). This saves a
kono
parents:
diff changeset
155 -- LOT of trouble in terms of visibility and semantics.
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 -- But of course we have to deal with the uplevel references. The idea is
kono
parents:
diff changeset
158 -- to rewrite these nested subprograms so that they no longer have any such
kono
parents:
diff changeset
159 -- uplevel references, so by the time they reach the back end, they all are
kono
parents:
diff changeset
160 -- case 1 (no uplevel references) and thus easily handled.
kono
parents:
diff changeset
161
kono
parents:
diff changeset
162 -- To deal with explicit uplevel references (case 2 above), we proceed with
kono
parents:
diff changeset
163 -- the following steps:
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 -- All entities marked as being uplevel referenced are marked as aliased
kono
parents:
diff changeset
166 -- since they will be accessed indirectly via an activation record as
kono
parents:
diff changeset
167 -- described below.
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 -- An activation record is created containing system address values
kono
parents:
diff changeset
170 -- for each uplevel referenced entity in a given scope. In the example
kono
parents:
diff changeset
171 -- given before, we would have:
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 -- type AREC1T is record
kono
parents:
diff changeset
174 -- b : Address;
kono
parents:
diff changeset
175 -- x : Address;
kono
parents:
diff changeset
176 -- rv : Address;
kono
parents:
diff changeset
177 -- end record;
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 -- type AREC1PT is access all AREC1T;
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 -- AREC1 : aliased AREC1T;
kono
parents:
diff changeset
182 -- AREC1P : constant AREC1PT := AREC1'Access;
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 -- The fields of AREC1 are set at the point the corresponding entity
kono
parents:
diff changeset
185 -- is declared (immediately for parameters).
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187 -- Note: the 1 in all these names is a unique index number. Different
kono
parents:
diff changeset
188 -- scopes requiring different ARECnT declarations will have different
kono
parents:
diff changeset
189 -- values of n to ensure uniqueness.
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 -- Note: normally the field names in the activation record match the
kono
parents:
diff changeset
192 -- name of the entity. An exception is when the entity is declared in
kono
parents:
diff changeset
193 -- a declare block, in which case we append the entity number, to avoid
kono
parents:
diff changeset
194 -- clashes between the same name declared in different declare blocks.
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 -- For all subprograms nested immediately within the corresponding scope,
kono
parents:
diff changeset
197 -- a parameter AREC1F is passed, and all calls to these routines have
kono
parents:
diff changeset
198 -- AREC1P added as an additional formal.
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 -- Now within the nested procedures, any reference to an uplevel entity
kono
parents:
diff changeset
201 -- xxx is replaced by typ'Deref(AREC1.xxx) where typ is the type of the
kono
parents:
diff changeset
202 -- reference.
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 -- Note: the reason that we use Address as the component type in the
kono
parents:
diff changeset
205 -- declaration of AREC1T is that we may create this type before we see
kono
parents:
diff changeset
206 -- the declaration of this type.
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 -- The following shows example 2 above after this translation:
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 -- procedure case2x (b : aliased Integer) is
kono
parents:
diff changeset
211 -- type AREC1T is record
kono
parents:
diff changeset
212 -- b : Address;
kono
parents:
diff changeset
213 -- x : Address;
kono
parents:
diff changeset
214 -- rv : Address;
kono
parents:
diff changeset
215 -- end record;
kono
parents:
diff changeset
216 --
kono
parents:
diff changeset
217 -- type AREC1PT is access all AREC1T;
kono
parents:
diff changeset
218 --
kono
parents:
diff changeset
219 -- AREC1 : aliased AREC1T;
kono
parents:
diff changeset
220 -- AREC1P : constant AREC1PT := AREC1'Access;
kono
parents:
diff changeset
221 --
kono
parents:
diff changeset
222 -- AREC1.b := b'Address;
kono
parents:
diff changeset
223 --
kono
parents:
diff changeset
224 -- procedure inner (bb : integer; AREC1F : AREC1PT);
kono
parents:
diff changeset
225 --
kono
parents:
diff changeset
226 -- procedure inner2 (AREC1F : AREC1PT) is
kono
parents:
diff changeset
227 -- begin
kono
parents:
diff changeset
228 -- inner(5, AREC1F);
kono
parents:
diff changeset
229 -- end;
kono
parents:
diff changeset
230 --
kono
parents:
diff changeset
231 -- x : aliased integer := 77;
kono
parents:
diff changeset
232 -- AREC1.x := X'Address;
kono
parents:
diff changeset
233 --
kono
parents:
diff changeset
234 -- y : constant Integer := 15 * 16;
kono
parents:
diff changeset
235 --
kono
parents:
diff changeset
236 -- rv : aliased Integer;
kono
parents:
diff changeset
237 -- AREC1.rv := rv'Address;
kono
parents:
diff changeset
238 --
kono
parents:
diff changeset
239 -- procedure inner (bb : integer; AREC1F : AREC1PT) is
kono
parents:
diff changeset
240 -- begin
kono
parents:
diff changeset
241 -- Integer'Deref(AREC1F.x) :=
kono
parents:
diff changeset
242 -- Integer'Deref(AREC1F.rv) + y + b + Integer_Deref(AREC1F.b);
kono
parents:
diff changeset
243 -- end;
kono
parents:
diff changeset
244 --
kono
parents:
diff changeset
245 -- begin
kono
parents:
diff changeset
246 -- inner2 (AREC1P);
kono
parents:
diff changeset
247 -- end case2x;
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 -- And now the inner procedures INNER2 and INNER have no uplevel references
kono
parents:
diff changeset
250 -- so they have been reduced to case 1, which is the case easily handled by
kono
parents:
diff changeset
251 -- the back end. Note that the generated code is not strictly legal Ada
kono
parents:
diff changeset
252 -- because of the assignments to AREC1 in the declarative sequence, but the
kono
parents:
diff changeset
253 -- GNAT tree always allows such mixing of declarations and statements, so
kono
parents:
diff changeset
254 -- the back end must be prepared to handle this in any case.
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 -- Case 3 where we have uplevel references to types is a bit more complex.
kono
parents:
diff changeset
257 -- That would especially be the case if we did a full transformation that
kono
parents:
diff changeset
258 -- completely eliminated such uplevel references as we did for case 2. But
kono
parents:
diff changeset
259 -- instead of trying to do that, we rewrite the subprogram so that the code
kono
parents:
diff changeset
260 -- generator can easily detect and deal with these uplevel type references.
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 -- First we distinguish two cases
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 -- Static types are one of the two following cases:
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 -- Discrete types whose bounds are known at compile time. This is not
kono
parents:
diff changeset
267 -- quite the same as what is tested by Is_OK_Static_Subtype, in that
kono
parents:
diff changeset
268 -- it allows compile time known values that are not static expressions.
kono
parents:
diff changeset
269
kono
parents:
diff changeset
270 -- Composite types, whose components are (recursively) static types.
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 -- Dynamic types are one of the two following cases:
kono
parents:
diff changeset
273
kono
parents:
diff changeset
274 -- Discrete types with at least one bound not known at compile time.
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 -- Composite types with at least one component that is (recursively)
kono
parents:
diff changeset
277 -- a dynamic type.
kono
parents:
diff changeset
278
kono
parents:
diff changeset
279 -- Uplevel references to static types are not a problem, the front end
kono
parents:
diff changeset
280 -- or the code generator fetches the bounds as required, and since they
kono
parents:
diff changeset
281 -- are compile time known values, this value can just be extracted and
kono
parents:
diff changeset
282 -- no actual uplevel reference is required.
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 -- Uplevel references to dynamic types are a potential problem, since
kono
parents:
diff changeset
285 -- such references may involve an implicit access to a dynamic bound,
kono
parents:
diff changeset
286 -- and this reference is an implicit uplevel access.
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 -- To fully unnest such references would be messy, since we would have
kono
parents:
diff changeset
289 -- to create local copies of the dynamic types involved, so that the
kono
parents:
diff changeset
290 -- front end or code generator could generate an explicit uplevel
kono
parents:
diff changeset
291 -- reference to the bound involved. Rather than do that, we set things
kono
parents:
diff changeset
292 -- up so that this situation can be easily detected and dealt with when
kono
parents:
diff changeset
293 -- there is an implicit reference to the bounds.
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 -- What we do is to always generate a local constant for any dynamic
kono
parents:
diff changeset
296 -- bound in a dynamic subtype xx with name xx_FIRST or xx_LAST. The one
kono
parents:
diff changeset
297 -- case where we can skip this is where the bound is already a constant.
kono
parents:
diff changeset
298 -- E.g. in the third example above, subtype dynam is expanded as
kono
parents:
diff changeset
299
kono
parents:
diff changeset
300 -- dynam_LAST : constant Integer := y + 3;
kono
parents:
diff changeset
301 -- subtype dynam is integer range x .. dynam_LAST;
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 -- Now if type dynam is uplevel referenced (as it is in this case), then
kono
parents:
diff changeset
304 -- the bounds x and dynam_LAST are marked as uplevel references
kono
parents:
diff changeset
305 -- so that appropriate entries are made in the activation record. Any
kono
parents:
diff changeset
306 -- explicit reference to such a bound in the front end generated code
kono
parents:
diff changeset
307 -- will be handled by the normal uplevel reference mechanism which we
kono
parents:
diff changeset
308 -- described above for case 2. For implicit references by a back end
kono
parents:
diff changeset
309 -- that needs to unnest things, any such implicit reference to one of
kono
parents:
diff changeset
310 -- these bounds can be replaced by an appropriate reference to the entry
kono
parents:
diff changeset
311 -- in the activation record for xx_FIRST or xx_LAST. Thus the back end
kono
parents:
diff changeset
312 -- can eliminate the problematical uplevel reference without the need to
kono
parents:
diff changeset
313 -- do the heavy tree modification to do that at the code expansion level.
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 -- Looking at case 3 again, here is the normal -gnatG expanded code
kono
parents:
diff changeset
316
kono
parents:
diff changeset
317 -- function case3 (x : integer; y : integer) return boolean is
kono
parents:
diff changeset
318 -- dynam_LAST : constant integer := y {+} 3;
kono
parents:
diff changeset
319 -- subtype dynam is integer range x .. dynam_LAST;
kono
parents:
diff changeset
320 -- subtype static is integer range 42 .. 73;
kono
parents:
diff changeset
321 --
kono
parents:
diff changeset
322 -- [constraint_error when
kono
parents:
diff changeset
323 -- not (y in x .. dynam_LAST)
kono
parents:
diff changeset
324 -- "range check failed"]
kono
parents:
diff changeset
325 --
kono
parents:
diff changeset
326 -- xx : dynam := y;
kono
parents:
diff changeset
327 --
kono
parents:
diff changeset
328 -- type darr is array (x .. dynam_LAST) of integer;
kono
parents:
diff changeset
329 -- type darec is record
kono
parents:
diff changeset
330 -- a : darr;
kono
parents:
diff changeset
331 -- b : integer;
kono
parents:
diff changeset
332 -- end record;
kono
parents:
diff changeset
333 -- [type TdarrB is array (x .. dynam_LAST range <>) of integer]
kono
parents:
diff changeset
334 -- freeze TdarrB []
kono
parents:
diff changeset
335 -- darecv : darec;
kono
parents:
diff changeset
336 --
kono
parents:
diff changeset
337 -- function inner (b : integer) return boolean is
kono
parents:
diff changeset
338 -- begin
kono
parents:
diff changeset
339 -- return b in x .. dynam_LAST and then darecv.b in 42 .. 73;
kono
parents:
diff changeset
340 -- end inner;
kono
parents:
diff changeset
341 -- begin
kono
parents:
diff changeset
342 -- return inner (42) and then inner (xx {*} 3 {-} y {*} 2);
kono
parents:
diff changeset
343 -- end case3;
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 -- Note: the actual expanded code has fully qualified names so for
kono
parents:
diff changeset
346 -- example function inner is actually function case3__inner. For now
kono
parents:
diff changeset
347 -- we ignore that detail to clarify the examples.
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349 -- Here we see that some of the bounds references are expanded by the
kono
parents:
diff changeset
350 -- front end, so that we get explicit references to y or dynam_Last. These
kono
parents:
diff changeset
351 -- cases are handled by the normal uplevel reference mechanism described
kono
parents:
diff changeset
352 -- above for case 2. This is the case for the constraint check for the
kono
parents:
diff changeset
353 -- initialization of xx, and the range check in function inner.
kono
parents:
diff changeset
354
kono
parents:
diff changeset
355 -- But the reference darecv.b in the return statement of function
kono
parents:
diff changeset
356 -- inner has an implicit reference to the bounds of dynam, since to
kono
parents:
diff changeset
357 -- compute the location of b in the record, we need the length of a.
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 -- Here is the full translation of the third example:
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 -- function case3x (x, y : integer) return boolean is
kono
parents:
diff changeset
362 -- type AREC1T is record
kono
parents:
diff changeset
363 -- x : Address;
kono
parents:
diff changeset
364 -- dynam_LAST : Address;
kono
parents:
diff changeset
365 -- end record;
kono
parents:
diff changeset
366 --
kono
parents:
diff changeset
367 -- type AREC1PT is access all AREC1T;
kono
parents:
diff changeset
368 --
kono
parents:
diff changeset
369 -- AREC1 : aliased AREC1T;
kono
parents:
diff changeset
370 -- AREC1P : constant AREC1PT := AREC1'Access;
kono
parents:
diff changeset
371 --
kono
parents:
diff changeset
372 -- AREC1.x := x'Address;
kono
parents:
diff changeset
373 --
kono
parents:
diff changeset
374 -- dynam_LAST : constant integer := y {+} 3;
kono
parents:
diff changeset
375 -- AREC1.dynam_LAST := dynam_LAST'Address;
kono
parents:
diff changeset
376 -- subtype dynam is integer range x .. dynam_LAST;
kono
parents:
diff changeset
377 -- xx : dynam := y;
kono
parents:
diff changeset
378 --
kono
parents:
diff changeset
379 -- [constraint_error when
kono
parents:
diff changeset
380 -- not (y in x .. dynam_LAST)
kono
parents:
diff changeset
381 -- "range check failed"]
kono
parents:
diff changeset
382 --
kono
parents:
diff changeset
383 -- subtype static is integer range 42 .. 73;
kono
parents:
diff changeset
384 --
kono
parents:
diff changeset
385 -- type darr is array (x .. dynam_LAST) of Integer;
kono
parents:
diff changeset
386 -- type darec is record
kono
parents:
diff changeset
387 -- A : darr;
kono
parents:
diff changeset
388 -- B : integer;
kono
parents:
diff changeset
389 -- end record;
kono
parents:
diff changeset
390 -- darecv : darec;
kono
parents:
diff changeset
391 --
kono
parents:
diff changeset
392 -- function inner (b : integer; AREC1F : AREC1PT) return boolean is
kono
parents:
diff changeset
393 -- begin
kono
parents:
diff changeset
394 -- return b in x .. Integer'Deref(AREC1F.dynam_LAST)
kono
parents:
diff changeset
395 -- and then darecv.b in 42 .. 73;
kono
parents:
diff changeset
396 -- end inner;
kono
parents:
diff changeset
397 --
kono
parents:
diff changeset
398 -- begin
kono
parents:
diff changeset
399 -- return inner (42, AREC1P) and then inner (xx * 3, AREC1P);
kono
parents:
diff changeset
400 -- end case3x;
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 -- And now the back end when it processes darecv.b will access the bounds
kono
parents:
diff changeset
403 -- of darecv.a by referencing the d and dynam_LAST fields of AREC1P.
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 -----------------------------
kono
parents:
diff changeset
406 -- Multiple Nesting Levels --
kono
parents:
diff changeset
407 -----------------------------
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 -- In our examples so far, we have only nested to a single level, but the
kono
parents:
diff changeset
410 -- scheme generalizes to multiple levels of nesting and in this section we
kono
parents:
diff changeset
411 -- discuss how this generalization works.
kono
parents:
diff changeset
412
kono
parents:
diff changeset
413 -- Consider this example with two nesting levels
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 -- To deal with elimination of uplevel references, we follow the same basic
kono
parents:
diff changeset
416 -- approach described above for case 2, except that we need an activation
kono
parents:
diff changeset
417 -- record at each nested level. Basically the rule is that any procedure
kono
parents:
diff changeset
418 -- that has nested procedures needs an activation record. When we do this,
kono
parents:
diff changeset
419 -- the inner activation records have a pointer (uplink) to the immediately
kono
parents:
diff changeset
420 -- enclosing activation record, the normal arrangement of static links. The
kono
parents:
diff changeset
421 -- following shows the full translation of this fourth case.
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 -- function case4x (x : integer) return integer is
kono
parents:
diff changeset
424 -- type AREC1T is record
kono
parents:
diff changeset
425 -- v1 : Address;
kono
parents:
diff changeset
426 -- end record;
kono
parents:
diff changeset
427 --
kono
parents:
diff changeset
428 -- type AREC1PT is access all AREC1T;
kono
parents:
diff changeset
429 --
kono
parents:
diff changeset
430 -- AREC1 : aliased AREC1T;
kono
parents:
diff changeset
431 -- AREC1P : constant AREC1PT := AREC1'Access;
kono
parents:
diff changeset
432 --
kono
parents:
diff changeset
433 -- v1 : integer := x;
kono
parents:
diff changeset
434 -- AREC1.v1 := v1'Address;
kono
parents:
diff changeset
435 --
kono
parents:
diff changeset
436 -- function inner1 (y : integer; AREC1F : AREC1PT) return integer is
kono
parents:
diff changeset
437 -- type AREC2T is record
kono
parents:
diff changeset
438 -- AREC1U : AREC1PT;
kono
parents:
diff changeset
439 -- v2 : Address;
kono
parents:
diff changeset
440 -- end record;
kono
parents:
diff changeset
441 --
kono
parents:
diff changeset
442 -- type AREC2PT is access all AREC2T;
kono
parents:
diff changeset
443 --
kono
parents:
diff changeset
444 -- AREC2 : aliased AREC2T;
kono
parents:
diff changeset
445 -- AREC2P : constant AREC2PT := AREC2'Access;
kono
parents:
diff changeset
446 --
kono
parents:
diff changeset
447 -- AREC2.AREC1U := AREC1F;
kono
parents:
diff changeset
448 --
kono
parents:
diff changeset
449 -- v2 : integer := Integer'Deref (AREC1F.v1) {+} 1;
kono
parents:
diff changeset
450 -- AREC2.v2 := v2'Address;
kono
parents:
diff changeset
451 --
kono
parents:
diff changeset
452 -- function inner2
kono
parents:
diff changeset
453 -- (z : integer; AREC2F : AREC2PT) return integer
kono
parents:
diff changeset
454 -- is
kono
parents:
diff changeset
455 -- begin
kono
parents:
diff changeset
456 -- return integer(z {+}
kono
parents:
diff changeset
457 -- Integer'Deref (AREC2F.AREC1U.v1) {+}
kono
parents:
diff changeset
458 -- Integer'Deref (AREC2F.v2).all);
kono
parents:
diff changeset
459 -- end inner2;
kono
parents:
diff changeset
460 -- begin
kono
parents:
diff changeset
461 -- return integer(y {+}
kono
parents:
diff changeset
462 -- inner2 (Integer'Deref (AREC1F.v1), AREC2P));
kono
parents:
diff changeset
463 -- end inner1;
kono
parents:
diff changeset
464 -- begin
kono
parents:
diff changeset
465 -- return inner1 (x, AREC1P);
kono
parents:
diff changeset
466 -- end case4x;
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 -- As can be seen in this example, the index numbers following AREC in the
kono
parents:
diff changeset
469 -- generated names avoid confusion between AREC names at different levels.
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 -------------------------
kono
parents:
diff changeset
472 -- Name Disambiguation --
kono
parents:
diff changeset
473 -------------------------
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 -- As described above, the translation scheme would raise issues when the
kono
parents:
diff changeset
476 -- code generator did the actual unnesting if identically named nested
kono
parents:
diff changeset
477 -- subprograms exist. Similarly overloading would cause a naming issue.
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 -- In fact, the expanded code includes qualified names which eliminate this
kono
parents:
diff changeset
480 -- problem. We omitted the qualification from the exapnded examples above
kono
parents:
diff changeset
481 -- for simplicity. But to see this in action, consider this example:
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 -- function Mnames return Boolean is
kono
parents:
diff changeset
484 -- procedure Inner is
kono
parents:
diff changeset
485 -- procedure Inner is
kono
parents:
diff changeset
486 -- begin
kono
parents:
diff changeset
487 -- null;
kono
parents:
diff changeset
488 -- end;
kono
parents:
diff changeset
489 -- begin
kono
parents:
diff changeset
490 -- Inner;
kono
parents:
diff changeset
491 -- end;
kono
parents:
diff changeset
492 -- function F (A : Boolean) return Boolean is
kono
parents:
diff changeset
493 -- begin
kono
parents:
diff changeset
494 -- return not A;
kono
parents:
diff changeset
495 -- end;
kono
parents:
diff changeset
496 -- function F (A : Integer) return Boolean is
kono
parents:
diff changeset
497 -- begin
kono
parents:
diff changeset
498 -- return A > 42;
kono
parents:
diff changeset
499 -- end;
kono
parents:
diff changeset
500 -- begin
kono
parents:
diff changeset
501 -- Inner;
kono
parents:
diff changeset
502 -- return F (42) or F (True);
kono
parents:
diff changeset
503 -- end;
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 -- The expanded code actually looks like:
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 -- function mnames return boolean is
kono
parents:
diff changeset
508 -- procedure mnames__inner is
kono
parents:
diff changeset
509 -- procedure mnames__inner__inner is
kono
parents:
diff changeset
510 -- begin
kono
parents:
diff changeset
511 -- null;
kono
parents:
diff changeset
512 -- return;
kono
parents:
diff changeset
513 -- end mnames__inner__inner;
kono
parents:
diff changeset
514 -- begin
kono
parents:
diff changeset
515 -- mnames__inner__inner;
kono
parents:
diff changeset
516 -- return;
kono
parents:
diff changeset
517 -- end mnames__inner;
kono
parents:
diff changeset
518 -- function mnames__f (a : boolean) return boolean is
kono
parents:
diff changeset
519 -- begin
kono
parents:
diff changeset
520 -- return not a;
kono
parents:
diff changeset
521 -- end mnames__f;
kono
parents:
diff changeset
522 -- function mnames__f__2 (a : integer) return boolean is
kono
parents:
diff changeset
523 -- begin
kono
parents:
diff changeset
524 -- return a > 42;
kono
parents:
diff changeset
525 -- end mnames__f__2;
kono
parents:
diff changeset
526 -- begin
kono
parents:
diff changeset
527 -- mnames__inner;
kono
parents:
diff changeset
528 -- return mnames__f__2 (42) or mnames__f (true);
kono
parents:
diff changeset
529 -- end mnames;
kono
parents:
diff changeset
530
kono
parents:
diff changeset
531 -- As can be seen from studying this example, the qualification deals both
kono
parents:
diff changeset
532 -- with the issue of clashing names (mnames__inner, mnames__inner__inner),
kono
parents:
diff changeset
533 -- and with overloading (mnames__f, mnames__f__2).
kono
parents:
diff changeset
534
kono
parents:
diff changeset
535 -- In addition, the declarations of ARECnT and ARECnPT get moved to the
kono
parents:
diff changeset
536 -- outer level when we actually generate C code, so we suffix these names
kono
parents:
diff changeset
537 -- with the corresponding entity name to make sure they are unique.
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 ---------------------------
kono
parents:
diff changeset
540 -- Terminology for Calls --
kono
parents:
diff changeset
541 ---------------------------
kono
parents:
diff changeset
542
kono
parents:
diff changeset
543 -- The level of a subprogram in the nest being analyzed is defined to be
kono
parents:
diff changeset
544 -- the level of nesting, so the outer level subprogram (the one passed to
kono
parents:
diff changeset
545 -- Unnest_Subprogram) is 1, subprograms immediately nested within this
kono
parents:
diff changeset
546 -- outer level subprogram have a level of 2, etc.
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 -- Calls within the nest being analyzed are of three types:
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 -- Downward call: this is a call from a subprogram to a subprogram that
kono
parents:
diff changeset
551 -- is immediately nested with in the caller, and thus has a level that
kono
parents:
diff changeset
552 -- is one greater than the caller. It is a fundamental property of the
kono
parents:
diff changeset
553 -- nesting structure and visibility that it is not possible to make a
kono
parents:
diff changeset
554 -- call from level N to level M, where M is greater than N + 1.
kono
parents:
diff changeset
555
kono
parents:
diff changeset
556 -- Parallel call: this is a call from a nested subprogram to another
kono
parents:
diff changeset
557 -- nested subprogram that is at the same level.
kono
parents:
diff changeset
558
kono
parents:
diff changeset
559 -- Upward call: this is a call from a subprogram to a subprogram that
kono
parents:
diff changeset
560 -- encloses the caller. The level of the callee is less than the level
kono
parents:
diff changeset
561 -- of the caller, and there is no limit on the difference, e.g. for an
kono
parents:
diff changeset
562 -- uplevel call, a subprogram at level 5 can call one at level 2 or even
kono
parents:
diff changeset
563 -- the outer level subprogram at level 1.
kono
parents:
diff changeset
564
kono
parents:
diff changeset
565 -----------
kono
parents:
diff changeset
566 -- Subps --
kono
parents:
diff changeset
567 -----------
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 -- Table to record subprograms within the nest being currently analyzed.
kono
parents:
diff changeset
570 -- Entries in this table are made for each subprogram expanded, and do not
kono
parents:
diff changeset
571 -- get cleared as we complete the expansion, since we want the table info
kono
parents:
diff changeset
572 -- around in Cprint for the actual unnesting operation. Subps_First in this
kono
parents:
diff changeset
573 -- unit records the starting entry in the table for the entries for Subp
kono
parents:
diff changeset
574 -- and this is also recorded in the Subps_Index field of the outer level
kono
parents:
diff changeset
575 -- subprogram in the nest. The last subps index for the nest can be found
kono
parents:
diff changeset
576 -- in the Subp_Entry Last field of this first entry.
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 subtype SI_Type is Nat;
kono
parents:
diff changeset
579 -- Index type for the table
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 Subps_First : SI_Type;
kono
parents:
diff changeset
582 -- Record starting index for entries in the current nest (this is the table
kono
parents:
diff changeset
583 -- index of the entry for Subp itself, and is recorded in the Subps_Index
kono
parents:
diff changeset
584 -- field of the entity for this subprogram).
kono
parents:
diff changeset
585
kono
parents:
diff changeset
586 type Subp_Entry is record
kono
parents:
diff changeset
587 Ent : Entity_Id;
kono
parents:
diff changeset
588 -- Entity of the subprogram
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 Bod : Node_Id;
kono
parents:
diff changeset
591 -- Subprogram_Body node for this subprogram
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 Lev : Nat;
kono
parents:
diff changeset
594 -- Subprogram level (1 = outer subprogram (Subp argument), 2 = nested
kono
parents:
diff changeset
595 -- immediately within this outer subprogram etc.)
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 Reachable : Boolean;
kono
parents:
diff changeset
598 -- This flag is set True if there is a call path from the outer level
kono
parents:
diff changeset
599 -- subprogram to this subprogram. If Reachable is False, it means that
kono
parents:
diff changeset
600 -- the subprogram is declared but not actually referenced. We remove
kono
parents:
diff changeset
601 -- such subprograms from the tree, which simplifies our task, because
kono
parents:
diff changeset
602 -- we don't have to worry about e.g. uplevel references from such an
kono
parents:
diff changeset
603 -- unreferenced subpogram, which might require (useless) activation
kono
parents:
diff changeset
604 -- records to be created. This is computed by setting the outer level
kono
parents:
diff changeset
605 -- subprogram (Subp itself) as reachable, and then doing a transitive
kono
parents:
diff changeset
606 -- closure following all calls.
kono
parents:
diff changeset
607
kono
parents:
diff changeset
608 Uplevel_Ref : Nat;
kono
parents:
diff changeset
609 -- The outermost level which defines entities which this subprogram
kono
parents:
diff changeset
610 -- references either directly or indirectly via a call. This cannot
kono
parents:
diff changeset
611 -- be greater than Lev. If it is equal to Lev, then it means that the
kono
parents:
diff changeset
612 -- subprogram does not make any uplevel references and that thus it
kono
parents:
diff changeset
613 -- does not need an activation record pointer passed. If it is less than
kono
parents:
diff changeset
614 -- Lev, then an activation record pointer is needed, since there is at
kono
parents:
diff changeset
615 -- least one uplevel reference. This is computed by initially setting
kono
parents:
diff changeset
616 -- Uplevel_Ref to Lev for all subprograms. Then on the initial tree
kono
parents:
diff changeset
617 -- traversal, decreasing Uplevel_Ref for an explicit uplevel reference,
kono
parents:
diff changeset
618 -- and finally by doing a transitive closure that follows calls (if A
kono
parents:
diff changeset
619 -- calls B and B has an uplevel reference to level X, then A references
kono
parents:
diff changeset
620 -- level X indirectly).
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 Declares_AREC : Boolean;
kono
parents:
diff changeset
623 -- This is set True for a subprogram which include the declarations
kono
parents:
diff changeset
624 -- for a local activation record to be passed on downward calls. It
kono
parents:
diff changeset
625 -- is set True for the target level of an uplevel reference, and for
kono
parents:
diff changeset
626 -- all intervening nested subprograms. For example, if a subprogram X
kono
parents:
diff changeset
627 -- at level 5 makes an uplevel reference to an entity declared in a
kono
parents:
diff changeset
628 -- level 2 subprogram, then the subprograms at levels 4,3,2 enclosing
kono
parents:
diff changeset
629 -- the level 5 subprogram will have this flag set True.
kono
parents:
diff changeset
630
kono
parents:
diff changeset
631 Uents : Elist_Id;
kono
parents:
diff changeset
632 -- This is a list of entities declared in this subprogram which are
kono
parents:
diff changeset
633 -- uplevel referenced. It contains both objects (which will be put in
kono
parents:
diff changeset
634 -- the corresponding AREC activation record), and types. The types are
kono
parents:
diff changeset
635 -- not put in the AREC activation record, but referenced bounds (i.e.
kono
parents:
diff changeset
636 -- generated _FIRST and _LAST entites, and formal parameters) will be
kono
parents:
diff changeset
637 -- in the list in their own right.
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 Last : SI_Type;
kono
parents:
diff changeset
640 -- This field is set only in the entry for the outer level subprogram
kono
parents:
diff changeset
641 -- in a nest, and records the last index in the Subp table for all the
kono
parents:
diff changeset
642 -- entries for subprograms in this nest.
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 ARECnF : Entity_Id;
kono
parents:
diff changeset
645 -- This entity is defined for all subprograms which need an extra formal
kono
parents:
diff changeset
646 -- that contains a pointer to the activation record needed for uplevel
kono
parents:
diff changeset
647 -- references. ARECnF must be defined for any subprogram which has a
kono
parents:
diff changeset
648 -- direct or indirect uplevel reference (i.e. Reference_Level < Lev).
kono
parents:
diff changeset
649
kono
parents:
diff changeset
650 ARECn : Entity_Id;
kono
parents:
diff changeset
651 ARECnT : Entity_Id;
kono
parents:
diff changeset
652 ARECnPT : Entity_Id;
kono
parents:
diff changeset
653 ARECnP : Entity_Id;
kono
parents:
diff changeset
654 -- These AREC entities are defined only for subprograms for which we
kono
parents:
diff changeset
655 -- generate an activation record declaration, i.e. for subprograms for
kono
parents:
diff changeset
656 -- which the Declares_AREC flag is set True.
kono
parents:
diff changeset
657
kono
parents:
diff changeset
658 ARECnU : Entity_Id;
kono
parents:
diff changeset
659 -- This AREC entity is the uplink component. It is other than Empty only
kono
parents:
diff changeset
660 -- for nested subprograms that declare an activation record as indicated
kono
parents:
diff changeset
661 -- by Declares_AREC being Ture, and which have uplevel references (Lev
kono
parents:
diff changeset
662 -- greater than Uplevel_Ref). It is the additional component in the
kono
parents:
diff changeset
663 -- activation record that references the ARECnF pointer (which points
kono
parents:
diff changeset
664 -- the activation record one level higher, thus forming the chain).
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 end record;
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 package Subps is new Table.Table (
kono
parents:
diff changeset
669 Table_Component_Type => Subp_Entry,
kono
parents:
diff changeset
670 Table_Index_Type => SI_Type,
kono
parents:
diff changeset
671 Table_Low_Bound => 1,
kono
parents:
diff changeset
672 Table_Initial => 1000,
kono
parents:
diff changeset
673 Table_Increment => 200,
kono
parents:
diff changeset
674 Table_Name => "Unnest_Subps");
kono
parents:
diff changeset
675 -- Records the subprograms in the nest whose outer subprogram is Subp
kono
parents:
diff changeset
676
kono
parents:
diff changeset
677 -----------------
kono
parents:
diff changeset
678 -- Subprograms --
kono
parents:
diff changeset
679 -----------------
kono
parents:
diff changeset
680
kono
parents:
diff changeset
681 function Get_Level (Subp : Entity_Id; Sub : Entity_Id) return Nat;
kono
parents:
diff changeset
682 -- Sub is either Subp itself, or a subprogram nested within Subp. This
kono
parents:
diff changeset
683 -- function returns the level of nesting (Subp = 1, subprograms that
kono
parents:
diff changeset
684 -- are immediately nested within Subp = 2, etc.).
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 function Subp_Index (Sub : Entity_Id) return SI_Type;
kono
parents:
diff changeset
687 -- Given the entity for a subprogram, return corresponding Subp's index
kono
parents:
diff changeset
688
kono
parents:
diff changeset
689 procedure Unnest_Subprograms (N : Node_Id);
kono
parents:
diff changeset
690 -- Called to unnest subprograms. If we are in unnest subprogram mode, this
kono
parents:
diff changeset
691 -- is the call that traverses the tree N and locates all the library level
kono
parents:
diff changeset
692 -- subprograms with nested subprograms to process them.
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 end Exp_Unst;