Initial revision
This commit is contained in:
565
lang/pc/comp/desig.c
Normal file
565
lang/pc/comp/desig.c
Normal file
@@ -0,0 +1,565 @@
|
||||
/* D E S I G N A T O R E V A L U A T I O N */
|
||||
|
||||
/* Code generation for designators.
|
||||
This file contains some routines that generate code common to address
|
||||
as well as value computations, and leave a description in a "desig"
|
||||
structure. It also contains routines to load an address, load a value
|
||||
or perform a store.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <em.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "desig.h"
|
||||
#include "main.h"
|
||||
#include "node.h"
|
||||
#include "scope.h"
|
||||
#include "type.h"
|
||||
|
||||
struct desig InitDesig = {DSG_INIT, 0, 0, NULLDEF, 0};
|
||||
struct withdesig *WithDesigs;
|
||||
|
||||
|
||||
STATIC int
|
||||
properly(ds, size, al)
|
||||
register struct desig *ds;
|
||||
arith size;
|
||||
{
|
||||
/* Check if it is allowed to load or store the value indicated
|
||||
by "ds" with LOI/STI.
|
||||
- if the size is not either a multiple or a dividor of the
|
||||
wordsize, then not.
|
||||
- if the alignment is at least "word" then OK.
|
||||
- if size is dividor of word_size and alignment >= size then OK.
|
||||
- otherwise check alignment of address. This can only be done
|
||||
with DSG_FIXED.
|
||||
*/
|
||||
|
||||
arith szmodword = size % word_size; /* 0 if multiple of wordsize */
|
||||
arith wordmodsz = word_size % size; /* 0 if dividor of wordsize */
|
||||
|
||||
if( szmodword && wordmodsz ) return 0;
|
||||
if( al >= word_align ) return 1;
|
||||
if( szmodword && al >= szmodword ) return 1;
|
||||
|
||||
return ds->dsg_kind == DSG_FIXED &&
|
||||
((! szmodword && ds->dsg_offset % word_align == 0) ||
|
||||
(! wordmodsz && ds->dsg_offset % size == 0));
|
||||
}
|
||||
|
||||
CodeCopy(lhs, rhs, sz, psize)
|
||||
register struct desig *lhs, *rhs;
|
||||
arith sz, *psize;
|
||||
{
|
||||
struct desig l, r;
|
||||
|
||||
l = *lhs;
|
||||
r = *rhs;
|
||||
*psize -= sz;
|
||||
lhs->dsg_offset += sz;
|
||||
rhs->dsg_offset += sz;
|
||||
CodeAddress(&r);
|
||||
C_loi(sz);
|
||||
CodeAddress(&l);
|
||||
C_sti(sz);
|
||||
}
|
||||
|
||||
CodeMove(rhs, left, rtp)
|
||||
register struct desig *rhs;
|
||||
register struct node *left;
|
||||
struct type *rtp;
|
||||
{
|
||||
struct desig dsl;
|
||||
register struct desig *lhs = &dsl;
|
||||
register struct type *ltp = left->nd_type;
|
||||
|
||||
dsl = InitDesig;
|
||||
/* Generate code for an assignment. Testing of type
|
||||
compatibility and the like is already done.
|
||||
Go through some (considerable) trouble to see if
|
||||
a BLM can be generated.
|
||||
*/
|
||||
|
||||
switch( rhs->dsg_kind ) {
|
||||
case DSG_LOADED:
|
||||
CodeDesig(left, lhs);
|
||||
if( rtp->tp_fund == T_STRING ) {
|
||||
CodeAddress(lhs);
|
||||
C_blm(lhs->dsg_packed ? ltp->tp_psize : ltp->tp_size);
|
||||
return;
|
||||
}
|
||||
CodeStore(lhs, ltp);
|
||||
return;
|
||||
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeAddress(rhs);
|
||||
CodeValue(rhs, rtp);
|
||||
CodeDStore(left);
|
||||
return;
|
||||
|
||||
case DSG_FIXED: {
|
||||
arith tpsize;
|
||||
|
||||
CodeDesig(left, lhs);
|
||||
tpsize = lhs->dsg_packed ? ltp->tp_psize : ltp->tp_size;
|
||||
if( lhs->dsg_kind == DSG_FIXED &&
|
||||
lhs->dsg_offset % word_size == rhs->dsg_offset % word_size
|
||||
) {
|
||||
arith size = tpsize;
|
||||
|
||||
if( size > 6 * word_size ) {
|
||||
/* Do a block move
|
||||
*/
|
||||
struct desig l, r;
|
||||
|
||||
l = *lhs;
|
||||
r = *rhs;
|
||||
CodeAddress(&r);
|
||||
CodeAddress(&l);
|
||||
C_blm(size);
|
||||
}
|
||||
else {
|
||||
register arith sz;
|
||||
|
||||
for( sz = 2 * word_size; sz; sz -= word_size) {
|
||||
while( size >= sz )
|
||||
/* Then copy dwords, words.
|
||||
Depend on peephole optimizer
|
||||
*/
|
||||
CodeCopy(lhs, rhs, sz, &size);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( lhs->dsg_kind == DSG_PLOADED ||
|
||||
lhs->dsg_kind == DSG_INDEXED ) {
|
||||
CodeAddress(lhs);
|
||||
}
|
||||
}
|
||||
default:
|
||||
crash("(CodeMove)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
CodeValue(ds, tp)
|
||||
register struct desig *ds;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Generate code to load the value of the designator described
|
||||
in "ds"
|
||||
*/
|
||||
arith size = ds->dsg_packed ? tp->tp_psize : tp->tp_size;
|
||||
int align = ds->dsg_packed ? tp->tp_palign : tp->tp_align;
|
||||
|
||||
switch( ds->dsg_kind ) {
|
||||
case DSG_LOADED:
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
if( ds->dsg_offset % word_size == 0 && size == word_size ) {
|
||||
if( ds->dsg_name )
|
||||
C_loe_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
else
|
||||
C_lol(ds->dsg_offset);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
if( properly(ds, size, align) ) {
|
||||
CodeAddress(ds);
|
||||
C_loi(size);
|
||||
break;
|
||||
}
|
||||
printf("(CodeValue) : not properly");
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_lar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeValue)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
ds->dsg_kind = DSG_LOADED;
|
||||
}
|
||||
|
||||
CodeStore(ds, tp)
|
||||
register struct desig *ds;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Generate code to store the value on the stack in the designator
|
||||
described in "ds"
|
||||
*/
|
||||
struct desig save;
|
||||
arith size = ds->dsg_packed ? tp->tp_psize : tp->tp_size;
|
||||
int align = ds->dsg_packed ? tp->tp_palign : tp->tp_align;
|
||||
|
||||
save = *ds;
|
||||
|
||||
switch( ds->dsg_kind ) {
|
||||
case DSG_FIXED:
|
||||
if( ds->dsg_offset % word_size == 0 && size == word_size ) {
|
||||
if( ds->dsg_name )
|
||||
C_ste_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
else
|
||||
C_stl(ds->dsg_offset);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeAddress(&save);
|
||||
if( properly(ds, size, align) ) {
|
||||
C_sti(size);
|
||||
break;
|
||||
}
|
||||
printf("(CodeStore) : not properly");
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_sar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeStore)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
ds->dsg_kind = DSG_INIT;
|
||||
}
|
||||
|
||||
CodeAddress(ds)
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code to load the address of the designator described
|
||||
in "ds"
|
||||
*/
|
||||
|
||||
switch( ds->dsg_kind ) {
|
||||
case DSG_PLOADED:
|
||||
if( ds->dsg_offset )
|
||||
C_adp(ds->dsg_offset);
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
if( ds->dsg_name ) {
|
||||
C_lae_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
break;
|
||||
}
|
||||
C_lal(ds->dsg_offset);
|
||||
if( ds->dsg_def )
|
||||
ds->dsg_def->df_flags |= D_NOREG;
|
||||
break;
|
||||
|
||||
case DSG_PFIXED:
|
||||
if( ds->dsg_name )
|
||||
C_loe_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
else
|
||||
C_lol(ds->dsg_offset);
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_aar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeAddress)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
}
|
||||
|
||||
CodeFieldDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a field designator. Only the code common for
|
||||
address as well as value computation is generated, and the
|
||||
resulting information on where to find the designator is placed
|
||||
in "ds". "df" indicates the definition of the field.
|
||||
*/
|
||||
|
||||
if( ds->dsg_kind == DSG_INIT ) {
|
||||
/* In a WITH statement. We must find the designator in the
|
||||
WITH statement, and act as if the field is a selection
|
||||
of this designator.
|
||||
So, first find the right WITH statement, which is the
|
||||
first one of the proper record type, which is
|
||||
recognized by its scope indication.
|
||||
*/
|
||||
register struct withdesig *wds = WithDesigs;
|
||||
|
||||
assert(wds != 0);
|
||||
|
||||
while( wds->w_scope != df->df_scope ) {
|
||||
wds = wds->w_next;
|
||||
assert(wds != 0);
|
||||
}
|
||||
|
||||
/* Found it. Now, act like it was a selection.
|
||||
*/
|
||||
*ds = wds->w_desig;
|
||||
assert(ds->dsg_kind == DSG_PFIXED);
|
||||
}
|
||||
|
||||
switch( ds->dsg_kind ) {
|
||||
case DSG_PLOADED:
|
||||
case DSG_FIXED:
|
||||
ds->dsg_offset += df->fld_off;
|
||||
break;
|
||||
|
||||
case DSG_PFIXED:
|
||||
case DSG_INDEXED:
|
||||
CodeAddress(ds);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = df->fld_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeFieldDesig)");
|
||||
}
|
||||
|
||||
ds->dsg_packed = df->fld_flags & F_PACKED;
|
||||
}
|
||||
|
||||
CodeVarDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a variable represented by a "def" structure.
|
||||
Of course, there are numerous cases: the variable is local,
|
||||
it is a value parameter, it is a var parameter, it is one of
|
||||
those of an enclosing procedure, or it is global.
|
||||
*/
|
||||
register struct scope *sc = df->df_scope;
|
||||
|
||||
assert(ds->dsg_kind == DSG_INIT);
|
||||
|
||||
if( df->var_name ) {
|
||||
/* this variable has been given a name, so it is global.
|
||||
It is directly accessible.
|
||||
*/
|
||||
ds->dsg_name = df->var_name;
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_FIXED;
|
||||
return;
|
||||
}
|
||||
|
||||
if( sc->sc_level != proclevel ) {
|
||||
/* the variable is local to a statically enclosing procedure.
|
||||
*/
|
||||
assert(proclevel > sc->sc_level);
|
||||
|
||||
df->df_flags |= D_NOREG;
|
||||
if( df->df_flags & (D_VARPAR|D_VALPAR) ) {
|
||||
/* value or var parameter
|
||||
*/
|
||||
C_lxa((arith) (proclevel - sc->sc_level));
|
||||
if( (df->df_flags & D_VARPAR) ||
|
||||
IsConformantArray(df->df_type) ) {
|
||||
/* var parameter or conformant array.
|
||||
For conformant array's, the address is
|
||||
passed.
|
||||
*/
|
||||
C_adp(df->var_off);
|
||||
C_loi(pointer_size);
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
C_lxl((arith) (proclevel - sc->sc_level));
|
||||
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = df->var_off;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, finally, we have a local variable or a local parameter
|
||||
*/
|
||||
if( (df->df_flags & D_VARPAR) || IsConformantArray(df->df_type) )
|
||||
/* a var parameter; address directly accessible. */
|
||||
ds->dsg_kind = DSG_PFIXED;
|
||||
else
|
||||
ds->dsg_kind = DSG_FIXED;
|
||||
|
||||
ds->dsg_offset = df->var_off;
|
||||
ds->dsg_def = df;
|
||||
}
|
||||
|
||||
CodeBoundDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for the lower- and upperbound of a conformant array */
|
||||
|
||||
assert(ds->dsg_kind == DSG_INIT);
|
||||
|
||||
if( df->df_scope->sc_level < proclevel ) {
|
||||
C_lxa((arith) (proclevel - df->df_scope->sc_level));
|
||||
if( df->df_kind == D_UBOUND ) {
|
||||
C_ldf(df->bnd_type->arr_cfdescr);
|
||||
C_adi(word_size);
|
||||
}
|
||||
else
|
||||
C_lof(df->bnd_type->arr_cfdescr);
|
||||
}
|
||||
else {
|
||||
if( df->df_kind == D_UBOUND ) {
|
||||
C_ldl(df->bnd_type->arr_cfdescr);
|
||||
C_adi(word_size);
|
||||
}
|
||||
else
|
||||
C_lol(df->bnd_type->arr_cfdescr);
|
||||
}
|
||||
|
||||
ds->dsg_kind = DSG_LOADED;
|
||||
}
|
||||
|
||||
CodeFuncDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* generate code to store the function result */
|
||||
|
||||
if( df->df_scope->sc_level + 1 < proclevel ) {
|
||||
/* Assignment to function-identifier in the declaration-part of
|
||||
the function (i.e. in the statement-part of a nested function
|
||||
or procedure).
|
||||
*/
|
||||
C_lxl((arith) (proclevel - df->df_scope->sc_level - 1));
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
}
|
||||
else {
|
||||
/* Assignment to function-identifier in the statement-part of
|
||||
the function.
|
||||
*/
|
||||
ds->dsg_kind = DSG_FIXED;
|
||||
}
|
||||
assert(df->prc_res < 0);
|
||||
ds->dsg_offset = df->prc_res;
|
||||
}
|
||||
|
||||
CodeDesig(nd, ds)
|
||||
register struct node *nd;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a designator. Use divide and conquer
|
||||
principle
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
switch( nd->nd_class ) { /* Divide */
|
||||
case Def:
|
||||
df = nd->nd_def;
|
||||
|
||||
switch( df->df_kind ) {
|
||||
case D_FIELD:
|
||||
CodeFieldDesig(df, ds);
|
||||
break;
|
||||
|
||||
case D_VARIABLE:
|
||||
CodeVarDesig(df, ds);
|
||||
break;
|
||||
|
||||
case D_LBOUND:
|
||||
case D_UBOUND:
|
||||
CodeBoundDesig(df, ds);
|
||||
break;
|
||||
|
||||
case D_FUNCTION:
|
||||
CodeFuncDesig(df, ds);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) Def");
|
||||
}
|
||||
break;
|
||||
|
||||
case LinkDef:
|
||||
assert(nd->nd_symb == '.');
|
||||
|
||||
CodeDesig(nd->nd_left, ds);
|
||||
CodeFieldDesig(nd->nd_def, ds);
|
||||
break;
|
||||
|
||||
case Arrsel: {
|
||||
struct type *tp;
|
||||
|
||||
assert(nd->nd_symb == '[');
|
||||
|
||||
CodeDesig(nd->nd_left, ds);
|
||||
CodeAddress(ds);
|
||||
CodePExpr(nd->nd_right);
|
||||
|
||||
/* Now load address of descriptor
|
||||
*/
|
||||
tp = nd->nd_left->nd_type;
|
||||
if( IsConformantArray(tp) ) {
|
||||
if( tp->arr_sclevel < proclevel ) {
|
||||
C_lxa((arith) (proclevel - tp->arr_sclevel));
|
||||
C_adp(tp->arr_cfdescr);
|
||||
}
|
||||
else
|
||||
C_lal(tp->arr_cfdescr);
|
||||
}
|
||||
else
|
||||
C_lae_dlb(tp->arr_ardescr, (arith) 0);
|
||||
|
||||
ds->dsg_kind = DSG_INDEXED;
|
||||
ds->dsg_packed = IsPacked(tp);
|
||||
break;
|
||||
}
|
||||
|
||||
case Arrow:
|
||||
assert(nd->nd_symb == '^');
|
||||
|
||||
if( nd->nd_right->nd_type->tp_fund == T_FILE ) {
|
||||
CodeDAddress(nd->nd_right);
|
||||
C_cal("_wdw");
|
||||
C_asp(pointer_size);
|
||||
C_lfr(pointer_size);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_packed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
CodeDesig(nd->nd_right, ds);
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_LOADED:
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeValue(ds, nd->nd_right->nd_type);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = 0;
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
ds->dsg_kind = DSG_PFIXED;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) Uoper");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) class");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user