/* a lot of the machine dependent parts of the second pass */
# define BITMASK(n) ((1L<<n)-1)
lineid( l
, fn
) char *fn
; {
/* identify line l and file fn */
printf( "/ line %d, file %s\n", l
, fn
);
OFFSZ spoff
; /* offset from stack pointer */
if( spoff
>= AUTOINIT
) spoff
-= AUTOINIT
;
printf( " .F%d = %Ld.\n", ftnno
, spoff
);
printf( " .globl fltused\n" );
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", q
->opstring
);
if( f
== 'F' ) printf( "f" );
cerror( "no hoptab for %s", opst
[o
] );
rnames
[]= { /* keyed to register number tokens */
"fr0", "fr1", "fr2", "fr3",
"fr4", "fr5", /* not accumulators - used for temps */
SAREG
|STAREG
, SAREG
|STAREG
,
SAREG
|STAREG
, SAREG
|STAREG
, SAREG
|STAREG
, /* use as scratch if not reg var */
SBREG
|STBREG
, SBREG
|STBREG
, SBREG
|STBREG
, SBREG
|STBREG
,
int toff
= 0; /* number of stack locations used for args */
zzzcode( p
, c
) NODE
*p
; {
case 'B': /* output b if type is byte */
if( p
->type
== CHAR
|| p
->type
== UCHAR
) printf( "b" );
case 'N': /* logical ops, turned into 0-1 */
/* use register given by register 1 */
cbgen( 0, m
=getlab(), 'I' );
printf( " clr %s\n", rnames
[getlr( p
, '1' )->rval
] );
if( p
->type
== LONG
|| p
->type
== ULONG
)
printf( " clr %s\n", rnames
[getlr( p
, '1' )->rval
+ 1] );
cbgen( p
->op
, p
->label
, c
);
/* logical operators for longs
defer comparisons until branch occurs */
case 'H': /* fix up unsigned shifts */
if( p
->op
== ASG LS
) return;
if( p
->op
!= ASG RS
) cerror( "ZH bad" );
if( p
->left
->op
!= REG
) cerror( "SH left bad" );
l
= (t
==LONG
|| t
== ULONG
);
if( t
!= UNSIGNED
&& t
!= UCHAR
&& t
!= ULONG
) return; /* signed is ok */
/* there are three cases: right side is a constant,
and has the shift value; right side is
a temporary reg, and has the - shift value,
and right side is something else: A1 has the
/* in the case where the value is known (rhs a constant),
the mask is just computed and put out... */
if( p
->right
->op
== ICON
){
printf( " clr r%d\n", r
);
if( s
>= 16 ) printf( " clr r%d\n", r
);
m
>>= s
; /* sign extends... */
printf( " bic $%o,r%d\n", m
, r
);
if( istnode( p
->right
) ) q
= p
->right
;
else q
= getlr( p
, '1' ); /* where -shift is stored */
/* first, we store the shifted value on the stack */
printf( " mov r%d,-(sp)\n", r
);
if( l
) printf( " mov r%d,-(sp)\n", r
+1 );
printf( " mov $100000,r%d\n", r
);
if( l
) printf( " clr r%d\n", r
+1 );
/* shift (arithmetically ) */
if( l
) expand( q
, RNOP
, " ashc AR" );
else expand( q
, RNOP
, " ash AR" );
if( l
) printf( " ashc $1,r%d\n", r
);
else printf( " asl r%d\n", r
);
/* now, we have a mask: use it to clear sp, and reload */
printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r
+1, r
+1 );
printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r
, r
);
/* sign extend or not -- register is one less than the
if( ISUNSIGNED(p
->type
) ){
printf( " clr r%d\n", m
);
printf( " sxt r%d\n", m
);
/* stack management macros */
if( toff
++ ) printf( "-" );
if( toff
== 0 ) ++toff
; /* can't push doubles that way */
p
->right
->lval
= ~p
->right
->lval
;
conput( getlr( p
, 'R' ) );
p
->right
->lval
= ~p
->right
->lval
;
p
->right
->lval
= -p
->right
->lval
;
conput( getlr( p
, 'R' ) );
p
->right
->lval
= -p
->right
->lval
;
case 'L': /* INIT for long constants */
lo
= p
->left
->lval
& BITMASK(SZINT
);
hi
= ( p
->left
->lval
>> SZINT
) & BITMASK(SZINT
);
printf( " %o; %o\n", hi
, lo
);
/* Truncate longs for type conversions:
LONG|ULONG -> CHAR|UCHAR|INT|UNSIGNED
increment offset to second word */
rfree( p
->rval
, p
->type
);
rbusy( p
->rval
, p
->type
);
cerror( "Illegal ZT type conversion" );
/* same as AL for exp under U* */
if( p
->left
->op
== UNARY MUL
) {
adrput( getlr( p
->left
, 'L' ) );
case 'W': /* structure size */
printf( "%d", p
->stsize
);
else cerror( "Not a structure" );
case 'S': /* structure assignment */
else if( p
->op
== STARG
){ /* store an arg onto the stack */
else cerror( "STASG bad" );
if( r
->op
== ICON
) r
->op
= NAME
;
else if( r
->op
== REG
) r
->op
= OREG
;
else if( r
->op
!= OREG
) cerror( "STASG-r" );
if( p
->op
== STASG
) l
->lval
+= size
;
while( count
-- ){ /* simple load/store loop */
expand( r
, FOREFF
, " mov AR," );
expand( l
, FOREFF
, "AR\n" );
if( r
->op
== NAME
) r
->op
= ICON
;
else if( r
->op
== OREG
) r
->op
= REG
;
cerror( "illegal zzzcode" );
rmove( rt
, rs
, t
) TWORD t
; {
printf( " %s %s,%s\n", (t
==FLOAT
||t
==DOUBLE
)?"movf":"mov", rnames
[rs
], rnames
[rt
] );
INTAREG
|INTBREG
, INTAREG
|INTBREG
,
INAREG
|INBREG
, INAREG
|INBREG
|SOREG
|STARREG
|SNAME
|STARNM
|SCON
,
setregs(){ /* set up temporary registers */
/* use any unused variable registers as scratch registers */
fregs
= maxtreg
>=MINRVAR
? maxtreg
+ 1 : MINRVAR
;
/* -x changes number of free regs to 2, -xx to 3, etc. */
if( (xdebug
+1) < fregs
) fregs
= xdebug
+1;
/* NOTE: for pdp11 fregs <= 4 for float regs */
if( fregs
> 4 ) fregs
= 4;
for( i
=MINRVAR
; i
<=MAXRVAR
; i
++ )
rstatus
[i
] = i
<fregs
? SAREG
|STAREG
: SAREG
;
szty(t
) TWORD t
; { /* size, in words, needed to hold thing of type t */
/* really is the number of registers to hold type t */
return( (p
->type
==DOUBLE
||p
->type
==FLOAT
) ? FR0
: R0
);
shltype( o
, p
) NODE
*p
; {
if( o
== NAME
|| o
==REG
|| o
== ICON
|| o
== OREG
) return( 1 );
return( o
==UNARY MUL
&& shumul(p
->left
) );
flshape( p
) register NODE
*p
; {
if( o
==NAME
|| o
==REG
|| o
==ICON
|| o
==OREG
) return( 1 );
return( o
==UNARY MUL
&& shumul(p
->left
)==STARNM
);
shtemp( p
) register NODE
*p
; {
if( p
->op
== UNARY MUL
) p
= p
->left
;
if( p
->op
== REG
|| p
->op
== OREG
) return( !istreg( p
->rval
) );
return( p
->op
== NAME
|| p
->op
== ICON
);
spsz( t
, v
) TWORD t
; CONSZ v
; {
/* is v the size to increment something of type t */
if( !ISPTR(t
) ) return( 0 );
if( ISPTR(t
) ) return( v
== 2 );
shumul( p
) register NODE
*p
; {
if( o
== NAME
|| o
== OREG
|| o
== ICON
) return( STARNM
);
if( ( o
== INCR
|| o
== ASG MINUS
) &&
( p
->left
->op
== REG
&& p
->right
->op
== ICON
) &&
p
->right
->name
[0] == '\0' &&
spsz( p
->left
->type
, p
->right
->lval
) )
adrcon( val
) CONSZ val
; {
conput( p
) register NODE
*p
; {
printf( "%s", rnames
[p
->rval
] );
cerror( "illegal conput" );
/* output the address of the second word in the
pair pointed to by p (for LONGs)*/
/* addressable value of the constant */
p
->lval
&= BITMASK(SZINT
);
printf( "%s", rnames
[p
->rval
+1] );
if( p
->rval
== R5
){ /* in the argument region */
if( p
->name
[0] != '\0' ) werror( "bad arg temp" );
if( p
->lval
!= 0 || p
->name
[0] != '\0' ) acon( p
);
printf( "(%s)", rnames
[p
->rval
] );
cerror( "illegal upper address" );
adrput( p
) register NODE
*p
; {
/* output an address, with offsets, from p */
/* addressable value of the constant */
if( szty( p
->type
) == 2 ) {
/* print the high order value */
p
->lval
= ( p
->lval
>> SZINT
) & BITMASK(SZINT
);
printf( "%s", rnames
[p
->rval
] );
if( p
->rval
== R5
){ /* in the argument region */
if( p
->name
[0] != '\0' ) werror( "bad arg temp" );
printf( CONFMT
, p
->lval
);
if( p
->lval
!= 0 || p
->name
[0] != '\0' ) acon( p
);
printf( "(%s)", rnames
[p
->rval
] );
/* STARNM or STARREG found */
if( tshape(p
, STARNM
) ) {
else { /* STARREG - really auto inc or dec */
/* turn into OREG so replacement node will
reflect the value of the expression */
for( i
=0; i
<NCHNAM
; i
++ )
p
->lval
-= l
->right
->lval
;
else { /* l->op == ASG MINUS */
cerror( "illegal address" );
acon( p
) register NODE
*p
; { /* print out a constant */
if( p
->name
[0] == '\0' ){ /* constant only */
printf( CONFMT
, p
->lval
);
else if( p
->lval
== 0 ) { /* name only */
printf( "%.8s", p
->name
);
else { /* name + offset */
printf( "%.8s+", p
->name
);
printf( CONFMT
, p
->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 */
if( p
->right
) temp
= argsize( p
->right
);
if( p
->right
){ /* generate args */
if( !shltype( p
->left
->op
, p
->left
) ) {
order( p
->left
, INAREG
|SOREG
);
m
= match( p
, INTAREG
|INTBREG
);
popargs( size
) register size
; {
/* pop arguments from stack */
if( toff
== 0 && size
>= 2 ) size
-= 2;
printf( " tst (sp)+\n" );
printf( " cmp (sp)+,(sp)+\n" );
printf( " add $%d.,sp\n", size
);
This table, when indexed by a logical operator,
selects a set of three logical conditions required
to generate long comparisons and branches. A zero
entry indicates that no branch is required.
E.G.: The <= operator would generate:
jlt lable / 1st entry LT -> lable
jgt 1f / 2nd entry GT -> 1f
jlos lable / 3rd entry ULE -> lable
/* logical relations when compared in reverse order (cmp R,L) */
cbgen( o
, lab
, mode
) { /* printf conditional and unconditional branches */
if( o
== 0 ) printf( " jbr L%d\n", lab
);
else if( o
> UGT
) cerror( "bad conditional branch: %s", opst
[o
] );
expand( brnode
, FORCC
, brcase
=='C' ? "\tcmp\tAL,AR\n" : "\ttst\tAR\n" );
printf( ccbranches
[*plb
-EQ
], lab
);
printf( ccbranches
[*plb
-EQ
], lab1f
);
expand( brnode
, FORCC
, brcase
=='C' ? "\tcmp\tUL,UR\n" : "\ttst\tUR\n" );
printf( ccbranches
[*++plb
-EQ
], lab
);
reclaim( brnode
, RNULL
, 0 );
if( mode
=='F' ) o
= revrel
[ o
-EQ
];
printf( 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
->op
) ) return( INTEMP
|INAREG
|INTAREG
|INTBREG
|INBREG
);
lastchance( p
, cook
) NODE
*p
; {
ASG DIV
, ULONG
, "auldiv",
ASG MOD
, ULONG
, "aulrem",
hardops(p
) register NODE
*p
; {
/* change hard to do operators into function calls.
for pdp11 do long * / % */
register struct functbl
*f
;
if( t
!=LONG
&& t
!=ULONG
) return;
for( f
=opfunc
; f
->fop
; f
++ ) {
if( o
==f
->fop
&& t
==f
->ftype
) goto convert
;
/* need address of left node for ASG OP */
/* WARNING - this won't work for long in a REG */
case UNARY MUL
: /* convert to address */
case NAME
: /* convert to ICON pointer */
p
->left
->type
= INCREF( p
->left
->type
);
case OREG
: /* convert OREG to address */
p
->left
->type
= INCREF( p
->left
->type
);
if( p
->left
->lval
!= 0 ) {
q
->right
->name
[0] = '\0';
q
->right
->lval
= p
->left
->lval
;
cerror( "Bad address for hard ops" );
/* build comma op for args to function */
/* put function name in left node of call */
q
->type
= INCREF( FTN
+ p
->type
);
strcpy( q
->name
, f
->func
);
optim2( p
) register NODE
*p
; {
/* do local tree transformations and optimizations */
/* commute L and R to eliminate compliments and constants */
if( p
->left
->op
==ICON
|| p
->left
->op
==COMPL
) {
/* change meaning of AND to ~R&L - bic on pdp11 */
if( r
->op
==ICON
) { /* compliment constant */
else if( r
->op
==COMPL
) { /* ~~A => A */
else { /* insert complement node */
p
->right
->type
= r
->type
;
myreader(p
) register NODE
*p
; {
walkf( p
, hardops
); /* convert ops to function calls */
canon( p
); /* expands r-vals for fileds */
toff
= 0; /* stack offset swindle */
special( p
, shape
) register NODE
*p
; {
/* special shape matching routine */
if( p
->op
== ICON
&& p
->name
[0]=='\0' && p
->lval
>= -128 && p
->lval
<=127 ) return( 1 );
if( p
->op
== ICON
&& p
->name
[0]=='\0' && p
->lval
>= 0 && p
->lval
<=32767 ) return( 1 );
cerror( "bad special shape" );
main( argc
, argv
) char *argv
[]; {
return( mainp2( argc
, argv
) );