]>
Commit | Line | Data |
---|---|---|
6de9cd9a | 1 | /* Common block and equivalence list handling |
710a179f | 2 | Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007 |
6c7a4dfd | 3 | Free Software Foundation, Inc. |
6de9cd9a DN |
4 | Contributed by Canqun Yang <canqun@nudt.edu.cn> |
5 | ||
9fc4d79b | 6 | This file is part of GCC. |
6de9cd9a | 7 | |
9fc4d79b TS |
8 | GCC is free software; you can redistribute it and/or modify it under |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 2, or (at your option) any later | |
11 | version. | |
6de9cd9a | 12 | |
9fc4d79b TS |
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
6de9cd9a DN |
17 | |
18 | You should have received a copy of the GNU General Public License | |
9fc4d79b | 19 | along with GCC; see the file COPYING. If not, write to the Free |
ab57747b KC |
20 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
21 | 02110-1301, USA. */ | |
6de9cd9a DN |
22 | |
23 | /* The core algorithm is based on Andy Vaught's g95 tree. Also the | |
24 | way to build UNION_TYPE is borrowed from Richard Henderson. | |
25 | ||
26 | Transform common blocks. An integral part of this is processing | |
1f2959f0 | 27 | equivalence variables. Equivalenced variables that are not in a |
6de9cd9a DN |
28 | common block end up in a private block of their own. |
29 | ||
30 | Each common block or local equivalence list is declared as a union. | |
31 | Variables within the block are represented as a field within the | |
32 | block with the proper offset. | |
33 | ||
34 | So if two variables are equivalenced, they just point to a common | |
35 | area in memory. | |
36 | ||
37 | Mathematically, laying out an equivalence block is equivalent to | |
38 | solving a linear system of equations. The matrix is usually a | |
39 | sparse matrix in which each row contains all zero elements except | |
40 | for a +1 and a -1, a sort of a generalized Vandermonde matrix. The | |
41 | matrix is usually block diagonal. The system can be | |
42 | overdetermined, underdetermined or have a unique solution. If the | |
43 | system is inconsistent, the program is not standard conforming. | |
44 | The solution vector is integral, since all of the pivots are +1 or -1. | |
45 | ||
46 | How we lay out an equivalence block is a little less complicated. | |
47 | In an equivalence list with n elements, there are n-1 conditions to | |
48 | be satisfied. The conditions partition the variables into what we | |
49 | will call segments. If A and B are equivalenced then A and B are | |
50 | in the same segment. If B and C are equivalenced as well, then A, | |
51 | B and C are in a segment and so on. Each segment is a block of | |
52 | memory that has one or more variables equivalenced in some way. A | |
53 | common block is made up of a series of segments that are joined one | |
54 | after the other. In the linear system, a segment is a block | |
55 | diagonal. | |
56 | ||
57 | To lay out a segment we first start with some variable and | |
58 | determine its length. The first variable is assumed to start at | |
59 | offset one and extends to however long it is. We then traverse the | |
60 | list of equivalences to find an unused condition that involves at | |
61 | least one of the variables currently in the segment. | |
62 | ||
63 | Each equivalence condition amounts to the condition B+b=C+c where B | |
64 | and C are the offsets of the B and C variables, and b and c are | |
65 | constants which are nonzero for array elements, substrings or | |
66 | structure components. So for | |
67 | ||
68 | EQUIVALENCE(B(2), C(3)) | |
69 | we have | |
70 | B + 2*size of B's elements = C + 3*size of C's elements. | |
71 | ||
72 | If B and C are known we check to see if the condition already | |
73 | holds. If B is known we can solve for C. Since we know the length | |
74 | of C, we can see if the minimum and maximum extents of the segment | |
75 | are affected. Eventually, we make a full pass through the | |
76 | equivalence list without finding any new conditions and the segment | |
77 | is fully specified. | |
78 | ||
79 | At this point, the segment is added to the current common block. | |
80 | Since we know the minimum extent of the segment, everything in the | |
81 | segment is translated to its position in the common block. The | |
82 | usual case here is that there are no equivalence statements and the | |
83 | common block is series of segments with one variable each, which is | |
84 | a diagonal matrix in the matrix formulation. | |
85 | ||
5291e69a | 86 | Each segment is described by a chain of segment_info structures. Each |
e2ae1407 | 87 | segment_info structure describes the extents of a single variable within |
5291e69a PB |
88 | the segment. This list is maintained in the order the elements are |
89 | positioned withing the segment. If two elements have the same starting | |
90 | offset the smaller will come first. If they also have the same size their | |
91 | ordering is undefined. | |
92 | ||
6de9cd9a DN |
93 | Once all common blocks have been created, the list of equivalences |
94 | is examined for still-unused equivalence conditions. We create a | |
95 | block for each merged equivalence list. */ | |
96 | ||
97 | #include "config.h" | |
98 | #include "system.h" | |
99 | #include "coretypes.h" | |
6c7a4dfd | 100 | #include "target.h" |
6de9cd9a DN |
101 | #include "tree.h" |
102 | #include "toplev.h" | |
103 | #include "tm.h" | |
25f2dfd3 | 104 | #include "rtl.h" |
6de9cd9a DN |
105 | #include "gfortran.h" |
106 | #include "trans.h" | |
107 | #include "trans-types.h" | |
108 | #include "trans-const.h" | |
9d99ee7b | 109 | #include "target-memory.h" |
6de9cd9a DN |
110 | |
111 | ||
a8b3b0b6 CR |
112 | /* TODO: This is defined in match.h, and probably shouldn't be here also, |
113 | but we need it for now at least and don't want to include the whole | |
114 | match.h. */ | |
115 | gfc_common_head *gfc_get_common (const char *, int); | |
116 | ||
117 | ||
49de9e73 | 118 | /* Holds a single variable in an equivalence set. */ |
6de9cd9a DN |
119 | typedef struct segment_info |
120 | { | |
121 | gfc_symbol *sym; | |
5291e69a PB |
122 | HOST_WIDE_INT offset; |
123 | HOST_WIDE_INT length; | |
ad6e2a18 | 124 | /* This will contain the field type until the field is created. */ |
a8a6b603 | 125 | tree field; |
6de9cd9a DN |
126 | struct segment_info *next; |
127 | } segment_info; | |
128 | ||
832ef1ce | 129 | static segment_info * current_segment; |
6de9cd9a DN |
130 | static gfc_namespace *gfc_common_ns = NULL; |
131 | ||
61321991 | 132 | |
ad6e2a18 TS |
133 | /* Make a segment_info based on a symbol. */ |
134 | ||
135 | static segment_info * | |
136 | get_segment_info (gfc_symbol * sym, HOST_WIDE_INT offset) | |
137 | { | |
138 | segment_info *s; | |
139 | ||
140 | /* Make sure we've got the character length. */ | |
141 | if (sym->ts.type == BT_CHARACTER) | |
142 | gfc_conv_const_charlen (sym->ts.cl); | |
143 | ||
144 | /* Create the segment_info and fill it in. */ | |
145 | s = (segment_info *) gfc_getmem (sizeof (segment_info)); | |
146 | s->sym = sym; | |
13795658 | 147 | /* We will use this type when building the segment aggregate type. */ |
ad6e2a18 TS |
148 | s->field = gfc_sym_type (sym); |
149 | s->length = int_size_in_bytes (s->field); | |
150 | s->offset = offset; | |
151 | ||
152 | return s; | |
153 | } | |
154 | ||
61321991 PT |
155 | |
156 | /* Add a copy of a segment list to the namespace. This is specifically for | |
157 | equivalence segments, so that dependency checking can be done on | |
158 | equivalence group members. */ | |
159 | ||
160 | static void | |
161 | copy_equiv_list_to_ns (segment_info *c) | |
162 | { | |
163 | segment_info *f; | |
164 | gfc_equiv_info *s; | |
165 | gfc_equiv_list *l; | |
166 | ||
167 | l = (gfc_equiv_list *) gfc_getmem (sizeof (gfc_equiv_list)); | |
168 | ||
169 | l->next = c->sym->ns->equiv_lists; | |
170 | c->sym->ns->equiv_lists = l; | |
171 | ||
172 | for (f = c; f; f = f->next) | |
173 | { | |
174 | s = (gfc_equiv_info *) gfc_getmem (sizeof (gfc_equiv_info)); | |
175 | s->next = l->equiv; | |
176 | l->equiv = s; | |
177 | s->sym = f->sym; | |
178 | s->offset = f->offset; | |
37311e71 | 179 | s->length = f->length; |
61321991 PT |
180 | } |
181 | } | |
182 | ||
183 | ||
a8a6b603 | 184 | /* Add combine segment V and segment LIST. */ |
5291e69a PB |
185 | |
186 | static segment_info * | |
187 | add_segments (segment_info *list, segment_info *v) | |
188 | { | |
189 | segment_info *s; | |
190 | segment_info *p; | |
191 | segment_info *next; | |
a8a6b603 | 192 | |
5291e69a PB |
193 | p = NULL; |
194 | s = list; | |
195 | ||
196 | while (v) | |
197 | { | |
198 | /* Find the location of the new element. */ | |
199 | while (s) | |
200 | { | |
201 | if (v->offset < s->offset) | |
202 | break; | |
203 | if (v->offset == s->offset | |
204 | && v->length <= s->length) | |
205 | break; | |
206 | ||
207 | p = s; | |
208 | s = s->next; | |
209 | } | |
210 | ||
211 | /* Insert the new element in between p and s. */ | |
212 | next = v->next; | |
213 | v->next = s; | |
214 | if (p == NULL) | |
215 | list = v; | |
216 | else | |
217 | p->next = v; | |
218 | ||
219 | p = v; | |
220 | v = next; | |
221 | } | |
a8a6b603 | 222 | |
5291e69a PB |
223 | return list; |
224 | } | |
225 | ||
a8b3b0b6 | 226 | |
6de9cd9a DN |
227 | /* Construct mangled common block name from symbol name. */ |
228 | ||
a8b3b0b6 CR |
229 | /* We need the bind(c) flag to tell us how/if we should mangle the symbol |
230 | name. There are few calls to this function, so few places that this | |
231 | would need to be added. At the moment, there is only one call, in | |
232 | build_common_decl(). We can't attempt to look up the common block | |
233 | because we may be building it for the first time and therefore, it won't | |
234 | be in the common_root. We also need the binding label, if it's bind(c). | |
235 | Therefore, send in the pointer to the common block, so whatever info we | |
236 | have so far can be used. All of the necessary info should be available | |
237 | in the gfc_common_head by now, so it should be accurate to test the | |
238 | isBindC flag and use the binding label given if it is bind(c). | |
239 | ||
240 | We may NOT know yet if it's bind(c) or not, but we can try at least. | |
241 | Will have to figure out what to do later if it's labeled bind(c) | |
242 | after this is called. */ | |
243 | ||
6de9cd9a | 244 | static tree |
a8b3b0b6 | 245 | gfc_sym_mangled_common_id (gfc_common_head *com) |
6de9cd9a DN |
246 | { |
247 | int has_underscore; | |
9056bd70 | 248 | char mangled_name[GFC_MAX_MANGLED_SYMBOL_LEN + 1]; |
a8b3b0b6 CR |
249 | char name[GFC_MAX_SYMBOL_LEN + 1]; |
250 | ||
251 | /* Get the name out of the common block pointer. */ | |
252 | strcpy (name, com->name); | |
253 | ||
254 | /* If we're suppose to do a bind(c). */ | |
255 | if (com->is_bind_c == 1 && com->binding_label[0] != '\0') | |
256 | return get_identifier (com->binding_label); | |
6de9cd9a | 257 | |
9056bd70 TS |
258 | if (strcmp (name, BLANK_COMMON_NAME) == 0) |
259 | return get_identifier (name); | |
a8a6b603 | 260 | |
6de9cd9a DN |
261 | if (gfc_option.flag_underscoring) |
262 | { | |
9056bd70 | 263 | has_underscore = strchr (name, '_') != 0; |
6de9cd9a | 264 | if (gfc_option.flag_second_underscore && has_underscore) |
9056bd70 | 265 | snprintf (mangled_name, sizeof mangled_name, "%s__", name); |
6de9cd9a | 266 | else |
9056bd70 | 267 | snprintf (mangled_name, sizeof mangled_name, "%s_", name); |
a8a6b603 | 268 | |
9056bd70 | 269 | return get_identifier (mangled_name); |
6de9cd9a DN |
270 | } |
271 | else | |
9056bd70 | 272 | return get_identifier (name); |
6de9cd9a DN |
273 | } |
274 | ||
275 | ||
ad6e2a18 | 276 | /* Build a field declaration for a common variable or a local equivalence |
6de9cd9a DN |
277 | object. */ |
278 | ||
ad6e2a18 | 279 | static void |
6de9cd9a DN |
280 | build_field (segment_info *h, tree union_type, record_layout_info rli) |
281 | { | |
ad6e2a18 TS |
282 | tree field; |
283 | tree name; | |
6de9cd9a | 284 | HOST_WIDE_INT offset = h->offset; |
5291e69a | 285 | unsigned HOST_WIDE_INT desired_align, known_align; |
6de9cd9a | 286 | |
ad6e2a18 TS |
287 | name = get_identifier (h->sym->name); |
288 | field = build_decl (FIELD_DECL, name, h->field); | |
c8cc8542 | 289 | gfc_set_decl_location (field, &h->sym->declared_at); |
6de9cd9a DN |
290 | known_align = (offset & -offset) * BITS_PER_UNIT; |
291 | if (known_align == 0 || known_align > BIGGEST_ALIGNMENT) | |
292 | known_align = BIGGEST_ALIGNMENT; | |
293 | ||
294 | desired_align = update_alignment_for_field (rli, field, known_align); | |
295 | if (desired_align > known_align) | |
296 | DECL_PACKED (field) = 1; | |
297 | ||
298 | DECL_FIELD_CONTEXT (field) = union_type; | |
299 | DECL_FIELD_OFFSET (field) = size_int (offset); | |
300 | DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; | |
301 | SET_DECL_OFFSET_ALIGN (field, known_align); | |
302 | ||
303 | rli->offset = size_binop (MAX_EXPR, rli->offset, | |
304 | size_binop (PLUS_EXPR, | |
305 | DECL_FIELD_OFFSET (field), | |
306 | DECL_SIZE_UNIT (field))); | |
ce2df7c6 | 307 | /* If this field is assigned to a label, we create another two variables. |
81871c2a | 308 | One will hold the address of target label or format label. The other will |
ce2df7c6 FW |
309 | hold the length of format label string. */ |
310 | if (h->sym->attr.assign) | |
311 | { | |
312 | tree len; | |
313 | tree addr; | |
314 | ||
315 | gfc_allocate_lang_decl (field); | |
316 | GFC_DECL_ASSIGN (field) = 1; | |
317 | len = gfc_create_var_np (gfc_charlen_type_node,h->sym->name); | |
318 | addr = gfc_create_var_np (pvoid_type_node, h->sym->name); | |
319 | TREE_STATIC (len) = 1; | |
320 | TREE_STATIC (addr) = 1; | |
321 | DECL_INITIAL (len) = build_int_cst (NULL_TREE, -2); | |
322 | gfc_set_decl_location (len, &h->sym->declared_at); | |
323 | gfc_set_decl_location (addr, &h->sym->declared_at); | |
324 | GFC_DECL_STRING_LEN (field) = pushdecl_top_level (len); | |
325 | GFC_DECL_ASSIGN_ADDR (field) = pushdecl_top_level (addr); | |
326 | } | |
327 | ||
ad6e2a18 | 328 | h->field = field; |
6de9cd9a DN |
329 | } |
330 | ||
331 | ||
332 | /* Get storage for local equivalence. */ | |
333 | ||
334 | static tree | |
57f0d086 | 335 | build_equiv_decl (tree union_type, bool is_init, bool is_saved) |
6de9cd9a DN |
336 | { |
337 | tree decl; | |
bae88af6 TS |
338 | char name[15]; |
339 | static int serial = 0; | |
5291e69a PB |
340 | |
341 | if (is_init) | |
342 | { | |
343 | decl = gfc_create_var (union_type, "equiv"); | |
344 | TREE_STATIC (decl) = 1; | |
6c7a4dfd | 345 | GFC_DECL_COMMON_OR_EQUIV (decl) = 1; |
5291e69a PB |
346 | return decl; |
347 | } | |
348 | ||
bae88af6 TS |
349 | snprintf (name, sizeof (name), "equiv.%d", serial++); |
350 | decl = build_decl (VAR_DECL, get_identifier (name), union_type); | |
6de9cd9a | 351 | DECL_ARTIFICIAL (decl) = 1; |
bae88af6 | 352 | DECL_IGNORED_P (decl) = 1; |
6de9cd9a | 353 | |
57f0d086 JJ |
354 | if (!gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl)) |
355 | || is_saved) | |
bae88af6 | 356 | TREE_STATIC (decl) = 1; |
6de9cd9a DN |
357 | |
358 | TREE_ADDRESSABLE (decl) = 1; | |
359 | TREE_USED (decl) = 1; | |
6c7a4dfd | 360 | GFC_DECL_COMMON_OR_EQUIV (decl) = 1; |
c8cc8542 PB |
361 | |
362 | /* The source location has been lost, and doesn't really matter. | |
363 | We need to set it to something though. */ | |
364 | gfc_set_decl_location (decl, &gfc_current_locus); | |
365 | ||
6de9cd9a DN |
366 | gfc_add_decl_to_function (decl); |
367 | ||
368 | return decl; | |
369 | } | |
370 | ||
371 | ||
372 | /* Get storage for common block. */ | |
373 | ||
374 | static tree | |
53814b8f | 375 | build_common_decl (gfc_common_head *com, tree union_type, bool is_init) |
6de9cd9a DN |
376 | { |
377 | gfc_symbol *common_sym; | |
378 | tree decl; | |
379 | ||
380 | /* Create a namespace to store symbols for common blocks. */ | |
381 | if (gfc_common_ns == NULL) | |
0366dfe9 | 382 | gfc_common_ns = gfc_get_namespace (NULL, 0); |
6de9cd9a | 383 | |
53814b8f | 384 | gfc_get_symbol (com->name, gfc_common_ns, &common_sym); |
6de9cd9a DN |
385 | decl = common_sym->backend_decl; |
386 | ||
387 | /* Update the size of this common block as needed. */ | |
388 | if (decl != NULL_TREE) | |
389 | { | |
5291e69a | 390 | tree size = TYPE_SIZE_UNIT (union_type); |
6de9cd9a DN |
391 | if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) |
392 | { | |
d8158369 PT |
393 | /* Named common blocks of the same name shall be of the same size |
394 | in all scoping units of a program in which they appear, but | |
395 | blank common blocks may be of different sizes. */ | |
396 | if (strcmp (com->name, BLANK_COMMON_NAME)) | |
a8a6b603 | 397 | gfc_warning ("Named COMMON block '%s' at %L shall be of the " |
53814b8f | 398 | "same size", com->name, &com->where); |
d8158369 PT |
399 | DECL_SIZE_UNIT (decl) = size; |
400 | TREE_TYPE (decl) = union_type; | |
401 | } | |
6de9cd9a DN |
402 | } |
403 | ||
404 | /* If this common block has been declared in a previous program unit, | |
405 | and either it is already initialized or there is no new initialization | |
406 | for it, just return. */ | |
407 | if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) | |
408 | return decl; | |
409 | ||
410 | /* If there is no backend_decl for the common block, build it. */ | |
411 | if (decl == NULL_TREE) | |
412 | { | |
53814b8f | 413 | decl = build_decl (VAR_DECL, get_identifier (com->name), union_type); |
a8b3b0b6 | 414 | SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com)); |
6de9cd9a DN |
415 | TREE_PUBLIC (decl) = 1; |
416 | TREE_STATIC (decl) = 1; | |
417 | DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; | |
418 | DECL_USER_ALIGN (decl) = 0; | |
6c7a4dfd | 419 | GFC_DECL_COMMON_OR_EQUIV (decl) = 1; |
5291e69a | 420 | |
c8cc8542 PB |
421 | gfc_set_decl_location (decl, &com->where); |
422 | ||
8893239d | 423 | if (com->threadprivate) |
6c7a4dfd JJ |
424 | DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); |
425 | ||
5291e69a PB |
426 | /* Place the back end declaration for this common block in |
427 | GLOBAL_BINDING_LEVEL. */ | |
428 | common_sym->backend_decl = pushdecl_top_level (decl); | |
6de9cd9a DN |
429 | } |
430 | ||
431 | /* Has no initial values. */ | |
432 | if (!is_init) | |
433 | { | |
434 | DECL_INITIAL (decl) = NULL_TREE; | |
435 | DECL_COMMON (decl) = 1; | |
436 | DECL_DEFER_OUTPUT (decl) = 1; | |
6de9cd9a DN |
437 | } |
438 | else | |
439 | { | |
440 | DECL_INITIAL (decl) = error_mark_node; | |
441 | DECL_COMMON (decl) = 0; | |
442 | DECL_DEFER_OUTPUT (decl) = 0; | |
6de9cd9a DN |
443 | } |
444 | return decl; | |
445 | } | |
446 | ||
447 | ||
9d99ee7b PT |
448 | /* Return a field that is the size of the union, if an equivalence has |
449 | overlapping initializers. Merge the initializers into a single | |
450 | initializer for this new field, then free the old ones. */ | |
451 | ||
452 | static tree | |
453 | get_init_field (segment_info *head, tree union_type, tree *field_init, | |
454 | record_layout_info rli) | |
455 | { | |
456 | segment_info *s; | |
457 | HOST_WIDE_INT length = 0; | |
458 | HOST_WIDE_INT offset = 0; | |
459 | unsigned HOST_WIDE_INT known_align, desired_align; | |
460 | bool overlap = false; | |
461 | tree tmp, field; | |
462 | tree init; | |
463 | unsigned char *data, *chk; | |
464 | VEC(constructor_elt,gc) *v = NULL; | |
465 | ||
466 | tree type = unsigned_char_type_node; | |
467 | int i; | |
468 | ||
469 | /* Obtain the size of the union and check if there are any overlapping | |
470 | initializers. */ | |
471 | for (s = head; s; s = s->next) | |
472 | { | |
473 | HOST_WIDE_INT slen = s->offset + s->length; | |
474 | if (s->sym->value) | |
475 | { | |
476 | if (s->offset < offset) | |
477 | overlap = true; | |
478 | offset = slen; | |
479 | } | |
480 | length = length < slen ? slen : length; | |
481 | } | |
482 | ||
483 | if (!overlap) | |
484 | return NULL_TREE; | |
485 | ||
486 | /* Now absorb all the initializer data into a single vector, | |
487 | whilst checking for overlapping, unequal values. */ | |
488 | data = (unsigned char*)gfc_getmem ((size_t)length); | |
489 | chk = (unsigned char*)gfc_getmem ((size_t)length); | |
490 | ||
491 | /* TODO - change this when default initialization is implemented. */ | |
492 | memset (data, '\0', (size_t)length); | |
493 | memset (chk, '\0', (size_t)length); | |
494 | for (s = head; s; s = s->next) | |
495 | if (s->sym->value) | |
496 | gfc_merge_initializers (s->sym->ts, s->sym->value, | |
497 | &data[s->offset], | |
498 | &chk[s->offset], | |
499 | (size_t)s->length); | |
500 | ||
501 | for (i = 0; i < length; i++) | |
502 | CONSTRUCTOR_APPEND_ELT (v, NULL, build_int_cst (type, data[i])); | |
503 | ||
504 | gfc_free (data); | |
505 | gfc_free (chk); | |
506 | ||
507 | /* Build a char[length] array to hold the initializers. Much of what | |
508 | follows is borrowed from build_field, above. */ | |
509 | ||
510 | tmp = build_int_cst (gfc_array_index_type, length - 1); | |
511 | tmp = build_range_type (gfc_array_index_type, | |
512 | gfc_index_zero_node, tmp); | |
513 | tmp = build_array_type (type, tmp); | |
514 | field = build_decl (FIELD_DECL, NULL_TREE, tmp); | |
515 | gfc_set_decl_location (field, &gfc_current_locus); | |
516 | ||
517 | known_align = BIGGEST_ALIGNMENT; | |
518 | ||
519 | desired_align = update_alignment_for_field (rli, field, known_align); | |
520 | if (desired_align > known_align) | |
521 | DECL_PACKED (field) = 1; | |
522 | ||
523 | DECL_FIELD_CONTEXT (field) = union_type; | |
524 | DECL_FIELD_OFFSET (field) = size_int (0); | |
525 | DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; | |
526 | SET_DECL_OFFSET_ALIGN (field, known_align); | |
527 | ||
528 | rli->offset = size_binop (MAX_EXPR, rli->offset, | |
529 | size_binop (PLUS_EXPR, | |
530 | DECL_FIELD_OFFSET (field), | |
531 | DECL_SIZE_UNIT (field))); | |
532 | ||
533 | init = build_constructor (TREE_TYPE (field), v); | |
534 | TREE_CONSTANT (init) = 1; | |
535 | TREE_INVARIANT (init) = 1; | |
536 | ||
537 | *field_init = init; | |
538 | ||
539 | for (s = head; s; s = s->next) | |
540 | { | |
541 | if (s->sym->value == NULL) | |
542 | continue; | |
543 | ||
544 | gfc_free_expr (s->sym->value); | |
545 | s->sym->value = NULL; | |
546 | } | |
547 | ||
548 | return field; | |
549 | } | |
550 | ||
551 | ||
6de9cd9a DN |
552 | /* Declare memory for the common block or local equivalence, and create |
553 | backend declarations for all of the elements. */ | |
554 | ||
555 | static void | |
66e4ab31 | 556 | create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) |
a8a6b603 TS |
557 | { |
558 | segment_info *s, *next_s; | |
6de9cd9a DN |
559 | tree union_type; |
560 | tree *field_link; | |
9d99ee7b | 561 | tree field; |
f84c7ed9 | 562 | tree field_init = NULL_TREE; |
6de9cd9a DN |
563 | record_layout_info rli; |
564 | tree decl; | |
565 | bool is_init = false; | |
57f0d086 | 566 | bool is_saved = false; |
6de9cd9a | 567 | |
a3122424 CY |
568 | /* Declare the variables inside the common block. |
569 | If the current common block contains any equivalence object, then | |
570 | make a UNION_TYPE node, otherwise RECORD_TYPE. This will let the | |
571 | alias analyzer work well when there is no address overlapping for | |
572 | common variables in the current common block. */ | |
573 | if (saw_equiv) | |
574 | union_type = make_node (UNION_TYPE); | |
575 | else | |
576 | union_type = make_node (RECORD_TYPE); | |
577 | ||
6de9cd9a DN |
578 | rli = start_record_layout (union_type); |
579 | field_link = &TYPE_FIELDS (union_type); | |
580 | ||
9d99ee7b PT |
581 | /* Check for overlapping initializers and replace them with a single, |
582 | artificial field that contains all the data. */ | |
583 | if (saw_equiv) | |
584 | field = get_init_field (head, union_type, &field_init, rli); | |
585 | else | |
586 | field = NULL_TREE; | |
587 | ||
588 | if (field != NULL_TREE) | |
589 | { | |
590 | is_init = true; | |
591 | *field_link = field; | |
592 | field_link = &TREE_CHAIN (field); | |
593 | } | |
594 | ||
832ef1ce | 595 | for (s = head; s; s = s->next) |
6de9cd9a | 596 | { |
a8a6b603 | 597 | build_field (s, union_type, rli); |
6de9cd9a DN |
598 | |
599 | /* Link the field into the type. */ | |
a8a6b603 TS |
600 | *field_link = s->field; |
601 | field_link = &TREE_CHAIN (s->field); | |
ad6e2a18 | 602 | |
a8a6b603 TS |
603 | /* Has initial value. */ |
604 | if (s->sym->value) | |
6de9cd9a | 605 | is_init = true; |
57f0d086 JJ |
606 | |
607 | /* Has SAVE attribute. */ | |
608 | if (s->sym->attr.save) | |
609 | is_saved = true; | |
6de9cd9a | 610 | } |
9d99ee7b | 611 | |
6de9cd9a DN |
612 | finish_record_layout (rli, true); |
613 | ||
9056bd70 | 614 | if (com) |
53814b8f | 615 | decl = build_common_decl (com, union_type, is_init); |
6de9cd9a | 616 | else |
57f0d086 | 617 | decl = build_equiv_decl (union_type, is_init, is_saved); |
6de9cd9a | 618 | |
5291e69a PB |
619 | if (is_init) |
620 | { | |
4038c495 | 621 | tree ctor, tmp; |
5291e69a | 622 | HOST_WIDE_INT offset = 0; |
4038c495 | 623 | VEC(constructor_elt,gc) *v = NULL; |
5291e69a | 624 | |
9d99ee7b PT |
625 | if (field != NULL_TREE && field_init != NULL_TREE) |
626 | CONSTRUCTOR_APPEND_ELT (v, field, field_init); | |
627 | else | |
628 | for (s = head; s; s = s->next) | |
629 | { | |
630 | if (s->sym->value) | |
631 | { | |
632 | /* Add the initializer for this field. */ | |
633 | tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts, | |
634 | TREE_TYPE (s->field), s->sym->attr.dimension, | |
635 | s->sym->attr.pointer || s->sym->attr.allocatable); | |
636 | ||
637 | CONSTRUCTOR_APPEND_ELT (v, s->field, tmp); | |
638 | offset = s->offset + s->length; | |
639 | } | |
640 | } | |
641 | ||
4038c495 GB |
642 | gcc_assert (!VEC_empty (constructor_elt, v)); |
643 | ctor = build_constructor (union_type, v); | |
5291e69a PB |
644 | TREE_CONSTANT (ctor) = 1; |
645 | TREE_INVARIANT (ctor) = 1; | |
646 | TREE_STATIC (ctor) = 1; | |
647 | DECL_INITIAL (decl) = ctor; | |
648 | ||
649 | #ifdef ENABLE_CHECKING | |
4038c495 GB |
650 | { |
651 | tree field, value; | |
652 | unsigned HOST_WIDE_INT idx; | |
653 | FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, field, value) | |
654 | gcc_assert (TREE_CODE (field) == FIELD_DECL); | |
655 | } | |
5291e69a PB |
656 | #endif |
657 | } | |
658 | ||
6de9cd9a | 659 | /* Build component reference for each variable. */ |
832ef1ce | 660 | for (s = head; s; s = next_s) |
6de9cd9a | 661 | { |
81871c2a JJ |
662 | tree var_decl; |
663 | ||
664 | var_decl = build_decl (VAR_DECL, DECL_NAME (s->field), | |
665 | TREE_TYPE (s->field)); | |
666 | gfc_set_decl_location (var_decl, &s->sym->declared_at); | |
667 | TREE_PUBLIC (var_decl) = TREE_PUBLIC (decl); | |
668 | TREE_STATIC (var_decl) = TREE_STATIC (decl); | |
669 | TREE_USED (var_decl) = TREE_USED (decl); | |
670 | if (s->sym->attr.target) | |
671 | TREE_ADDRESSABLE (var_decl) = 1; | |
672 | /* This is a fake variable just for debugging purposes. */ | |
673 | TREE_ASM_WRITTEN (var_decl) = 1; | |
674 | ||
675 | if (com) | |
676 | var_decl = pushdecl_top_level (var_decl); | |
677 | else | |
678 | gfc_add_decl_to_function (var_decl); | |
679 | ||
680 | SET_DECL_VALUE_EXPR (var_decl, | |
681 | build3 (COMPONENT_REF, TREE_TYPE (s->field), | |
682 | decl, s->field, NULL_TREE)); | |
683 | DECL_HAS_VALUE_EXPR_P (var_decl) = 1; | |
6c7a4dfd | 684 | GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1; |
81871c2a JJ |
685 | |
686 | if (s->sym->attr.assign) | |
687 | { | |
688 | gfc_allocate_lang_decl (var_decl); | |
689 | GFC_DECL_ASSIGN (var_decl) = 1; | |
690 | GFC_DECL_STRING_LEN (var_decl) = GFC_DECL_STRING_LEN (s->field); | |
691 | GFC_DECL_ASSIGN_ADDR (var_decl) = GFC_DECL_ASSIGN_ADDR (s->field); | |
692 | } | |
693 | ||
694 | s->sym->backend_decl = var_decl; | |
6de9cd9a | 695 | |
a8a6b603 TS |
696 | next_s = s->next; |
697 | gfc_free (s); | |
6de9cd9a | 698 | } |
a8a6b603 | 699 | } |
6de9cd9a DN |
700 | |
701 | ||
702 | /* Given a symbol, find it in the current segment list. Returns NULL if | |
a8a6b603 | 703 | not found. */ |
6de9cd9a | 704 | |
a8a6b603 | 705 | static segment_info * |
6de9cd9a | 706 | find_segment_info (gfc_symbol *symbol) |
a8a6b603 | 707 | { |
6de9cd9a DN |
708 | segment_info *n; |
709 | ||
710 | for (n = current_segment; n; n = n->next) | |
5291e69a PB |
711 | { |
712 | if (n->sym == symbol) | |
713 | return n; | |
714 | } | |
6de9cd9a | 715 | |
a8a6b603 TS |
716 | return NULL; |
717 | } | |
6de9cd9a DN |
718 | |
719 | ||
6de9cd9a | 720 | /* Given an expression node, make sure it is a constant integer and return |
a8a6b603 | 721 | the mpz_t value. */ |
6de9cd9a | 722 | |
a8a6b603 TS |
723 | static mpz_t * |
724 | get_mpz (gfc_expr *e) | |
6de9cd9a | 725 | { |
a8a6b603 TS |
726 | |
727 | if (e->expr_type != EXPR_CONSTANT) | |
6de9cd9a DN |
728 | gfc_internal_error ("get_mpz(): Not an integer constant"); |
729 | ||
a8a6b603 TS |
730 | return &e->value.integer; |
731 | } | |
6de9cd9a DN |
732 | |
733 | ||
734 | /* Given an array specification and an array reference, figure out the | |
735 | array element number (zero based). Bounds and elements are guaranteed | |
736 | to be constants. If something goes wrong we generate an error and | |
a8a6b603 | 737 | return zero. */ |
6de9cd9a | 738 | |
5291e69a | 739 | static HOST_WIDE_INT |
6de9cd9a | 740 | element_number (gfc_array_ref *ar) |
a8a6b603 TS |
741 | { |
742 | mpz_t multiplier, offset, extent, n; | |
6de9cd9a | 743 | gfc_array_spec *as; |
a8a6b603 | 744 | HOST_WIDE_INT i, rank; |
6de9cd9a DN |
745 | |
746 | as = ar->as; | |
747 | rank = as->rank; | |
748 | mpz_init_set_ui (multiplier, 1); | |
749 | mpz_init_set_ui (offset, 0); | |
750 | mpz_init (extent); | |
a8a6b603 | 751 | mpz_init (n); |
6de9cd9a | 752 | |
a8a6b603 | 753 | for (i = 0; i < rank; i++) |
6de9cd9a | 754 | { |
a8a6b603 | 755 | if (ar->dimen_type[i] != DIMEN_ELEMENT) |
6de9cd9a DN |
756 | gfc_internal_error ("element_number(): Bad dimension type"); |
757 | ||
a8a6b603 | 758 | mpz_sub (n, *get_mpz (ar->start[i]), *get_mpz (as->lower[i])); |
6de9cd9a | 759 | |
a8a6b603 TS |
760 | mpz_mul (n, n, multiplier); |
761 | mpz_add (offset, offset, n); | |
6de9cd9a | 762 | |
a8a6b603 | 763 | mpz_sub (extent, *get_mpz (as->upper[i]), *get_mpz (as->lower[i])); |
6de9cd9a DN |
764 | mpz_add_ui (extent, extent, 1); |
765 | ||
766 | if (mpz_sgn (extent) < 0) | |
767 | mpz_set_ui (extent, 0); | |
768 | ||
769 | mpz_mul (multiplier, multiplier, extent); | |
770 | } | |
771 | ||
a8a6b603 | 772 | i = mpz_get_ui (offset); |
6de9cd9a DN |
773 | |
774 | mpz_clear (multiplier); | |
775 | mpz_clear (offset); | |
776 | mpz_clear (extent); | |
a8a6b603 | 777 | mpz_clear (n); |
6de9cd9a | 778 | |
a8a6b603 | 779 | return i; |
6de9cd9a DN |
780 | } |
781 | ||
782 | ||
783 | /* Given a single element of an equivalence list, figure out the offset | |
784 | from the base symbol. For simple variables or full arrays, this is | |
785 | simply zero. For an array element we have to calculate the array | |
786 | element number and multiply by the element size. For a substring we | |
787 | have to calculate the further reference. */ | |
788 | ||
5291e69a | 789 | static HOST_WIDE_INT |
a8a6b603 | 790 | calculate_offset (gfc_expr *e) |
6de9cd9a | 791 | { |
a8a6b603 | 792 | HOST_WIDE_INT n, element_size, offset; |
6de9cd9a DN |
793 | gfc_typespec *element_type; |
794 | gfc_ref *reference; | |
795 | ||
796 | offset = 0; | |
a8a6b603 | 797 | element_type = &e->symtree->n.sym->ts; |
6de9cd9a | 798 | |
a8a6b603 | 799 | for (reference = e->ref; reference; reference = reference->next) |
6de9cd9a DN |
800 | switch (reference->type) |
801 | { | |
802 | case REF_ARRAY: | |
803 | switch (reference->u.ar.type) | |
804 | { | |
805 | case AR_FULL: | |
806 | break; | |
807 | ||
808 | case AR_ELEMENT: | |
a8a6b603 | 809 | n = element_number (&reference->u.ar); |
6de9cd9a DN |
810 | if (element_type->type == BT_CHARACTER) |
811 | gfc_conv_const_charlen (element_type->cl); | |
812 | element_size = | |
813 | int_size_in_bytes (gfc_typenode_for_spec (element_type)); | |
a8a6b603 | 814 | offset += n * element_size; |
6de9cd9a DN |
815 | break; |
816 | ||
817 | default: | |
a8a6b603 | 818 | gfc_error ("Bad array reference at %L", &e->where); |
6de9cd9a DN |
819 | } |
820 | break; | |
821 | case REF_SUBSTRING: | |
822 | if (reference->u.ss.start != NULL) | |
823 | offset += mpz_get_ui (*get_mpz (reference->u.ss.start)) - 1; | |
824 | break; | |
825 | default: | |
5291e69a | 826 | gfc_error ("Illegal reference type at %L as EQUIVALENCE object", |
a8a6b603 TS |
827 | &e->where); |
828 | } | |
6de9cd9a DN |
829 | return offset; |
830 | } | |
831 | ||
a8a6b603 | 832 | |
5291e69a PB |
833 | /* Add a new segment_info structure to the current segment. eq1 is already |
834 | in the list, eq2 is not. */ | |
6de9cd9a DN |
835 | |
836 | static void | |
837 | new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2) | |
838 | { | |
5291e69a | 839 | HOST_WIDE_INT offset1, offset2; |
6de9cd9a | 840 | segment_info *a; |
a8a6b603 | 841 | |
6de9cd9a DN |
842 | offset1 = calculate_offset (eq1->expr); |
843 | offset2 = calculate_offset (eq2->expr); | |
844 | ||
ad6e2a18 TS |
845 | a = get_segment_info (eq2->expr->symtree->n.sym, |
846 | v->offset + offset1 - offset2); | |
6de9cd9a | 847 | |
5291e69a | 848 | current_segment = add_segments (current_segment, a); |
6de9cd9a DN |
849 | } |
850 | ||
851 | ||
852 | /* Given two equivalence structures that are both already in the list, make | |
853 | sure that this new condition is not violated, generating an error if it | |
854 | is. */ | |
855 | ||
856 | static void | |
a8a6b603 | 857 | confirm_condition (segment_info *s1, gfc_equiv *eq1, segment_info *s2, |
6de9cd9a DN |
858 | gfc_equiv *eq2) |
859 | { | |
5291e69a | 860 | HOST_WIDE_INT offset1, offset2; |
6de9cd9a DN |
861 | |
862 | offset1 = calculate_offset (eq1->expr); | |
863 | offset2 = calculate_offset (eq2->expr); | |
a8a6b603 TS |
864 | |
865 | if (s1->offset + offset1 != s2->offset + offset2) | |
5291e69a | 866 | gfc_error ("Inconsistent equivalence rules involving '%s' at %L and " |
a8a6b603 TS |
867 | "'%s' at %L", s1->sym->name, &s1->sym->declared_at, |
868 | s2->sym->name, &s2->sym->declared_at); | |
869 | } | |
870 | ||
6de9cd9a | 871 | |
5291e69a PB |
872 | /* Process a new equivalence condition. eq1 is know to be in segment f. |
873 | If eq2 is also present then confirm that the condition holds. | |
874 | Otherwise add a new variable to the segment list. */ | |
6de9cd9a DN |
875 | |
876 | static void | |
5291e69a | 877 | add_condition (segment_info *f, gfc_equiv *eq1, gfc_equiv *eq2) |
6de9cd9a | 878 | { |
5291e69a | 879 | segment_info *n; |
6de9cd9a | 880 | |
5291e69a | 881 | n = find_segment_info (eq2->expr->symtree->n.sym); |
6de9cd9a | 882 | |
5291e69a PB |
883 | if (n == NULL) |
884 | new_condition (f, eq1, eq2); | |
885 | else | |
886 | confirm_condition (f, eq1, n, eq2); | |
6de9cd9a DN |
887 | } |
888 | ||
889 | ||
5291e69a | 890 | /* Given a segment element, search through the equivalence lists for unused |
30aabb86 PT |
891 | conditions that involve the symbol. Add these rules to the segment. */ |
892 | ||
5291e69a | 893 | static bool |
a8a6b603 | 894 | find_equivalence (segment_info *n) |
6de9cd9a | 895 | { |
30aabb86 | 896 | gfc_equiv *e1, *e2, *eq; |
5291e69a | 897 | bool found; |
30aabb86 | 898 | |
5291e69a | 899 | found = FALSE; |
30aabb86 | 900 | |
a8a6b603 | 901 | for (e1 = n->sym->ns->equiv; e1; e1 = e1->next) |
5291e69a | 902 | { |
30aabb86 | 903 | eq = NULL; |
5291e69a | 904 | |
30aabb86 PT |
905 | /* Search the equivalence list, including the root (first) element |
906 | for the symbol that owns the segment. */ | |
907 | for (e2 = e1; e2; e2 = e2->eq) | |
908 | { | |
909 | if (!e2->used && e2->expr->symtree->n.sym == n->sym) | |
5291e69a | 910 | { |
a8a6b603 | 911 | eq = e2; |
30aabb86 | 912 | break; |
5291e69a | 913 | } |
30aabb86 PT |
914 | } |
915 | ||
916 | /* Go to the next root element. */ | |
917 | if (eq == NULL) | |
918 | continue; | |
919 | ||
920 | eq->used = 1; | |
921 | ||
922 | /* Now traverse the equivalence list matching the offsets. */ | |
923 | for (e2 = e1; e2; e2 = e2->eq) | |
924 | { | |
925 | if (!e2->used && e2 != eq) | |
5291e69a | 926 | { |
30aabb86 PT |
927 | add_condition (n, eq, e2); |
928 | e2->used = 1; | |
5291e69a | 929 | found = TRUE; |
5291e69a PB |
930 | } |
931 | } | |
932 | } | |
933 | return found; | |
6de9cd9a DN |
934 | } |
935 | ||
a8a6b603 | 936 | |
66e4ab31 | 937 | /* Add all symbols equivalenced within a segment. We need to scan the |
8a0b57b3 PT |
938 | segment list multiple times to include indirect equivalences. Since |
939 | a new segment_info can inserted at the beginning of the segment list, | |
940 | depending on its offset, we have to force a final pass through the | |
941 | loop by demanding that completion sees a pass with no matches; ie. | |
942 | all symbols with equiv_built set and no new equivalences found. */ | |
6de9cd9a | 943 | |
5291e69a | 944 | static void |
a3122424 | 945 | add_equivalences (bool *saw_equiv) |
6de9cd9a | 946 | { |
6de9cd9a | 947 | segment_info *f; |
8a0b57b3 | 948 | bool seen_one, more; |
6de9cd9a | 949 | |
8a0b57b3 | 950 | seen_one = false; |
5291e69a PB |
951 | more = TRUE; |
952 | while (more) | |
6de9cd9a | 953 | { |
5291e69a PB |
954 | more = FALSE; |
955 | for (f = current_segment; f; f = f->next) | |
956 | { | |
957 | if (!f->sym->equiv_built) | |
958 | { | |
959 | f->sym->equiv_built = 1; | |
8a0b57b3 PT |
960 | seen_one = find_equivalence (f); |
961 | if (seen_one) | |
962 | { | |
963 | *saw_equiv = true; | |
964 | more = true; | |
965 | } | |
5291e69a PB |
966 | } |
967 | } | |
6de9cd9a | 968 | } |
61321991 PT |
969 | |
970 | /* Add a copy of this segment list to the namespace. */ | |
971 | copy_equiv_list_to_ns (current_segment); | |
6de9cd9a | 972 | } |
a8a6b603 TS |
973 | |
974 | ||
43a5ef69 | 975 | /* Returns the offset necessary to properly align the current equivalence. |
832ef1ce PB |
976 | Sets *palign to the required alignment. */ |
977 | ||
978 | static HOST_WIDE_INT | |
66e4ab31 | 979 | align_segment (unsigned HOST_WIDE_INT *palign) |
832ef1ce PB |
980 | { |
981 | segment_info *s; | |
982 | unsigned HOST_WIDE_INT offset; | |
983 | unsigned HOST_WIDE_INT max_align; | |
984 | unsigned HOST_WIDE_INT this_align; | |
985 | unsigned HOST_WIDE_INT this_offset; | |
986 | ||
987 | max_align = 1; | |
988 | offset = 0; | |
989 | for (s = current_segment; s; s = s->next) | |
990 | { | |
991 | this_align = TYPE_ALIGN_UNIT (s->field); | |
992 | if (s->offset & (this_align - 1)) | |
993 | { | |
994 | /* Field is misaligned. */ | |
995 | this_offset = this_align - ((s->offset + offset) & (this_align - 1)); | |
996 | if (this_offset & (max_align - 1)) | |
997 | { | |
998 | /* Aligning this field would misalign a previous field. */ | |
999 | gfc_error ("The equivalence set for variable '%s' " | |
eb6d74fa | 1000 | "declared at %L violates alignment requirements", |
832ef1ce PB |
1001 | s->sym->name, &s->sym->declared_at); |
1002 | } | |
1003 | offset += this_offset; | |
1004 | } | |
1005 | max_align = this_align; | |
1006 | } | |
1007 | if (palign) | |
1008 | *palign = max_align; | |
1009 | return offset; | |
1010 | } | |
1011 | ||
1012 | ||
1013 | /* Adjust segment offsets by the given amount. */ | |
a8a6b603 | 1014 | |
6de9cd9a | 1015 | static void |
66e4ab31 | 1016 | apply_segment_offset (segment_info *s, HOST_WIDE_INT offset) |
6de9cd9a | 1017 | { |
832ef1ce PB |
1018 | for (; s; s = s->next) |
1019 | s->offset += offset; | |
1020 | } | |
1021 | ||
1022 | ||
1023 | /* Lay out a symbol in a common block. If the symbol has already been seen | |
1024 | then check the location is consistent. Otherwise create segments | |
1025 | for that symbol and all the symbols equivalenced with it. */ | |
1026 | ||
1027 | /* Translate a single common block. */ | |
1028 | ||
1029 | static void | |
1030 | translate_common (gfc_common_head *common, gfc_symbol *var_list) | |
1031 | { | |
1032 | gfc_symbol *sym; | |
1033 | segment_info *s; | |
1034 | segment_info *common_segment; | |
1035 | HOST_WIDE_INT offset; | |
1036 | HOST_WIDE_INT current_offset; | |
1037 | unsigned HOST_WIDE_INT align; | |
1038 | unsigned HOST_WIDE_INT max_align; | |
a3122424 | 1039 | bool saw_equiv; |
832ef1ce PB |
1040 | |
1041 | common_segment = NULL; | |
1042 | current_offset = 0; | |
1043 | max_align = 1; | |
a3122424 | 1044 | saw_equiv = false; |
832ef1ce PB |
1045 | |
1046 | /* Add symbols to the segment. */ | |
1047 | for (sym = var_list; sym; sym = sym->common_next) | |
1048 | { | |
30aabb86 PT |
1049 | current_segment = common_segment; |
1050 | s = find_segment_info (sym); | |
832ef1ce | 1051 | |
30aabb86 PT |
1052 | /* Symbol has already been added via an equivalence. Multiple |
1053 | use associations of the same common block result in equiv_built | |
1054 | being set but no information about the symbol in the segment. */ | |
1055 | if (s && sym->equiv_built) | |
1056 | { | |
832ef1ce PB |
1057 | /* Ensure the current location is properly aligned. */ |
1058 | align = TYPE_ALIGN_UNIT (s->field); | |
1059 | current_offset = (current_offset + align - 1) &~ (align - 1); | |
1060 | ||
1061 | /* Verify that it ended up where we expect it. */ | |
1062 | if (s->offset != current_offset) | |
1063 | { | |
1064 | gfc_error ("Equivalence for '%s' does not match ordering of " | |
1065 | "COMMON '%s' at %L", sym->name, | |
1066 | common->name, &common->where); | |
1067 | } | |
1068 | } | |
1069 | else | |
1070 | { | |
1071 | /* A symbol we haven't seen before. */ | |
1072 | s = current_segment = get_segment_info (sym, current_offset); | |
a8a6b603 | 1073 | |
832ef1ce PB |
1074 | /* Add all objects directly or indirectly equivalenced with this |
1075 | symbol. */ | |
a3122424 | 1076 | add_equivalences (&saw_equiv); |
ad6e2a18 | 1077 | |
832ef1ce PB |
1078 | if (current_segment->offset < 0) |
1079 | gfc_error ("The equivalence set for '%s' cause an invalid " | |
1080 | "extension to COMMON '%s' at %L", sym->name, | |
1081 | common->name, &common->where); | |
6de9cd9a | 1082 | |
832ef1ce | 1083 | offset = align_segment (&align); |
6de9cd9a | 1084 | |
832ef1ce PB |
1085 | if (offset & (max_align - 1)) |
1086 | { | |
1087 | /* The required offset conflicts with previous alignment | |
1088 | requirements. Insert padding immediately before this | |
1089 | segment. */ | |
1090 | gfc_warning ("Padding of %d bytes required before '%s' in " | |
eb83e811 | 1091 | "COMMON '%s' at %L", (int)offset, s->sym->name, |
832ef1ce PB |
1092 | common->name, &common->where); |
1093 | } | |
1094 | else | |
1095 | { | |
1096 | /* Offset the whole common block. */ | |
1097 | apply_segment_offset (common_segment, offset); | |
1098 | } | |
6de9cd9a | 1099 | |
832ef1ce PB |
1100 | /* Apply the offset to the new segments. */ |
1101 | apply_segment_offset (current_segment, offset); | |
1102 | current_offset += offset; | |
1103 | if (max_align < align) | |
1104 | max_align = align; | |
1105 | ||
1106 | /* Add the new segments to the common block. */ | |
1107 | common_segment = add_segments (common_segment, current_segment); | |
1108 | } | |
1109 | ||
1110 | /* The offset of the next common variable. */ | |
1111 | current_offset += s->length; | |
1112 | } | |
1113 | ||
b8ea6dbc PT |
1114 | if (common_segment == NULL) |
1115 | { | |
1116 | gfc_error ("COMMON '%s' at %L does not exist", | |
1117 | common->name, &common->where); | |
1118 | return; | |
1119 | } | |
1120 | ||
832ef1ce PB |
1121 | if (common_segment->offset != 0) |
1122 | { | |
1123 | gfc_warning ("COMMON '%s' at %L requires %d bytes of padding at start", | |
eb83e811 | 1124 | common->name, &common->where, (int)common_segment->offset); |
832ef1ce PB |
1125 | } |
1126 | ||
a3122424 | 1127 | create_common (common, common_segment, saw_equiv); |
6de9cd9a DN |
1128 | } |
1129 | ||
1130 | ||
1131 | /* Create a new block for each merged equivalence list. */ | |
1132 | ||
1133 | static void | |
1134 | finish_equivalences (gfc_namespace *ns) | |
1135 | { | |
1136 | gfc_equiv *z, *y; | |
1137 | gfc_symbol *sym; | |
30aabb86 | 1138 | gfc_common_head * c; |
36c028f6 PB |
1139 | HOST_WIDE_INT offset; |
1140 | unsigned HOST_WIDE_INT align; | |
a3122424 | 1141 | bool dummy; |
6de9cd9a DN |
1142 | |
1143 | for (z = ns->equiv; z; z = z->next) | |
a8a6b603 | 1144 | for (y = z->eq; y; y = y->eq) |
6de9cd9a | 1145 | { |
a8a6b603 TS |
1146 | if (y->used) |
1147 | continue; | |
6de9cd9a | 1148 | sym = z->expr->symtree->n.sym; |
ad6e2a18 | 1149 | current_segment = get_segment_info (sym, 0); |
6de9cd9a | 1150 | |
66e4ab31 SK |
1151 | /* All objects directly or indirectly equivalenced with this |
1152 | symbol. */ | |
a3122424 | 1153 | add_equivalences (&dummy); |
6de9cd9a | 1154 | |
36c028f6 PB |
1155 | /* Align the block. */ |
1156 | offset = align_segment (&align); | |
832ef1ce | 1157 | |
36c028f6 PB |
1158 | /* Ensure all offsets are positive. */ |
1159 | offset -= current_segment->offset & ~(align - 1); | |
6de9cd9a | 1160 | |
36c028f6 | 1161 | apply_segment_offset (current_segment, offset); |
6de9cd9a | 1162 | |
66e4ab31 SK |
1163 | /* Create the decl. If this is a module equivalence, it has a |
1164 | unique name, pointed to by z->module. This is written to a | |
1165 | gfc_common_header to push create_common into using | |
1166 | build_common_decl, so that the equivalence appears as an | |
1167 | external symbol. Otherwise, a local declaration is built using | |
1168 | build_equiv_decl. */ | |
30aabb86 PT |
1169 | if (z->module) |
1170 | { | |
1171 | c = gfc_get_common_head (); | |
1172 | /* We've lost the real location, so use the location of the | |
66e4ab31 | 1173 | enclosing procedure. */ |
30aabb86 PT |
1174 | c->where = ns->proc_name->declared_at; |
1175 | strcpy (c->name, z->module); | |
1176 | } | |
1177 | else | |
1178 | c = NULL; | |
1179 | ||
1180 | create_common (c, current_segment, true); | |
6de9cd9a DN |
1181 | break; |
1182 | } | |
1183 | } | |
1184 | ||
1185 | ||
6de9cd9a DN |
1186 | /* Work function for translating a named common block. */ |
1187 | ||
1188 | static void | |
9056bd70 | 1189 | named_common (gfc_symtree *st) |
6de9cd9a | 1190 | { |
53814b8f | 1191 | translate_common (st->n.common, st->n.common->head); |
6de9cd9a DN |
1192 | } |
1193 | ||
1194 | ||
1195 | /* Translate the common blocks in a namespace. Unlike other variables, | |
1196 | these have to be created before code, because the backend_decl depends | |
1197 | on the rest of the common block. */ | |
a8a6b603 TS |
1198 | |
1199 | void | |
6de9cd9a DN |
1200 | gfc_trans_common (gfc_namespace *ns) |
1201 | { | |
9056bd70 | 1202 | gfc_common_head *c; |
6de9cd9a DN |
1203 | |
1204 | /* Translate the blank common block. */ | |
9056bd70 | 1205 | if (ns->blank_common.head != NULL) |
6de9cd9a | 1206 | { |
9056bd70 | 1207 | c = gfc_get_common_head (); |
41433497 | 1208 | |
c8cc8542 PB |
1209 | /* We've lost the real location, so use the location of the |
1210 | enclosing procedure. */ | |
41433497 BF |
1211 | if (ns->proc_name != NULL) |
1212 | c->where = ns->proc_name->declared_at; | |
1213 | else | |
1214 | c->where = ns->blank_common.head->common_head->where; | |
1215 | ||
53814b8f TS |
1216 | strcpy (c->name, BLANK_COMMON_NAME); |
1217 | translate_common (c, ns->blank_common.head); | |
6de9cd9a | 1218 | } |
41433497 | 1219 | |
6de9cd9a | 1220 | /* Translate all named common blocks. */ |
a8a6b603 | 1221 | gfc_traverse_symtree (ns->common_root, named_common); |
6de9cd9a | 1222 | |
6de9cd9a DN |
1223 | /* Translate local equivalence. */ |
1224 | finish_equivalences (ns); | |
613e2ac8 PT |
1225 | |
1226 | /* Commit the newly created symbols for common blocks and module | |
1227 | equivalences. */ | |
1228 | gfc_commit_symbols (); | |
6de9cd9a | 1229 | } |