/* gencode.c - generate code for an expression tree for bcc */ /* Copyright (C) 1992 Bruce Evans */ #define islvalop(op) \ (((op) >= ASSIGNOP && (op) <= SUBABOP) || (op) == PTRADDABOP) #include "bcc.h" #include "align.h" #include "condcode.h" #include "reg.h" #include "sc.h" #include "scan.h" #include "type.h" #undef EXTERN #define EXTERN #include "gencode.h" #include "sizes.h" #define FIRSTOPDATA GTOP #if MAXINDIRECT <= 1 # define istooindirect(t) ((t)->indcount > MAXINDIRECT) #else # define istooindirect(t) ((t)->indcount >= MAXINDIRECT && \ ((t)->indcount > MAXINDIRECT || \ (t)->type->typesize > maxregsize || \ (t)->type->constructor & FUNCTION)) #endif #ifdef I8088 #if NOTFINISHED PUBLIC store_pt allregs = BREG | DREG | DATREG1 | DATREG2 | INDREG0 | INDREG1 | INDREG2; #else PUBLIC store_pt allregs = BREG | DREG | INDREG0 | INDREG1 | INDREG2; #endif PUBLIC store_pt allindregs = INDREG0 | INDREG1 | INDREG2; PUBLIC uoffset_T alignmask = ~(uoffset_T) 0x0001; PUBLIC bool_t arg1inreg = FALSE; PUBLIC store_pt calleemask = INDREG1 | INDREG2; PUBLIC bool_t callersaves = FALSE; PUBLIC char *callstring = "call\t"; PUBLIC store_pt doubleargregs = DREG | INDREG0 | DATREG1 | DATREG2; PUBLIC store_pt doubleregs = DREG | INDREG0 | DATREG1 | DATREG2; PUBLIC store_pt doublreturnregs = DREG | INDREG0 | DATREG1 | DATREG2; PUBLIC offset_T jcclonger = 3; PUBLIC offset_T jmplonger = 1; PUBLIC char *jumpstring = "br \t"; PUBLIC char *regpulllist = "f2ax2ax2bx2si2di2bp2qx2qx2cx2dx2"; PUBLIC char *regpushlist = "dx2cx2qx2qx2bp2di2si2bx2ax2ax2f2"; #if NOTFINISHED PUBLIC store_pt regregs = INDREG1 | INDREG2 | DATREG1 | DATREG2; #else PUBLIC store_pt regregs = INDREG1 | INDREG2; #endif PUBLIC char *acclostr = "al"; PUBLIC char *accumstr = "ax"; PUBLIC char *badregstr = "qx"; PUBLIC char *dreg1str = "cx"; PUBLIC char *dreg1bstr = "cl"; PUBLIC char *dreg2str = "dx"; PUBLIC char *ireg0str = "bx"; PUBLIC char *ireg1str = "si"; PUBLIC char *ireg2str = "di"; #ifdef FRAMEPOINTER PUBLIC char *localregstr = "bp"; #else PUBLIC char *localregstr = "sp"; #endif PUBLIC char *stackregstr = "sp"; #endif #ifdef MC6809 PUBLIC store_pt allregs = BREG | DREG | INDREG0 | INDREG1 | INDREG2; PUBLIC store_pt allindregs = INDREG0 | INDREG1 | INDREG2; PUBLIC uoffset_T alignmask = ~(uoffset_T) 0x0000; PUBLIC bool_t arg1inreg = TRUE; PUBLIC store_pt calleemask = INDREG1 | INDREG2; PUBLIC bool_t callersaves = TRUE; PUBLIC char *callstring = "JSR\t>"; #ifndef VERY_SMALL_MEMORY PUBLIC bool_t ancient = FALSE; #endif PUBLIC store_pt doubleargregs = DREG | INDREG0 | INDREG1 | INDREG2; PUBLIC store_pt doubleregs = DREG | INDREG0 | INDREG1 | INDREG2; PUBLIC store_pt doublreturnregs = DREG | INDREG0 | INDREG1 | INDREG2; PUBLIC offset_T jcclonger = 2; PUBLIC offset_T jmplonger = 1; PUBLIC char *jumpstring = "JMP\t>"; PUBLIC char *regpulllist = "CC1B1D2X2U2Y2DP1PC2"; PUBLIC char *regpushlist = "PC2DP1Y2U2X2D2B1CC1"; PUBLIC store_pt regregs = INDREG1 | INDREG2; PUBLIC char *acclostr = "B"; PUBLIC char *accumstr = "D"; PUBLIC char *badregstr = "Q"; PUBLIC char *ireg0str = "X"; PUBLIC char *ireg1str = "U"; PUBLIC char *ireg2str = "Y"; PUBLIC char *localregstr = "S"; #endif PUBLIC uoffset_T accregsize = 2; #ifdef FRAMEPOINTER PUBLIC uoffset_T frameregsize = 2; #endif PUBLIC uoffset_T maxregsize = 2; PUBLIC uoffset_T opregsize = 2; PUBLIC uoffset_T pshregsize = 2; PUBLIC uoffset_T returnadrsize = 2; #ifndef MC6809 PUBLIC uvalue_t intmaskto = 0xFFFFL; PUBLIC uvalue_t maxintto = 0x7FFFL; PUBLIC uvalue_t maxlongto = 0x7FFFFFFFL; PUBLIC uvalue_t maxoffsetto = 0x7FFFL; PUBLIC uvalue_t maxshortto = 0x7FFFL; PUBLIC uvalue_t maxuintto = 0xFFFFL; PUBLIC uvalue_t maxushortto = 0xFFFFL; PUBLIC uvalue_t shortmaskto = 0xFFFFL; #endif PRIVATE store_pt callermask; PRIVATE offset_T lastargsp; PRIVATE smalin_t opdata[] = { /* GTOP, LTOP, ADDOP, DIVOP, */ GT, LT, 0, 0, /* MODOP, LOGNOTOP, NOTOP, STRUCELTOP, */ 0, 0, 0, 0, /* STRUCPTROP, ASSIGNOP, ADDABOP, ANDABOP, */ 0, 0, 0, ANDOP, /* DIVABOP, EORABOP, MODABOP, MULABOP, */ DIVOP, EOROP, MODOP, MULOP, /* ORABOP, SLABOP, SRABOP, SUBABOP, */ OROP, SLOP, SROP, 0, /* COMMAOP, COLONOP, LOGOROP, LOGANDOP, */ 0, 0, 0, 0, /* EQOP, NEOP, GEOP, LEOP, */ EQ, NE, GE, LE, }; FORWARD void abop P((op_pt op, struct symstruct *source, struct symstruct *target)); FORWARD void smakeleaf P((struct nodestruct *exp)); FORWARD void tcheck P((struct nodestruct *exp)); PRIVATE void abop(op, source, target) op_pt op; struct symstruct *source; struct symstruct *target; { store_pt regmark; store_pt regpushed; store_pt regtemp; struct symstruct temptarg; regpushed = preslval(source, target); temptarg = *target; if ((source->type->scalar ^ target->type->scalar) & (DLONG | RSCALAR) && op != SLABOP && op != SRABOP) /* XXX - perhaps not float */ { pres2(target, source); cast(source->type, &temptarg); } switch (op) { case ADDABOP: add(source, &temptarg); break; case ANDABOP: case EORABOP: case ORABOP: op1((opdata - FIRSTOPDATA)[op], source, &temptarg); break; case DIVABOP: case MODABOP: case MULABOP: case SLABOP: case SRABOP: softop((opdata - FIRSTOPDATA)[op], source, &temptarg); break; case PTRADDABOP: regtemp = 0; if ((reguse & allindregs) == allindregs) { /* free a temporary index not used for source or target */ regmark = reguse; reguse = source->storage | temptarg.storage; pushreg(regtemp = getindexreg()); reguse = regmark & ~regtemp; } indexadr(source, &temptarg); if (regtemp) { load(&temptarg, DREG); recovlist(regtemp); } break; case SUBABOP: sub(source, &temptarg); break; } assign(&temptarg, target); recovlist(regpushed); } PUBLIC void bileaf(exp) struct nodestruct *exp; { bool_t commutop; bool_t tookaddress; store_t regmark; struct nodestruct *indchase; struct nodestruct *left; struct nodestruct *right; struct symstruct *source; struct symstruct *target; left = exp->left.nodeptr; if ((right = exp->right) == NULL) { makeleaf(left); #ifdef DBNODE dbnode(exp); #endif return; } switch (exp->tag) { case ADDOP: case ANDOP: case EOROP: case OROP: case EQOP: case NEOP: case MULOP: commutop = TRUE; break; case FUNCOP: makeleaf(left); if ((target = left->left.symptr)->storage & allregs && right->tag != LEAF && target->flags != REGVAR) { if (target->indcount == 0) push(target); else { --target->indcount; push(target); ++target->indcount; } } default: commutop = FALSE; break; } regmark = reguse; if (right->tag != LEAF) { if (left->tag != LEAF && commutop && left->weight > right->weight) { exp->left.nodeptr = right; right = exp->right = left; left = exp->left.nodeptr; #ifdef DBNODE dbnodeswap(); #endif } makeleaf(right); } else if (left->tag != LEAF) makeleaf(left); source = right->left.symptr; if (left->tag != LEAF) { for (indchase = left; indchase->tag == INDIRECTOP || indchase->tag == STRUCELTOP; indchase = indchase->left.nodeptr) ; tookaddress = FALSE; if (source->storage & allindregs || indchase->tag != LEAF) { if (exp->nodetype->constructor & STRUCTU && exp->tag == ASSIGNOP) { address(source); tookaddress = TRUE; } if (source->storage & allindregs && source->indcount == 0 && (source->type->scalar & (DLONG | RSCALAR) || (left->tag == FUNCOP && source->flags != REGVAR))) push(source); /* XXX - perhaps not float */ else preserve(source); } makeleaf(left); if (tookaddress) indirec(source); } target = left->left.symptr; if (istooindirect(source)) { /* want to makelessindirect(source) */ /* this uses source->storage if that is a free index */ /* otherwise, must preserve target if that is an index */ tookaddress = FALSE; if (!(source->storage & ~reguse & allindregs) && target->storage & allindregs) { /* want to pres2(source, target) */ /* this requires target to be < MAXINDIRECT indirect */ /* it is safe to makelessindirect(target) */ /* since source is not a free index */ if (islvalop(exp->tag) && target->indcount != 0) { address(target); tookaddress = TRUE; } if (istooindirect(target)) makelessindirect(target); pres2(source, target); } makelessindirect(source); if (tookaddress) indirec(target); } if (istooindirect(target)) { tookaddress = FALSE; if (!(target->storage & ~reguse & allindregs) && source->storage & allindregs) { if (exp->nodetype->constructor & STRUCTU && exp->tag == ASSIGNOP) { address(source); tookaddress = TRUE; } pres2(target, source); } makelessindirect(target); if (tookaddress) indirec(source); } reguse = regmark; #ifdef DBNODE dbnode(exp); #endif if (commutop && ((target->storage == CONSTANT && !(target->type->scalar & (DLONG | RSCALAR))) || source->storage & ALLDATREGS || (source->type->scalar & (DLONG | RSCALAR) && source->indcount == 0 && target->indcount != 0))) { exp->left.nodeptr = right; exp->right = left; #ifdef DBNODE dbnodeswap(); #endif } } PUBLIC fastin_pt bitcount(number) register uvalue_t number; { register fastin_pt count; for (count = 0; number != 0; number >>= 1) if (number & 1) ++count; return count; } PUBLIC void codeinit() { #ifdef I80386 if (i386_32) { /* Need DATREG2 for doubles although handling of extra data regs is * not finished. * XXX - might need more regs for 16-bit mode doubles or floats. */ allregs = BREG | DREG | INDREG0 | INDREG1 | INDREG2 | DATREG1 | DATREG1B | DATREG2; #if NOTFINISHED allindregs = INDREG0 | INDREG1 | INDREG2 | DATREG1 | DATREG2; #else allindregs = INDREG0 | INDREG1 | INDREG2; #endif alignmask = ~(uoffset_T) 0x00000003; calleemask = INDREG0 | INDREG1 | INDREG2; doubleargregs = DREG | DATREG2; doubleregs = DREG | DATREG2; doublreturnregs = DREG | DATREG2; jcclonger = 4; jmplonger = 3; regpulllist = "fd4eax4eax4ebx4esi4edi4ebp4qx4qx4ecx4edx4"; regpushlist = "edx4ecx4qx4qx4ebp4edi4esi4ebx4eax4eax4fd4"; accumstr = "eax"; dreg1str = "ecx"; dreg2str = "edx"; ireg0str = "ebx"; ireg1str = "esi"; ireg2str = "edi"; #ifdef FRAMEPOINTER localregstr = "ebp"; #else localregstr = "esp"; #endif stackregstr = "esp"; opregsize = returnadrsize = pshregsize = maxregsize = #ifdef FRAMEPOINTER frameregsize = #endif accregsize = 4; intmaskto = (unsigned long) 0xFFFFFFFFL; maxintto = 0x7FFFFFFFL; maxoffsetto = 0x7FFFFFFFL; maxuintto = (unsigned long) 0xFFFFFFFFL; } #endif #ifdef POSINDEPENDENT if (posindependent) { # ifdef MC6809 callstring = "LBSR\t"; jumpstring = "LBRA\t"; # endif } #endif if (callersaves) calleemask = 0; callermask = ~calleemask; #ifdef FRAMEPOINTER funcsaveregsize = bitcount((uvalue_t) calleemask) * maxregsize + frameregsize; funcdsaveregsize = bitcount((uvalue_t) calleemask & ~doubleregs) * maxregsize + frameregsize; framelist = FRAMEREG | calleemask; #else funcsaveregsize = bitcount((uvalue_t) calleemask) * maxregsize; funcdsaveregsize = bitcount((uvalue_t) calleemask & ~doubleregs) * maxregsize; #endif } PUBLIC fastin_pt highbit(number) register uvalue_t number; { register fastin_pt bit; for (bit = -1; number != 0; number >>= 1) ++bit; return bit; } PUBLIC void makeleaf(exp) struct nodestruct *exp; { ccode_t condtrue; op_pt op; store_t regmark; offset_T saveargsp = 0; /* for -Wall */ store_t savelist = 0; /* for -Wall */ offset_T saveoffset = 0; /* for -Wall */ struct symstruct *source; offset_T spmark; struct symstruct *structarg = 0; /* for -Wall */ struct symstruct *target; if ((op_t) (op = exp->tag) == LEAF) { target = exp->left.symptr; if (istooindirect(target)) makelessindirect(target); #ifdef SELFTYPECHECK tcheck(exp); #endif return; } if ((op_t) op == INDIRECTOP || (op_t) op == STRUCELTOP) { smakeleaf(exp); target = exp->left.symptr; if (istooindirect(target)) makelessindirect(target); #ifdef SELFTYPECHECK tcheck(exp); #endif return; } if ((op_t) op == COMMAOP) { spmark = sp; makeleaf(exp->left.nodeptr); modstk(spmark); makeleaf(exp->right); exp->tag = LEAF; exp->left.symptr = exp->right->left.symptr; #ifdef SELFTYPECHECK tcheck(exp); #endif return; } if ((op_t) op == CONDOP) { condop(exp); #ifdef SELFTYPECHECK tcheck(exp); #endif return; } if ((op_t) op == LOGANDOP || (op_t) op == LOGNOTOP || (op_t) op == LOGOROP) { logop(exp); #ifdef SELFTYPECHECK tcheck(exp); #endif return; } regmark = reguse; if ((op_t) op == FUNCOP) { saveargsp = lastargsp; lastargsp = savelist = 0; if (exp->nodetype->constructor & STRUCTU) { modstk(sp - (offset_T) exp->nodetype->typesize); onstack(structarg = constsym((value_t) 0)); } else { if (exp->nodetype->scalar & DOUBLE) { if (regmark & doublreturnregs) savelist = doublreturnregs; } else if (regmark & RETURNREG) /* XXX size long == float ? */ savelist = exp->nodetype->scalar & DLONG ? LONGRETURNREGS : RETURNREG; if (savelist != 0) modstk(saveoffset = sp - exp->nodetype->typesize); } pushlist(regmark & callermask); } spmark = sp; bileaf(exp); if (exp->right != NULL) source = exp->right->left.symptr; else source = NULL; target = exp->left.nodeptr->left.symptr; switch ((op_t) op) { case ADDABOP: case ANDABOP: case DIVABOP: case EORABOP: case SUBABOP: case MODABOP: case MULABOP: case ORABOP: case PTRADDABOP: case SLABOP: case SRABOP: abop(op, source, target); break; case ADDOP: add(source, target); break; case ADDRESSOP: address(target); break; case ANDOP: case EOROP: case OROP: op1(op, source, target); break; case ASSIGNOP: assign(source, target); break; case CASTOP: cast(source->type, target); break; case DIVOP: case MODOP: case MULOP: case SLOP: case SROP: softop(op, source, target); break; case EQOP: case GEOP: case GTOP: case LEOP: case LTOP: case NEOP: condtrue = (opdata - FIRSTOPDATA)[op]; cmp(source, target, &condtrue); break; case FUNCOP: /* kludge update pushed regs */ /* may only work for si, di */ /* -2 skips for ax and bx */ /* need dirtymask to mostly avoid this */ savereturn(regmark & callermask & regregs, spmark - 2 * (offset_T) pshregsize); if (exp->nodetype->constructor & STRUCTU) { address(structarg); push(structarg); } function(target); break; case INDIRECTOP: indirec(target); break; case LISTOP: listo(target, lastargsp); lastargsp = sp; break; case NEGOP: neg(target); break; case NOTOP: not(target); break; case POSTDECOP: case POSTINCOP: case PREDECOP: case PREINCOP: incdec(op, target); break; case PTRADDOP: indexadr(source, target); break; case PTRSUBOP: ptrsub(source, target); break; case ROOTLISTOP: listroot(target); lastargsp = sp; break; case STRUCELTOP: struc(source, target); break; case SUBOP: sub(source, target); break; } if (target->storage == LOCAL && target->offset.offi < spmark && target->flags == TEMP) spmark = target->offset.offi; #if 1 /* XXX - why does sp get changed without this? */ if ((op_t) op != ROOTLISTOP) #endif modstk(spmark); if ((op_t) op == FUNCOP) { lastargsp = saveargsp; if (savelist != 0) { savereturn(savelist, saveoffset); onstack(target); target->offset.offi = saveoffset; } recovlist(regmark & callermask); } reguse = regmark; exp->tag = LEAF; exp->left.symptr = target; if (istooindirect(target)) makelessindirect(target); #ifdef SELFTYPECHECK tcheck(exp); #endif } PRIVATE void smakeleaf(exp) struct nodestruct *exp; { struct nodestruct *left; left = exp->left.nodeptr; if (left->tag == INDIRECTOP || left->tag == STRUCELTOP) smakeleaf(left); else if (left->tag != LEAF) makeleaf(left); if (exp->tag == INDIRECTOP) indirec(left->left.symptr); else { if (left->left.symptr->indcount > MAXINDIRECT + 1) makelessindirect(left->left.symptr); struc(exp->right->left.symptr, left->left.symptr); } exp->tag = LEAF; exp->left.symptr = left->left.symptr; } #ifdef SELFTYPECHECK PRIVATE void tcheck(exp) register struct nodestruct *exp; { register struct symstruct *target; if (exp->nodetype != (target = exp->left.symptr)->type) { { bugerror("botched nodetype calculation"); #ifdef DBNODE comment(); outstr("runtime type is "); dbtype(target->type); outstr(", calculated type is "); dbtype(exp->nodetype); outnl(); #endif } } } #endif /* SELFTYPECHECK */