static char sccsid
[] = "@(#)local2.c 1.28 (Berkeley) %G%";
# define putstr(s) fputs((s), stdout)
# define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR)
/* a lot of the machine dependent parts of the second pass */
# define BITMASK(n) ((1L<<n)-1)
fprintf( stderr
, "%s, line %d: ", filename
, lineno
);
lineid( l
, fn
) char *fn
; {
/* identify line l and file fn */
printf( "# line %d, file %s\n", l
, fn
);
register OFFSZ spoff
; /* offset from stack pointer */
extern int ftlab1
, ftlab2
;
printf( " .set .F%d,%ld\n", ftnno
, spoff
);
/* SHOULD BE L%d ... ftnno but must change pc/f77 */
printf( " .set LF%d,%ld\n", ftnno
, spoff
);
printf( " .set LWM%d,0x%x\n", ftnno
, ent_mask
&0x1ffc|0x1000);
printf( " .set L%d,0x%x\n", ftnno
, ent_mask
&0x1ffc);
printf( "L%d:\n", ftlab1
);
printf( " subl3 $%ld,fp,sp\n", spoff
);
printf( " jbr L%d\n", ftlab2
);
struct hoptab
{ int opmask
; char * opstring
; } ioptab
[] = {
/* output the appropriate string from the above table */
register struct hoptab
*q
;
for( q
= ioptab
; q
->opmask
>=0; ++q
){
printf( "e%s", q
->opstring
);
printf( "%s%c", q
->opstring
, tolower(f
));
cerror( "no hoptab for %s", opst
[o
] );
rnames
[] = { /* keyed to register number tokens */
"r6", "r7", "r8", "r9", "r10", "r11",
/* output register name and update entry mask */
SAREG
|STAREG
, SAREG
|STAREG
,
SAREG
|STAREG
, SAREG
|STAREG
, SAREG
|STAREG
, SAREG
|STAREG
,
SAREG
, SAREG
, SAREG
, SAREG
, SAREG
, SAREG
,
SAREG
, SAREG
, SAREG
, SAREG
,
mixtypes(p
, q
) NODE
*p
, *q
;
return( (tp
==FLOAT
|| tp
==DOUBLE
) !=
(tq
==FLOAT
|| tq
==DOUBLE
) );
if ( !ISPTR( n
->in
.type
) ) cerror("zzzcode- bad type");
zzzcode( p
, c
) register NODE
*p
; {
case 'N': /* logical ops, turned into 0-1 */
/* use register given by register 1 */
cbgen( 0, m
=getlab(), 'I' );
printf( " clrl %s\n", rname(getlr( p
, '1' )->tn
.rval
) );
cbgen( p
->in
.op
, p
->bn
.label
, c
);
case 'G': /* i *= f; asgops with int lhs and float rhs */
register NODE
*l
, *r
, *s
;
if (lt
!= INT
&& lt
!= UNSIGNED
) {
s
->in
.type
= ISUNSIGNED(lt
) ? UNSIGNED
: INT
;
s
->in
.left
= lt
== UNSIGNED
? l
: resc
;
adrput(lt
== INT
? l
: resc
);
hopcode(rt
== FLOAT
? 'F' : 'D', p
->in
.op
);
s
->in
.left
= r
; /* we need only the type */
case 'J': /* unsigned DIV/MOD with constant divisors */
register int ck
= INAREG
;
/* case constant <= 1 is handled by optim() in pass 1 */
/* case constant < 0x80000000 is handled in table */
/* case DIV: handled in optim2() */
if( p
->in
.left
->in
.op
== REG
&&
p
->in
.left
->tn
.rval
== resc
->tn
.rval
)
expand(p
, ck
, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
printf("\tjlssu\tL%d\n", label1
);
expand(p
, ck
, "\tsubl2\tAR,A1\n");
expand(p
, ck
, "cmpl\tAL,AR\n");
printf("\tjgequ\tL%d\n", label1
);
expand(p
, ck
, "\tmovl\t$1,AL\n");
printf("\tjbr\tL%d\nL%d:\n", label2
, label1
);
expand(p
, ck
, "\tclrl\tAL\n");
expand(p
, ck
, "cmpl\tAL,AR\n");
printf("\tjlssu\tL%d\n", label1
);
expand(p
, ck
, "\tsubl2\tAR,AL\n");
case 'B': /* get oreg value in temp register for shift */
if (xdebug
) eprint(p
, 0, &val
, &val
);
if( tlen(r
) == SZINT
/SZCHAR
&& r
->in
.type
!= FLOAT
)
putstr(ISUNSIGNED(r
->in
.type
) ? "movz" : "cvt");
case 'C': /* generate 'call[fs] $bytes' */
if (xdebug
) printf("->%d<-",gc_numbytes
);
(p
->in
.left
->in
.op
==ICON
&& gc_numbytes
<60)?'f':'s',
/* don't change to double (here's the only place to catch it) */
case 'D': /* INCR and DECR */
zzzcode(p
->in
.left
, 'U');
case 'E': /* INCR and DECR, FOREFF */
if (p
->in
.right
->tn
.lval
== 1)
putstr(p
->in
.op
== INCR
? "inc" : "dec");
putstr(p
->in
.op
== INCR
? "add" : "sub");
case 'F': /* masked constant for fields */
printf(ACONFMT
, (p
->in
.right
->tn
.lval
&((1<<fldsz
)-1))<<fldshf
);
case 'I': /* produce value of bitfield assignment */
/* avoid shifts -- shifts are SLOW on this machine */
/* XXX this wouldn't be necessary if we were smarter
and masked BEFORE shifting XXX */
register NODE
*r
= p
->in
.right
;
if(r
->in
.op
== ICON
&& r
->tn
.name
[0] == '\0') {
printf(ACONFMT
, r
->tn
.lval
& ((1<<fldsz
)-1));
printf(ACONFMT
, (1 << fldsz
) - 1);
case 'H': /* opcode for shift */
if(p
->in
.op
== LS
|| p
->in
.op
== ASG LS
)
else if(ISUNSIGNED(p
->in
.left
->in
.type
))
case 'L': /* type of left operand */
case 'R': /* type of right operand */
if (xdebug
) printf("->%d<-", n
->in
.type
);
case 'M': { /* initiate ediv for mod and unsigned div */
printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m
= getlab());
case 'T': { /* rounded structure length for arguments */
int size
= p
->stn
.stsize
;
printf("movab -%d(sp),sp", size
);
case 'S': /* structure assignment */
#ifdef I_don_t_understand_this
case 'X': /* multiplication for short and char */
if (ISUNSIGNED(p
->in
.left
->in
.type
))
if (ISUNSIGNED(p
->in
.right
->in
.type
))
case 'V': /* SCONV with FORCC */
case 'W': { /* SCONV or ASSIGN float/double => unsigned */
NODE
*src
= p
->in
.op
== SCONV
? p
->in
.left
: p
->in
.right
;
case 'Y': /* SCONV or ASSIGN unsigned => float/double */
unsigned_to_float(p
); /* stores into accumulator */
#ifdef I_don_t_understand_this
printf("$%d", p
->tn
.lval
);
cerror( "illegal zzzcode" );
#define MOVB(dst, src, off) { \
putstr("\tmovb\t"); upput(src, off); putchar(','); \
upput(dst, off); putchar('\n'); \
#define MOVW(dst, src, off) { \
putstr("\tmovw\t"); upput(src, off); putchar(','); \
upput(dst, off); putchar('\n'); \
#define MOVL(dst, src, off) { \
putstr("\tmovl\t"); upput(src, off); putchar(','); \
upput(dst, off); putchar('\n'); \
* Generate code for a structure assignment.
case STASG
: /* regular assignment */
case STARG
: /* place arg on the stack */
* Pun source for use in code generation.
if (size
<= 0 || size
> 65535)
cerror("structure size out of range");
* Generate optimized code based on structure size
* and alignment properties....
if (p
->stn
.stalign
!= 2) {
if (p
->stn
.stalign
!= 4) {
if (p
->stn
.stalign
!= 2) {
if (p
->stn
.stalign
== 4) {
* Can we ever get a register conflict with R1 here?
if(r
->in
.op
== OREG
&& r
->tn
.rval
== R1
)
printf(",r0\n\tmovab\t");
putstr(",r1\n\tmovab\t");
printf("\tmovl\t$%d,r2\n\tmovblk\n", size
);
* Reverse above pun for reclaim.
else if (r
->in
.op
== OREG
)
* Convert a float or double in the accumulator into an unsigned int.
* Unlike the vax, the tahoe stores 0 into the destination
* on a conversion of > 2 ** 31, so we compensate.
register NODE
*l
= p
->in
.left
;
printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1
);
if (src
->in
.type
== DOUBLE
)
putstr(", 0x00000000 # .double");
putstr(" 2147483648\n\t.text\n\tcmp");
printf("\tL%d\n\tjlss\tL%d\n\tsub", label1
, label2
);
printf("\tL%d\n\tcv", label1
);
putstr("\n\taddl2\t$-2147483648,");
printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3
, label2
);
printf("\nL%d:", label3
);
* Convert an unsigned int into a float or double, leaving the result
printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2
);
if (p
->in
.type
== DOUBLE
)
putstr(", 0x00000000 # .double");
putstr(" 4294967296\n\t.text\n\tmovl\t");
printf("\n\tjgeq\tL%d\n\tadd", label1
);
printf("\tL%d\nL%d:", label2
, label1
);
* Prlen() is a cheap prtype()...
static char convtab
[SZINT
/SZCHAR
+ 1] = {
#define prlen(len) putchar(convtab[len])
* Generate code for integral scalar conversions.
* Some of this code is designed to work around a tahoe misfeature
* that causes sign- and zero- extension to be defeated in
* Basically if the source operand of a CVT or MOVZ instruction is
* shorter than the destination, and the source is a register
* or an immediate constant, sign- and zero- extension are
* ignored and the high bits of the source are copied. (Note
* that zero-extension is not a problem for immediate
register NODE
*src
, *dst
;
register int srclen
, dstlen
;
if (p
->in
.op
== ASSIGN
) {
} else if (p
->in
.op
== SCONV
) {
} else /* if (p->in.op == OPLEAF) */ {
dsttype
= ISUNSIGNED(src
->in
.type
) ? UNSIGNED
: INT
;
srctype
= ISUNSIGNED(src
->in
.type
) ? UNSIGNED
: INT
;
if (src
->in
.op
== ICON
&& src
->tn
.name
[0] == '\0') {
src
->tn
.lval
= (char) src
->tn
.lval
;
src
->tn
.lval
= (unsigned char) src
->tn
.lval
;
src
->tn
.lval
= (short) src
->tn
.lval
;
src
->tn
.lval
= (unsigned short) src
->tn
.lval
;
val
= -src
->tn
.lval
& ((1 << dstlen
* SZCHAR
) - 1);
if ((unsigned) val
< 64) {
++neg
; /* MNEGx may be shorter */
if (srctype
== CHAR
&& dsttype
== USHORT
&& dst
->in
.op
== REG
) {
/* (unsigned short) c; => sign extend to 16 bits */
putstr(",-(sp)\n\tmovzwl\t2(sp),");
putstr("\n\tmovab\t4(sp),sp");
genconv(ISUNSIGNED(srctype
),
srclen
, dst
->in
.op
== REG
? SZINT
/SZCHAR
: dstlen
,
if (srclen
> dstlen
&& dst
->in
.op
== REG
) {
/* if dst is a register, the result must look like an int */
if (ISUNSIGNED(dsttype
)) {
val
= (1 << dstlen
* SZCHAR
) - 1;
if (src
->tn
.rval
== dst
->tn
.rval
)
/* conversion in place */
printf("andl2\t$%ld,", val
);
printf("andl3\t$%ld,", val
);
* Sign extension in register can also be
* accomplished by shifts, but unfortunately
* shifts are extremely slow, due to the lack
printf("l\t%d(sp),", SZINT
/SZCHAR
- dstlen
);
putstr("\n\tmovab\t4(sp),sp");
if ((src
->in
.op
== NAME
) ||
(src
->in
.op
== UNARY MUL
&& src
->in
.left
->in
.op
== ICON
) ||
(src
->in
.op
== OREG
&& !R2TEST(src
->tn
.rval
))) {
/* we can increment src's address & pun it */
tmp
->tn
.lval
+= srclen
- dstlen
;
/* we must store src's address */
tmp
->tn
.lval
= srclen
- dstlen
;
genconv(ISUNSIGNED(dsttype
), dstlen
, SZINT
/SZCHAR
, tmp
, dst
);
genconv(neg
? -1 : ISUNSIGNED(dsttype
),
srclen
, dst
->in
.op
== REG
? SZINT
/SZCHAR
: dstlen
,
genconv(srcflag
, srclen
, dstlen
, src
, dst
)
register int srclen
, dstlen
;
if (srcflag
> 0 && srclen
< dstlen
)
rmove( rt
, rs
, t
) TWORD t
; {
printf( " movl %s,%s\n", rname(rs
), rname(rt
) );
printf( " movl %s,%s\n", rname(rs
+1), rname(rt
+1) );
INTAREG
|INTBREG
, INTAREG
|INTBREG
,
INAREG
|INBREG
, INAREG
|INBREG
|SOREG
|STARREG
|STARNM
|SNAME
|SCON
,
INTEMP
, INTAREG
|INAREG
|INTBREG
|INBREG
|SOREG
|STARREG
|STARNM
,
setregs(){ /* set up temporary registers */
fregs
= 6; /* tbl- 6 free regs on Tahoe (0-5) */
szty(t
) TWORD t
;{ /* size, in registers, needed to hold thing of type t */
return(t
==DOUBLE
? 2 : 1 );
base( p
) register NODE
*p
; {
register int o
= p
->in
.op
;
if( o
==ICON
&& p
->in
.name
[0] != '\0' ) return( 100 ); /* ie no base reg */
if( o
==REG
) return( p
->tn
.rval
);
if( (o
==PLUS
|| o
==MINUS
) && p
->in
.left
->in
.op
== REG
&& p
->in
.right
->in
.op
==ICON
)
return( p
->in
.left
->tn
.rval
);
if( o
==OREG
&& !R2TEST(p
->tn
.rval
) && (p
->in
.type
==INT
|| p
->in
.type
==UNSIGNED
|| ISPTR(p
->in
.type
)) )
return( p
->tn
.rval
+ 0200*1 );
if( o
==NAME
) return( 100 + 0200*1 );
offset( p
, tyl
) register NODE
*p
; int tyl
; {
(p
->in
.type
==INT
|| p
->in
.type
==UNSIGNED
) )
p
->in
.left
->in
.op
==REG
&&
(p
->in
.left
->in
.type
==INT
|| p
->in
.left
->in
.type
==UNSIGNED
) &&
p
->in
.right
->in
.op
==ICON
&&
p
->in
.right
->in
.name
[0]=='\0' &&
(1<<p
->in
.right
->tn
.lval
)==tyl
)
return( p
->in
.left
->tn
.rval
);
(p
->in
.left
->in
.type
==INT
|| p
->in
.left
->in
.type
==UNSIGNED
) &&
p
->in
.left
->in
.op
==REG
&&
p
->in
.right
->in
.op
==REG
&&
p
->in
.left
->tn
.rval
==p
->in
.right
->tn
.rval
)
return( p
->in
.left
->tn
.rval
);
makeor2( p
, q
, b
, o
) register NODE
*p
, *q
; register int b
, o
; {
f
= p
->in
.left
; /* have to free this subtree later */
q
->in
.right
->tn
.lval
= -q
->in
.right
->tn
.lval
;
cerror("illegal makeor2");
p
->in
.name
[i
] = t
->in
.name
[i
];
p
->tn
.rval
= R2PACK( (b
& 0177), o
, (b
>>7) );
register int o
= p
->in
.op
;
if( o
==NAME
|| o
==REG
|| o
==ICON
|| o
==OREG
|| (o
==UNARY MUL
&& shumul(p
->in
.left
)) ) return(1);
shltype( o
, p
) register NODE
*p
; {
return( o
== REG
|| o
== NAME
|| o
== ICON
|| o
== OREG
|| ( o
==UNARY MUL
&& shumul(p
->in
.left
)) );
register int o
= p
->in
.op
;
if( o
==NAME
|| o
==REG
|| o
==ICON
|| o
==OREG
|| (o
==UNARY MUL
&& shumul(p
->in
.left
)) ) return(1);
/* INTEMP shapes must not contain any temporary registers */
shtemp( p
) register NODE
*p
; {
if( p
->in
.op
== STARG
) p
= p
->in
.left
;
return( !istreg(p
->tn
.rval
) );
return( p
->in
.op
!= UNARY MUL
&& shtemp(p
) );
if( optype( p
->in
.op
) != LTYPE
) return(0);
shumul( p
) register NODE
*p
; {
printf("\nshumul:op=%d,lop=%d,rop=%d", p
->in
.op
, p
->in
.left
->in
.op
, p
->in
.right
->in
.op
);
printf(" prname=%s,plty=%d, prlval=%D\n", p
->in
.right
->in
.name
, p
->in
.left
->in
.type
, p
->in
.right
->tn
.lval
);
if(( o
== NAME
|| (o
== OREG
&& !R2TEST(p
->tn
.rval
)) || o
== ICON
)
&& p
->in
.type
!= PTR
+DOUBLE
)
special( p
, shape
) register NODE
*p
; {
if( shape
==SIREG
&& p
->in
.op
== OREG
&& R2TEST(p
->tn
.rval
) ) return(1);
adrcon( val
) CONSZ val
; {
conput( p
) register NODE
*p
; {
putstr(rname(p
->tn
.rval
));
cerror( "illegal conput" );
* Output the address of the second item in the
p
->tn
.lval
+= size
/SZCHAR
;
putstr(rname(p
->tn
.rval
+1));
cerror("illegal upper address op %s size %d",
adrput( p
) register NODE
*p
; {
/* output an address, with offsets, from p */
/* addressable value of the constant */
putstr(rname(p
->tn
.rval
));
if(p
->in
.type
== DOUBLE
) /* for entry mask */
(void) rname(p
->tn
.rval
+1);
if( R2TEST(r
) ){ /* double indexing */
if( flags
& 1 ) putchar('*');
if( p
->tn
.lval
!= 0 || p
->in
.name
[0] != '\0' ) acon(p
);
if( R2UPK1(r
) != 100) printf( "(%s)", rname(R2UPK1(r
)) );
printf( "[%s]", rname(R2UPK2(r
)) );
if( r
== FP
&& p
->tn
.lval
> 0 ){ /* in the argument region */
if( p
->in
.name
[0] != '\0' ) werror( "bad arg temp" );
printf( CONFMT
, p
->tn
.lval
);
if( p
->tn
.lval
!= 0 || p
->in
.name
[0] != '\0') acon( p
);
printf( "(%s)", rname(p
->tn
.rval
) );
/* STARNM or STARREG found */
if( tshape(p
, STARNM
) ) {
cerror( "illegal address" );
acon( p
) register NODE
*p
; { /* print out a constant */
if( p
->in
.name
[0] == '\0' )
printf( CONFMT
, p
->tn
.lval
);
printf( "%.8s", p
->in
.name
);
printf( CONFMT
, p
->tn
.lval
);
genscall( p
, cookie
) register NODE
*p
; {
/* structure valued call */
return( gencall( p
, cookie
) );
genfcall( p
, cookie
) register NODE
*p
; {
static char *funcops
[6] = {
"sin", "cos", "sqrt", "exp", "log", "atan"
/* generate function opcodes */
if(p
->in
.op
==UNARY FORTCALL
&& p
->in
.type
==FLOAT
&&
(p1
= p
->in
.left
)->in
.op
==ICON
&&
p1
->tn
.lval
==0 && p1
->in
.type
==INCREF(FTN
|FLOAT
)) {
strcpy(p1
->in
.name
, p1
->in
.name
[1]);
if(!strcmp(p1
->in
.name
, funcops
[m
]))
uerror("no opcode for fortarn function %s", p1
->in
.name
);
uerror("illegal type of fortarn function");
order( p1
, INAREG
|INBREG
|SOREG
|STARREG
|STARNM
);
m
= match( p
, INTAREG
|INTBREG
);
gencall( p
, cookie
) register NODE
*p
; {
/* generate the call given by p */
register NODE
*p1
, *ptemp
;
register int temp
, temp1
;
if( p
->in
.right
) temp
= argsize( p
->in
.right
);
if( p
->in
.op
== STCALL
|| p
->in
.op
== UNARY STCALL
){
/* set aside room for structure return */
if( p
->stn
.stsize
> temp
) temp1
= p
->stn
.stsize
;
if( temp
> maxargs
) maxargs
= temp
;
if( p
->in
.right
){ /* make temp node, put offset in, and generate args */
ptemp
->in
.name
[0] = '\0';
genargs( p
->in
.right
, ptemp
);
if( p1
->in
.op
!= OREG
|| R2TEST(p1
->tn
.rval
) ){
setup gc_numbytes so reference to ZC works */
gc_numbytes
= temp
&(0x3ff);
m
= match( p
, INTAREG
|INTBREG
);
cbgen( o
, lab
, mode
) { /* printf conditional and unconditional branches */
if( o
!= 0 && ( o
< EQ
|| o
> UGT
) )
cerror( "bad conditional branch: %s", opst
[o
] );
printf( " j%s L%d\n", o
== 0 ? "br" : ccbranches
[o
-EQ
], lab
);
nextcook( p
, cookie
) NODE
*p
; {
/* we have failed to match p with cookie; try another */
if( cookie
== FORREW
) return( 0 ); /* hopeless! */
if( !(cookie
&(INTAREG
|INTBREG
)) ) return( INTAREG
|INTBREG
);
if( !(cookie
&INTEMP
) && asgop(p
->in
.op
) ) return( INTEMP
|INAREG
|INTAREG
|INTBREG
|INBREG
);
lastchance( p
, cook
) NODE
*p
; {
optim2( p
) register NODE
*p
; {
/* do local tree transformations and optimizations */
/* simple ASG OPSIMP -- reduce range of constant rhs */
if( tlen(l
) < SZINT
/SZCHAR
&&
r
->in
.op
==ICON
&& r
->in
.name
[0]==0 ){
mask
= (1 << tlen(l
) * SZCHAR
) - 1;
if( r
->tn
.lval
& (mask
& ~(mask
>> 1)) )
if( r
->in
.op
==ICON
&& r
->in
.name
[0]==0 ) {
/* check for degenerate operations */
mask
= (1 << tlen(l
) * SZCHAR
) - 1;
if( o
== ASG AND
|| ISUNSIGNED(r
->in
.type
) ) {
/* all bits masked off */
if( tlen(l
) < SZINT
/SZCHAR
){
if( r
->tn
.lval
& (mask
& ~(mask
>> 1)) )
else if( r
->tn
.lval
== mask
&&
tlen(l
) < SZINT
/SZCHAR
) {
/* use movz instead of and */
r
->in
.type
= ENUNSIGN(l
->in
.type
);
r
->in
.su
= l
->in
.su
> 1 ? l
->in
.su
: 1;
if( p
->in
.type
== FLOAT
|| p
->in
.type
== DOUBLE
||
l
->in
.type
== FLOAT
|| l
->in
.type
== DOUBLE
)
if( (l
->in
.op
== CALL
|| l
->in
.op
== UNARY CALL
) &&
l
->in
.type
!= INT
&& l
->in
.type
!= UNSIGNED
)
/* Only trust it to get it right if the size is the same */
* Conversions are equivalent to assignments;
* when the two operations are combined,
* we can sometimes zap the conversion.
if ( r
->in
.op
== SCONV
&&
p
->in
.right
= r
->in
.left
;
if( p
->in
.left
->in
.op
== SCONV
&&
p
->in
.right
->in
.op
== SCONV
) {
if( l
->in
.type
== DOUBLE
&&
l
->in
.left
->in
.type
== FLOAT
&&
r
->in
.left
->in
.type
== FLOAT
) {
/* nuke the conversions */
p
->in
.right
= r
->in
.left
;
if( p
->in
.right
->in
.op
== ICON
&&
p
->in
.right
->tn
.name
[0] == '\0' &&
ISUNSIGNED(p
->in
.right
->in
.type
) &&
(unsigned) p
->in
.right
->tn
.lval
>= 0x80000000 ) {
/* easy to do here, harder to do in zzzcode() */
* basically we spot UCHAR and USHORT and try to do them
* as signed ints... this may need tuning for the tahoe.
if( !ISUNSIGNED(r
->in
.type
) ||
tlen(l
) >= SZINT
/SZCHAR
||
!(tlen(r
) < SZINT
/SZCHAR
||
(r
->in
.op
== ICON
&& r
->tn
.name
[0] == '\0')) )
if( o
== DIV
|| o
== MOD
) {
/* handle asgops in table */
/* pick up degenerate shifts */
if( !(r
->in
.op
== ICON
&& r
->tn
.name
[0] == '\0') )
/* front end 'fixes' this? */
if( o
== LS
|| o
== ASG LS
)
if( (o
== RS
|| o
== ASG RS
) &&
!ISUNSIGNED(l
->in
.type
) )
/* can't optimize signed right shifts */
if( i
< tlen(l
) * SZCHAR
)
if( tshape(l
, SAREG
|SNAME
|SCON
|SOREG
|STARNM
) ) {
degenerate(p
) register NODE
*p
; {
* try to keep degenerate comparisons with constants
lower
= -(1 << SZCHAR
- 1);
upper
= (1 << SZCHAR
- 1) - 1;
upper
= (1 << SZCHAR
) - 1;
lower
= -(1 << SZSHORT
- 1);
upper
= (1 << SZSHORT
- 1) - 1;
upper
= (1 << SZSHORT
) - 1;
cerror("unsupported type in degenerate()");
/* DIV and MOD work like EQ */
if( lower
== 0 && (unsigned) i
> upper
)
else if( i
< lower
|| i
> upper
)
if( lower
== 0 && (unsigned) i
> upper
)
if( lower
== 0 && (unsigned) i
>= upper
)
cerror("unknown op in degenerate()");
if( o
== MOD
|| o
== ASG MOD
) {
else if( o
!= ASG DIV
&& tshape(l
, SAREG
|SNAME
|SCON
|SOREG
|STARNM
) ) {
hardops(p
) register NODE
*p
; {
/* change hard to do operators into function calls. */
register struct functbl
*f
;
if( ! (optype(o
)==BITYPE
&&
(ISUNSIGNED(p
->in
.left
->in
.type
) ||
ISUNSIGNED(p
->in
.right
->in
.type
))) )
for( f
=opfunc
; f
->fop
; f
++ ) {
if( o
==f
->fop
) goto convert
;
if( p
->in
.right
->in
.op
== ICON
&& p
->in
.right
->tn
.name
[0] == '\0' )
/* 'J' in zzzcode() -- assumes DIV or MOD operations */
/* save a subroutine call -- use at most 5 instructions */
if( tlen(p
->in
.left
) < SZINT
/SZCHAR
&& tlen(p
->in
.right
) < SZINT
/SZCHAR
)
/* optim2() will modify the op into an ordinary int op */
switch( p
->in
.left
->in
.op
){
* rewrite (lval.fld /= rval); as
* ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
* else the compiler will evaluate lval twice.
if( q
->in
.op
== UNARY MUL
){
/* first allocate a temp storage */
temp
->tn
.lval
= BITOOR(freetemp(1));
temp
->in
.type
= INCREF(p
->in
.type
);
/* change ASG OP to a simple OP */
q
->in
.op
= NOASG p
->in
.op
;
q
->in
.left
= tcopy(p
->in
.left
);
q
->in
.right
= p
->in
.right
;
f
-= 2; /* Note: this depends on the table order */
/* on the right side only - replace *temp with
*(temp = &lval), build the assignment node */
temp
= q
->in
.left
->in
.left
; /* the "*" node */
q
->in
.left
= temp
->in
.left
;
q
->in
.type
= old
->in
.type
;
/* avoid doing side effects twice */
cerror( "hardops: can't compute & LHS" );
/* build comma op for args to function */
q
->in
.right
= p
->in
.right
;
/* put function name in left node of call */
p
->in
.left
= q
= talloc();
q
->in
.type
= INCREF( FTN
+ p
->in
.type
);
strcpy( q
->in
.name
, f
->func
);
/* look for ++ and -- operators and remove them */
p
->in
.right
->in
.op
= FREE
; /* zap constant */
if( ty
== BITYPE
) zappost( p
->in
.right
);
if( ty
!= LTYPE
) zappost( p
->in
.left
);
if( ty
== BITYPE
) fixpre( p
->in
.right
);
if( ty
!= LTYPE
) fixpre( p
->in
.left
);
NODE
* addroreg(l
) NODE
*l
;
/* OREG was built in clocal()
* for an auto or formal parameter
* now its address is being taken
* local code must unwind it
* back to PLUS/MINUS REG ICON
* according to local conventions
cerror("address of OREG taken");
main( argc
, argv
) char *argv
[]; {
return( mainp2( argc
, argv
) );
strip(p
) register NODE
*p
; {
/* strip nodes off the top when no side effects occur */
case SCONV
: /* remove lint tidbits */
/* could probably add a few more here */
myreader(p
) register NODE
*p
; {
strip( p
); /* strip off operations with no side effects */
canon( p
); /* expands r-vals for fields */
walkf( p
, hardops
); /* convert ops to function calls */