400 lines
9.3 KiB
C
400 lines
9.3 KiB
C
|
/****************************************************************
|
||
|
Copyright 1990 by AT&T Bell Laboratories and Bellcore.
|
||
|
|
||
|
Permission to use, copy, modify, and distribute this software
|
||
|
and its documentation for any purpose and without fee is hereby
|
||
|
granted, provided that the above copyright notice appear in all
|
||
|
copies and that both that the copyright notice and this
|
||
|
permission notice and warranty disclaimer appear in supporting
|
||
|
documentation, and that the names of AT&T Bell Laboratories or
|
||
|
Bellcore or any of their entities not be used in advertising or
|
||
|
publicity pertaining to distribution of the software without
|
||
|
specific, written prior permission.
|
||
|
|
||
|
AT&T and Bellcore disclaim all warranties with regard to this
|
||
|
software, including all implied warranties of merchantability
|
||
|
and fitness. In no event shall AT&T or Bellcore be liable for
|
||
|
any special, indirect or consequential damages or any damages
|
||
|
whatsoever resulting from loss of use, data or profits, whether
|
||
|
in an action of contract, negligence or other tortious action,
|
||
|
arising out of or in connection with the use or performance of
|
||
|
this software.
|
||
|
****************************************************************/
|
||
|
|
||
|
/*
|
||
|
* INTERMEDIATE CODE GENERATION PROCEDURES COMMON TO BOTH
|
||
|
* JOHNSON (PORTABLE) AND RITCHIE FAMILIES OF SECOND PASSES
|
||
|
*/
|
||
|
|
||
|
#include "defs.h"
|
||
|
#include "names.h" /* For LOCAL_CONST_NAME */
|
||
|
#include "pccdefs.h"
|
||
|
#include "p1defs.h"
|
||
|
|
||
|
/* Definitions for putconst() */
|
||
|
|
||
|
#define LIT_CHAR 1
|
||
|
#define LIT_FLOAT 2
|
||
|
#define LIT_INT 3
|
||
|
|
||
|
|
||
|
/*
|
||
|
char *ops [ ] =
|
||
|
{
|
||
|
"??", "+", "-", "*", "/", "**", "-",
|
||
|
"OR", "AND", "EQV", "NEQV", "NOT",
|
||
|
"CONCAT",
|
||
|
"<", "==", ">", "<=", "!=", ">=",
|
||
|
" of ", " ofC ", " = ", " += ", " *= ", " CONV ", " << ", " % ",
|
||
|
" , ", " ? ", " : "
|
||
|
" abs ", " min ", " max ", " addr ", " indirect ",
|
||
|
" bitor ", " bitand ", " bitxor ", " bitnot ", " >> ",
|
||
|
};
|
||
|
*/
|
||
|
|
||
|
/* Each of these values is defined in pccdefs */
|
||
|
|
||
|
int ops2 [ ] =
|
||
|
{
|
||
|
P2BAD, P2PLUS, P2MINUS, P2STAR, P2SLASH, P2BAD, P2NEG,
|
||
|
P2OROR, P2ANDAND, P2EQ, P2NE, P2NOT,
|
||
|
P2BAD,
|
||
|
P2LT, P2EQ, P2GT, P2LE, P2NE, P2GE,
|
||
|
P2CALL, P2CALL, P2ASSIGN, P2PLUSEQ, P2STAREQ, P2CONV, P2LSHIFT, P2MOD,
|
||
|
P2COMOP, P2QUEST, P2COLON,
|
||
|
1, P2BAD, P2BAD, P2BAD, P2BAD,
|
||
|
P2BITOR, P2BITAND, P2BITXOR, P2BITNOT, P2RSHIFT,
|
||
|
P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD,
|
||
|
P2BAD, P2BAD, P2BAD, P2BAD,
|
||
|
1,1,1,1,1, /* OPNEG1, OPDMIN, OPDMAX, OPASSIGNI, OPIDENTITY */
|
||
|
1,1,1,1 /* OPCHARCAST, OPDABS, OPMIN2, OPMAX2 */
|
||
|
};
|
||
|
|
||
|
|
||
|
int types2 [ ] =
|
||
|
{
|
||
|
P2BAD, P2INT|P2PTR, P2SHORT, P2LONG, P2REAL, P2DREAL,
|
||
|
P2REAL, P2DREAL, P2LONG, P2CHAR, P2INT, P2BAD
|
||
|
};
|
||
|
|
||
|
|
||
|
setlog()
|
||
|
{
|
||
|
types2[TYLOGICAL] = types2[tylogical];
|
||
|
typesize[TYLOGICAL] = typesize[tylogical];
|
||
|
typealign[TYLOGICAL] = typealign[tylogical];
|
||
|
}
|
||
|
|
||
|
|
||
|
void putex1(p)
|
||
|
expptr p;
|
||
|
{
|
||
|
/* Write the expression to the p1 file */
|
||
|
|
||
|
p = (expptr) putx (fixtype (p));
|
||
|
p1_expr (p);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expptr putassign(lp, rp)
|
||
|
expptr lp, rp;
|
||
|
{
|
||
|
return putx(fixexpr((Exprp)mkexpr(OPASSIGN, lp, rp)));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void puteq(lp, rp)
|
||
|
expptr lp, rp;
|
||
|
{
|
||
|
putexpr(mkexpr(OPASSIGN, lp, rp) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* put code for a *= b */
|
||
|
|
||
|
expptr putsteq(a, b)
|
||
|
Addrp a, b;
|
||
|
{
|
||
|
return putx( fixexpr((Exprp)
|
||
|
mkexpr(OPSTAREQ, cpexpr((expptr)a), cpexpr((expptr)b))));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Addrp mkfield(res, f, ty)
|
||
|
register Addrp res;
|
||
|
char *f;
|
||
|
int ty;
|
||
|
{
|
||
|
res -> vtype = ty;
|
||
|
res -> Field = f;
|
||
|
return res;
|
||
|
} /* mkfield */
|
||
|
|
||
|
|
||
|
Addrp realpart(p)
|
||
|
register Addrp p;
|
||
|
{
|
||
|
register Addrp q;
|
||
|
expptr mkrealcon();
|
||
|
|
||
|
if (p -> uname_tag == UNAM_CONST && ISCOMPLEX (p->vtype)) {
|
||
|
return (Addrp)mkrealcon (p -> vtype + TYREAL - TYCOMPLEX,
|
||
|
p->user.kludge.vstg1 ? p->user.Const.cds[0]
|
||
|
: cds(dtos(p->user.Const.cd[0]),CNULL));
|
||
|
} /* if p -> uname_tag */
|
||
|
|
||
|
q = (Addrp) cpexpr((expptr) p);
|
||
|
if( ISCOMPLEX(p->vtype) )
|
||
|
q = mkfield (q, "r", p -> vtype + TYREAL - TYCOMPLEX);
|
||
|
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expptr imagpart(p)
|
||
|
register Addrp p;
|
||
|
{
|
||
|
register Addrp q;
|
||
|
expptr mkrealcon();
|
||
|
|
||
|
if( ISCOMPLEX(p->vtype) )
|
||
|
{
|
||
|
if (p -> uname_tag == UNAM_CONST)
|
||
|
return mkrealcon (p -> vtype + TYREAL - TYCOMPLEX,
|
||
|
p->user.kludge.vstg1 ? p->user.Const.cds[1]
|
||
|
: cds(dtos(p->user.Const.cd[1]),CNULL));
|
||
|
q = (Addrp) cpexpr((expptr) p);
|
||
|
q = mkfield (q, "i", p -> vtype + TYREAL - TYCOMPLEX);
|
||
|
return( (expptr) q );
|
||
|
}
|
||
|
else
|
||
|
|
||
|
/* Cast an integer type onto a Double Real type */
|
||
|
|
||
|
return( mkrealcon( ISINT(p->vtype) ? TYDREAL : p->vtype , "0"));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* ncat -- computes the number of adjacent concatenation operations */
|
||
|
|
||
|
ncat(p)
|
||
|
register expptr p;
|
||
|
{
|
||
|
if(p->tag==TEXPR && p->exprblock.opcode==OPCONCAT)
|
||
|
return( ncat(p->exprblock.leftp) + ncat(p->exprblock.rightp) );
|
||
|
else return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* lencat -- returns the length of the concatenated string. Each
|
||
|
substring must have a static (i.e. compile-time) fixed length */
|
||
|
|
||
|
ftnint lencat(p)
|
||
|
register expptr p;
|
||
|
{
|
||
|
if(p->tag==TEXPR && p->exprblock.opcode==OPCONCAT)
|
||
|
return( lencat(p->exprblock.leftp) + lencat(p->exprblock.rightp) );
|
||
|
else if( p->headblock.vleng!=NULL && ISICON(p->headblock.vleng) )
|
||
|
return(p->headblock.vleng->constblock.Const.ci);
|
||
|
else if(p->tag==TADDR && p->addrblock.varleng!=0)
|
||
|
return(p->addrblock.varleng);
|
||
|
else
|
||
|
{
|
||
|
err("impossible element in concatenation");
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* putconst -- Creates a new Addrp value which maps onto the input
|
||
|
constant value. The Addrp doesn't retain the value of the constant,
|
||
|
instead that value is copied into a table of constants (called
|
||
|
litpool, for pool of literal values). The only way to retrieve the
|
||
|
actual value of the constant is to look at the memno field of the
|
||
|
Addrp result. You know that the associated literal is the one referred
|
||
|
to by q when (q -> memno == litp -> litnum).
|
||
|
*/
|
||
|
|
||
|
Addrp putconst(p)
|
||
|
register Constp p;
|
||
|
{
|
||
|
register Addrp q;
|
||
|
struct Literal *litp, *lastlit;
|
||
|
int k, len, type;
|
||
|
int litflavor;
|
||
|
double cd[2];
|
||
|
ftnint nblanks;
|
||
|
char *strp;
|
||
|
char cdsbuf0[64], cdsbuf1[64], *ds[2];
|
||
|
|
||
|
if (p->tag != TCONST)
|
||
|
badtag("putconst", p->tag);
|
||
|
|
||
|
q = ALLOC(Addrblock);
|
||
|
q->tag = TADDR;
|
||
|
type = p->vtype;
|
||
|
q->vtype = ( type==TYADDR ? tyint : type );
|
||
|
q->vleng = (expptr) cpexpr(p->vleng);
|
||
|
q->vstg = STGCONST;
|
||
|
|
||
|
/* Create the new label for the constant. This is wasteful of labels
|
||
|
because when the constant value already exists in the literal pool,
|
||
|
this label gets thrown away and is never reclaimed. It might be
|
||
|
cleaner to move this down past the first switch() statement below */
|
||
|
|
||
|
q->memno = newlabel();
|
||
|
q->memoffset = ICON(0);
|
||
|
q -> uname_tag = UNAM_CONST;
|
||
|
|
||
|
/* Copy the constant info into the Addrblock; do this by copying the
|
||
|
largest storage elts */
|
||
|
|
||
|
q -> user.Const = p -> Const;
|
||
|
q->user.kludge.vstg1 = p->vstg; /* distinguish string from binary fp */
|
||
|
|
||
|
/* check for value in literal pool, and update pool if necessary */
|
||
|
|
||
|
k = 1;
|
||
|
switch(type)
|
||
|
{
|
||
|
case TYCHAR:
|
||
|
if (halign) {
|
||
|
strp = p->Const.ccp;
|
||
|
nblanks = p->Const.ccp1.blanks;
|
||
|
len = p->vleng->constblock.Const.ci;
|
||
|
litflavor = LIT_CHAR;
|
||
|
goto loop;
|
||
|
}
|
||
|
else
|
||
|
q->memno = BAD_MEMNO;
|
||
|
break;
|
||
|
case TYCOMPLEX:
|
||
|
case TYDCOMPLEX:
|
||
|
k = 2;
|
||
|
if (p->vstg)
|
||
|
cd[1] = atof(ds[1] = p->Const.cds[1]);
|
||
|
else
|
||
|
ds[1] = cds(dtos(cd[1] = p->Const.cd[1]), cdsbuf1);
|
||
|
case TYREAL:
|
||
|
case TYDREAL:
|
||
|
litflavor = LIT_FLOAT;
|
||
|
if (p->vstg)
|
||
|
cd[0] = atof(ds[0] = p->Const.cds[0]);
|
||
|
else
|
||
|
ds[0] = cds(dtos(cd[0] = p->Const.cd[0]), cdsbuf0);
|
||
|
goto loop;
|
||
|
|
||
|
case TYLOGICAL:
|
||
|
type = tylogical;
|
||
|
goto lit_int_flavor;
|
||
|
case TYLONG:
|
||
|
type = tyint;
|
||
|
case TYSHORT:
|
||
|
lit_int_flavor:
|
||
|
litflavor = LIT_INT;
|
||
|
|
||
|
/* Scan the literal pool for this constant value. If this same constant
|
||
|
has been assigned before, use the same label. Note that this routine
|
||
|
does NOT consider two differently-typed constants with the same bit
|
||
|
pattern to be the same constant */
|
||
|
|
||
|
loop:
|
||
|
lastlit = litpool + nliterals;
|
||
|
for(litp = litpool ; litp<lastlit ; ++litp)
|
||
|
|
||
|
/* Remove this type checking to ensure that all bit patterns are reused */
|
||
|
|
||
|
if(type == litp->littype) switch(litflavor)
|
||
|
{
|
||
|
case LIT_CHAR:
|
||
|
if (len == (int)litp->litval.litival2[0]
|
||
|
&& nblanks == litp->litval.litival2[1]
|
||
|
&& !memcmp(strp, litp->cds[0], len)) {
|
||
|
q->memno = litp->litnum;
|
||
|
frexpr((expptr)p);
|
||
|
return(q);
|
||
|
}
|
||
|
break;
|
||
|
case LIT_FLOAT:
|
||
|
if(cd[0] == litp->litval.litdval[0]
|
||
|
&& !strcmp(ds[0], litp->cds[0])
|
||
|
&& (k == 1 ||
|
||
|
cd[1] == litp->litval.litdval[1]
|
||
|
&& !strcmp(ds[1], litp->cds[1]))) {
|
||
|
ret:
|
||
|
q->memno = litp->litnum;
|
||
|
frexpr((expptr)p);
|
||
|
return(q);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LIT_INT:
|
||
|
if(p->Const.ci == litp->litval.litival)
|
||
|
goto ret;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* If there's room in the literal pool, add this new value to the pool */
|
||
|
|
||
|
if(nliterals < maxliterals)
|
||
|
{
|
||
|
++nliterals;
|
||
|
|
||
|
/* litp now points to the next free elt */
|
||
|
|
||
|
litp->littype = type;
|
||
|
litp->litnum = q->memno;
|
||
|
switch(litflavor)
|
||
|
{
|
||
|
case LIT_CHAR:
|
||
|
litp->litval.litival2[0] = len;
|
||
|
litp->litval.litival2[1] = nblanks;
|
||
|
q->user.Const.ccp = litp->cds[0] =
|
||
|
memcpy(gmem(len,0), strp, len);
|
||
|
break;
|
||
|
|
||
|
case LIT_FLOAT:
|
||
|
litp->litval.litdval[0] = cd[0];
|
||
|
litp->cds[0] = copys(ds[0]);
|
||
|
if (k == 2) {
|
||
|
litp->litval.litdval[1] = cd[1];
|
||
|
litp->cds[1] = copys(ds[1]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LIT_INT:
|
||
|
litp->litval.litival = p->Const.ci;
|
||
|
break;
|
||
|
} /* switch (litflavor) */
|
||
|
}
|
||
|
else
|
||
|
many("literal constants", 'L', maxliterals);
|
||
|
|
||
|
break;
|
||
|
case TYADDR:
|
||
|
break;
|
||
|
default:
|
||
|
badtype ("putconst", p -> vtype);
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
if (type != TYCHAR || halign)
|
||
|
frexpr((expptr)p);
|
||
|
return( q );
|
||
|
}
|