/* storag.c -- Implementation File (module.c template V1.0) Copyright (C) 1995, 1996 Free Software Foundation, Inc. Contributed by James Craig Burley. 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: Maintains information on storage (memory) relationships between COMMON, dummy, and local variables, plus their equivalences (dummies don't have equivalences, however). Modifications: */ /* Include files. */ #include "proj.h" #include "storag.h" #include "data.h" #include "malloc.h" #include "symbol.h" #include "target.h" /* Externals defined here. */ ffestoragList_ ffestorag_list_; /* Simple definitions and enumerations. */ /* Internal typedefs. */ /* Private include files. */ /* Internal structure definitions. */ /* Static objects accessed by functions in this module. */ static ffetargetOffset ffestorag_local_size_; /* #units allocated so far. */ static bool ffestorag_reported_;/* Reports happen only once. */ /* Static functions (internal). */ /* Internal macros. */ #define ffestorag_next_(s) ((s)->next) #define ffestorag_previous_(s) ((s)->previous) /* ffestorag_drive -- Drive fn from list of storage objects ffestoragList sl; void (*fn)(ffestorag mst,ffestorag st); ffestorag mst; // the master ffestorag object (or whatever) ffestorag_drive(sl,fn,mst); Calls (*fn)(mst,st) for every st in the list sl. */ void ffestorag_drive (ffestoragList sl, void (*fn) (ffestorag mst, ffestorag st), ffestorag mst) { ffestorag st; for (st = sl->first; st != (ffestorag) &sl->first; st = st->next) (*fn) (mst, st); } /* ffestorag_dump -- Dump information on storage object ffestorag s; // the ffestorag object ffestorag_dump(s); Dumps information in the storage object. */ void ffestorag_dump (ffestorag s) { if (s == NULL) { fprintf (dmpout, "(no storage object)"); return; } switch (s->type) { case FFESTORAG_typeCBLOCK: fprintf (dmpout, "CBLOCK "); break; case FFESTORAG_typeCOMMON: fprintf (dmpout, "COMMON "); break; case FFESTORAG_typeLOCAL: fprintf (dmpout, "LOCAL "); break; case FFESTORAG_typeEQUIV: fprintf (dmpout, "EQUIV "); break; default: fprintf (dmpout, "?%d? ", s->type); break; } if (s->symbol != NULL) fprintf (dmpout, "\"%s\" ", ffesymbol_text (s->symbol)); fprintf (dmpout, "at %" ffetargetOffset_f "d size %" ffetargetOffset_f "d, align loc%%%" ffetargetAlign_f "u=%" ffetargetAlign_f "u, bt=%s, kt=%s", s->offset, s->size, (unsigned int) s->alignment, (unsigned int) s->modulo, ffeinfo_basictype_string (s->basic_type), ffeinfo_kindtype_string (s->kind_type)); if (s->equivs_.first != (ffestorag) &s->equivs_.first) { ffestorag sq; fprintf (dmpout, " with equivs"); for (sq = s->equivs_.first; sq != (ffestorag) &s->equivs_.first; sq = ffestorag_next_ (sq)) { if (ffestorag_previous_ (sq) == (ffestorag) &s->equivs_.first) fputc (' ', dmpout); else fputc (',', dmpout); fprintf (dmpout, "%s", ffesymbol_text (ffestorag_symbol (sq))); } } } /* ffestorag_init_2 -- Initialize for new program unit ffestorag_init_2(); */ void ffestorag_init_2 () { ffestorag_list_.first = ffestorag_list_.last = (ffestorag) &ffestorag_list_.first; ffestorag_local_size_ = 0; ffestorag_reported_ = FALSE; } /* ffestorag_end_layout -- Do final layout for symbol ffesymbol s; ffestorag_end_layout(s); */ void ffestorag_end_layout (ffesymbol s) { if (ffesymbol_storage (s) != NULL) return; /* Already laid out. */ ffestorag_exec_layout (s); /* Do what we have in common. */ #if 0 assert (ffesymbol_storage (s) == NULL); /* I'd like to know what cases miss going through ffecom_sym_learned, and why; I don't think we should have to do the exec_layout thing at all here. */ /* Now I think I know: we have to do exec_layout here, because equivalence handling could encounter an error that takes a variable off of its equivalence object (and vice versa), and we should then layout the var as a local entity. */ #endif } /* ffestorag_exec_layout -- Do initial layout for symbol ffesymbol s; ffestorag_exec_layout(s); */ void ffestorag_exec_layout (ffesymbol s) { ffetargetAlign alignment; ffetargetAlign modulo; ffetargetOffset size; ffetargetOffset num_elements; ffetargetAlign pad; ffestorag st; ffestorag stv; ffebld list; ffebld item; ffesymbol var; bool init; if (ffesymbol_storage (s) != NULL) return; /* Already laid out. */ switch (ffesymbol_kind (s)) { default: return; /* Do nothing. */ case FFEINFO_kindENTITY: switch (ffesymbol_where (s)) { case FFEINFO_whereLOCAL: if (ffesymbol_equiv (s) != NULL) return; /* Let ffeequiv handle this guy. */ if (ffesymbol_rank (s) == 0) num_elements = 1; else { if (ffebld_op (ffesymbol_arraysize (s)) != FFEBLD_opCONTER) return; /* An adjustable local array, just like a dummy. */ num_elements = ffebld_constant_integerdefault (ffebld_conter (ffesymbol_arraysize (s))); } ffetarget_layout (ffesymbol_text (s), &alignment, &modulo, &size, ffesymbol_basictype (s), ffesymbol_kindtype (s), ffesymbol_size (s), num_elements); st = ffestorag_new (ffestorag_list_master ()); st->parent = NULL; /* Initializations happen at sym level. */ st->init = NULL; st->accretion = NULL; st->symbol = s; st->size = size; st->offset = 0; st->alignment = alignment; st->modulo = modulo; st->type = FFESTORAG_typeLOCAL; st->basic_type = ffesymbol_basictype (s); st->kind_type = ffesymbol_kindtype (s); st->type_symbol = s; st->is_save = ffesymbol_is_save (s); st->is_init = ffesymbol_is_init (s); ffesymbol_set_storage (s, st); if (ffesymbol_is_init (s)) ffecom_notify_init_symbol (s); /* Init completed before, but we didn't have a storage object for it; maybe back end wants to see the sym again now. */ ffesymbol_signal_unreported (s); return; case FFEINFO_whereCOMMON: return; /* Allocate storage for entire common block at once. */ case FFEINFO_whereDUMMY: return; /* Don't do anything about dummies for now. */ case FFEINFO_whereRESULT: case FFEINFO_whereIMMEDIATE: case FFEINFO_whereCONSTANT: case FFEINFO_whereNONE: return; /* These don't get storage (esp. NONE, which is UNCERTAIN). */ default: assert ("bad ENTITY where" == NULL); return; } break; case FFEINFO_kindCOMMON: assert (ffesymbol_where (s) == FFEINFO_whereLOCAL); st = ffestorag_new (ffestorag_list_master ()); st->parent = NULL; /* Initializations happen here. */ st->init = NULL; st->accretion = NULL; st->symbol = s; st->size = 0; st->offset = 0; st->alignment = 1; st->modulo = 0; st->type = FFESTORAG_typeCBLOCK; if (ffesymbol_commonlist (s) != NULL) { var = ffebld_symter (ffebld_head (ffesymbol_commonlist (s))); st->basic_type = ffesymbol_basictype (var); st->kind_type = ffesymbol_kindtype (var); st->type_symbol = var; } else { /* Special case for empty common area: NONE/NONE means nothing. */ st->basic_type = FFEINFO_basictypeNONE; st->kind_type = FFEINFO_kindtypeNONE; st->type_symbol = NULL; } st->is_save = ffesymbol_is_save (s); st->is_init = ffesymbol_is_init (s); if (!ffe_is_mainprog ()) ffeglobal_save_common (s, st->is_save || ffe_is_saveall (), ffesymbol_where_line (s), ffesymbol_where_column (s)); ffesymbol_set_storage (s, st); init = FALSE; for (list = ffesymbol_commonlist (s); list != NULL; list = ffebld_trail (list)) { item = ffebld_head (list); assert (ffebld_op (item) == FFEBLD_opSYMTER); var = ffebld_symter (item); if (ffesymbol_basictype (var) == FFEINFO_basictypeANY) continue; /* Ignore any symbols that have errors. */ if (ffesymbol_rank (var) == 0) num_elements = 1; else num_elements = ffebld_constant_integerdefault (ffebld_conter (ffesymbol_arraysize (var))); ffetarget_layout (ffesymbol_text (var), &alignment, &modulo, &size, ffesymbol_basictype (var), ffesymbol_kindtype (var), ffesymbol_size (var), num_elements); pad = ffetarget_align (&st->alignment, &st->modulo, st->size, alignment, modulo); if (pad != 0) { /* Warn about padding in the midst of a common area. */ char padding[20]; sprintf (&padding[0], "%" ffetargetAlign_f "u", pad); ffebad_start (FFEBAD_COMMON_PAD); ffebad_string (padding); ffebad_string (ffesymbol_text (var)); ffebad_string (ffesymbol_text (s)); ffebad_string ((pad == 1) ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS); ffebad_here (0, ffesymbol_where_line (s), ffesymbol_where_column (s)); ffebad_finish (); } stv = ffestorag_new (ffestorag_list_master ()); stv->parent = st; /* Initializations happen in COMMON block. */ stv->init = NULL; stv->accretion = NULL; stv->symbol = var; stv->size = size; if (!ffetarget_offset_add (&stv->offset, st->size, pad)) { /* Common block size plus pad, complain if overflow. */ ffetarget_offset_overflow (ffesymbol_text (s)); } if (!ffetarget_offset_add (&st->size, stv->offset, stv->size)) { /* Adjust size of common block, complain if overflow. */ ffetarget_offset_overflow (ffesymbol_text (s)); } stv->alignment = alignment; stv->modulo = modulo; stv->type = FFESTORAG_typeCOMMON; stv->basic_type = ffesymbol_basictype (var); stv->kind_type = ffesymbol_kindtype (var); stv->type_symbol = var; stv->is_save = st->is_save; stv->is_init = st->is_init; ffesymbol_set_storage (var, stv); ffesymbol_signal_unreported (var); ffestorag_update (st, var, ffesymbol_basictype (var), ffesymbol_kindtype (var)); if (ffesymbol_is_init (var)) init = TRUE; /* Must move inits over to COMMON's ffestorag. */ } if (ffeequiv_layout_cblock (st)) init = TRUE; ffeglobal_pad_common (s, st->modulo, ffesymbol_where_line (s), ffesymbol_where_column (s)); if (init) ffedata_gather (st); /* Gather subordinate inits into one init. */ ffesymbol_signal_unreported (s); return; } } /* ffestorag_new -- Create new ffestorag object, append to list ffestorag s; ffestoragList sl; s = ffestorag_new(sl); */ ffestorag ffestorag_new (ffestoragList sl) { ffestorag s; s = (ffestorag) malloc_new_kp (ffe_pool_program_unit (), "ffestorag", sizeof (*s)); s->next = (ffestorag) &sl->first; s->previous = sl->last; #ifdef FFECOM_storageHOOK s->hook = FFECOM_storageNULL; #endif s->previous->next = s; sl->last = s; s->equivs_.first = s->equivs_.last = (ffestorag) &s->equivs_.first; return s; } /* Report info on LOCAL non-sym-assoc'ed entities if needed. */ void ffestorag_report () { ffestorag s; if (ffestorag_reported_) return; for (s = ffestorag_list_.first; s != (ffestorag) &ffestorag_list_.first; s = s->next) { if (s->symbol == NULL) { ffestorag_reported_ = TRUE; fputs ("Storage area: ", dmpout); ffestorag_dump (s); fputc ('\n', dmpout); } } } /* ffestorag_update -- Update type info for ffestorag object ffestorag s; // existing object ffeinfoBasictype bt; // basic type for newly added member of object ffeinfoKindtype kt; // kind type for it ffestorag_update(s,bt,kt); If the existing type for the storage object agrees with the new type info, just returns. If the basic types agree but not the kind types, sets the kind type for the object to NONE. If the basic types disagree, sets the kind type to NONE, and the basic type to NONE if the basic types both are not CHARACTER, otherwise to ANY. If the basic type for the object already is NONE, it is set to ANY if the new basic type is CHARACTER. Any time a transition is made to ANY and pedantic mode is on, a message is issued that mixing CHARACTER and non-CHARACTER stuff in the same COMMON/EQUIVALENCE is invalid. */ void ffestorag_update (ffestorag s, ffesymbol sym, ffeinfoBasictype bt, ffeinfoKindtype kt) { if (s->basic_type == bt) { if (s->kind_type == kt) return; s->kind_type = FFEINFO_kindtypeNONE; return; } switch (s->basic_type) { case FFEINFO_basictypeANY: return; /* No need to do anything further. */ case FFEINFO_basictypeCHARACTER: any: /* :::::::::::::::::::: */ s->basic_type = FFEINFO_basictypeANY; s->kind_type = FFEINFO_kindtypeANY; if (ffe_is_pedantic ()) { ffebad_start (FFEBAD_MIXED_TYPES); ffebad_string (ffesymbol_text (s->type_symbol)); ffebad_string (ffesymbol_text (sym)); ffebad_finish (); } return; default: if (bt == FFEINFO_basictypeCHARACTER) goto any; /* :::::::::::::::::::: */ s->basic_type = FFEINFO_basictypeNONE; s->kind_type = FFEINFO_kindtypeNONE; return; } } /* Update INIT flag for storage object. If the INIT flag for the object is already TRUE, return. Else, set it to TRUE and call ffe*_update_init for all contained objects. */ void ffestorag_update_init (ffestorag s) { ffestorag sq; if (s->is_init) return; s->is_init = TRUE; if ((s->symbol != NULL) && !ffesymbol_is_init (s->symbol)) ffesymbol_update_init (s->symbol); if (s->parent != NULL) ffestorag_update_init (s->parent); for (sq = s->equivs_.first; sq != (ffestorag) &s->equivs_.first; sq = ffestorag_next_ (sq)) { if (!sq->is_init) ffestorag_update_init (sq); } } /* Update SAVE flag for storage object. If the SAVE flag for the object is already TRUE, return. Else, set it to TRUE and call ffe*_update_save for all contained objects. */ void ffestorag_update_save (ffestorag s) { ffestorag sq; if (s->is_save) return; s->is_save = TRUE; if ((s->symbol != NULL) && !ffesymbol_is_save (s->symbol)) ffesymbol_update_save (s->symbol); if (s->parent != NULL) ffestorag_update_save (s->parent); for (sq = s->equivs_.first; sq != (ffestorag) &s->equivs_.first; sq = ffestorag_next_ (sq)) { if (!sq->is_save) ffestorag_update_save (sq); } }