gfortran.h (struct gfc_symbol): Add equiv_built.
* gfortran.h (struct gfc_symbol): Add equiv_built. * trans-common.c: Change int to HOST_WIDE_INT. Capitalize error messages. (current_length): Remove. (add_segments): New function. (build_equiv_decl): Create initialized common blocks. (build_common_decl): Always add decl to bindings. (create_common): Create initializers. (find_segment_info): Reformat to match coding conventions. (new_condition): Use add_segments. (add_condition, find_equivalence, add_equivalences): Move iteration inside functions. Only process each segment once. (new_segment, finish_equivalences, translate_common): Simplify. testsuite/ * gfortran.fortran-torture/execute/common_init_1.f90: New test. * gfortran.fortran-torture/execute/equiv_init.f90: New test. Co-Authored-By: Victor Leikehman <lei@haifasphere.co.il> From-SVN: r82165
This commit is contained in:
parent
68ca19239c
commit
5291e69ade
@ -1,3 +1,20 @@
|
||||
2004-05-23 Paul Brook <paul@codesourcery.com>
|
||||
Victor Leikehman <lei@haifasphere.co.il>
|
||||
|
||||
* gfortran.h (struct gfc_symbol): Add equiv_built.
|
||||
* trans-common.c: Change int to HOST_WIDE_INT. Capitalize error
|
||||
messages.
|
||||
(current_length): Remove.
|
||||
(add_segments): New function.
|
||||
(build_equiv_decl): Create initialized common blocks.
|
||||
(build_common_decl): Always add decl to bindings.
|
||||
(create_common): Create initializers.
|
||||
(find_segment_info): Reformat to match coding conventions.
|
||||
(new_condition): Use add_segments.
|
||||
(add_condition, find_equivalence, add_equivalences): Move iteration
|
||||
inside functions. Only process each segment once.
|
||||
(new_segment, finish_equivalences, translate_common): Simplify.
|
||||
|
||||
2004-05-23 Steven G. Kargl <kargls@comcast.net>
|
||||
|
||||
* check.c (gfc_check_random_seed): Issue for too many arguments.
|
||||
|
@ -651,6 +651,9 @@ typedef struct gfc_symbol
|
||||
|
||||
struct gfc_symbol *old_symbol, *tlink;
|
||||
unsigned mark:1, new:1;
|
||||
/* Nonzero if all equivalences associated with this symbol have been
|
||||
processed. */
|
||||
unsigned equiv_built:1;
|
||||
int refs;
|
||||
struct gfc_namespace *ns; /* namespace containing this symbol */
|
||||
|
||||
|
@ -82,6 +82,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
common block is series of segments with one variable each, which is
|
||||
a diagonal matrix in the matrix formulation.
|
||||
|
||||
Each segment is described by a chain of segment_info structures. Each
|
||||
segment_info structure describes the extents of a single varible within
|
||||
the segment. This list is maintained in the order the elements are
|
||||
positioned withing the segment. If two elements have the same starting
|
||||
offset the smaller will come first. If they also have the same size their
|
||||
ordering is undefined.
|
||||
|
||||
Once all common blocks have been created, the list of equivalences
|
||||
is examined for still-unused equivalence conditions. We create a
|
||||
block for each merged equivalence list. */
|
||||
@ -96,19 +103,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "trans.h"
|
||||
#include "trans-types.h"
|
||||
#include "trans-const.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct segment_info
|
||||
{
|
||||
gfc_symbol *sym;
|
||||
int offset;
|
||||
int length;
|
||||
HOST_WIDE_INT offset;
|
||||
HOST_WIDE_INT length;
|
||||
tree field;
|
||||
struct segment_info *next;
|
||||
} segment_info;
|
||||
|
||||
static segment_info *current_segment, *current_common;
|
||||
static int current_length, current_offset;
|
||||
static HOST_WIDE_INT current_offset;
|
||||
static gfc_namespace *gfc_common_ns = NULL;
|
||||
|
||||
#define get_segment_info() gfc_getmem (sizeof (segment_info))
|
||||
@ -116,6 +124,47 @@ static gfc_namespace *gfc_common_ns = NULL;
|
||||
#define BLANK_COMMON_NAME "__BLNK__"
|
||||
|
||||
|
||||
/* Add combine segment V and segement LIST. */
|
||||
|
||||
static segment_info *
|
||||
add_segments (segment_info *list, segment_info *v)
|
||||
{
|
||||
segment_info *s;
|
||||
segment_info *p;
|
||||
segment_info *next;
|
||||
|
||||
p = NULL;
|
||||
s = list;
|
||||
|
||||
while (v)
|
||||
{
|
||||
/* Find the location of the new element. */
|
||||
while (s)
|
||||
{
|
||||
if (v->offset < s->offset)
|
||||
break;
|
||||
if (v->offset == s->offset
|
||||
&& v->length <= s->length)
|
||||
break;
|
||||
|
||||
p = s;
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
/* Insert the new element in between p and s. */
|
||||
next = v->next;
|
||||
v->next = s;
|
||||
if (p == NULL)
|
||||
list = v;
|
||||
else
|
||||
p->next = v;
|
||||
|
||||
p = v;
|
||||
v = next;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Construct mangled common block name from symbol name. */
|
||||
|
||||
static tree
|
||||
@ -150,7 +199,7 @@ build_field (segment_info *h, tree union_type, record_layout_info rli)
|
||||
tree name = get_identifier (h->sym->name);
|
||||
tree field = build_decl (FIELD_DECL, name, type);
|
||||
HOST_WIDE_INT offset = h->offset;
|
||||
unsigned int desired_align, known_align;
|
||||
unsigned HOST_WIDE_INT desired_align, known_align;
|
||||
|
||||
known_align = (offset & -offset) * BITS_PER_UNIT;
|
||||
if (known_align == 0 || known_align > BIGGEST_ALIGNMENT)
|
||||
@ -179,13 +228,18 @@ static tree
|
||||
build_equiv_decl (tree union_type, bool is_init)
|
||||
{
|
||||
tree decl;
|
||||
|
||||
if (is_init)
|
||||
{
|
||||
decl = gfc_create_var (union_type, "equiv");
|
||||
TREE_STATIC (decl) = 1;
|
||||
return decl;
|
||||
}
|
||||
|
||||
decl = build_decl (VAR_DECL, NULL, union_type);
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
|
||||
if (is_init)
|
||||
DECL_COMMON (decl) = 0;
|
||||
else
|
||||
DECL_COMMON (decl) = 1;
|
||||
DECL_COMMON (decl) = 1;
|
||||
|
||||
TREE_ADDRESSABLE (decl) = 1;
|
||||
TREE_USED (decl) = 1;
|
||||
@ -213,14 +267,14 @@ build_common_decl (gfc_symbol *sym, tree union_type, bool is_init)
|
||||
/* Update the size of this common block as needed. */
|
||||
if (decl != NULL_TREE)
|
||||
{
|
||||
tree size = build_int_2 (current_length, 0);
|
||||
tree size = TYPE_SIZE_UNIT (union_type);
|
||||
if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size))
|
||||
{
|
||||
/* Named common blocks of the same name shall be of the same size
|
||||
in all scoping units of a program in which they appear, but
|
||||
blank common blocks may be of different sizes. */
|
||||
if (strcmp (sym->name, BLANK_COMMON_NAME))
|
||||
gfc_warning ("named COMMON block '%s' at %L shall be of the "
|
||||
gfc_warning ("Named COMMON block '%s' at %L shall be of the "
|
||||
"same size", sym->name, &sym->declared_at);
|
||||
DECL_SIZE_UNIT (decl) = size;
|
||||
}
|
||||
@ -241,6 +295,10 @@ build_common_decl (gfc_symbol *sym, tree union_type, bool is_init)
|
||||
TREE_STATIC (decl) = 1;
|
||||
DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
|
||||
DECL_USER_ALIGN (decl) = 0;
|
||||
|
||||
/* Place the back end declaration for this common block in
|
||||
GLOBAL_BINDING_LEVEL. */
|
||||
common_sym->backend_decl = pushdecl_top_level (decl);
|
||||
}
|
||||
|
||||
/* Has no initial values. */
|
||||
@ -250,16 +308,12 @@ build_common_decl (gfc_symbol *sym, tree union_type, bool is_init)
|
||||
DECL_COMMON (decl) = 1;
|
||||
DECL_DEFER_OUTPUT (decl) = 1;
|
||||
|
||||
/* Place the back end declaration for this common block in
|
||||
GLOBAL_BINDING_LEVEL. */
|
||||
common_sym->backend_decl = pushdecl_top_level (decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
DECL_INITIAL (decl) = error_mark_node;
|
||||
DECL_COMMON (decl) = 0;
|
||||
DECL_DEFER_OUTPUT (decl) = 0;
|
||||
common_sym->backend_decl = decl;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
@ -300,14 +354,73 @@ create_common (gfc_symbol *sym)
|
||||
}
|
||||
finish_record_layout (rli, true);
|
||||
|
||||
if (is_init)
|
||||
gfc_todo_error ("initial values for COMMON or EQUIVALENCE");
|
||||
|
||||
if (sym)
|
||||
decl = build_common_decl (sym, union_type, is_init);
|
||||
else
|
||||
decl = build_equiv_decl (union_type, is_init);
|
||||
|
||||
if (is_init)
|
||||
{
|
||||
tree list, ctor, tmp;
|
||||
gfc_se se;
|
||||
HOST_WIDE_INT offset = 0;
|
||||
|
||||
list = NULL_TREE;
|
||||
for (h = current_common; h; h = h->next)
|
||||
{
|
||||
if (h->sym->value)
|
||||
{
|
||||
if (h->offset < offset)
|
||||
{
|
||||
/* We have overlapping initializers. It could either be
|
||||
partially initilalized arrays (lagal), or the user
|
||||
specified multiple initial values (illegal).
|
||||
We don't implement this yet, so bail out. */
|
||||
gfc_todo_error ("Initialization of overlapping variables");
|
||||
}
|
||||
if (h->sym->attr.dimension)
|
||||
{
|
||||
tmp = gfc_conv_array_initializer (TREE_TYPE (h->field),
|
||||
h->sym->value);
|
||||
list = tree_cons (h->field, tmp, list);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (h->sym->ts.type)
|
||||
{
|
||||
case BT_CHARACTER:
|
||||
se.expr = gfc_conv_string_init
|
||||
(h->sym->ts.cl->backend_decl, h->sym->value);
|
||||
break;
|
||||
|
||||
case BT_DERIVED:
|
||||
gfc_init_se (&se, NULL);
|
||||
gfc_conv_structure (&se, sym->value, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
gfc_init_se (&se, NULL);
|
||||
gfc_conv_expr (&se, h->sym->value);
|
||||
break;
|
||||
}
|
||||
list = tree_cons (h->field, se.expr, list);
|
||||
}
|
||||
offset = h->offset + h->length;
|
||||
}
|
||||
}
|
||||
assert (list);
|
||||
ctor = build1 (CONSTRUCTOR, union_type, nreverse(list));
|
||||
TREE_CONSTANT (ctor) = 1;
|
||||
TREE_INVARIANT (ctor) = 1;
|
||||
TREE_STATIC (ctor) = 1;
|
||||
DECL_INITIAL (decl) = ctor;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
for (tmp = CONSTRUCTOR_ELTS (ctor); tmp; tmp = TREE_CHAIN (tmp))
|
||||
assert (TREE_CODE (TREE_PURPOSE (tmp)) == FIELD_DECL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Build component reference for each variable. */
|
||||
for (h = current_common; h; h = next_s)
|
||||
{
|
||||
@ -329,7 +442,10 @@ find_segment_info (gfc_symbol *symbol)
|
||||
segment_info *n;
|
||||
|
||||
for (n = current_segment; n; n = n->next)
|
||||
if (n->sym == symbol) return n;
|
||||
{
|
||||
if (n->sym == symbol)
|
||||
return n;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -338,10 +454,10 @@ find_segment_info (gfc_symbol *symbol)
|
||||
/* Given a variable symbol, calculate the total length in bytes of the
|
||||
variable. */
|
||||
|
||||
static int
|
||||
static HOST_WIDE_INT
|
||||
calculate_length (gfc_symbol *symbol)
|
||||
{
|
||||
int j, element_size;
|
||||
HOST_WIDE_INT j, element_size;
|
||||
mpz_t elements;
|
||||
|
||||
if (symbol->ts.type == BT_CHARACTER)
|
||||
@ -378,12 +494,12 @@ get_mpz (gfc_expr *g)
|
||||
to be constants. If something goes wrong we generate an error and
|
||||
return zero. */
|
||||
|
||||
static int
|
||||
static HOST_WIDE_INT
|
||||
element_number (gfc_array_ref *ar)
|
||||
{
|
||||
mpz_t multiplier, offset, extent, l;
|
||||
gfc_array_spec *as;
|
||||
int b, rank;
|
||||
HOST_WIDE_INT b, rank;
|
||||
|
||||
as = ar->as;
|
||||
rank = as->rank;
|
||||
@ -428,10 +544,10 @@ element_number (gfc_array_ref *ar)
|
||||
element number and multiply by the element size. For a substring we
|
||||
have to calculate the further reference. */
|
||||
|
||||
static int
|
||||
static HOST_WIDE_INT
|
||||
calculate_offset (gfc_expr *s)
|
||||
{
|
||||
int a, element_size, offset;
|
||||
HOST_WIDE_INT a, element_size, offset;
|
||||
gfc_typespec *element_type;
|
||||
gfc_ref *reference;
|
||||
|
||||
@ -457,7 +573,7 @@ calculate_offset (gfc_expr *s)
|
||||
break;
|
||||
|
||||
default:
|
||||
gfc_error ("bad array reference at %L", &s->where);
|
||||
gfc_error ("Bad array reference at %L", &s->where);
|
||||
}
|
||||
break;
|
||||
case REF_SUBSTRING:
|
||||
@ -465,20 +581,20 @@ calculate_offset (gfc_expr *s)
|
||||
offset += mpz_get_ui (*get_mpz (reference->u.ss.start)) - 1;
|
||||
break;
|
||||
default:
|
||||
gfc_error ("illegal reference type at %L as EQUIVALENCE object",
|
||||
gfc_error ("Illegal reference type at %L as EQUIVALENCE object",
|
||||
&s->where);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
/* Add a new segment_info structure to the current eq1 is already in the
|
||||
list at s1, eq2 is not. */
|
||||
/* Add a new segment_info structure to the current segment. eq1 is already
|
||||
in the list, eq2 is not. */
|
||||
|
||||
static void
|
||||
new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2)
|
||||
{
|
||||
int offset1, offset2;
|
||||
HOST_WIDE_INT offset1, offset2;
|
||||
segment_info *a;
|
||||
|
||||
offset1 = calculate_offset (eq1->expr);
|
||||
@ -490,8 +606,7 @@ new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2)
|
||||
a->offset = v->offset + offset1 - offset2;
|
||||
a->length = calculate_length (eq2->expr->symtree->n.sym);
|
||||
|
||||
a->next = current_segment;
|
||||
current_segment = a;
|
||||
current_segment = add_segments (current_segment, a);
|
||||
}
|
||||
|
||||
|
||||
@ -503,97 +618,102 @@ static void
|
||||
confirm_condition (segment_info *k, gfc_equiv *eq1, segment_info *e,
|
||||
gfc_equiv *eq2)
|
||||
{
|
||||
int offset1, offset2;
|
||||
HOST_WIDE_INT offset1, offset2;
|
||||
|
||||
offset1 = calculate_offset (eq1->expr);
|
||||
offset2 = calculate_offset (eq2->expr);
|
||||
|
||||
if (k->offset + offset1 != e->offset + offset2)
|
||||
gfc_error ("inconsistent equivalence rules involving '%s' at %L and "
|
||||
gfc_error ("Inconsistent equivalence rules involving '%s' at %L and "
|
||||
"'%s' at %L", k->sym->name, &k->sym->declared_at,
|
||||
e->sym->name, &e->sym->declared_at);
|
||||
}
|
||||
|
||||
|
||||
/* At this point we have a new equivalence condition to process. If both
|
||||
variables are already present, then we are confirming that the condition
|
||||
holds. Otherwise we are adding a new variable to the segment list. */
|
||||
/* Process a new equivalence condition. eq1 is know to be in segment f.
|
||||
If eq2 is also present then confirm that the condition holds.
|
||||
Otherwise add a new variable to the segment list. */
|
||||
|
||||
static void
|
||||
add_condition (gfc_equiv *eq1, gfc_equiv *eq2)
|
||||
add_condition (segment_info *f, gfc_equiv *eq1, gfc_equiv *eq2)
|
||||
{
|
||||
segment_info *n, *t;
|
||||
segment_info *n;
|
||||
|
||||
eq1->expr->symtree->n.sym->mark = 1;
|
||||
eq2->expr->symtree->n.sym->mark = 1;
|
||||
n = find_segment_info (eq2->expr->symtree->n.sym);
|
||||
|
||||
eq2->used = 1;
|
||||
|
||||
n = find_segment_info (eq1->expr->symtree->n.sym);
|
||||
t = find_segment_info (eq2->expr->symtree->n.sym);
|
||||
|
||||
if (n == NULL && t == NULL)
|
||||
abort ();
|
||||
if (n != NULL && t == NULL)
|
||||
new_condition (n, eq1, eq2);
|
||||
if (n == NULL && t != NULL)
|
||||
new_condition (t, eq2, eq1);
|
||||
if (n != NULL && t != NULL)
|
||||
confirm_condition (n, eq1, t, eq2);
|
||||
if (n == NULL)
|
||||
new_condition (f, eq1, eq2);
|
||||
else
|
||||
confirm_condition (f, eq1, n, eq2);
|
||||
}
|
||||
|
||||
|
||||
/* Given a symbol, search through the equivalence lists for an unused
|
||||
condition that involves the symbol. If a rule is found, we return
|
||||
nonzero, the rule is marked as used and the eq1 and eq2 pointers point
|
||||
to the rule. */
|
||||
/* Given a segment element, search through the equivalence lists for unused
|
||||
conditions that involve the symbol. Add these rules to the segment. */
|
||||
|
||||
static int
|
||||
find_equivalence (gfc_symbol *sym, gfc_equiv **eq1, gfc_equiv **eq2)
|
||||
static bool
|
||||
find_equivalence (segment_info *f)
|
||||
{
|
||||
gfc_equiv *c, *l;
|
||||
gfc_equiv *c, *l, *eq, *other;
|
||||
bool found;
|
||||
|
||||
for (c = sym->ns->equiv; c; c = c->next)
|
||||
for (l = c->eq; l; l = l->eq)
|
||||
{
|
||||
if (l->used) continue;
|
||||
found = FALSE;
|
||||
for (c = f->sym->ns->equiv; c; c = c->next)
|
||||
{
|
||||
other = NULL;
|
||||
for (l = c->eq; l; l = l->eq)
|
||||
{
|
||||
if (l->used)
|
||||
continue;
|
||||
|
||||
if (c->expr->symtree->n.sym == sym || l->expr->symtree->n.sym == sym)
|
||||
{
|
||||
*eq1 = c;
|
||||
*eq2 = l;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if (c->expr->symtree->n.sym ==f-> sym)
|
||||
{
|
||||
eq = c;
|
||||
other = l;
|
||||
}
|
||||
else if (l->expr->symtree->n.sym == f->sym)
|
||||
{
|
||||
eq = l;
|
||||
other = c;
|
||||
}
|
||||
else
|
||||
eq = NULL;
|
||||
|
||||
if (eq)
|
||||
{
|
||||
add_condition (f, eq, other);
|
||||
l->used = 1;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/* Function for adding symbols to current segment. Returns zero if the
|
||||
segment was modified. Equivalence rules are considered to be between
|
||||
the first expression in the list and each of the other expressions in
|
||||
the list. Symbols are scanned multiple times because a symbol can be
|
||||
equivalenced more than once. */
|
||||
/* Add all symbols equivalenced within a segment. We need to scan the
|
||||
segment list multiple times to include indirect equivalences. */
|
||||
|
||||
static int
|
||||
static void
|
||||
add_equivalences (void)
|
||||
{
|
||||
int segment_modified;
|
||||
gfc_equiv *eq1, *eq2;
|
||||
segment_info *f;
|
||||
bool more;
|
||||
|
||||
segment_modified = 0;
|
||||
|
||||
for (f = current_segment; f; f = f->next)
|
||||
if (find_equivalence (f->sym, &eq1, &eq2)) break;
|
||||
|
||||
if (f != NULL)
|
||||
more = TRUE;
|
||||
while (more)
|
||||
{
|
||||
add_condition (eq1, eq2);
|
||||
segment_modified = 1;
|
||||
more = FALSE;
|
||||
for (f = current_segment; f; f = f->next)
|
||||
{
|
||||
if (!f->sym->equiv_built)
|
||||
{
|
||||
f->sym->equiv_built = 1;
|
||||
more = find_equivalence (f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return segment_modified;
|
||||
}
|
||||
|
||||
|
||||
@ -603,8 +723,7 @@ add_equivalences (void)
|
||||
static void
|
||||
new_segment (gfc_symbol *common_sym, gfc_symbol *sym)
|
||||
{
|
||||
segment_info *v;
|
||||
int length;
|
||||
HOST_WIDE_INT length;
|
||||
|
||||
current_segment = get_segment_info ();
|
||||
current_segment->sym = sym;
|
||||
@ -612,34 +731,20 @@ new_segment (gfc_symbol *common_sym, gfc_symbol *sym)
|
||||
length = calculate_length (sym);
|
||||
current_segment->length = length;
|
||||
|
||||
sym->mark = 1;
|
||||
|
||||
/* Add all object directly or indirectly equivalenced with this common
|
||||
variable. */
|
||||
while (add_equivalences ());
|
||||
add_equivalences ();
|
||||
|
||||
/* Calculate the storage size to hold the common block. */
|
||||
for (v = current_segment; v; v = v->next)
|
||||
{
|
||||
if (v->offset < 0)
|
||||
gfc_error ("the equivalence set for '%s' cause an invalid extension "
|
||||
"to COMMON '%s' at %L",
|
||||
sym->name, common_sym->name, &common_sym->declared_at);
|
||||
if (current_length < (v->offset + v->length))
|
||||
current_length = v->offset + v->length;
|
||||
}
|
||||
if (current_segment->offset < 0)
|
||||
gfc_error ("The equivalence set for '%s' cause an invalid extension "
|
||||
"to COMMON '%s' at %L",
|
||||
sym->name, common_sym->name, &common_sym->declared_at);
|
||||
|
||||
/* The offset of the next common variable. */
|
||||
current_offset += length;
|
||||
|
||||
/* Append the current segment to the current common. */
|
||||
v = current_segment;
|
||||
while (v->next != NULL)
|
||||
v = v->next;
|
||||
|
||||
v->next = current_common;
|
||||
current_common = current_segment;
|
||||
current_segment = NULL;
|
||||
/* Add these to the common block. */
|
||||
current_common = add_segments (current_common, current_segment);
|
||||
}
|
||||
|
||||
|
||||
@ -651,36 +756,27 @@ finish_equivalences (gfc_namespace *ns)
|
||||
gfc_equiv *z, *y;
|
||||
gfc_symbol *sym;
|
||||
segment_info *v;
|
||||
int min_offset;
|
||||
HOST_WIDE_INT min_offset;
|
||||
|
||||
for (z = ns->equiv; z; z = z->next)
|
||||
for (y= z->eq; y; y = y->eq)
|
||||
{
|
||||
if (y->used) continue;
|
||||
sym = z->expr->symtree->n.sym;
|
||||
current_length = 0;
|
||||
current_segment = get_segment_info ();
|
||||
current_segment->sym = sym;
|
||||
current_segment->offset = 0;
|
||||
current_segment->length = calculate_length (sym);
|
||||
sym->mark = 1;
|
||||
|
||||
/* All object directly or indrectly equivalenced with this symbol. */
|
||||
while (add_equivalences ());
|
||||
/* All objects directly or indrectly equivalenced with this symbol. */
|
||||
add_equivalences ();
|
||||
|
||||
/* Calculate the minimal offset. */
|
||||
min_offset = 0;
|
||||
for (v = current_segment; v; v = v->next)
|
||||
min_offset = (min_offset >= v->offset) ? v->offset : min_offset;
|
||||
min_offset = current_segment->offset;
|
||||
|
||||
/* Adjust the offset of each equivalence object, and calculate the
|
||||
maximal storage size to hold them. */
|
||||
/* Adjust the offset of each equivalence object. */
|
||||
for (v = current_segment; v; v = v->next)
|
||||
{
|
||||
v->offset -= min_offset;
|
||||
if (current_length < (v->offset + v->length))
|
||||
current_length = v->offset + v->length;
|
||||
}
|
||||
v->offset -= min_offset;
|
||||
|
||||
current_common = current_segment;
|
||||
create_common (NULL);
|
||||
@ -697,22 +793,13 @@ translate_common (gfc_symbol *common_sym, gfc_symbol *var_list)
|
||||
gfc_symbol *sym;
|
||||
|
||||
current_common = NULL;
|
||||
current_length = 0;
|
||||
current_offset = 0;
|
||||
|
||||
/* Mark bits indicate which symbols have already been placed in a
|
||||
common area. */
|
||||
/* Add symbols to the segment. */
|
||||
for (sym = var_list; sym; sym = sym->common_next)
|
||||
sym->mark = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (sym = var_list; sym; sym = sym->common_next)
|
||||
if (!sym->mark) break;
|
||||
|
||||
/* All symbols have been placed in a common. */
|
||||
if (sym == NULL) break;
|
||||
new_segment (common_sym, sym);
|
||||
if (! sym->equiv_built)
|
||||
new_segment (common_sym, sym);
|
||||
}
|
||||
|
||||
create_common (common_sym);
|
||||
|
@ -1,3 +1,9 @@
|
||||
2004-05-23 Paul Brook <paul@codesourcery.com>
|
||||
Victor Leikehman <lei@haifasphere.co.il>
|
||||
|
||||
* gfortran.fortran-torture/execute/common_init_1.f90: New test.
|
||||
* gfortran.fortran-torture/execute/equiv_init.f90: New test.
|
||||
|
||||
2004-05-22 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/15285
|
||||
|
@ -0,0 +1,24 @@
|
||||
! Program to test initialization of common blocks.
|
||||
subroutine test()
|
||||
character(len=15) :: c
|
||||
integer d, e
|
||||
real f
|
||||
common /block2/ c
|
||||
common /block/ d, e, f
|
||||
|
||||
if ((d .ne. 42) .or. (e .ne. 43) .or. (f .ne. 2.0)) call abort ()
|
||||
if (c .ne. "Hello World ") call abort ()
|
||||
end subroutine
|
||||
|
||||
program prog
|
||||
integer a(2)
|
||||
real b
|
||||
character(len=15) :: s
|
||||
common /block/ a, b
|
||||
common /block2/ s
|
||||
data b, a/2.0, 42, 43/
|
||||
data s /"Hello World"/
|
||||
|
||||
call test ()
|
||||
end program
|
||||
|
@ -0,0 +1,94 @@
|
||||
! Program to test initialization of equivalence blocks. PR13742.
|
||||
! Some forms are not yet implemented. These are indicated by !!$
|
||||
|
||||
subroutine test0s
|
||||
character*10 :: x = "abcdefghij"
|
||||
character*10 :: y
|
||||
equivalence (x,y)
|
||||
|
||||
character*10 :: xs(10)
|
||||
character*10 :: ys(10)
|
||||
equivalence (xs,ys)
|
||||
data xs /10*"abcdefghij"/
|
||||
|
||||
if (y.ne."abcdefghij") call abort
|
||||
if (ys(1).ne."abcdefghij") call abort
|
||||
if (ys(10).ne."abcdefghij") call abort
|
||||
end
|
||||
|
||||
subroutine test0
|
||||
integer :: x = 123
|
||||
integer :: y
|
||||
equivalence (x,y)
|
||||
if (y.ne.123) call abort
|
||||
end
|
||||
|
||||
subroutine test1
|
||||
integer :: a(3)
|
||||
integer :: x = 1
|
||||
integer :: y
|
||||
integer :: z = 3
|
||||
equivalence (a(1), x)
|
||||
equivalence (a(3), z)
|
||||
if (x.ne.1) call abort
|
||||
if (z.ne.3) call abort
|
||||
if (a(1).ne.1) call abort
|
||||
if (a(3).ne.3) call abort
|
||||
end
|
||||
|
||||
subroutine test2
|
||||
integer :: x
|
||||
integer :: z
|
||||
integer :: a(3) = 123
|
||||
equivalence (a(1), x)
|
||||
equivalence (a(3), z)
|
||||
if (x.ne.123) call abort
|
||||
if (z.ne.123) call abort
|
||||
end
|
||||
|
||||
subroutine test3
|
||||
integer :: x
|
||||
!!$ integer :: y = 2
|
||||
integer :: z
|
||||
integer :: a(3)
|
||||
equivalence (a(1),x), (a(2),y), (a(3),z)
|
||||
data a(1) /1/, a(3) /3/
|
||||
if (x.ne.1) call abort
|
||||
!!$ if (y.ne.2) call abort
|
||||
if (z.ne.3) call abort
|
||||
end
|
||||
|
||||
subroutine test4
|
||||
integer a(2)
|
||||
integer b(2)
|
||||
integer c
|
||||
equivalence (a(2),b(1)), (b(2),c)
|
||||
data a/1,2/
|
||||
data c/3/
|
||||
if (b(1).ne.2) call abort
|
||||
if (b(2).ne.3) call abort
|
||||
end
|
||||
|
||||
!!$subroutine test5
|
||||
!!$ integer a(2)
|
||||
!!$ integer b(2)
|
||||
!!$ integer c
|
||||
!!$ equivalence (a(2),b(1)), (b(2),c)
|
||||
!!$ data a(1)/1/
|
||||
!!$ data b(1)/2/
|
||||
!!$ data c/3/
|
||||
!!$ if (a(2).ne.2) call abort
|
||||
!!$ if (b(2).ne.3) call abort
|
||||
!!$ print *, "Passed test5"
|
||||
!!$end
|
||||
|
||||
program main
|
||||
call test0s
|
||||
call test0
|
||||
call test1
|
||||
call test2
|
||||
call test3
|
||||
call test4
|
||||
!!$ call test5
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user