char maprel
[] { EQUAL
, NEQUAL
, GREATEQ
, GREAT
, LESSEQ
,
LESS
, GREATQP
, GREATP
, LESSEQP
, LESSP
char notrel
[] { NEQUAL
, EQUAL
, GREAT
, GREATEQ
, LESS
,
LESSEQ
, GREATP
, GREATQP
, LESSP
, LESSEQP
struct tconst czero
{ CON
, INT
, 0, 0};
struct tconst cone
{ CON
, INT
, 0, 1};
struct tconst fczero
{ SFCON
, DOUBLE
, 0, 0 };
if(fopen(argv
[1], ascbuf
)<0) {
error("Missing temp file");
if ((fout
= creat(argv
[3], 0666)) < 0) {
error("Can't create %s", argv
[3]);
* If any floating-point instructions
* were used, generate a reference which
* pulls in the floating-point part of printf.
printf(".globl fltused\n");
* tack on the string file.
if (fopen(argv
[2], ascbuf
)<0) {
error("Missing temp file");
printf(".globl\n.data\n");
* Given a tree, a code table, and a
* count of available registers, find the code table
* for the appropriate operator such that the operands
* are of the right type and the number of registers
* required is not too large.
* Return a ptr to the table entry or 0 if none found.
char *match(atree
, table
, nrleft
)
int op
, d1
, d2
, t1
, t2
, dope
;
register struct tnode
*p1
, *tree
;
register struct optab
*opt
;
* If a subtree starts off with a conversion operator,
* try for a match with the conversion eliminated.
* E.g. int = double can be done without generating
* the converted int in a register by
* movf double,fr0; movfi fr0,int .
if(opdope
[p1
->op
]&CNVRT
&& (opdope
[p2
->op
]&CNVRT
)==0) {
if (opt
= match(tree
, table
, nrleft
))
} else if (opdope
[p2
->op
]&CNVRT
&& (opdope
[p1
->op
]&CNVRT
)==0) {
if (opt
= match(tree
, table
, nrleft
))
for (; table
->op
!=op
; table
++)
for (opt
= table
->tabp
; opt
->tabdeg1
!=0; opt
++) {
if (d1
> (opt
->tabdeg1
&077)
|| (opt
->tabdeg1
>= 0100 && (p1
->op
!= STAR
)))
if (notcompat(p1
, opt
->tabtyp1
, op
)) {
if ((opdope
[op
]&BINARY
)!=0 && p2
!=0) {
if (d2
> (opt
->tabdeg2
&077)
|| (opt
->tabdeg2
>= 0100) && (p2
->op
!= STAR
) )
if (notcompat(p2
,opt
->tabtyp2
, 0))
* Given a tree, a code table, and a register,
* produce code to evaluate the tree with the appropriate table.
* Registers reg and upcan be used.
* If there is a value, it is desired that it appear in reg.
* The routine returns the register in which the value actually appears.
* This routine must work or there is an error.
* If the table called for is cctab, sptab, or efftab,
* and tree can't be done using the called-for table,
* If the tree can't be compiled using cctab, regtab is
* used and a "tst" instruction is produced.
* If the tree can't be compiled using sptab,
* regtab is used and the register is pushed on the stack.
* If the tree can't be compiled using efftab,
* Regtab must succeed or an "op not found" error results.
* A number of special cases are recognized, and
* there is an interaction with the optimizer routines.
rcexpr(atree
, atable
, reg
)
register struct tnode
*tree
;
register struct table
*table
;
cbranch(optim(tree
->btree
), tree
->lbl
, tree
->cond
, 0);
* An initializing expression
if (tree
->tr1
->op
== AMPER
)
tree
->tr1
= tree
->tr1
->tr1
;
error("Illegal initialization");
* Put the value of an expression in r0,
* for a switch or a return
if((r
=rcexpr(tree
->tr1
, regtab
, reg
)) != 0)
printf("mov%c r%d,r0\n", isfloat(tree
->tr1
), r
);
rcexpr(tree
->tr1
, efftab
, reg
);
atree
= tree
= tree
->tr2
;
* In the generated &~ operator,
* fiddle things so a PDP-11 "bit"
* instruction will be produced when cctab is used.
tree
->tr2
= optim(block(1, COMPL
, INT
, 0, tree
->tr2
));
* Handle a subroutine call. It has to be done
* here because if cexpr got called twice, the
* arguments might be compiled twice.
* There is also some fiddling so the
* first argument, in favorable circumstances,
* goes to (sp) instead of -(sp), reducing
* the amount of stack-popping.
if (tree
->tr1
->op
!=NAME
) { /* get nargs right */
while (tree
->op
==COMMA
) {
r
=+ comarg(tree
->tr2
, &modf
);
r
=+ comarg(tree
, &modf
);
if (modf
&& tree
->tr1
->op
==NAME
&& tree
->tr1
->class==EXTERN
)
cexpr(tree
, regtab
, reg
);
if (table
==efftab
|| table
==regtab
)
* Longs need special treatment.
tree
->tr2
= tree
->tr2
->tr1
;
* Try to change * and / to shifts.
* Try to find postfix ++ and -- operators that can be
* pulled out and done after the rest of the expression
if (table
!=cctab
&& table
!=cregtab
&& recurf
<2
&& (opdope
[tree
->op
]&LEAF
)==0) {
if (r
=delay(&atree
, table
, reg
)) {
* Basically, try to reorder the computation
* so reg = x+y is done as reg = x; reg =+ y
if (recurf
==0 && reorder(&atree
, table
, reg
)) {
if (table
==cctab
&& atree
->op
==NAME
)
if (table
==efftab
&& tree
->op
==NAME
)
if ((r
=cexpr(tree
, table
, reg
))>=0)
if((r
=cexpr(tree
, regtab
, reg
))>=0) {
if (table
==sptab
|| table
==lsptab
) {
printf("mov\tr%d,-(sp)\n",r
+1);
printf("mov%c r%d,%c(sp)\n", modf
, r
,
printf("tst%c r%d\n", modf
, r
);
if (tree
->op
>0 && tree
->op
<RFORCE
&& opntab
[tree
->op
])
error("No code table for op: %s", opntab
[tree
->op
]);
error("No code table for op %d", tree
->op
);
* Try to compile the tree with the code table using
* registers areg and up. If successful,
* return the register where the value actually ended up.
* If unsuccessful, return -1.
* Most of the work is the macro-expansion of the
cexpr(atree
, table
, areg
)
register struct tnode
*p
, *p1
, *tree
;
int reg
, reg1
, rreg
, flag
, opd
;
* When the value of a relational or a logical expression is
* desired, more work must be done.
if ((opd
&RELAT
||c
==LOGAND
||c
==LOGOR
||c
==EXCLA
) && table
!=cctab
) {
cbranch(tree
, c
=isn
++, 1, reg
);
rcexpr(&czero
, table
, reg
);
rcexpr(&cone
, table
, reg
);
cbranch(tree
->tr1
, c
=isn
++, 0, reg
);
rreg
= rcexpr(p1
->tr1
, table
, reg
);
reg
= rcexpr(p1
->tr2
, table
, rreg
);
printf("mov%c r%d,r%d\n",
* long values take 2 registers.
if (tree
->type
==LONG
&& tree
->op
!=ITOL
)
* Leaves of the expression tree
if ((r
= chkleaf(tree
, table
, reg
)) >= 0)
* x + (-1) is better done as x-1.
if ((tree
->op
==PLUS
||tree
->op
==ASPLUS
) &&
(p1
=tree
->tr2
)->op
== CON
&& p1
->value
== -1) {
tree
->op
=+ (MINUS
-PLUS
);
* The following peculiar code depends on the fact that
* if you just want the codition codes set, efftab
* will generate the right code unless the operator is
* postfix ++ or --. Unravelled, if the table is
* cctab and the operator is not special, try first
* for efftab; if the table isn't, if the operator is,
* or the first match fails, try to match
* with the table actually asked for.
if (table
!=cctab
|| c
==INCAFT
|| c
==DECAFT
|| (opt
= match(tree
, efftab
, nreg
-reg
)) == 0)
if ((opt
=match(tree
, table
, nreg
-reg
))==0)
if (opdope
[tree
->op
]&BINARY
)
* The 0200 bit asks for a tab.
if ((c
= *string
++) & 0200) {
if (tree
->op
==DIVIDE
|| tree
->op
==ASDIV
)
} else if (*string
=='+') {
prins(tree
->op
, c
, instab
);
if (p1
->type
==CHAR
|| p2
->type
==CHAR
)
c
=| 020; /* force right register */
if ((flag
&01) && ctable
==regtab
&& (c
&01)==0
&& (tree
->op
==DIVIDE
||tree
->op
==MOD
|| tree
->op
==ASDIV
||tree
->op
==ASMOD
))
if(collcon(p
) && ctable
!=sptab
) {
if (table
==lsptab
&& ctable
==sptab
)
if (opdope
[p
->op
]&LEAF
|| p
->degree
< 2)
rreg
= rcexpr(p
, ctable
, r
);
if (ctable
!=regtab
&& ctable
!=cregtab
)
printf("mov%c r%d,r%d\n",
isfloat(tree
),rreg
,reg1
);
if ((c
&020)==0 && oddreg(tree
, 0)==0 && (flag
&04 ||
&& xdcalc(p2
, nreg
-rreg
-1) <= (opt
->tabdeg2
&077)
&& xdcalc(p1
,nreg
-rreg
-1) <= (opt
->tabdeg1
&077))) {
printf("mov%c\tr%d,r%d\n",
isfloat(tree
), rreg
, reg
);
error("Register overflow: simplify expression");
case '-': /* check -(sp) */
case ')': /* check (sp)+ */
if ((p
= p
->tr2
)->op
== CON
) {
case 'T': /* "tst R" if 1st op not in cctab */
if (dcalc(p1
, 5)>12 && !match(p1
, cctab
, 10))
printf("tst r%d\n", reg
);
case 'V': /* adc or sbc as required for longs */
while ((c
= *string
++)!='\n' && c
!='\0');
* This routine just calls sreorder (below)
* on the subtrees and then on the tree itself.
* It returns non-zero if anything changed.
reorder(treep
, table
, reg
)
register struct tnode
*p
;
while(sreorder(&p
->tr1
, table
, reg
))
if (opdope
[p
->op
]&BINARY
)
while(sreorder(&p
->tr2
, table
, reg
))
while (sreorder(treep
, table
, reg
))
* Basically this routine carries out two kinds of optimization.
* First, it observes that "x + (reg = y)" where actually
* the = is any assignment op is better done as "reg=y; x+reg".
* In this case rcexpr is called to do the first part and the
* tree is modified so the name of the register
* replaces the assignment.
* Moreover, expressions like "reg = x+y" are best done as
* "reg = x; reg =+ y" (so long as "reg" and "y" are not the same!).
sreorder(treep
, table
, reg
)
register struct tnode
*p
, *p1
;
if (reorder(&p
->tr2
, table
, reg
))
if (p
->op
==STAR
|| p
->op
==PLUS
) {
if (reorder(&p
->tr1
, table
, reg
))
if (p1
->op
==NAME
) switch(p
->op
) {
if (p1
->class != REG
|| isfloat(p
->tr2
))
if (p
->op
==ASSIGN
) switch (p
->tr2
->op
) {
&&(p1
->nloc
==p
->tr1
->nloc
|| p1
->regno
==p
->tr1
->nloc
))
|| p1
->tr1
->nloc
!=p
->tr1
->nloc
)
p
->op
= p1
->op
+ ASPLUS
- PLUS
;
if (table
==cctab
||table
==cregtab
)
rcexpr(optim(p
), efftab
, ~reg
);
* Delay handles postfix ++ and --
* It observes that "x + y++" is better
* treated as "x + y; y++".
* If the operator is ++ or -- itself,
* it calls rcexpr to load the operand, letting
* the calling instance of rcexpr to do the
* Otherwise it uses sdelay to search for inc/dec
register struct tnode
*p
, *p1
;
if (table
!=efftab
&& (p
->op
==INCAFT
||p
->op
==DECAFT
)
return(1+rcexpr(p
->tr1
, table
, reg
));
if (opdope
[p
->op
]&BINARY
)
r
= rcexpr(optim(p
), table
, reg
);
register struct tnode
*p
, *p1
;
if ((p
->op
==INCAFT
||p
->op
==DECAFT
) && p
->tr1
->op
==NAME
) {
if (p
->op
==STAR
|| p
->op
==PLUS
)
* Copy a tree node for a register variable.
* Used by sdelay because if *reg-- is turned
* into *reg; reg-- the *reg will in turn
* be changed to some offset class, accidentally
register struct tname
*p
;
return(block(3, NAME
, p
->type
, p
->elsize
, p
->tr1
,
* If the tree can be immediately loaded into a register,
* produce code to do so and return success.
chkleaf(atree
, table
, reg
)
register struct tnode
*tree
;
if (tree
->op
!=STAR
&& dcalc(tree
, nreg
-reg
) > 12)
lbuf
.degree
= tree
->degree
;
return(rcexpr(&lbuf
, table
, reg
));
* Compile a function argument.
* If the stack is currently empty, put it in (sp)
* rather than -(sp); this will save a pop.
* Return the number of bytes pushed,
register struct tnode
*tree
;
if (nstack
|| isfloat(tree
) || tree
->type
==LONG
) {
retval
= arlength(tree
->type
);