* array.c: Don't include assert.h.
[official-gcc.git] / gcc / fortran / trans-common.c
blobf692f3eee22e8cddb34367f0cc03df694e5dc01a
1 /* Common block and equivalence list handling
2 Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Canqun Yang <canqun@nudt.edu.cn>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
22 /* The core algorithm is based on Andy Vaught's g95 tree. Also the
23 way to build UNION_TYPE is borrowed from Richard Henderson.
25 Transform common blocks. An integral part of this is processing
26 equvalence variables. Equivalenced variables that are not in a
27 common block end up in a private block of their own.
29 Each common block or local equivalence list is declared as a union.
30 Variables within the block are represented as a field within the
31 block with the proper offset.
33 So if two variables are equivalenced, they just point to a common
34 area in memory.
36 Mathematically, laying out an equivalence block is equivalent to
37 solving a linear system of equations. The matrix is usually a
38 sparse matrix in which each row contains all zero elements except
39 for a +1 and a -1, a sort of a generalized Vandermonde matrix. The
40 matrix is usually block diagonal. The system can be
41 overdetermined, underdetermined or have a unique solution. If the
42 system is inconsistent, the program is not standard conforming.
43 The solution vector is integral, since all of the pivots are +1 or -1.
45 How we lay out an equivalence block is a little less complicated.
46 In an equivalence list with n elements, there are n-1 conditions to
47 be satisfied. The conditions partition the variables into what we
48 will call segments. If A and B are equivalenced then A and B are
49 in the same segment. If B and C are equivalenced as well, then A,
50 B and C are in a segment and so on. Each segment is a block of
51 memory that has one or more variables equivalenced in some way. A
52 common block is made up of a series of segments that are joined one
53 after the other. In the linear system, a segment is a block
54 diagonal.
56 To lay out a segment we first start with some variable and
57 determine its length. The first variable is assumed to start at
58 offset one and extends to however long it is. We then traverse the
59 list of equivalences to find an unused condition that involves at
60 least one of the variables currently in the segment.
62 Each equivalence condition amounts to the condition B+b=C+c where B
63 and C are the offsets of the B and C variables, and b and c are
64 constants which are nonzero for array elements, substrings or
65 structure components. So for
67 EQUIVALENCE(B(2), C(3))
68 we have
69 B + 2*size of B's elements = C + 3*size of C's elements.
71 If B and C are known we check to see if the condition already
72 holds. If B is known we can solve for C. Since we know the length
73 of C, we can see if the minimum and maximum extents of the segment
74 are affected. Eventually, we make a full pass through the
75 equivalence list without finding any new conditions and the segment
76 is fully specified.
78 At this point, the segment is added to the current common block.
79 Since we know the minimum extent of the segment, everything in the
80 segment is translated to its position in the common block. The
81 usual case here is that there are no equivalence statements and the
82 common block is series of segments with one variable each, which is
83 a diagonal matrix in the matrix formulation.
85 Each segment is described by a chain of segment_info structures. Each
86 segment_info structure describes the extents of a single varible within
87 the segment. This list is maintained in the order the elements are
88 positioned withing the segment. If two elements have the same starting
89 offset the smaller will come first. If they also have the same size their
90 ordering is undefined.
92 Once all common blocks have been created, the list of equivalences
93 is examined for still-unused equivalence conditions. We create a
94 block for each merged equivalence list. */
96 #include "config.h"
97 #include "system.h"
98 #include "coretypes.h"
99 #include "tree.h"
100 #include "toplev.h"
101 #include "tm.h"
102 #include "gfortran.h"
103 #include "trans.h"
104 #include "trans-types.h"
105 #include "trans-const.h"
108 /* Holds a single variable in a equivalence set. */
109 typedef struct segment_info
111 gfc_symbol *sym;
112 HOST_WIDE_INT offset;
113 HOST_WIDE_INT length;
114 /* This will contain the field type until the field is created. */
115 tree field;
116 struct segment_info *next;
117 } segment_info;
119 static segment_info *current_segment, *current_common;
120 static HOST_WIDE_INT current_offset;
121 static gfc_namespace *gfc_common_ns = NULL;
123 #define BLANK_COMMON_NAME "__BLNK__"
125 /* Make a segment_info based on a symbol. */
127 static segment_info *
128 get_segment_info (gfc_symbol * sym, HOST_WIDE_INT offset)
130 segment_info *s;
132 /* Make sure we've got the character length. */
133 if (sym->ts.type == BT_CHARACTER)
134 gfc_conv_const_charlen (sym->ts.cl);
136 /* Create the segment_info and fill it in. */
137 s = (segment_info *) gfc_getmem (sizeof (segment_info));
138 s->sym = sym;
139 /* We will use this type when building the segment aggreagate type. */
140 s->field = gfc_sym_type (sym);
141 s->length = int_size_in_bytes (s->field);
142 s->offset = offset;
144 return s;
147 /* Add combine segment V and segment LIST. */
149 static segment_info *
150 add_segments (segment_info *list, segment_info *v)
152 segment_info *s;
153 segment_info *p;
154 segment_info *next;
156 p = NULL;
157 s = list;
159 while (v)
161 /* Find the location of the new element. */
162 while (s)
164 if (v->offset < s->offset)
165 break;
166 if (v->offset == s->offset
167 && v->length <= s->length)
168 break;
170 p = s;
171 s = s->next;
174 /* Insert the new element in between p and s. */
175 next = v->next;
176 v->next = s;
177 if (p == NULL)
178 list = v;
179 else
180 p->next = v;
182 p = v;
183 v = next;
186 return list;
189 /* Construct mangled common block name from symbol name. */
191 static tree
192 gfc_sym_mangled_common_id (const char *name)
194 int has_underscore;
195 char mangled_name[GFC_MAX_MANGLED_SYMBOL_LEN + 1];
197 if (strcmp (name, BLANK_COMMON_NAME) == 0)
198 return get_identifier (name);
200 if (gfc_option.flag_underscoring)
202 has_underscore = strchr (name, '_') != 0;
203 if (gfc_option.flag_second_underscore && has_underscore)
204 snprintf (mangled_name, sizeof mangled_name, "%s__", name);
205 else
206 snprintf (mangled_name, sizeof mangled_name, "%s_", name);
208 return get_identifier (mangled_name);
210 else
211 return get_identifier (name);
215 /* Build a field declaration for a common variable or a local equivalence
216 object. */
218 static void
219 build_field (segment_info *h, tree union_type, record_layout_info rli)
221 tree field;
222 tree name;
223 HOST_WIDE_INT offset = h->offset;
224 unsigned HOST_WIDE_INT desired_align, known_align;
226 name = get_identifier (h->sym->name);
227 field = build_decl (FIELD_DECL, name, h->field);
228 gfc_set_decl_location (field, &h->sym->declared_at);
229 known_align = (offset & -offset) * BITS_PER_UNIT;
230 if (known_align == 0 || known_align > BIGGEST_ALIGNMENT)
231 known_align = BIGGEST_ALIGNMENT;
233 desired_align = update_alignment_for_field (rli, field, known_align);
234 if (desired_align > known_align)
235 DECL_PACKED (field) = 1;
237 DECL_FIELD_CONTEXT (field) = union_type;
238 DECL_FIELD_OFFSET (field) = size_int (offset);
239 DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
240 SET_DECL_OFFSET_ALIGN (field, known_align);
242 rli->offset = size_binop (MAX_EXPR, rli->offset,
243 size_binop (PLUS_EXPR,
244 DECL_FIELD_OFFSET (field),
245 DECL_SIZE_UNIT (field)));
246 h->field = field;
250 /* Get storage for local equivalence. */
252 static tree
253 build_equiv_decl (tree union_type, bool is_init)
255 tree decl;
257 if (is_init)
259 decl = gfc_create_var (union_type, "equiv");
260 TREE_STATIC (decl) = 1;
261 return decl;
264 decl = build_decl (VAR_DECL, NULL, union_type);
265 DECL_ARTIFICIAL (decl) = 1;
267 DECL_COMMON (decl) = 1;
269 TREE_ADDRESSABLE (decl) = 1;
270 TREE_USED (decl) = 1;
272 /* The source location has been lost, and doesn't really matter.
273 We need to set it to something though. */
274 gfc_set_decl_location (decl, &gfc_current_locus);
276 gfc_add_decl_to_function (decl);
278 return decl;
282 /* Get storage for common block. */
284 static tree
285 build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
287 gfc_symbol *common_sym;
288 tree decl;
290 /* Create a namespace to store symbols for common blocks. */
291 if (gfc_common_ns == NULL)
292 gfc_common_ns = gfc_get_namespace (NULL);
294 gfc_get_symbol (com->name, gfc_common_ns, &common_sym);
295 decl = common_sym->backend_decl;
297 /* Update the size of this common block as needed. */
298 if (decl != NULL_TREE)
300 tree size = TYPE_SIZE_UNIT (union_type);
301 if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size))
303 /* Named common blocks of the same name shall be of the same size
304 in all scoping units of a program in which they appear, but
305 blank common blocks may be of different sizes. */
306 if (strcmp (com->name, BLANK_COMMON_NAME))
307 gfc_warning ("Named COMMON block '%s' at %L shall be of the "
308 "same size", com->name, &com->where);
309 DECL_SIZE_UNIT (decl) = size;
313 /* If this common block has been declared in a previous program unit,
314 and either it is already initialized or there is no new initialization
315 for it, just return. */
316 if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl)))
317 return decl;
319 /* If there is no backend_decl for the common block, build it. */
320 if (decl == NULL_TREE)
322 decl = build_decl (VAR_DECL, get_identifier (com->name), union_type);
323 SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com->name));
324 TREE_PUBLIC (decl) = 1;
325 TREE_STATIC (decl) = 1;
326 DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
327 DECL_USER_ALIGN (decl) = 0;
329 gfc_set_decl_location (decl, &com->where);
331 /* Place the back end declaration for this common block in
332 GLOBAL_BINDING_LEVEL. */
333 common_sym->backend_decl = pushdecl_top_level (decl);
336 /* Has no initial values. */
337 if (!is_init)
339 DECL_INITIAL (decl) = NULL_TREE;
340 DECL_COMMON (decl) = 1;
341 DECL_DEFER_OUTPUT (decl) = 1;
343 else
345 DECL_INITIAL (decl) = error_mark_node;
346 DECL_COMMON (decl) = 0;
347 DECL_DEFER_OUTPUT (decl) = 0;
349 return decl;
353 /* Declare memory for the common block or local equivalence, and create
354 backend declarations for all of the elements. */
356 static void
357 create_common (gfc_common_head *com)
359 segment_info *s, *next_s;
360 tree union_type;
361 tree *field_link;
362 record_layout_info rli;
363 tree decl;
364 bool is_init = false;
366 /* Declare the variables inside the common block. */
367 union_type = make_node (UNION_TYPE);
368 rli = start_record_layout (union_type);
369 field_link = &TYPE_FIELDS (union_type);
371 for (s = current_common; s; s = s->next)
373 build_field (s, union_type, rli);
375 /* Link the field into the type. */
376 *field_link = s->field;
377 field_link = &TREE_CHAIN (s->field);
379 /* Has initial value. */
380 if (s->sym->value)
381 is_init = true;
383 finish_record_layout (rli, true);
385 if (com)
386 decl = build_common_decl (com, union_type, is_init);
387 else
388 decl = build_equiv_decl (union_type, is_init);
390 if (is_init)
392 tree list, ctor, tmp;
393 HOST_WIDE_INT offset = 0;
395 list = NULL_TREE;
396 for (s = current_common; s; s = s->next)
398 if (s->sym->value)
400 if (s->offset < offset)
402 /* We have overlapping initializers. It could either be
403 partially initilalized arrays (legal), or the user
404 specified multiple initial values (illegal).
405 We don't implement this yet, so bail out. */
406 gfc_todo_error ("Initialization of overlapping variables");
408 /* Add the initializer for this field. */
409 tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts,
410 TREE_TYPE (s->field), s->sym->attr.dimension,
411 s->sym->attr.pointer || s->sym->attr.allocatable);
412 list = tree_cons (s->field, tmp, list);
413 offset = s->offset + s->length;
416 gcc_assert (list);
417 ctor = build1 (CONSTRUCTOR, union_type, nreverse(list));
418 TREE_CONSTANT (ctor) = 1;
419 TREE_INVARIANT (ctor) = 1;
420 TREE_STATIC (ctor) = 1;
421 DECL_INITIAL (decl) = ctor;
423 #ifdef ENABLE_CHECKING
424 for (tmp = CONSTRUCTOR_ELTS (ctor); tmp; tmp = TREE_CHAIN (tmp))
425 gcc_assert (TREE_CODE (TREE_PURPOSE (tmp)) == FIELD_DECL);
426 #endif
429 /* Build component reference for each variable. */
430 for (s = current_common; s; s = next_s)
432 s->sym->backend_decl = build3 (COMPONENT_REF, TREE_TYPE (s->field),
433 decl, s->field, NULL_TREE);
435 next_s = s->next;
436 gfc_free (s);
441 /* Given a symbol, find it in the current segment list. Returns NULL if
442 not found. */
444 static segment_info *
445 find_segment_info (gfc_symbol *symbol)
447 segment_info *n;
449 for (n = current_segment; n; n = n->next)
451 if (n->sym == symbol)
452 return n;
455 return NULL;
459 /* Given an expression node, make sure it is a constant integer and return
460 the mpz_t value. */
462 static mpz_t *
463 get_mpz (gfc_expr *e)
466 if (e->expr_type != EXPR_CONSTANT)
467 gfc_internal_error ("get_mpz(): Not an integer constant");
469 return &e->value.integer;
473 /* Given an array specification and an array reference, figure out the
474 array element number (zero based). Bounds and elements are guaranteed
475 to be constants. If something goes wrong we generate an error and
476 return zero. */
478 static HOST_WIDE_INT
479 element_number (gfc_array_ref *ar)
481 mpz_t multiplier, offset, extent, n;
482 gfc_array_spec *as;
483 HOST_WIDE_INT i, rank;
485 as = ar->as;
486 rank = as->rank;
487 mpz_init_set_ui (multiplier, 1);
488 mpz_init_set_ui (offset, 0);
489 mpz_init (extent);
490 mpz_init (n);
492 for (i = 0; i < rank; i++)
494 if (ar->dimen_type[i] != DIMEN_ELEMENT)
495 gfc_internal_error ("element_number(): Bad dimension type");
497 mpz_sub (n, *get_mpz (ar->start[i]), *get_mpz (as->lower[i]));
499 mpz_mul (n, n, multiplier);
500 mpz_add (offset, offset, n);
502 mpz_sub (extent, *get_mpz (as->upper[i]), *get_mpz (as->lower[i]));
503 mpz_add_ui (extent, extent, 1);
505 if (mpz_sgn (extent) < 0)
506 mpz_set_ui (extent, 0);
508 mpz_mul (multiplier, multiplier, extent);
511 i = mpz_get_ui (offset);
513 mpz_clear (multiplier);
514 mpz_clear (offset);
515 mpz_clear (extent);
516 mpz_clear (n);
518 return i;
522 /* Given a single element of an equivalence list, figure out the offset
523 from the base symbol. For simple variables or full arrays, this is
524 simply zero. For an array element we have to calculate the array
525 element number and multiply by the element size. For a substring we
526 have to calculate the further reference. */
528 static HOST_WIDE_INT
529 calculate_offset (gfc_expr *e)
531 HOST_WIDE_INT n, element_size, offset;
532 gfc_typespec *element_type;
533 gfc_ref *reference;
535 offset = 0;
536 element_type = &e->symtree->n.sym->ts;
538 for (reference = e->ref; reference; reference = reference->next)
539 switch (reference->type)
541 case REF_ARRAY:
542 switch (reference->u.ar.type)
544 case AR_FULL:
545 break;
547 case AR_ELEMENT:
548 n = element_number (&reference->u.ar);
549 if (element_type->type == BT_CHARACTER)
550 gfc_conv_const_charlen (element_type->cl);
551 element_size =
552 int_size_in_bytes (gfc_typenode_for_spec (element_type));
553 offset += n * element_size;
554 break;
556 default:
557 gfc_error ("Bad array reference at %L", &e->where);
559 break;
560 case REF_SUBSTRING:
561 if (reference->u.ss.start != NULL)
562 offset += mpz_get_ui (*get_mpz (reference->u.ss.start)) - 1;
563 break;
564 default:
565 gfc_error ("Illegal reference type at %L as EQUIVALENCE object",
566 &e->where);
568 return offset;
572 /* Add a new segment_info structure to the current segment. eq1 is already
573 in the list, eq2 is not. */
575 static void
576 new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2)
578 HOST_WIDE_INT offset1, offset2;
579 segment_info *a;
581 offset1 = calculate_offset (eq1->expr);
582 offset2 = calculate_offset (eq2->expr);
584 a = get_segment_info (eq2->expr->symtree->n.sym,
585 v->offset + offset1 - offset2);
587 current_segment = add_segments (current_segment, a);
591 /* Given two equivalence structures that are both already in the list, make
592 sure that this new condition is not violated, generating an error if it
593 is. */
595 static void
596 confirm_condition (segment_info *s1, gfc_equiv *eq1, segment_info *s2,
597 gfc_equiv *eq2)
599 HOST_WIDE_INT offset1, offset2;
601 offset1 = calculate_offset (eq1->expr);
602 offset2 = calculate_offset (eq2->expr);
604 if (s1->offset + offset1 != s2->offset + offset2)
605 gfc_error ("Inconsistent equivalence rules involving '%s' at %L and "
606 "'%s' at %L", s1->sym->name, &s1->sym->declared_at,
607 s2->sym->name, &s2->sym->declared_at);
611 /* Process a new equivalence condition. eq1 is know to be in segment f.
612 If eq2 is also present then confirm that the condition holds.
613 Otherwise add a new variable to the segment list. */
615 static void
616 add_condition (segment_info *f, gfc_equiv *eq1, gfc_equiv *eq2)
618 segment_info *n;
620 n = find_segment_info (eq2->expr->symtree->n.sym);
622 if (n == NULL)
623 new_condition (f, eq1, eq2);
624 else
625 confirm_condition (f, eq1, n, eq2);
629 /* Given a segment element, search through the equivalence lists for unused
630 conditions that involve the symbol. Add these rules to the segment. Only
631 checks for rules involving the first symbol in the equivalence set. */
633 static bool
634 find_equivalence (segment_info *n)
636 gfc_equiv *e1, *e2, *eq, *other;
637 bool found;
639 found = FALSE;
640 for (e1 = n->sym->ns->equiv; e1; e1 = e1->next)
642 other = NULL;
643 for (e2 = e1->eq; e2; e2 = e2->eq)
645 if (e2->used)
646 continue;
648 if (e1->expr->symtree->n.sym == n->sym)
650 eq = e1;
651 other = e2;
653 else if (e2->expr->symtree->n.sym == n->sym)
655 eq = e2;
656 other = e1;
658 else
659 eq = NULL;
661 if (eq)
663 add_condition (n, eq, other);
664 eq->used = 1;
665 found = TRUE;
666 /* If this symbol is the first in the chain we may find other
667 matches. Otherwise we can skip to the next equivalence. */
668 if (eq == e2)
669 break;
673 return found;
677 /* Add all symbols equivalenced within a segment. We need to scan the
678 segment list multiple times to include indirect equivalences. */
680 static void
681 add_equivalences (void)
683 segment_info *f;
684 bool more;
686 more = TRUE;
687 while (more)
689 more = FALSE;
690 for (f = current_segment; f; f = f->next)
692 if (!f->sym->equiv_built)
694 f->sym->equiv_built = 1;
695 more = find_equivalence (f);
702 /* Given a seed symbol, create a new segment consisting of that symbol
703 and all of the symbols equivalenced with that symbol. */
705 static void
706 new_segment (gfc_common_head *common, gfc_symbol *sym)
709 current_segment = get_segment_info (sym, current_offset);
711 /* The offset of the next common variable. */
712 current_offset += current_segment->length;
714 /* Add all object directly or indirectly equivalenced with this common
715 variable. */
716 add_equivalences ();
718 if (current_segment->offset < 0)
719 gfc_error ("The equivalence set for '%s' cause an invalid "
720 "extension to COMMON '%s' at %L", sym->name,
721 common->name, &common->where);
723 /* Add these to the common block. */
724 current_common = add_segments (current_common, current_segment);
728 /* Create a new block for each merged equivalence list. */
730 static void
731 finish_equivalences (gfc_namespace *ns)
733 gfc_equiv *z, *y;
734 gfc_symbol *sym;
735 segment_info *v;
736 HOST_WIDE_INT min_offset;
738 for (z = ns->equiv; z; z = z->next)
739 for (y = z->eq; y; y = y->eq)
741 if (y->used)
742 continue;
743 sym = z->expr->symtree->n.sym;
744 current_segment = get_segment_info (sym, 0);
746 /* All objects directly or indrectly equivalenced with this symbol. */
747 add_equivalences ();
749 /* Calculate the minimal offset. */
750 min_offset = current_segment->offset;
752 /* Adjust the offset of each equivalence object. */
753 for (v = current_segment; v; v = v->next)
754 v->offset -= min_offset;
756 current_common = current_segment;
757 create_common (NULL);
758 break;
763 /* Translate a single common block. */
765 static void
766 translate_common (gfc_common_head *common, gfc_symbol *var_list)
768 gfc_symbol *sym;
770 current_common = NULL;
771 current_offset = 0;
773 /* Add symbols to the segment. */
774 for (sym = var_list; sym; sym = sym->common_next)
776 if (! sym->equiv_built)
777 new_segment (common, sym);
780 create_common (common);
784 /* Work function for translating a named common block. */
786 static void
787 named_common (gfc_symtree *st)
790 translate_common (st->n.common, st->n.common->head);
794 /* Translate the common blocks in a namespace. Unlike other variables,
795 these have to be created before code, because the backend_decl depends
796 on the rest of the common block. */
798 void
799 gfc_trans_common (gfc_namespace *ns)
801 gfc_common_head *c;
803 /* Translate the blank common block. */
804 if (ns->blank_common.head != NULL)
806 c = gfc_get_common_head ();
807 /* We've lost the real location, so use the location of the
808 enclosing procedure. */
809 c->where = ns->proc_name->declared_at;
810 strcpy (c->name, BLANK_COMMON_NAME);
811 translate_common (c, ns->blank_common.head);
814 /* Translate all named common blocks. */
815 gfc_traverse_symtree (ns->common_root, named_common);
817 /* Commit the newly created symbols for common blocks. */
818 gfc_commit_symbols ();
820 /* Translate local equivalence. */
821 finish_equivalences (ns);