399 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			399 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 );
 | |
| }
 |