static char *sccsid
="@(#)reader.c 4.2 (Berkeley) %G%";
/* some storage declarations */
char filename
[100] = ""; /* the name of the file */
int ftnno
; /* number of current function */
OFFSZ tmpoff
; /* offset for first temporary, in bits for current block */
OFFSZ maxoff
; /* maximum temporary offset over all blocks in current ftn, in bits */
p2init( argc
, argv
) char *argv
[];{
/* set the values of the pass 2 arguments */
allo0(); /* free all regs */
if( *(cp
=argv
[c
]) == '-' ){
case 'X': /* pass1 flags */
while( *++cp
) { /* VOID */ }
case 'e': /* expressions */
case 'r': /* register allocation */
case 't': /* ttype calls */
case 'u': /* Sethi-Ullman testing (machine dependent) */
case 'x': /* general machine-dependent debugging flag */
case 'W': /* shut up warnings */
case 'O': /* optimizing */
cerror( "bad option: %c", *cp
);
else files
= 1; /* assumed to be a filename */
mainp2( argc
, argv
) char *argv
[]; {
files
= p2init( argc
, argv
);
while( files
< argc
&& argv
[files
][0] == '-' ) {
if( files
> argc
) return( nerrors
);
freopen( argv
[files
], "r", stdin
);
while( (c
=getchar()) > 0 ) switch( c
){
/* copy line unchanged */
PUTCHAR( c
); /* initial tab */
while( (c
=getchar()) > 0 ){
/* beginning of a block */
temp
= rdin(10); /* ftnno */
tmpoff
= baseoff
= (unsigned int) rdin(10); /* autooff for block gives max offset of autos in block */
if( getchar() != '\n' ) cerror( "intermediate file format error");
if( temp
!= ftnno
){ /* beginning of function */
if( baseoff
> maxoff
) maxoff
= baseoff
;
/* maxoff at end of ftn is max of autos and temps
over all blocks in the function */
case BEND
: /* end of block */
SETOFF( maxoff
, ALSTACK
);
while( (c
=getchar()) != '\n' ){
if( c
<= 0 ) cerror( "intermediate file format eof" );
/* compile code for an expression */
for( cp
=filename
; (*cp
=getchar()) != '\n'; ++cp
) ; /* VOID, reads filename */
if( lflag
) lineid( lineno
, filename
);
tmpoff
= baseoff
; /* expression at top level reuses temps */
if( edebug
) fwalk( p
, eprint
, 0 );
MYREADER(p
); /* do your own laundering of the input */
delay( p
); /* expression statement throws out results */
cerror( "intermediate file format error" );
p2compile( p
) NODE
*p
; {
if( lflag
) lineid( lineno
, filename
);
tmpoff
= baseoff
; /* expression at top level reuses temps */
/* generate code for the tree p */
if( edebug
) fwalk( p
, eprint
, 0 );
MYREADER(p
); /* do your own laundering of the input */
delay( p
); /* do the code generation */
/* can't do tcheck here; some stuff (e.g., attributes) may be around from first pass */
/* first pass will do it... */
tmpoff
= baseoff
= (unsigned int) aoff
;
if( myftn
!= ftnno
){ /* beginning of function */
if( baseoff
> maxoff
) maxoff
= baseoff
;
/* maxoff at end of ftn is max of autos and temps over all blocks */
SETOFF( maxoff
, ALSTACK
);
delay( p
) register NODE
*p
; {
/* look in all legal places for COMOP's and ++ and -- ops to delay */
/* note; don't delay ++ and -- within calls or things like
/* getchar (in their macro forms) will start behaving strangely */
/* look for visible COMOPS, and rewrite repeatedly */
while( delay1( p
) ) { /* VOID */ }
/* look for visible, delayable ++ and -- */
codgen( p
, FOREFF
); /* do what is left */
for( i
= 0; i
<deli
; ++i
) codgen( deltrees
[i
], FOREFF
); /* do the rest */
delay1( p
) register NODE
*p
; { /* look for COMOPS */
if( ty
== LTYPE
) return( 0 );
else if( ty
== UTYPE
) return( delay1( p
->in
.left
) );
return( delay1(p
->in
.left
) );
case COMOP
: /* the meat of the routine */
delay( p
->in
.left
); /* completely evaluate the LHS */
return( delay1(p
->in
.left
) || delay1(p
->in
.right
) );
delay2( p
) register NODE
*p
; {
/* look for delayable ++ and -- operators */
/* for the moment, don7t delay past a conditional context, or
/* if *p++, do not rewrite */
if( autoincr( p
) ) return;
deltrees
[deli
++] = tcopy(p
);
p
->in
.right
->in
.op
= FREE
; /* zap constant */
if( ty
== BITYPE
) delay2( p
->in
.right
);
if( ty
!= LTYPE
) delay2( p
->in
.left
);
codgen( p
, cookie
) NODE
*p
; {
/* generate the code for p;
order may call codgen recursively */
/* cookie is used to describe the context */
canon(p
); /* creats OREG from * if possible and does sucomp */
printf( "store called on:\n" );
if( stotree
==NIL
) break;
/* because it's minimal, can do w.o. stores */
order( stotree
, stocook
);
/* print a nice-looking description of cookie */
if( cookie
== SZERO
) printf( "SZERO" );
else if( cookie
== SONE
) printf( "SONE" );
else if( cookie
== SMONE
) printf( "SMONE" );
else printf( "SPECIAL+%d", cookie
& ~SPECIAL
);
for( i
=0; cnames
[i
]; ++i
){
if( flag
) printf( "|" );
/* by this time, p should be able to be generated without stores;
the only question is how */
return; /* whole tree was done */
/* if any rewriting and canonicalization has put
* the tree (p) into a shape that cook is happy
* with (exclusive of FOREFF, FORREW, and INTEMP)
* this allows us to call order with shapes in
* addition to cookies and stop short if possible.
if( tshape(p
, cook
&(~(FOREFF
|FORREW
|INTEMP
))) )return;
printf( "order( %o, ", p
);
/* first of all, for most ops, see if it is in the table */
/* look for op in table */
if( (m
= match( p
, cookie
) ) == MDONE
) goto cleanup
;
if( !(cookie
= nextcook( p
, cookie
) ) ) goto nomat
;
/* don't even go near the table... */
/* get here to do rewriting if no match or
fall through from above for hard ops */
if( ty
== BITYPE
) p2
= p
->in
.right
;
printf( "order( %o, ", p
);
printf( ", rewrite %s\n", opst
[m
] );
cerror( "no table entry for op %s", opst
[p
->in
.op
] );
p2
->in
.rall
= p
->in
.rall
;
/* recurse, letting the work be done by rallo */
cbranch( p1
, -1, m
=getlab() );
p2
->in
.left
->in
.rall
= p
->in
.rall
;
codgen( p2
->in
.left
, INTAREG
|INTBREG
);
/* force right to compute result into same reg used by left */
p2
->in
.right
->in
.rall
= p2
->in
.left
->tn
.rval
|MUSTDO
;
reclaim( p2
->in
.left
, RNULL
, 0 );
cbgen( 0, m1
= getlab(), 'I' );
codgen( p2
->in
.right
, INTAREG
|INTBREG
);
p
->in
.op
= REG
; /* set up node describing result */
p
->tn
.rval
= p2
->in
.right
->tn
.rval
;
p
->in
.type
= p2
->in
.right
->in
.type
;
case NOT
: /* logical operators */
/* if here, must be a logical operator for 0-1 value */
cbranch( p
, -1, m
=getlab() );
case FLD
: /* fields of funny type */
if ( p1
->in
.op
== UNARY MUL
){
order( p1
, INBREG
|INAREG
);
/* all leaves end up here ... */
if( o
== REG
) goto nomat
;
order( p
, INTAREG
|INTBREG
);
uerror( "illegal initialization" );
o
= p
->in
.op
= UNARY FORTCALL
;
if( genfcall( p
, cookie
) ) goto nomat
;
o
= p
->in
.op
= UNARY CALL
;
if( gencall( p
, cookie
) ) goto nomat
;
o
= p
->in
.op
= UNARY STCALL
;
if( genscall( p
, cookie
) ) goto nomat
;
/* if arguments are passed in register, care must be taken that reclaim
/* not throw away the register which now has the result... */
order( p
->in
.left
, FOREFF
);
case INCR
: /* INCR and DECR */
if( setincr(p
) ) goto again
;
/* x++ becomes (x += 1) -1; */
if( cook
& FOREFF
){ /* result not needed so inc or dec and be done with it */
p
->in
.op
= (p
->in
.op
==INCR
)?ASG PLUS
:ASG MINUS
;
reclaim( p
->in
.left
, RNULL
, 0 );
p1
->in
.op
= (p
->in
.op
==INCR
)?ASG PLUS
:ASG MINUS
;
p
->in
.op
= (p
->in
.op
==INCR
)?MINUS
:PLUS
;
if( setstr( p
) ) goto again
;
case ASG PLUS
: /* and other assignment ops */
if( setasop(p
) ) goto again
;
/* there are assumed to be no side effects in LHS */
reclaim( p
->in
.right
, RNULL
, 0 );
if( odebug
) fwalk( p
, eprint
, 0 );
order( p2
->in
.left
, INTBREG
|INTAREG
);
order( p2
, INTBREG
|INTAREG
);
if( setasg( p
) ) goto again
;
if( setbin( p
) ) goto again
;
/* try to replace binary ops by =ops */
/* if it is not yet in the right state, put it there */
if( p
->in
.op
==FREE
) return;
if( tshape( p
, cook
) ) return;
if( (m
=match(p
,cook
) ) == MDONE
) return;
/* we are in bad shape, try one last chance */
if( lastchance( p
, cook
) ) goto again
;
store( p
) register NODE
*p
; {
/* find a subtree of p which should be stored */
if( ty
== LTYPE
) return;
if( asgop(p
->in
.left
->in
.op
) ) stoasg( p
->in
.left
, UNARY MUL
);
stoarg( p
->in
.right
, o
);
if( p
->in
.right
->in
.su
> fregs
) SETSTO( p
, INTEMP
);
if( p
->in
.right
->in
.su
> fregs
) SETSTO( p
, INTEMP
);
case CBRANCH
: /* to prevent complicated expressions on the LHS from being stored */
if( asgop( p
->in
.right
->in
.op
) ) stoasg( p
->in
.right
, o
);
if( p
->in
.su
>fregs
){ /* must store */
mkadrs( p
); /* set up stotree and stocook to subtree
constore( p
) register NODE
*p
; {
/* store conditional expressions */
/* the point is, avoid storing expressions in conditional
conditional context, since the evaluation order is predetermined */
markcall( p
) register NODE
*p
; { /* mark off calls below the current node */
switch( optype( p
->in
.op
) ){
/* eliminate recursion (aren't I clever...) */
stoarg( p
, calltype
) register NODE
*p
; {
/* arrange to store the args */
stoarg( p
->in
.left
, calltype
);
else if( calltype
== STCALL
){
if( callflag
){ /* prevent two calls from being active at once */
store(p
); /* do again to preserve bottom up nature.... */
int negrel
[] = { NE
, EQ
, GT
, GE
, LT
, LE
, UGT
, UGE
, ULT
, ULE
} ; /* negatives of relationals */
cbranch( p
, true, false ) NODE
*p
; {
/* evaluate p for truth value, and branch to true or false
/* accordingly: label <0 means fall through */
register o
, lab
, flab
, tlab
;
o
= p
->in
.op
= negrel
[ o
-EQ
];
if( p
->in
.right
->in
.op
== ICON
&& p
->in
.right
->tn
.lval
== 0 && p
->in
.right
->in
.name
[0] == '\0' ){
o
= p
->in
.op
= (o
==UGT
)?NE
:EQ
;
if( logop(p
->in
.left
->in
.op
) ){
/* strange situation: e.g., (a!=0) == 0 */
/* must prevent reference to p->in.left->lable, so get 0/1 */
/* we could optimize, but why bother */
codgen( p
->in
.left
, INAREG
|INBREG
);
codgen( p
->in
.left
, FORCC
);
codgen(p
->in
.left
, FORCC
);
cbgen( 0, true, 'I' ); /* unconditional branch */
codgen(p
->in
.left
, FORCC
);
if( false>=0 ) cbgen( 0, false, 'I' );
lab
= false<0 ? getlab() : false ;
cbranch( p
->in
.left
, -1, lab
);
cbranch( p
->in
.right
, true, false );
if( false < 0 ) deflab( lab
);
lab
= true<0 ? getlab() : true;
cbranch( p
->in
.left
, lab
, -1 );
cbranch( p
->in
.right
, true, false );
if( true < 0 ) deflab( lab
);
cbranch( p
->in
.left
, false, true );
codgen( p
->in
.left
, FOREFF
);
cbranch( p
->in
.right
, true, false );
flab
= false<0 ? getlab() : false;
tlab
= true<0 ? getlab() : true;
cbranch( p
->in
.left
, -1, lab
= getlab() );
cbranch( p
->in
.right
->in
.left
, tlab
, flab
);
cbranch( p
->in
.right
->in
.right
, true, false );
if( true < 0 ) deflab( tlab
);
if( false < 0 ) deflab( flab
);
p
->in
.right
->in
.op
= FREE
;
if( p
->in
.type
!= FLOAT
&& p
->in
.type
!= DOUBLE
){
if( p
->tn
.lval
|| p
->in
.name
[0] ){
/* addresses of C objects are never 0 */
if( true>=0 ) cbgen( 0, true, 'I' );
else if( false>=0 ) cbgen( 0, false, 'I' );
/* fall through to default with other strange constants */
/* get condition codes */
if( true >= 0 ) cbgen( NE
, true, 'I' );
if( false >= 0 ) cbgen( true >= 0 ? 0 : EQ
, false, 'I' );
rcount(){ /* count recursions */
cerror( "expression causes compiler loop: try simplifying" );
eprint( p
, down
, a
, b
) NODE
*p
; int *a
, *b
; {
if( down
-- ) printf( " " );
printf( "%o) %s", p
, opst
[p
->in
.op
] );
switch( p
->in
.op
) { /* special cases */
printf( " %s", rnames
[p
->tn
.rval
] );
printf( " size=%d", p
->stn
.stsize
);
printf( " align=%d", p
->stn
.stalign
);
if( p
->in
.rall
== NOPREF
) printf( "NOPREF" );
if( p
->in
.rall
& MUSTDO
) printf( "MUSTDO " );
printf( "%s", rnames
[p
->in
.rall
&~MUSTDO
]);
printf( ", SU= %d\n", p
->in
.su
);
/* call eread recursively to get subtrees, if any */
if( i
== LTYPE
) p
->tn
.lval
= rdin( 10 );
if( i
!= BITYPE
) p
->tn
.rval
= rdin( 10 );
p
->in
.rall
= NOPREF
; /* register allocation information */
if( p
->in
.op
== STASG
|| p
->in
.op
== STARG
|| p
->in
.op
== STCALL
|| p
->in
.op
== UNARY STCALL
){
p
->stn
.stsize
= (rdin( 10 ) + (SZCHAR
-1) )/SZCHAR
;
p
->stn
.stalign
= rdin(10) / SZCHAR
;
if( getchar() != '\n' ) cerror( "illegal \n" );
if( p
->in
.op
== REG
) rbusy( p
->tn
.rval
, p
->in
.type
); /* non usually, but sometimes justified */
for( pc
=p
->in
.name
,j
=0; ( c
= getchar() ) != '\n'; ++j
){
if( j
< NCHNAM
) *pc
++ = c
;
if( j
< NCHNAM
) *pc
= '\0';
for( pc
=buf
,j
=0; ( c
= getchar() ) != '\n'; ++j
){
if( j
< BUFSIZ
) *pc
++ = c
;
if( j
< BUFSIZ
) *pc
= '\0';
/* now, recursively read descendents, if any */
if( i
!= LTYPE
) p
->in
.left
= eread();
if( i
== BITYPE
) p
->in
.right
= eread();
while( (c
=getchar()) > 0 ) {
if( val
!= 0 ) cerror( "illegal -");
cerror( "illegal character `%c' on intermediate file", c
);
cerror( "unexpected EOF");
/* do this if there is no special hardware support for fields */
ffld( p
, down
, down1
, down2
) NODE
*p
; int *down1
, *down2
; {
/* look for fields that are not in an lvalue context, and rewrite them... */
*down1
= asgop( p
->in
.op
);
if( !down
&& p
->in
.op
== FLD
){ /* rewrite the node */
ty
= (szty(p
->in
.type
) == 2)? LONG
: INT
;
o
= UPKFOFF(v
); /* amount to shift */
o
= szty(p
->in
.type
)*SZINT
- s
- UPKFOFF(v
); /* amount to shift */
p
->in
.left
->in
.type
= ty
;
p
->in
.right
->in
.op
= ICON
;
p
->in
.right
->in
.rall
= NOPREF
;
p
->in
.right
->in
.type
= ty
;
p
->in
.right
->tn
.lval
= 1;
p
->in
.right
->tn
.rval
= 0;
p
->in
.right
->in
.name
[0] = '\0';
p
->in
.right
->in
.name
= "";
p
->in
.right
->tn
.lval
<<= s
;
/* now, if a shift is needed, do it */
shp
->in
.left
= p
->in
.left
;
shp
->in
.right
= talloc();
shp
->in
.right
->in
.op
= ICON
;
shp
->in
.right
->in
.rall
= NOPREF
;
shp
->in
.right
->in
.type
= ty
;
shp
->in
.right
->tn
.rval
= 0;
shp
->in
.right
->tn
.lval
= o
; /* amount to shift */
shp
->in
.right
->in
.name
[0] = '\0';
shp
->in
.right
->in
.name
= "";
oreg2( p
) register NODE
*p
; {
/* look for situations where we can turn * into OREG */
if( p
->in
.op
== UNARY MUL
){
if( q
->in
.op
!= PLUS
&& q
->in
.op
!= MINUS
) return;
/* look for doubly indexed expressions */
if( (r
=base(ql
))>=0 && (i
=offset(qr
, tlen(p
)))>=0) {
} else if( (r
=base(qr
))>=0 && (i
=offset(ql
, tlen(p
)))>=0) {
if( (q
->in
.op
==PLUS
|| q
->in
.op
==MINUS
) && qr
->in
.op
== ICON
&&
ql
->in
.op
==REG
&& szty(qr
->in
.type
)==1) {
if( q
->in
.op
== MINUS
) temp
= -temp
;
if( *cp
&& ( q
->in
.op
== MINUS
|| *ql
->in
.name
) ) return;
if( !*cp
) cp
= ql
->in
.name
;
if( notoff( p
->in
.type
, r
, temp
, cp
) ) return;
for( i
=0; i
<NCHNAM
; ++i
)
/* put p in canonical form */
fwalk( p
, ffld
, 0 ); /* look for field operators */
walkf( p
, oreg2
); /* look for and create OREG nodes */
MYCANON(p
); /* your own canonicalization routine(s) */
walkf( p
, sucomp
); /* do the Sethi-Ullman computation */