1445 lines
43 KiB
C
1445 lines
43 KiB
C
|
/* equiv.c -- Implementation File (module.c template V1.0)
|
|||
|
Copyright (C) 1995-1997 Free Software Foundation, Inc.
|
|||
|
Contributed by James Craig Burley (burley@gnu.ai.mit.edu).
|
|||
|
|
|||
|
This file is part of GNU Fortran.
|
|||
|
|
|||
|
GNU Fortran is free software; you can redistribute it and/or modify
|
|||
|
it under the terms of the GNU General Public License as published by
|
|||
|
the Free Software Foundation; either version 2, or (at your option)
|
|||
|
any later version.
|
|||
|
|
|||
|
GNU Fortran is distributed in the hope that it will be useful,
|
|||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
GNU General Public License for more details.
|
|||
|
|
|||
|
You should have received a copy of the GNU General Public License
|
|||
|
along with GNU Fortran; see the file COPYING. If not, write to
|
|||
|
the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
|
02111-1307, USA.
|
|||
|
|
|||
|
Related Modules:
|
|||
|
None
|
|||
|
|
|||
|
Description:
|
|||
|
Handles the EQUIVALENCE relationships in a program unit.
|
|||
|
|
|||
|
Modifications:
|
|||
|
*/
|
|||
|
|
|||
|
#define FFEEQUIV_DEBUG 0
|
|||
|
|
|||
|
/* Include files. */
|
|||
|
|
|||
|
#include "proj.h"
|
|||
|
#include "equiv.h"
|
|||
|
#include "bad.h"
|
|||
|
#include "bld.h"
|
|||
|
#include "com.h"
|
|||
|
#include "data.h"
|
|||
|
#include "global.h"
|
|||
|
#include "lex.h"
|
|||
|
#include "malloc.h"
|
|||
|
#include "symbol.h"
|
|||
|
|
|||
|
/* Externals defined here. */
|
|||
|
|
|||
|
|
|||
|
/* Simple definitions and enumerations. */
|
|||
|
|
|||
|
|
|||
|
/* Internal typedefs. */
|
|||
|
|
|||
|
|
|||
|
/* Private include files. */
|
|||
|
|
|||
|
|
|||
|
/* Internal structure definitions. */
|
|||
|
|
|||
|
struct _ffeequiv_list_
|
|||
|
{
|
|||
|
ffeequiv first;
|
|||
|
ffeequiv last;
|
|||
|
};
|
|||
|
|
|||
|
/* Static objects accessed by functions in this module. */
|
|||
|
|
|||
|
static struct _ffeequiv_list_ ffeequiv_list_;
|
|||
|
|
|||
|
/* Static functions (internal). */
|
|||
|
|
|||
|
static void ffeequiv_destroy_ (ffeequiv eq);
|
|||
|
static void ffeequiv_layout_local_ (ffeequiv eq);
|
|||
|
static bool ffeequiv_offset_ (ffetargetOffset *offset, ffesymbol s,
|
|||
|
ffebld expr, bool subtract,
|
|||
|
ffetargetOffset adjust, bool no_precede);
|
|||
|
|
|||
|
/* Internal macros. */
|
|||
|
|
|||
|
|
|||
|
static void
|
|||
|
ffeequiv_destroy_ (ffeequiv victim)
|
|||
|
{
|
|||
|
ffebld list;
|
|||
|
ffebld item;
|
|||
|
ffebld expr;
|
|||
|
|
|||
|
for (list = victim->list; list != NULL; list = ffebld_trail (list))
|
|||
|
{
|
|||
|
for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
ffesymbol sym;
|
|||
|
|
|||
|
expr = ffebld_head (item);
|
|||
|
sym = ffeequiv_symbol (expr);
|
|||
|
if (sym == NULL)
|
|||
|
continue;
|
|||
|
if (ffesymbol_equiv (sym) != NULL)
|
|||
|
ffesymbol_set_equiv (sym, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
ffeequiv_kill (victim);
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_layout_local_ -- Lay out storage for local equivalenced vars
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffeequiv_layout_local_(eq);
|
|||
|
|
|||
|
Makes a single master ffestorag object that contains all the vars
|
|||
|
in the equivalence, and makes subordinate ffestorag objects for the
|
|||
|
vars with the correct offsets.
|
|||
|
|
|||
|
The resulting var offsets are relative not necessarily to 0 -- the
|
|||
|
are relative to the offset of the master area, which might be 0 or
|
|||
|
negative, but should never be positive. */
|
|||
|
|
|||
|
static void
|
|||
|
ffeequiv_layout_local_ (ffeequiv eq)
|
|||
|
{
|
|||
|
ffestorag st; /* Equivalence storage area. */
|
|||
|
ffebld list; /* List of list of equivalences. */
|
|||
|
ffebld item; /* List of equivalences. */
|
|||
|
ffebld root_exp; /* Expression for root sym. */
|
|||
|
ffestorag root_st; /* Storage for root. */
|
|||
|
ffesymbol root_sym; /* Root itself. */
|
|||
|
ffebld rooted_exp; /* Expression for rooted sym in an eqlist. */
|
|||
|
ffestorag rooted_st; /* Storage for rooted. */
|
|||
|
ffesymbol rooted_sym; /* Rooted symbol itself. */
|
|||
|
ffetargetOffset eqlist_offset;/* Offset for eqlist from rooted sym. */
|
|||
|
ffetargetAlign alignment;
|
|||
|
ffetargetAlign modulo;
|
|||
|
ffetargetAlign pad;
|
|||
|
ffetargetOffset size;
|
|||
|
ffetargetOffset num_elements;
|
|||
|
bool new_storage; /* Established new storage info. */
|
|||
|
bool need_storage; /* Have need for more storage info. */
|
|||
|
bool init;
|
|||
|
|
|||
|
assert (eq != NULL);
|
|||
|
|
|||
|
if (ffeequiv_common (eq) != NULL)
|
|||
|
{ /* Put in common due to programmer error. */
|
|||
|
ffeequiv_destroy_ (eq);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* Find the symbol for the first valid item in the list of lists, use that
|
|||
|
as the root symbol. Doesn't matter if it won't end up at the beginning
|
|||
|
of the list, though. */
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, "Equiv1:\n");
|
|||
|
#endif
|
|||
|
|
|||
|
root_sym = NULL;
|
|||
|
root_exp = NULL;
|
|||
|
|
|||
|
for (list = ffeequiv_list (eq);
|
|||
|
list != NULL;
|
|||
|
list = ffebld_trail (list))
|
|||
|
{ /* For every equivalence list in the list of
|
|||
|
equivs */
|
|||
|
for (item = ffebld_head (list);
|
|||
|
item != NULL;
|
|||
|
item = ffebld_trail (item))
|
|||
|
{ /* For every equivalence item in the list */
|
|||
|
ffetargetOffset ign; /* Ignored. */
|
|||
|
|
|||
|
root_exp = ffebld_head (item);
|
|||
|
root_sym = ffeequiv_symbol (root_exp);
|
|||
|
if (root_sym == NULL)
|
|||
|
continue; /* Ignore me. */
|
|||
|
|
|||
|
assert (ffesymbol_storage (root_sym) == NULL); /* No storage yet. */
|
|||
|
|
|||
|
if (!ffeequiv_offset_ (&ign, root_sym, root_exp, FALSE, 0, FALSE))
|
|||
|
{
|
|||
|
/* We can't just eliminate this one symbol from the list
|
|||
|
of candidates, because it might be the only one that
|
|||
|
ties all these equivs together. So just destroy the
|
|||
|
whole list. */
|
|||
|
|
|||
|
ffeequiv_destroy_ (eq);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
break; /* Use first valid eqv expr for root exp/sym. */
|
|||
|
}
|
|||
|
if (root_sym != NULL)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (root_sym == NULL)
|
|||
|
{
|
|||
|
ffeequiv_destroy_ (eq);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " Root: `%s'\n", ffesymbol_text (root_sym));
|
|||
|
#endif
|
|||
|
|
|||
|
/* We've got work to do, so make the LOCAL storage object that'll hold all
|
|||
|
the equivalenced vars inside it. */
|
|||
|
|
|||
|
st = ffestorag_new (ffestorag_list_master ());
|
|||
|
ffestorag_set_parent (st, NULL); /* Initializations happen here. */
|
|||
|
ffestorag_set_init (st, NULL);
|
|||
|
ffestorag_set_accretion (st, NULL);
|
|||
|
ffestorag_set_offset (st, 0); /* Assume equiv will be at root offset 0 for now. */
|
|||
|
ffestorag_set_alignment (st, 1);
|
|||
|
ffestorag_set_modulo (st, 0);
|
|||
|
ffestorag_set_type (st, FFESTORAG_typeLOCAL);
|
|||
|
ffestorag_set_basictype (st, ffesymbol_basictype (root_sym));
|
|||
|
ffestorag_set_kindtype (st, ffesymbol_kindtype (root_sym));
|
|||
|
ffestorag_set_typesymbol (st, root_sym);
|
|||
|
ffestorag_set_is_save (st, ffeequiv_is_save (eq));
|
|||
|
if (ffesymbol_is_save (root_sym))
|
|||
|
ffestorag_update_save (st);
|
|||
|
ffestorag_set_is_init (st, ffeequiv_is_init (eq));
|
|||
|
if (ffesymbol_is_init (root_sym))
|
|||
|
ffestorag_update_init (st);
|
|||
|
ffestorag_set_symbol (st, root_sym); /* Assume this will be the root until
|
|||
|
we know better (used only to generate
|
|||
|
the internal name for the aggregate area,
|
|||
|
e.g. for debugging). */
|
|||
|
|
|||
|
/* Make the EQUIV storage object for the root symbol. */
|
|||
|
|
|||
|
if (ffesymbol_rank (root_sym) == 0)
|
|||
|
num_elements = 1;
|
|||
|
else
|
|||
|
num_elements = ffebld_constant_integerdefault (ffebld_conter
|
|||
|
(ffesymbol_arraysize (root_sym)));
|
|||
|
ffetarget_layout (ffesymbol_text (root_sym), &alignment, &modulo, &size,
|
|||
|
ffesymbol_basictype (root_sym), ffesymbol_kindtype (root_sym),
|
|||
|
ffesymbol_size (root_sym), num_elements);
|
|||
|
ffestorag_set_size (st, size); /* Set initial size of aggregate area. */
|
|||
|
|
|||
|
pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
|
|||
|
ffestorag_ptr_to_modulo (st), 0, alignment,
|
|||
|
modulo);
|
|||
|
assert (pad == 0);
|
|||
|
|
|||
|
root_st = ffestorag_new (ffestorag_list_equivs (st));
|
|||
|
ffestorag_set_parent (root_st, st); /* Initializations happen there. */
|
|||
|
ffestorag_set_init (root_st, NULL);
|
|||
|
ffestorag_set_accretion (root_st, NULL);
|
|||
|
ffestorag_set_symbol (root_st, root_sym);
|
|||
|
ffestorag_set_size (root_st, size);
|
|||
|
ffestorag_set_offset (root_st, 0); /* Will not change; always 0 relative to itself! */
|
|||
|
ffestorag_set_alignment (root_st, alignment);
|
|||
|
ffestorag_set_modulo (root_st, modulo);
|
|||
|
ffestorag_set_type (root_st, FFESTORAG_typeEQUIV);
|
|||
|
ffestorag_set_basictype (root_st, ffesymbol_basictype (root_sym));
|
|||
|
ffestorag_set_kindtype (root_st, ffesymbol_kindtype (root_sym));
|
|||
|
ffestorag_set_typesymbol (root_st, root_sym);
|
|||
|
ffestorag_set_is_save (root_st, FALSE); /* Assume FALSE, then... */
|
|||
|
if (ffestorag_is_save (st)) /* ...update to TRUE if needed. */
|
|||
|
ffestorag_update_save (root_st);
|
|||
|
ffestorag_set_is_init (root_st, FALSE); /* Assume FALSE, then... */
|
|||
|
if (ffestorag_is_init (st)) /* ...update to TRUE if needed. */
|
|||
|
ffestorag_update_init (root_st);
|
|||
|
ffesymbol_set_storage (root_sym, root_st);
|
|||
|
ffesymbol_signal_unreported (root_sym);
|
|||
|
init = ffesymbol_is_init (root_sym);
|
|||
|
|
|||
|
/* Now that we know the root (offset=0) symbol, revisit all the lists and
|
|||
|
do the actual storage allocation. Keep doing this until we've gone
|
|||
|
through them all without making any new storage objects. */
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
new_storage = FALSE;
|
|||
|
need_storage = FALSE;
|
|||
|
for (list = ffeequiv_list (eq);
|
|||
|
list != NULL;
|
|||
|
list = ffebld_trail (list))
|
|||
|
{ /* For every equivalence list in the list of
|
|||
|
equivs */
|
|||
|
/* Now find a "rooted" symbol in this list. That is, find the
|
|||
|
first item we can that is valid and whose symbol already
|
|||
|
has a storage area, because that means we know where it
|
|||
|
belongs in the equivalence area and can then allocate the
|
|||
|
rest of the items in the list accordingly. */
|
|||
|
|
|||
|
rooted_sym = NULL;
|
|||
|
rooted_exp = NULL;
|
|||
|
eqlist_offset = 0;
|
|||
|
|
|||
|
for (item = ffebld_head (list);
|
|||
|
item != NULL;
|
|||
|
item = ffebld_trail (item))
|
|||
|
{ /* For every equivalence item in the list */
|
|||
|
rooted_exp = ffebld_head (item);
|
|||
|
rooted_sym = ffeequiv_symbol (rooted_exp);
|
|||
|
if ((rooted_sym == NULL)
|
|||
|
|| ((rooted_st = ffesymbol_storage (rooted_sym)) == NULL))
|
|||
|
{
|
|||
|
rooted_sym = NULL;
|
|||
|
continue; /* Ignore me. */
|
|||
|
}
|
|||
|
|
|||
|
need_storage = TRUE; /* Somebody is likely to need
|
|||
|
storage. */
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " Rooted: `%s' at %" ffetargetOffset_f "d\n",
|
|||
|
ffesymbol_text (rooted_sym),
|
|||
|
ffestorag_offset (rooted_st));
|
|||
|
#endif
|
|||
|
|
|||
|
/* The offset of this symbol from the equiv's root symbol
|
|||
|
is already known, and the size of this symbol is already
|
|||
|
incorporated in the size of the equiv's aggregate area.
|
|||
|
What we now determine is the offset of this equivalence
|
|||
|
_list_ from the equiv's root symbol.
|
|||
|
|
|||
|
For example, if we know that A is at offset 16 from the
|
|||
|
root symbol, given EQUIVALENCE (B(24),A(2)), we're looking
|
|||
|
at A(2), meaning that the offset for this equivalence list
|
|||
|
is 20 (4 bytes beyond the beginning of A, assuming typical
|
|||
|
array types, dimensions, and type info). */
|
|||
|
|
|||
|
if (!ffeequiv_offset_ (&eqlist_offset, rooted_sym, rooted_exp, FALSE,
|
|||
|
ffestorag_offset (rooted_st), FALSE))
|
|||
|
|
|||
|
{ /* Can't use this one. */
|
|||
|
ffesymbol_set_equiv (rooted_sym, NULL);/* Equiv area slated for
|
|||
|
death. */
|
|||
|
rooted_sym = NULL;
|
|||
|
continue; /* Something's wrong with eqv expr, try another. */
|
|||
|
}
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " Eqlist offset: %" ffetargetOffset_f "d\n",
|
|||
|
eqlist_offset);
|
|||
|
#endif
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/* If no rooted symbol, it means this list has no roots -- yet.
|
|||
|
So, forget this list this time around, but we'll get back
|
|||
|
to it after the outer loop iterates at least one more time,
|
|||
|
and, ultimately, it will have a root. */
|
|||
|
|
|||
|
if (rooted_sym == NULL)
|
|||
|
{
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, "No roots.\n");
|
|||
|
#endif
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* We now have a rooted symbol/expr and the offset of this equivalence
|
|||
|
list from the root symbol. The other expressions in this
|
|||
|
list all identify an initial storage unit that must have the
|
|||
|
same offset. */
|
|||
|
|
|||
|
for (item = ffebld_head (list);
|
|||
|
item != NULL;
|
|||
|
item = ffebld_trail (item))
|
|||
|
{ /* For every equivalence item in the list */
|
|||
|
ffebld item_exp; /* Expression for equivalence. */
|
|||
|
ffestorag item_st; /* Storage for var. */
|
|||
|
ffesymbol item_sym; /* Var itself. */
|
|||
|
ffetargetOffset item_offset; /* Offset for var from root. */
|
|||
|
|
|||
|
item_exp = ffebld_head (item);
|
|||
|
item_sym = ffeequiv_symbol (item_exp);
|
|||
|
if ((item_sym == NULL)
|
|||
|
|| (ffesymbol_equiv (item_sym) == NULL))
|
|||
|
continue; /* Ignore me. */
|
|||
|
|
|||
|
if (item_sym == rooted_sym)
|
|||
|
continue; /* Rooted sym already set up. */
|
|||
|
|
|||
|
if (!ffeequiv_offset_ (&item_offset, item_sym, item_exp, TRUE,
|
|||
|
eqlist_offset, FALSE))
|
|||
|
{
|
|||
|
ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " Item `%s' at %" ffetargetOffset_f "d",
|
|||
|
ffesymbol_text (item_sym), item_offset);
|
|||
|
#endif
|
|||
|
|
|||
|
if (ffesymbol_rank (item_sym) == 0)
|
|||
|
num_elements = 1;
|
|||
|
else
|
|||
|
num_elements = ffebld_constant_integerdefault (ffebld_conter
|
|||
|
(ffesymbol_arraysize (item_sym)));
|
|||
|
ffetarget_layout (ffesymbol_text (item_sym), &alignment, &modulo,
|
|||
|
&size, ffesymbol_basictype (item_sym),
|
|||
|
ffesymbol_kindtype (item_sym), ffesymbol_size (item_sym),
|
|||
|
num_elements);
|
|||
|
pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
|
|||
|
ffestorag_ptr_to_modulo (st),
|
|||
|
item_offset, alignment, modulo);
|
|||
|
if (pad != 0)
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_ALIGN);
|
|||
|
ffebad_string (ffesymbol_text (item_sym));
|
|||
|
ffebad_finish ();
|
|||
|
ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* If the variable's offset is less than the offset for the
|
|||
|
aggregate storage area, it means it has to expand backwards
|
|||
|
-- i.e. the new known starting point of the area precedes the
|
|||
|
old one. This can't happen with COMMON areas (the standard,
|
|||
|
and common sense, disallow it), but it is normal for local
|
|||
|
EQUIVALENCE areas.
|
|||
|
|
|||
|
Also handle choosing the "documented" rooted symbol for this
|
|||
|
area here. It's the symbol at the bottom (lowest offset)
|
|||
|
of the aggregate area, with ties going to the name that would
|
|||
|
sort to the top of the list of ties. */
|
|||
|
|
|||
|
if (item_offset == ffestorag_offset (st))
|
|||
|
{
|
|||
|
if ((item_sym != ffestorag_symbol (st))
|
|||
|
&& (strcmp (ffesymbol_text (item_sym),
|
|||
|
ffesymbol_text (ffestorag_symbol (st)))
|
|||
|
< 0))
|
|||
|
ffestorag_set_symbol (st, item_sym);
|
|||
|
}
|
|||
|
else if (item_offset < ffestorag_offset (st))
|
|||
|
{
|
|||
|
ffetargetOffset new_size;
|
|||
|
|
|||
|
/* Increase size of equiv area to start for lower offset relative
|
|||
|
to root symbol. */
|
|||
|
|
|||
|
if (!ffetarget_offset_add (&new_size,
|
|||
|
ffestorag_offset (st) - item_offset,
|
|||
|
ffestorag_size (st)))
|
|||
|
ffetarget_offset_overflow (ffesymbol_text (s));
|
|||
|
else
|
|||
|
ffestorag_set_size (st, new_size);
|
|||
|
|
|||
|
ffestorag_set_symbol (st, item_sym);
|
|||
|
ffestorag_set_offset (st, item_offset);
|
|||
|
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " [eq offset=%" ffetargetOffset_f
|
|||
|
"d, size=%" ffetargetOffset_f "d]",
|
|||
|
item_offset, new_size);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
if ((item_st = ffesymbol_storage (item_sym)) == NULL)
|
|||
|
{ /* Create new ffestorag object, extend equiv
|
|||
|
area. */
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, ".\n");
|
|||
|
#endif
|
|||
|
new_storage = TRUE;
|
|||
|
item_st = ffestorag_new (ffestorag_list_equivs (st));
|
|||
|
ffestorag_set_parent (item_st, st); /* Initializations
|
|||
|
happen there. */
|
|||
|
ffestorag_set_init (item_st, NULL);
|
|||
|
ffestorag_set_accretion (item_st, NULL);
|
|||
|
ffestorag_set_symbol (item_st, item_sym);
|
|||
|
ffestorag_set_size (item_st, size);
|
|||
|
ffestorag_set_offset (item_st, item_offset);
|
|||
|
ffestorag_set_alignment (item_st, alignment);
|
|||
|
ffestorag_set_modulo (item_st, modulo);
|
|||
|
ffestorag_set_type (item_st, FFESTORAG_typeEQUIV);
|
|||
|
ffestorag_set_basictype (item_st, ffesymbol_basictype (item_sym));
|
|||
|
ffestorag_set_kindtype (item_st, ffesymbol_kindtype (item_sym));
|
|||
|
ffestorag_set_typesymbol (item_st, item_sym);
|
|||
|
ffestorag_set_is_save (item_st, FALSE); /* Assume FALSE... */
|
|||
|
if (ffestorag_is_save (st)) /* ...update TRUE */
|
|||
|
ffestorag_update_save (item_st); /* if needed. */
|
|||
|
ffestorag_set_is_init (item_st, FALSE); /* Assume FALSE... */
|
|||
|
if (ffestorag_is_init (st)) /* ...update TRUE */
|
|||
|
ffestorag_update_init (item_st); /* if needed. */
|
|||
|
ffesymbol_set_storage (item_sym, item_st);
|
|||
|
ffesymbol_signal_unreported (item_sym);
|
|||
|
if (ffesymbol_is_init (item_sym))
|
|||
|
init = TRUE;
|
|||
|
|
|||
|
/* Determine new size of equiv area, complain if overflow. */
|
|||
|
|
|||
|
if (!ffetarget_offset_add (&size, item_offset, size)
|
|||
|
|| !ffetarget_offset_add (&size, -ffestorag_offset (st), size))
|
|||
|
ffetarget_offset_overflow (ffesymbol_text (s));
|
|||
|
else if (size > ffestorag_size (st))
|
|||
|
ffestorag_set_size (st, size);
|
|||
|
ffestorag_update (st, item_sym, ffesymbol_basictype (item_sym),
|
|||
|
ffesymbol_kindtype (item_sym));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if FFEEQUIV_DEBUG
|
|||
|
fprintf (stderr, " (was %" ffetargetOffset_f "d).\n",
|
|||
|
ffestorag_offset (item_st));
|
|||
|
#endif
|
|||
|
/* Make sure offset agrees with known offset. */
|
|||
|
if (item_offset != ffestorag_offset (item_st))
|
|||
|
{
|
|||
|
char io1[40];
|
|||
|
char io2[40];
|
|||
|
|
|||
|
sprintf (&io1[0], "%" ffetargetOffset_f "d", item_offset);
|
|||
|
sprintf (&io2[0], "%" ffetargetOffset_f "d", ffestorag_offset (item_st));
|
|||
|
ffebad_start (FFEBAD_EQUIV_MISMATCH);
|
|||
|
ffebad_string (ffesymbol_text (item_sym));
|
|||
|
ffebad_string (ffesymbol_text (root_sym));
|
|||
|
ffebad_string (io1);
|
|||
|
ffebad_string (io2);
|
|||
|
ffebad_finish ();
|
|||
|
}
|
|||
|
}
|
|||
|
ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
|
|||
|
} /* (For every equivalence item in the list) */
|
|||
|
ffebld_set_head (list, NULL); /* Don't do this list again. */
|
|||
|
} /* (For every equivalence list in the list of
|
|||
|
equivs) */
|
|||
|
} while (new_storage && need_storage);
|
|||
|
|
|||
|
ffesymbol_set_equiv (root_sym, NULL); /* This one has storage now. */
|
|||
|
|
|||
|
ffeequiv_kill (eq); /* Fully processed, no longer needed. */
|
|||
|
|
|||
|
if (init)
|
|||
|
ffedata_gather (st); /* Gather subordinate inits into one init. */
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_offset_ -- Determine offset from start of symbol
|
|||
|
|
|||
|
ffetargetOffset offset;
|
|||
|
ffesymbol s; // Symbol for error reporting.
|
|||
|
ffebld expr; // opSUBSTR, opARRAYREF, opSYMTER, opANY.
|
|||
|
bool subtract; // FALSE means add to adjust, TRUE means subtract from it.
|
|||
|
ffetargetOffset adjust; // Helps keep answer in pos range (unsigned).
|
|||
|
if (!ffeequiv_offset_(&offset,s,expr,subtract,adjust))
|
|||
|
// error doing the calculation, message already printed
|
|||
|
|
|||
|
Returns the offset represented by the SUBSTR, ARRAYREF, or SUBSTR/ARRAYREF
|
|||
|
combination added-to/subtracted-from the adjustment specified. If there
|
|||
|
is an error of some kind, returns FALSE, else returns TRUE. Note that
|
|||
|
only the first storage unit specified is considered; A(1:1) and A(1:2000)
|
|||
|
have the same first storage unit and so return the same offset. */
|
|||
|
|
|||
|
static bool
|
|||
|
ffeequiv_offset_ (ffetargetOffset *offset, ffesymbol s UNUSED,
|
|||
|
ffebld expr, bool subtract, ffetargetOffset adjust,
|
|||
|
bool no_precede)
|
|||
|
{
|
|||
|
ffetargetIntegerDefault value = 0;
|
|||
|
ffetargetOffset cval; /* Converted value. */
|
|||
|
ffesymbol sym;
|
|||
|
|
|||
|
if (expr == NULL)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
again: /* :::::::::::::::::::: */
|
|||
|
|
|||
|
switch (ffebld_op (expr))
|
|||
|
{
|
|||
|
case FFEBLD_opANY:
|
|||
|
return FALSE;
|
|||
|
|
|||
|
case FFEBLD_opSYMTER:
|
|||
|
{
|
|||
|
ffetargetOffset size; /* Size of a single unit. */
|
|||
|
ffetargetAlign a; /* Ignored. */
|
|||
|
ffetargetAlign m; /* Ignored. */
|
|||
|
|
|||
|
sym = ffebld_symter (expr);
|
|||
|
if (ffesymbol_basictype (sym) == FFEINFO_basictypeANY)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
ffetarget_layout (ffesymbol_text (sym), &a, &m, &size,
|
|||
|
ffesymbol_basictype (sym),
|
|||
|
ffesymbol_kindtype (sym), 1, 1);
|
|||
|
|
|||
|
if (value < 0)
|
|||
|
{ /* Really invalid, as in A(-2:5), but in case
|
|||
|
it's wanted.... */
|
|||
|
if (!ffetarget_offset (&cval, -value))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (!ffetarget_offset_multiply (&cval, cval, size))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (subtract)
|
|||
|
return ffetarget_offset_add (offset, cval, adjust);
|
|||
|
|
|||
|
if (no_precede && (cval > adjust))
|
|||
|
{
|
|||
|
neg: /* :::::::::::::::::::: */
|
|||
|
ffebad_start (FFEBAD_COMMON_NEG);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_finish ();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
return ffetarget_offset_add (offset, -cval, adjust);
|
|||
|
}
|
|||
|
|
|||
|
if (!ffetarget_offset (&cval, value))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (!ffetarget_offset_multiply (&cval, cval, size))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (!subtract)
|
|||
|
return ffetarget_offset_add (offset, cval, adjust);
|
|||
|
|
|||
|
if (no_precede && (cval > adjust))
|
|||
|
goto neg; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
return ffetarget_offset_add (offset, -cval, adjust);
|
|||
|
}
|
|||
|
|
|||
|
case FFEBLD_opARRAYREF:
|
|||
|
{
|
|||
|
ffebld symexp = ffebld_left (expr);
|
|||
|
ffebld subscripts = ffebld_right (expr);
|
|||
|
ffebld dims;
|
|||
|
ffetargetIntegerDefault width;
|
|||
|
ffetargetIntegerDefault arrayval;
|
|||
|
ffetargetIntegerDefault lowbound;
|
|||
|
ffetargetIntegerDefault highbound;
|
|||
|
ffebld subscript;
|
|||
|
ffebld dim;
|
|||
|
ffebld low;
|
|||
|
ffebld high;
|
|||
|
int rank = 0;
|
|||
|
|
|||
|
if (ffebld_op (symexp) != FFEBLD_opSYMTER)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
sym = ffebld_symter (symexp);
|
|||
|
if (ffesymbol_basictype (sym) == FFEINFO_basictypeANY)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (ffesymbol_size (sym) == FFETARGET_charactersizeNONE)
|
|||
|
width = 1;
|
|||
|
else
|
|||
|
width = ffesymbol_size (sym);
|
|||
|
dims = ffesymbol_dims (sym);
|
|||
|
|
|||
|
while (subscripts != NULL)
|
|||
|
{
|
|||
|
++rank;
|
|||
|
if (dims == NULL)
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_MANY);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_finish ();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
subscript = ffebld_head (subscripts);
|
|||
|
dim = ffebld_head (dims);
|
|||
|
|
|||
|
assert (ffebld_op (subscript) == FFEBLD_opCONTER);
|
|||
|
assert (ffeinfo_basictype (ffebld_info (subscript))
|
|||
|
== FFEINFO_basictypeINTEGER);
|
|||
|
assert (ffeinfo_kindtype (ffebld_info (subscript))
|
|||
|
== FFEINFO_kindtypeINTEGERDEFAULT);
|
|||
|
arrayval = ffebld_constant_integerdefault (ffebld_conter
|
|||
|
(subscript));
|
|||
|
|
|||
|
assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
|
|||
|
low = ffebld_left (dim);
|
|||
|
high = ffebld_right (dim);
|
|||
|
|
|||
|
if (low == NULL)
|
|||
|
lowbound = 1;
|
|||
|
else
|
|||
|
{
|
|||
|
assert (ffeinfo_basictype (ffebld_info (low))
|
|||
|
== FFEINFO_basictypeINTEGER);
|
|||
|
assert (ffeinfo_kindtype (ffebld_info (low))
|
|||
|
== FFEINFO_kindtypeINTEGERDEFAULT);
|
|||
|
lowbound
|
|||
|
= ffebld_constant_integerdefault (ffebld_conter (low));
|
|||
|
}
|
|||
|
|
|||
|
assert (ffebld_op (high) == FFEBLD_opCONTER);
|
|||
|
assert (ffeinfo_basictype (ffebld_info (high))
|
|||
|
== FFEINFO_basictypeINTEGER);
|
|||
|
assert (ffeinfo_kindtype (ffebld_info (high))
|
|||
|
== FFEINFO_kindtypeINTEGER1);
|
|||
|
highbound
|
|||
|
= ffebld_constant_integerdefault (ffebld_conter (high));
|
|||
|
|
|||
|
if ((arrayval < lowbound) || (arrayval > highbound))
|
|||
|
{
|
|||
|
char rankstr[10];
|
|||
|
|
|||
|
sprintf (rankstr, "%d", rank);
|
|||
|
ffebad_start (FFEBAD_EQUIV_SUBSCRIPT);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_string (rankstr);
|
|||
|
ffebad_finish ();
|
|||
|
}
|
|||
|
|
|||
|
subscripts = ffebld_trail (subscripts);
|
|||
|
dims = ffebld_trail (dims);
|
|||
|
|
|||
|
value += width * (arrayval - lowbound);
|
|||
|
if (subscripts != NULL)
|
|||
|
width *= highbound - lowbound + 1;
|
|||
|
}
|
|||
|
|
|||
|
if (dims != NULL)
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_FEW);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_finish ();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
expr = symexp;
|
|||
|
}
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
case FFEBLD_opSUBSTR:
|
|||
|
{
|
|||
|
ffebld begin = ffebld_head (ffebld_right (expr));
|
|||
|
|
|||
|
expr = ffebld_left (expr);
|
|||
|
if (ffebld_op (expr) == FFEBLD_opARRAYREF)
|
|||
|
sym = ffebld_symter (ffebld_left (expr));
|
|||
|
else if (ffebld_op (expr) == FFEBLD_opSYMTER)
|
|||
|
sym = ffebld_symter (expr);
|
|||
|
else
|
|||
|
sym = NULL;
|
|||
|
|
|||
|
if ((sym != NULL)
|
|||
|
&& (ffesymbol_basictype (sym) == FFEINFO_basictypeANY))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (begin == NULL)
|
|||
|
value = 0;
|
|||
|
else
|
|||
|
{
|
|||
|
assert (ffebld_op (begin) == FFEBLD_opCONTER);
|
|||
|
assert (ffeinfo_basictype (ffebld_info (begin))
|
|||
|
== FFEINFO_basictypeINTEGER);
|
|||
|
assert (ffeinfo_kindtype (ffebld_info (begin))
|
|||
|
== FFEINFO_kindtypeINTEGERDEFAULT);
|
|||
|
|
|||
|
value = ffebld_constant_integerdefault (ffebld_conter (begin));
|
|||
|
|
|||
|
if ((value < 1)
|
|||
|
|| ((sym != NULL)
|
|||
|
&& (value > ffesymbol_size (sym))))
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_RANGE);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_finish ();
|
|||
|
}
|
|||
|
|
|||
|
--value;
|
|||
|
}
|
|||
|
if ((sym != NULL)
|
|||
|
&& (ffesymbol_basictype (sym) != FFEINFO_basictypeCHARACTER))
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_SUBSTR);
|
|||
|
ffebad_string (ffesymbol_text (sym));
|
|||
|
ffebad_finish ();
|
|||
|
value = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
default:
|
|||
|
assert ("bad op" == NULL);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_add -- Add list of equivalences to list of lists for eq object
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffebld list;
|
|||
|
ffelexToken t; // points to first item in equivalence list
|
|||
|
ffeequiv_add(eq,list,t);
|
|||
|
|
|||
|
Check the list to make sure only one common symbol is involved (even
|
|||
|
if multiple times) and agrees with the common symbol for the equivalence
|
|||
|
object (or it has no common symbol until now). Prepend (or append, it
|
|||
|
doesn't matter) the list to the list of lists for the equivalence object.
|
|||
|
Otherwise report an error and return. */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_add (ffeequiv eq, ffebld list, ffelexToken t)
|
|||
|
{
|
|||
|
ffebld item;
|
|||
|
ffesymbol symbol;
|
|||
|
ffesymbol common = ffeequiv_common (eq);
|
|||
|
|
|||
|
for (item = list; item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
symbol = ffeequiv_symbol (ffebld_head (item));
|
|||
|
|
|||
|
if (ffesymbol_common (symbol) != NULL) /* Is symbol known in COMMON yet? */
|
|||
|
{
|
|||
|
if (common == NULL)
|
|||
|
common = ffesymbol_common (symbol);
|
|||
|
else if (common != ffesymbol_common (symbol))
|
|||
|
{
|
|||
|
/* Yes, and symbol disagrees with others on the COMMON area. */
|
|||
|
ffebad_start (FFEBAD_EQUIV_COMMON);
|
|||
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|||
|
ffebad_string (ffesymbol_text (common));
|
|||
|
ffebad_string (ffesymbol_text (ffesymbol_common (symbol)));
|
|||
|
ffebad_finish ();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((common != NULL)
|
|||
|
&& (ffeequiv_common (eq) == NULL)) /* Is COMMON involved already? */
|
|||
|
ffeequiv_set_common (eq, common); /* No, but it is now. */
|
|||
|
|
|||
|
for (item = list; item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
symbol = ffeequiv_symbol (ffebld_head (item));
|
|||
|
|
|||
|
if (ffesymbol_equiv (symbol) == NULL)
|
|||
|
ffesymbol_set_equiv (symbol, eq);
|
|||
|
else
|
|||
|
assert (ffesymbol_equiv (symbol) == eq);
|
|||
|
|
|||
|
if (ffesymbol_common (symbol) == NULL) /* Is symbol in a COMMON
|
|||
|
area? */
|
|||
|
{ /* No (at least not yet). */
|
|||
|
if (ffesymbol_is_save (symbol))
|
|||
|
ffeequiv_update_save (eq); /* EQUIVALENCE has >=1 SAVEd entity. */
|
|||
|
if (ffesymbol_is_init (symbol))
|
|||
|
ffeequiv_update_init (eq); /* EQUIVALENCE has >=1 init'd entity. */
|
|||
|
continue; /* Nothing more to do here. */
|
|||
|
}
|
|||
|
|
|||
|
#if FFEGLOBAL_ENABLED
|
|||
|
if (ffesymbol_is_init (symbol))
|
|||
|
ffeglobal_init_common (ffesymbol_common (symbol), t);
|
|||
|
#endif
|
|||
|
|
|||
|
if (ffesymbol_is_save (ffesymbol_common (symbol)))
|
|||
|
ffeequiv_update_save (eq); /* EQUIVALENCE is in a SAVEd COMMON block. */
|
|||
|
if (ffesymbol_is_init (ffesymbol_common (symbol)))
|
|||
|
ffeequiv_update_init (eq); /* EQUIVALENCE is in a init'd COMMON block. */
|
|||
|
}
|
|||
|
|
|||
|
ffeequiv_set_list (eq, ffebld_new_item (list, ffeequiv_list (eq)));
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_dump -- Dump info on equivalence object
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffeequiv_dump(eq); */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_dump (ffeequiv eq)
|
|||
|
{
|
|||
|
if (ffeequiv_common (eq) != NULL)
|
|||
|
fprintf (dmpout, "(common %s) ", ffesymbol_text (ffeequiv_common (eq)));
|
|||
|
ffebld_dump (ffeequiv_list (eq));
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_exec_transition -- Do the hard work on all the equivalence objects
|
|||
|
|
|||
|
ffeequiv_exec_transition(); */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_exec_transition ()
|
|||
|
{
|
|||
|
while (ffeequiv_list_.first != (ffeequiv) &ffeequiv_list_.first)
|
|||
|
ffeequiv_layout_local_ (ffeequiv_list_.first);
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_init_2 -- Initialize for new program unit
|
|||
|
|
|||
|
ffeequiv_init_2();
|
|||
|
|
|||
|
Initializes the list of equivalences. */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_init_2 ()
|
|||
|
{
|
|||
|
ffeequiv_list_.first = (ffeequiv) &ffeequiv_list_.first;
|
|||
|
ffeequiv_list_.last = (ffeequiv) &ffeequiv_list_.first;
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_kill -- Kill equivalence object after removing from list
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffeequiv_kill(eq);
|
|||
|
|
|||
|
Removes equivalence object from master list, then kills it. */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_kill (ffeequiv victim)
|
|||
|
{
|
|||
|
victim->next->previous = victim->previous;
|
|||
|
victim->previous->next = victim->next;
|
|||
|
if (ffe_is_do_internal_checks ())
|
|||
|
{
|
|||
|
ffebld list;
|
|||
|
ffebld item;
|
|||
|
ffebld expr;
|
|||
|
|
|||
|
/* Assert that nobody our victim points to still points to it. */
|
|||
|
|
|||
|
assert ((victim->common == NULL)
|
|||
|
|| (ffesymbol_equiv (victim->common) == NULL));
|
|||
|
|
|||
|
for (list = victim->list; list != NULL; list = ffebld_trail (list))
|
|||
|
{
|
|||
|
for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
ffesymbol sym;
|
|||
|
|
|||
|
expr = ffebld_head (item);
|
|||
|
sym = ffeequiv_symbol (expr);
|
|||
|
if (sym == NULL)
|
|||
|
continue;
|
|||
|
assert (ffesymbol_equiv (sym) != victim);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
malloc_kill_ks (ffe_pool_program_unit (), victim, sizeof (*victim));
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_layout_cblock -- Lay out storage for common area
|
|||
|
|
|||
|
ffestorag st;
|
|||
|
if (ffeequiv_layout_cblock(st))
|
|||
|
// at least one equiv'd symbol has init/accretion expr.
|
|||
|
|
|||
|
Now that the explicitly COMMONed variables in the common area (whose
|
|||
|
ffestorag object is passed) have been laid out, lay out the storage
|
|||
|
for all variables equivalenced into the area by making subordinate
|
|||
|
ffestorag objects for them. */
|
|||
|
|
|||
|
bool
|
|||
|
ffeequiv_layout_cblock (ffestorag st)
|
|||
|
{
|
|||
|
ffesymbol s = ffestorag_symbol (st); /* CBLOCK symbol. */
|
|||
|
ffebld list; /* List of explicit common vars, in order, in
|
|||
|
s. */
|
|||
|
ffebld item; /* List of list of equivalences in a given
|
|||
|
explicit common var. */
|
|||
|
ffebld root; /* Expression for (1st) explicit common var
|
|||
|
in list of eqs. */
|
|||
|
ffestorag rst; /* Storage for root. */
|
|||
|
ffetargetOffset root_offset; /* Offset for root into common area. */
|
|||
|
ffesymbol sr; /* Root itself. */
|
|||
|
ffeequiv seq; /* Its equivalence object, if any. */
|
|||
|
ffebld var; /* Expression for equivalence. */
|
|||
|
ffestorag vst; /* Storage for var. */
|
|||
|
ffetargetOffset var_offset; /* Offset for var into common area. */
|
|||
|
ffesymbol sv; /* Var itself. */
|
|||
|
ffebld altroot; /* Alternate root. */
|
|||
|
ffesymbol altrootsym; /* Alternate root symbol. */
|
|||
|
ffetargetAlign alignment;
|
|||
|
ffetargetAlign modulo;
|
|||
|
ffetargetAlign pad;
|
|||
|
ffetargetOffset size;
|
|||
|
ffetargetOffset num_elements;
|
|||
|
bool new_storage; /* Established new storage info. */
|
|||
|
bool need_storage; /* Have need for more storage info. */
|
|||
|
bool ok;
|
|||
|
bool init = FALSE;
|
|||
|
|
|||
|
assert (st != NULL);
|
|||
|
assert (ffestorag_type (st) == FFESTORAG_typeCBLOCK);
|
|||
|
assert (ffesymbol_kind (ffestorag_symbol (st)) == FFEINFO_kindCOMMON);
|
|||
|
|
|||
|
for (list = ffesymbol_commonlist (ffestorag_symbol (st));
|
|||
|
list != NULL;
|
|||
|
list = ffebld_trail (list))
|
|||
|
{ /* For every variable in the common area */
|
|||
|
assert (ffebld_op (ffebld_head (list)) == FFEBLD_opSYMTER);
|
|||
|
sr = ffebld_symter (ffebld_head (list));
|
|||
|
if ((seq = ffesymbol_equiv (sr)) == NULL)
|
|||
|
continue; /* No equivalences to process. */
|
|||
|
rst = ffesymbol_storage (sr);
|
|||
|
if (rst == NULL)
|
|||
|
{
|
|||
|
assert (ffesymbol_kind (sr) == FFEINFO_kindANY);
|
|||
|
continue;
|
|||
|
}
|
|||
|
ffesymbol_set_equiv (sr, NULL); /* Cancel ref to equiv obj. */
|
|||
|
do
|
|||
|
{
|
|||
|
new_storage = FALSE;
|
|||
|
need_storage = FALSE;
|
|||
|
for (item = ffeequiv_list (seq); /* Get list of equivs. */
|
|||
|
item != NULL;
|
|||
|
item = ffebld_trail (item))
|
|||
|
{ /* For every eqv list in the list of equivs
|
|||
|
for the variable */
|
|||
|
altroot = NULL;
|
|||
|
altrootsym = NULL;
|
|||
|
for (root = ffebld_head (item);
|
|||
|
root != NULL;
|
|||
|
root = ffebld_trail (root))
|
|||
|
{ /* For every equivalence item in the list */
|
|||
|
sv = ffeequiv_symbol (ffebld_head (root));
|
|||
|
if (sv == sr)
|
|||
|
break; /* Found first mention of "rooted" symbol. */
|
|||
|
if (ffesymbol_storage (sv) != NULL)
|
|||
|
{
|
|||
|
altroot = root; /* If no mention, use this guy
|
|||
|
instead. */
|
|||
|
altrootsym = sv;
|
|||
|
}
|
|||
|
}
|
|||
|
if (root != NULL)
|
|||
|
{
|
|||
|
root = ffebld_head (root); /* Lose its opITEM. */
|
|||
|
ok = ffeequiv_offset_ (&root_offset, sr, root, FALSE,
|
|||
|
ffestorag_offset (rst), TRUE);
|
|||
|
/* Equiv point prior to start of common area? */
|
|||
|
}
|
|||
|
else if (altroot != NULL)
|
|||
|
{
|
|||
|
/* Equiv point prior to start of common area? */
|
|||
|
root = ffebld_head (altroot);
|
|||
|
ok = ffeequiv_offset_ (&root_offset, altrootsym, root,
|
|||
|
FALSE,
|
|||
|
ffestorag_offset (ffesymbol_storage (altrootsym)),
|
|||
|
TRUE);
|
|||
|
ffesymbol_set_equiv (altrootsym, NULL);
|
|||
|
}
|
|||
|
else
|
|||
|
/* No rooted symbol in list of equivalences! */
|
|||
|
{ /* Assume this was due to opANY and ignore
|
|||
|
this list for now. */
|
|||
|
need_storage = TRUE;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* We now know the root symbol and the operating offset of that
|
|||
|
root into the common area. The other expressions in the
|
|||
|
list all identify an initial storage unit that must have the
|
|||
|
same offset. */
|
|||
|
|
|||
|
for (var = ffebld_head (item);
|
|||
|
var != NULL;
|
|||
|
var = ffebld_trail (var))
|
|||
|
{ /* For every equivalence item in the list */
|
|||
|
if (ffebld_head (var) == root)
|
|||
|
continue; /* Except root, of course. */
|
|||
|
sv = ffeequiv_symbol (ffebld_head (var));
|
|||
|
if (sv == NULL)
|
|||
|
continue; /* Except erroneous stuff (opANY). */
|
|||
|
ffesymbol_set_equiv (sv, NULL); /* Don't need this ref
|
|||
|
anymore. */
|
|||
|
if (!ok
|
|||
|
|| !ffeequiv_offset_ (&var_offset, sv,
|
|||
|
ffebld_head (var), TRUE,
|
|||
|
root_offset, TRUE))
|
|||
|
continue; /* Can't do negative offset wrt COMMON. */
|
|||
|
|
|||
|
if (ffesymbol_rank (sv) == 0)
|
|||
|
num_elements = 1;
|
|||
|
else
|
|||
|
num_elements = ffebld_constant_integerdefault
|
|||
|
(ffebld_conter (ffesymbol_arraysize (sv)));
|
|||
|
ffetarget_layout (ffesymbol_text (sv), &alignment,
|
|||
|
&modulo, &size,
|
|||
|
ffesymbol_basictype (sv),
|
|||
|
ffesymbol_kindtype (sv),
|
|||
|
ffesymbol_size (sv), num_elements);
|
|||
|
pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
|
|||
|
ffestorag_ptr_to_modulo (st),
|
|||
|
var_offset, alignment, modulo);
|
|||
|
if (pad != 0)
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_ALIGN);
|
|||
|
ffebad_string (ffesymbol_text (sv));
|
|||
|
ffebad_finish ();
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if ((vst = ffesymbol_storage (sv)) == NULL)
|
|||
|
{ /* Create new ffestorag object, extend
|
|||
|
cblock. */
|
|||
|
new_storage = TRUE;
|
|||
|
vst = ffestorag_new (ffestorag_list_equivs (st));
|
|||
|
ffestorag_set_parent (vst, st); /* Initializations
|
|||
|
happen there. */
|
|||
|
ffestorag_set_init (vst, NULL);
|
|||
|
ffestorag_set_accretion (vst, NULL);
|
|||
|
ffestorag_set_symbol (vst, sv);
|
|||
|
ffestorag_set_size (vst, size);
|
|||
|
ffestorag_set_offset (vst, var_offset);
|
|||
|
ffestorag_set_alignment (vst, alignment);
|
|||
|
ffestorag_set_modulo (vst, modulo);
|
|||
|
ffestorag_set_type (vst, FFESTORAG_typeEQUIV);
|
|||
|
ffestorag_set_basictype (vst, ffesymbol_basictype (sv));
|
|||
|
ffestorag_set_kindtype (vst, ffesymbol_kindtype (sv));
|
|||
|
ffestorag_set_typesymbol (vst, sv);
|
|||
|
ffestorag_set_is_save (vst, FALSE); /* Assume FALSE... */
|
|||
|
if (ffestorag_is_save (st)) /* ...update TRUE */
|
|||
|
ffestorag_update_save (vst); /* if needed. */
|
|||
|
ffestorag_set_is_init (vst, FALSE); /* Assume FALSE... */
|
|||
|
if (ffestorag_is_init (st)) /* ...update TRUE */
|
|||
|
ffestorag_update_init (vst); /* if needed. */
|
|||
|
if (!ffetarget_offset_add (&size, var_offset, size))
|
|||
|
/* Find one size of common block, complain if
|
|||
|
overflow. */
|
|||
|
ffetarget_offset_overflow (ffesymbol_text (s));
|
|||
|
else if (size > ffestorag_size (st))
|
|||
|
/* Extend common. */
|
|||
|
ffestorag_set_size (st, size);
|
|||
|
ffesymbol_set_storage (sv, vst);
|
|||
|
ffesymbol_set_common (sv, s);
|
|||
|
ffesymbol_signal_unreported (sv);
|
|||
|
ffestorag_update (st, sv, ffesymbol_basictype (sv),
|
|||
|
ffesymbol_kindtype (sv));
|
|||
|
if (ffesymbol_is_init (sv))
|
|||
|
init = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Make sure offset agrees with known offset. */
|
|||
|
if (var_offset != ffestorag_offset (vst))
|
|||
|
{
|
|||
|
char io1[40];
|
|||
|
char io2[40];
|
|||
|
|
|||
|
sprintf (&io1[0], "%" ffetargetOffset_f "d", var_offset);
|
|||
|
sprintf (&io2[0], "%" ffetargetOffset_f "d", ffestorag_offset (vst));
|
|||
|
ffebad_start (FFEBAD_EQUIV_MISMATCH);
|
|||
|
ffebad_string (ffesymbol_text (sv));
|
|||
|
ffebad_string (ffesymbol_text (s));
|
|||
|
ffebad_string (io1);
|
|||
|
ffebad_string (io2);
|
|||
|
ffebad_finish ();
|
|||
|
}
|
|||
|
}
|
|||
|
} /* (For every equivalence item in the list) */
|
|||
|
} /* (For every eqv list in the list of equivs
|
|||
|
for the variable) */
|
|||
|
}
|
|||
|
while (new_storage && need_storage);
|
|||
|
|
|||
|
ffeequiv_kill (seq); /* Kill equiv obj. */
|
|||
|
} /* (For every variable in the common area) */
|
|||
|
|
|||
|
return init;
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_merge -- Merge two equivalence objects, return the merged result
|
|||
|
|
|||
|
ffeequiv eq1;
|
|||
|
ffeequiv eq2;
|
|||
|
ffelexToken t; // points to current equivalence item forcing the merge.
|
|||
|
eq1 = ffeequiv_merge(eq1,eq2,t);
|
|||
|
|
|||
|
If the two equivalence objects can be merged, they are, all the
|
|||
|
ffesymbols in their lists of lists are adjusted to point to the merged
|
|||
|
equivalence object, and the merged object is returned.
|
|||
|
|
|||
|
Otherwise, the two equivalence objects have different non-NULL common
|
|||
|
symbols, so the merge cannot take place. An error message is issued and
|
|||
|
NULL is returned. */
|
|||
|
|
|||
|
ffeequiv
|
|||
|
ffeequiv_merge (ffeequiv eq1, ffeequiv eq2, ffelexToken t)
|
|||
|
{
|
|||
|
ffebld list;
|
|||
|
ffebld eqs;
|
|||
|
ffesymbol symbol;
|
|||
|
ffebld last = NULL;
|
|||
|
|
|||
|
/* If both equivalence objects point to different common-based symbols,
|
|||
|
complain. Of course, one or both might have NULL common symbols now,
|
|||
|
and get COMMONed later, but the COMMON statement handler checks for
|
|||
|
this. */
|
|||
|
|
|||
|
if ((ffeequiv_common (eq1) != NULL) && (ffeequiv_common (eq2) != NULL)
|
|||
|
&& (ffeequiv_common (eq1) != ffeequiv_common (eq2)))
|
|||
|
{
|
|||
|
ffebad_start (FFEBAD_EQUIV_COMMON);
|
|||
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|||
|
ffebad_string (ffesymbol_text (ffeequiv_common (eq1)));
|
|||
|
ffebad_string (ffesymbol_text (ffeequiv_common (eq2)));
|
|||
|
ffebad_finish ();
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
/* Make eq1 the new, merged object (arbitrarily). */
|
|||
|
|
|||
|
if (ffeequiv_common (eq1) == NULL)
|
|||
|
ffeequiv_set_common (eq1, ffeequiv_common (eq2));
|
|||
|
|
|||
|
/* If the victim object has any init'ed entities, so does the new object. */
|
|||
|
|
|||
|
if (eq2->is_init)
|
|||
|
eq1->is_init = TRUE;
|
|||
|
|
|||
|
#if FFEGLOBAL_ENABLED
|
|||
|
if (eq1->is_init && (ffeequiv_common (eq1) != NULL))
|
|||
|
ffeglobal_init_common (ffeequiv_common (eq1), t);
|
|||
|
#endif
|
|||
|
|
|||
|
/* If the victim object has any SAVEd entities, then the new object has
|
|||
|
some. */
|
|||
|
|
|||
|
if (ffeequiv_is_save (eq2))
|
|||
|
ffeequiv_update_save (eq1);
|
|||
|
|
|||
|
/* If the victim object has any init'd entities, then the new object has
|
|||
|
some. */
|
|||
|
|
|||
|
if (ffeequiv_is_init (eq2))
|
|||
|
ffeequiv_update_init (eq1);
|
|||
|
|
|||
|
/* Adjust all the symbols in the list of lists of equivalences for the
|
|||
|
victim equivalence object so they point to the new merged object
|
|||
|
instead. */
|
|||
|
|
|||
|
for (list = ffeequiv_list (eq2); list != NULL; list = ffebld_trail (list))
|
|||
|
{
|
|||
|
for (eqs = ffebld_head (list); eqs != NULL; eqs = ffebld_trail (eqs))
|
|||
|
{
|
|||
|
symbol = ffeequiv_symbol (ffebld_head (eqs));
|
|||
|
if (ffesymbol_equiv (symbol) == eq2)
|
|||
|
ffesymbol_set_equiv (symbol, eq1);
|
|||
|
else
|
|||
|
assert (ffesymbol_equiv (symbol) == eq1); /* Can see a sym > once. */
|
|||
|
}
|
|||
|
|
|||
|
/* For convenience, remember where the last ITEM in the outer list is. */
|
|||
|
|
|||
|
if (ffebld_trail (list) == NULL)
|
|||
|
{
|
|||
|
last = list;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Append the list of lists in the new, merged object to the list of lists
|
|||
|
in the victim object, then use the new combined list in the new merged
|
|||
|
object. */
|
|||
|
|
|||
|
ffebld_set_trail (last, ffeequiv_list (eq1));
|
|||
|
ffeequiv_set_list (eq1, ffeequiv_list (eq2));
|
|||
|
|
|||
|
/* Unlink and kill the victim object. */
|
|||
|
|
|||
|
ffeequiv_kill (eq2);
|
|||
|
|
|||
|
return eq1; /* Return the new merged object. */
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_new -- Create new equivalence object, put in list
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
eq = ffeequiv_new();
|
|||
|
|
|||
|
Creates a new equivalence object and adds it to the list of equivalence
|
|||
|
objects. */
|
|||
|
|
|||
|
ffeequiv
|
|||
|
ffeequiv_new ()
|
|||
|
{
|
|||
|
ffeequiv eq;
|
|||
|
|
|||
|
eq = malloc_new_ks (ffe_pool_program_unit (), "ffeequiv", sizeof (*eq));
|
|||
|
eq->next = (ffeequiv) &ffeequiv_list_.first;
|
|||
|
eq->previous = ffeequiv_list_.last;
|
|||
|
ffeequiv_set_common (eq, NULL); /* No COMMON area yet. */
|
|||
|
ffeequiv_set_list (eq, NULL); /* No list of lists of equivalences yet. */
|
|||
|
ffeequiv_set_is_save (eq, FALSE);
|
|||
|
ffeequiv_set_is_init (eq, FALSE);
|
|||
|
eq->next->previous = eq;
|
|||
|
eq->previous->next = eq;
|
|||
|
|
|||
|
return eq;
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_symbol -- Return symbol for equivalence expression
|
|||
|
|
|||
|
ffesymbol symbol;
|
|||
|
ffebld expr;
|
|||
|
symbol = ffeequiv_symbol(expr);
|
|||
|
|
|||
|
Finds the terminal SYMTER in an equivalence expression and returns the
|
|||
|
ffesymbol for it. */
|
|||
|
|
|||
|
ffesymbol
|
|||
|
ffeequiv_symbol (ffebld expr)
|
|||
|
{
|
|||
|
assert (expr != NULL);
|
|||
|
|
|||
|
again: /* :::::::::::::::::::: */
|
|||
|
|
|||
|
switch (ffebld_op (expr))
|
|||
|
{
|
|||
|
case FFEBLD_opARRAYREF:
|
|||
|
case FFEBLD_opSUBSTR:
|
|||
|
expr = ffebld_left (expr);
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
case FFEBLD_opSYMTER:
|
|||
|
return ffebld_symter (expr);
|
|||
|
|
|||
|
case FFEBLD_opANY:
|
|||
|
return NULL;
|
|||
|
|
|||
|
default:
|
|||
|
assert ("bad eq expr" == NULL);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_update_init -- Update the INIT flag for the area to TRUE
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffeequiv_update_init(eq);
|
|||
|
|
|||
|
If the INIT flag for the <eq> object is already set, return. Else,
|
|||
|
set it TRUE and call ffe*_update_init for all objects contained in
|
|||
|
this one. */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_update_init (ffeequiv eq)
|
|||
|
{
|
|||
|
ffebld list; /* Current list in list of lists. */
|
|||
|
ffebld item; /* Current item in current list. */
|
|||
|
ffebld expr; /* Expression in head of current item. */
|
|||
|
|
|||
|
if (eq->is_init)
|
|||
|
return;
|
|||
|
|
|||
|
eq->is_init = TRUE;
|
|||
|
|
|||
|
if ((eq->common != NULL)
|
|||
|
&& !ffesymbol_is_init (eq->common))
|
|||
|
ffesymbol_update_init (eq->common); /* Shouldn't be needed. */
|
|||
|
|
|||
|
for (list = eq->list; list != NULL; list = ffebld_trail (list))
|
|||
|
{
|
|||
|
for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
expr = ffebld_head (item);
|
|||
|
|
|||
|
again: /* :::::::::::::::::::: */
|
|||
|
|
|||
|
switch (ffebld_op (expr))
|
|||
|
{
|
|||
|
case FFEBLD_opANY:
|
|||
|
break;
|
|||
|
|
|||
|
case FFEBLD_opSYMTER:
|
|||
|
if (!ffesymbol_is_init (ffebld_symter (expr)))
|
|||
|
ffesymbol_update_init (ffebld_symter (expr));
|
|||
|
break;
|
|||
|
|
|||
|
case FFEBLD_opARRAYREF:
|
|||
|
expr = ffebld_left (expr);
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
case FFEBLD_opSUBSTR:
|
|||
|
expr = ffebld_left (expr);
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
default:
|
|||
|
assert ("bad op for ffeequiv_update_init" == NULL);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* ffeequiv_update_save -- Update the SAVE flag for the area to TRUE
|
|||
|
|
|||
|
ffeequiv eq;
|
|||
|
ffeequiv_update_save(eq);
|
|||
|
|
|||
|
If the SAVE flag for the <eq> object is already set, return. Else,
|
|||
|
set it TRUE and call ffe*_update_save for all objects contained in
|
|||
|
this one. */
|
|||
|
|
|||
|
void
|
|||
|
ffeequiv_update_save (ffeequiv eq)
|
|||
|
{
|
|||
|
ffebld list; /* Current list in list of lists. */
|
|||
|
ffebld item; /* Current item in current list. */
|
|||
|
ffebld expr; /* Expression in head of current item. */
|
|||
|
|
|||
|
if (eq->is_save)
|
|||
|
return;
|
|||
|
|
|||
|
eq->is_save = TRUE;
|
|||
|
|
|||
|
if ((eq->common != NULL)
|
|||
|
&& !ffesymbol_is_save (eq->common))
|
|||
|
ffesymbol_update_save (eq->common); /* Shouldn't be needed. */
|
|||
|
|
|||
|
for (list = eq->list; list != NULL; list = ffebld_trail (list))
|
|||
|
{
|
|||
|
for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
|
|||
|
{
|
|||
|
expr = ffebld_head (item);
|
|||
|
|
|||
|
again: /* :::::::::::::::::::: */
|
|||
|
|
|||
|
switch (ffebld_op (expr))
|
|||
|
{
|
|||
|
case FFEBLD_opANY:
|
|||
|
break;
|
|||
|
|
|||
|
case FFEBLD_opSYMTER:
|
|||
|
if (!ffesymbol_is_save (ffebld_symter (expr)))
|
|||
|
ffesymbol_update_save (ffebld_symter (expr));
|
|||
|
break;
|
|||
|
|
|||
|
case FFEBLD_opARRAYREF:
|
|||
|
expr = ffebld_left (expr);
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
case FFEBLD_opSUBSTR:
|
|||
|
expr = ffebld_left (expr);
|
|||
|
goto again; /* :::::::::::::::::::: */
|
|||
|
|
|||
|
default:
|
|||
|
assert ("bad op for ffeequiv_update_save" == NULL);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|