static char *sccsid
="@(#)local2.c 1.39 (Berkeley) 5/11/88";
# define putstr(s) fputs((s), stdout)
/* 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
;
if( spoff
>= AUTOINIT
) spoff
-= AUTOINIT
;
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( "L%d:\n", ftlab1
);
printf( " subl2 $%ld,sp\n", spoff
);
printf( " movab -%ld(sp),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( "%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",
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", rnames
[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
;
hopcode(rt
== FLOAT
? 'F' : 'D', p
->in
.op
);
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 left 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': /* num words pushed on arg stack */
if (xdebug
) printf("->%d<-",gc_numbytes
);
printf("$%d", gc_numbytes
/(SZLONG
/SZCHAR
) );
case 'D': /* INCR and DECR */
zzzcode(p
->in
.left
, 'A');
case 'E': /* INCR and DECR, FOREFF */
if (p
->in
.right
->in
.op
== ICON
&& p
->in
.right
->tn
.lval
== 1)
putstr(p
->in
.op
== INCR
? "inc" : "dec");
putstr(p
->in
.op
== INCR
? "add" : "sub");
case 'F': /* register type of right operand */
if (xdebug
) printf("->%d<-", ty
);
if ( ty
==DOUBLE
) putchar('d');
else if ( ty
==FLOAT
) putchar('f');
case 'L': /* type of left operand */
case 'R': /* type of right operand */
if (xdebug
) printf("->%d<-", n
->in
.type
);
case 'Z': /* AND for CC with ICON -- lval is complemented */
m
= (1 << tlen(l
) * SZCHAR
) - 1;
r
->tn
.lval
= ~r
->tn
.lval
;
if( (l
->in
.type
== CHAR
|| l
->in
.type
== SHORT
) &&
else if( l
->in
.type
== UCHAR
|| l
->in
.type
== USHORT
)
/* remove trash left over from complementing */
printf("\t$%ld", r
->tn
.lval
);
case 'U': /* 32 - n, for unsigned right shifts */
printf("$%d", 32 - p
->in
.right
->tn
.lval
);
case 'T': /* rounded structure length for arguments */
case 'S': /* structure assignment */
cerror( "illegal zzzcode" );
else if( p
->in
.op
== STARG
){ /* store an arg into a temporary */
else cerror( "STASG bad" );
if( r
->in
.op
== ICON
) r
->in
.op
= NAME
;
else if( r
->in
.op
== REG
) r
->in
.op
= OREG
;
else if( r
->in
.op
!= OREG
) cerror( "STASG-r" );
if( size
<= 0 || size
> 65535 )
cerror("structure size <0=0 or >65535");
printf(" movc3 $%d,", size
);
if( r
->in
.op
== NAME
) r
->in
.op
= ICON
;
else if( r
->in
.op
== OREG
) r
->in
.op
= REG
;
NODE
*makearg( ty
) int ty
; {
/* build a -(sp) operand */
/* the type needn't be right, just consistent */
/* size of floating argument is always 2 */
p
->tn
.lval
= (1 + (ty
== FLOAT
|| ty
== DOUBLE
)) * (SZINT
/SZCHAR
);
sconv( p
, forarg
) register NODE
*p
; {
if (xdebug
) eprint(p
, 0, &val
, &val
);
else if (p
->in
.op
== SCONV
) {
m
= (r
->in
.type
==FLOAT
|| r
->in
.type
==DOUBLE
? r
->in
.type
: INT
);
if (r
->in
.name
[0] == '\0') {
(r
->in
.type
== DOUBLE
|| r
->in
.type
== FLOAT
||
if (r
->tn
.lval
< 0 && r
->tn
.lval
>= -63) {
r
->tn
.lval
= -r
->tn
.lval
;
r
->in
.type
= r
->tn
.lval
>= -128 ? CHAR
: (r
->tn
.lval
>= -32768 ? SHORT
else if (l
->in
.type
== FLOAT
||
r
->in
.type
= r
->tn
.lval
<= 63 ? INT
: (r
->tn
.lval
<= 127 ? CHAR
: (r
->tn
.lval
<= 32767 ? SHORT
r
->in
.type
= r
->tn
.lval
<= 63 ? INT
: (r
->tn
.lval
<= 127 ? CHAR
: (r
->tn
.lval
<= 255 ? UCHAR
: (r
->tn
.lval
<= 32767 ? SHORT
: (r
->tn
.lval
<= 65535 ? USHORT
if (forarg
&& r
->in
.type
== INT
) {
if (forarg
&& tlen(r
) == SZINT
/SZCHAR
) {
!(l
->in
.type
== FLOAT
|| l
->in
.type
== DOUBLE
) &&
* Because registers must always contain objects
* of the same width as INTs, we may have to
* perform two conversions to get an INT. Can
* the conversions be collapsed into one?
if (m
= collapsible(l
, r
))
/* two steps are required */
if (tlen(x
) > tlen(r
) && ISUNSIGNED(r
->in
.type
))
l
->in
.type
= (ISUNSIGNED(l
->in
.type
) ? UNSIGNED
: INT
);
else if ((forarg
|| l
== resc
) &&
tlen(l
) < SZINT
/SZCHAR
&&
/* two steps needed here too */
l
->in
.type
= (ISUNSIGNED(l
->in
.type
) ? UNSIGNED
: INT
);
else if ((r
->in
.type
== UNSIGNED
|| r
->in
.type
== ULONG
) &&
#if defined(FORT) || defined(SPRECC)
/* compute in register, convert to double when done */
printf("\n\tjgeq\tL%d\n\tadd", label1
);
putstr("4.294967296e9,");
printf("\nL%d:", label1
);
#if defined(FORT) || defined(SPRECC)
if (!forarg
&& (l
->in
.type
== DOUBLE
|| l
!= resc
))
else if( (l
->in
.type
== FLOAT
|| l
->in
.type
== DOUBLE
) &&
(r
->in
.type
== UCHAR
|| r
->in
.type
== USHORT
) ) {
/* skip unnecessary unsigned to floating conversion */
#if defined(FORT) || defined(SPRECC)
#if defined(FORT) || defined(SPRECC)
if (forarg
&& l
->in
.type
== FLOAT
)
if ((forarg
|| l
== resc
) && l
->in
.type
== FLOAT
)
/* perform an implicit conversion to double */
if (r
->in
.type
!= FLOAT
&&
/* trim bits from the mantissa */
if (tlen(l
) == tlen(r
)) {
if (forarg
&& tlen(l
) == SZINT
/SZCHAR
) {
if (l
->in
.type
== DOUBLE
)
else if(l
->in
.type
== FLOAT
)
else if (tlen(l
) > tlen(r
) && ISUNSIGNED(r
->in
.type
))
* collapsible(dest, src) -- if a conversion with a register destination
* can be accomplished in one instruction, return the type of src
* that will do the job correctly; otherwise return 0. Note that
* a register must always end up having type INT or UNSIGNED.
* Are there side effects of evaluating src?
* If the derived type will not be the same size as src,
* we may have to use two steps.
if (tlen(src
) > tlen(dest
)) {
if (tshape(src
, STARREG
))
if (src
->in
.op
== OREG
&& R2TEST(src
->tn
.rval
))
* Can we get an object of dest's type by punning src?
* Praises be to great Cthulhu for little-endian machines...
if (st
== CHAR
&& dt
== USHORT
)
* Special case -- we must sign-extend to 16 bits.
if (tlen(src
) < tlen(dest
))
rmove( rt
, rs
, t
) TWORD t
; {
!Oflag
? (t
==DOUBLE
? "movq" : "movl") :
(t
==FLOAT
? "movf" : (t
==DOUBLE
? "movd" : "movl")),
rnames
[rs
], rnames
[rt
] );
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 VAX (0-5) */
base( p
) register NODE
*p
; {
register int o
= p
->in
.op
;
if( o
==ICON
&& p
->tn
.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
==INCR
&& p
->in
.left
->in
.op
==REG
) return( p
->in
.left
->tn
.rval
+ 0200*2 );
if( o
==ASG MINUS
&& p
->in
.left
->in
.op
==REG
) return( p
->in
.left
->tn
.rval
+ 0200*4 );
if( o
==UNARY MUL
&& p
->in
.left
->in
.op
==INCR
&& p
->in
.left
->in
.left
->in
.op
==REG
&& (p
->in
.type
==INT
|| p
->in
.type
==UNSIGNED
|| ISPTR(p
->in
.type
)) )
return( p
->in
.left
->in
.left
->tn
.rval
+ 0200*(1+2) );
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);
register int o
= p
->in
.op
;
return( o
== REG
|| o
== NAME
|| o
== ICON
||
(o
== OREG
&& (!R2TEST(p
->tn
.rval
) || tlen(p
) == 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
; {
eprint(p
, 0, &val
, &val
);
if( o
== NAME
|| (o
== OREG
&& !R2TEST(p
->tn
.rval
)) || o
== ICON
) return( STARNM
);
if( ( o
== INCR
|| o
== ASG MINUS
) &&
( p
->in
.left
->in
.op
== REG
&& p
->in
.right
->in
.op
== ICON
) &&
p
->in
.right
->in
.name
[0] == '\0' )
if ( ISPTR(p
->in
.type
) &&
ISPTR(DECREF(p
->in
.type
)) ) {
return( p
->in
.right
->tn
.lval
== o
? STARREG
: 0);
adrcon( val
) CONSZ val
; {
conput( p
) register NODE
*p
; {
putstr( rnames
[p
->tn
.rval
] );
cerror( "illegal conput" );
upput( p
, size
) NODE
*p
; int size
; {
if( size
== SZLONG
&& p
->in
.op
== REG
) {
putstr( rnames
[p
->tn
.rval
+ 1] );
adrput( p
) register NODE
*p
; {
/* output an address, with offsets, from p */
/* addressable value of the constant */
putstr( rnames
[p
->tn
.rval
] );
if( R2TEST(r
) ){ /* double indexing */
if( flags
& 1 ) putchar('*');
if( flags
& 4 ) putchar('-');
if( p
->tn
.lval
!= 0 || p
->in
.name
[0] != '\0' ) acon(p
);
if( R2UPK1(r
) != 100) printf( "(%s)", rnames
[R2UPK1(r
)] );
if( flags
& 2 ) putchar('+');
printf( "[%s]", rnames
[R2UPK2(r
)] );
if( r
== AP
){ /* 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)", rnames
[p
->tn
.rval
] );
/* STARNM or STARREG found */
if( tshape(p
, STARNM
) ) {
else { /* STARREG - really auto inc or dec */
if( q
->in
.right
->tn
.lval
!= tlen(p
) )
cerror("adrput: bad auto-increment/decrement");
printf("%s(%s)%s", (q
->in
.op
==INCR
? "" : "-"),
rnames
[q
->in
.left
->tn
.rval
],
(q
->in
.op
==INCR
? "+" : "") );
p
->tn
.rval
= q
->in
.left
->tn
.rval
;
p
->tn
.lval
= (q
->in
.op
== INCR
? -q
->in
.right
->tn
.lval
: 0);
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
) );
gencall( p
, cookie
) register NODE
*p
; {
/* generate the call given by p */
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 */
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
);
/* compensate for deficiency in 'ret' instruction ... wah,kre */
/* (plus in assignment to gc_numbytes above, for neatness only) */
printf(" addl2 $%d,sp\n", (temp
&(~0x3ff)));
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)) )
/* commute L and R to eliminate complements and constants */
if( (l
= p
->in
.left
)->in
.op
== ICON
&& l
->in
.name
[0] == 0 ||
p
->in
.left
= p
->in
.right
;
/* change meaning of AND to ~R&L - bic on pdp11/vax */
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 bic */
r
->in
.type
= ENUNSIGN(l
->in
.type
);
r
->in
.su
= l
->in
.su
> 1 ? l
->in
.su
: 1;
/* complement constant */
r
->tn
.lval
= ~r
->tn
.lval
;
else if( r
->in
.op
==COMPL
) { /* ~~A => A */
p
->in
.right
= r
->in
.left
;
else { /* insert complement node */
p
->in
.right
= l
= talloc();
#if defined(FORT) || defined(SPRECC)
if( p
->in
.type
== FLOAT
|| p
->in
.type
== DOUBLE
||
l
->in
.type
== FLOAT
|| l
->in
.type
== DOUBLE
)
if( mixtypes(p
, l
) ) return;
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... apparently div+mul+sub is always
* faster than ediv for finding MOD on the VAX, when
* full unsigned MOD isn't needed.
* a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub
* are faster for unsigned dividend and a constant divisor
* in the right range (.5 to 1 of dividend's range for the
* first, .333+ to .5 for the second). full unsigned is
* already done cmp+sub in the appropriate case; the
* other cases are less common and require more ambition.
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', 'K' 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 */