/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * fix.c * * Motorola has is not consistent in what operations allow * which operands. This section compensates for that -- * tries to find the best way to do something. */ #include #include "param.h" #include "nodes.h" #include "flags.h" #include "bstok.h" #include "gen.h" #include "ops.h" #define FAIL 0 #define OKAY 1 #define CL_IMM IOPD #define CL_AREG AOPD #define CL_DREG DOPD #define CL_ADR MOPD #define RETAREG 0x100 #define RETDREG 0x200 #define RETLEFT 0x400 #define RETRIGHT 0x800 #define LISTMP 1 #define RISTMP 2 #define NDASSOC 4 #define CANRL 8 #define CANLR 0x10 #define CANRD 0x20 #define CANDL 0x40 #define CANLD 0x80 #define CANDD 0x100 #define CANDR 0x200 struct mtbl { int restr; char *code; int needregs; } tbl2[] = { {LISTMP|CANRL, "\tN.S\t>A,A\n", RETRIGHT}, {CANRD, "\tmove.S\tA,A\n", RETDREG}, {CANLD|NDASSOC, "\tmove.S\t>A,A\n\tN.S\tA,R1\n\tN.S\tR1,A\n", RETLEFT|1}, {CANDR|RISTMP|NDASSOC, "\tmove.S\tA,R1\n\tN.S\tR1,A\n", RETDREG|1}, {0} }; struct mtbl tblmul[] = { {CANRL|LISTMP, "\tmulU\t>A,A\n", RETRIGHT}, {CANRD, "\tmove.w\t>A,A\n\tmulU\tA,A,A\n", RETDREG}, {0} }; struct mtbl tbludiv[] = { {CANRD, "\tclr.l\tA\n\tmove.w\tA,A\n", RETDREG}, {0} }; struct mtbl tblc[] = { {CANRL, "\tcmp.A,A,R1\n", 1}, /* shouldnt get to here! */ {CANDL, "\tmove.A,R1\n\tcmp.A,R1\n\tmove.A,A,R1\n\tN.S\tR1,A\n", 1|RETLEFT}, /* only MUL, DIV and shifts should get to here */ {CANRD, "\tmove.S\tA,A\n\tmove.S\tA,A,A\n\tN.S\tA,R1\n\tN.S\tR1,A\n\tmove.S\tA,A,A\n\tmove.w\t>A,A,A\n\tmove.w\tA,A,A,A\n\tmove.w\tA,A,A\n\tmove.w\tA,A,A,A\n\tswap\tA\n\tmove.w\tA,A,A\n\tswap\tA\n\tmove.w\tA,g_token) { case ICON: return CL_IMM; case ONAME: return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR; case OREG: return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR; case PUSHER: return CL_ADR; case REGVAR: if (np->g_rno < AREG) return CL_DREG; else return CL_AREG; default: printf("Weird class "); return CL_IMM; } } int canswap; NODEP matchnp; fix_cmp(np, flags) NODEP np; { NODEP rp = np->n_right; /* special stuff for ICON 0 */ if (rp->g_token == ICON && rp->g_offs == 0 && (rp->g_flags & IMMEDID)) { addcode(np, "g_ty == ET_U ? tbludiv : tbldiv); } fixmod(np, flags) NODEP np; { int r; r = fixdiv(np, flags); addcode(np, "\tswap\tA\n"); return r; } fixamul(np, flags) NODEP np; { return fix_sub(np, flags, tblamul); } fixadiv(np, flags) NODEP np; { return fix_sub(np, flags, np->g_ty == ET_U ? tbluadiv : tbladiv); } fixamod(np, flags) NODEP np; { return fix_sub(np, flags, np->g_ty == ET_U ? tbluamod : tblamod); } fix_asn(np, flags) NODEP np; { canswap = 0; return fix_sub(np, flags, tblas); } fix_sub(np, flags, tbl) register NODEP np; struct mtbl *tbl; { NODEP lp = np->n_left, rp = np->n_right; int lclass, rclass; register struct mtbl *p; int rv; lclass = class(lp); rclass = class(rp); matchnp = np; for (p = tbl; p->restr; p++) if ((rv = cando(flags, p->restr, lclass, rclass))) { dotbl(p, np); return OKAY; } printf("no code table match! "); return FAIL; } dotbl(p, np) struct mtbl *p; NODEP np; { register int i, k; if (p->needregs) { i = p->needregs; if (i & RETLEFT) inherit(np); else if (i & RETRIGHT) rinherit(np); else if (i & RETAREG) retreg(np, ralloc(AREG)); else if (i & RETDREG) retreg(np, ralloc(0)); k = i & 7; while (k--) tempr(np, 0); k = (i/AREG) & 7; while (k--) tempr(np, AREG); } addcode(np, p->code); } #define canflag(l,r) (l << cansh[r]) short cansh[] = {0, 0, 4, 0, 8, 0, 0, 0, 12}; cando(flags, restr, lc, rc) register restr; { NODEP lp = matchnp->n_left, rp = matchnp->n_right; if (restr & RISTMP) { if ((rc & (CL_DREG|CL_AREG)) == 0 || istemp(rp->g_rno) == 0) return 0; } else if (restr & LISTMP) { if ((lc & (CL_DREG|CL_AREG)) == 0 || istemp(lp->g_rno) == 0) return 0; } if (restr & NDASSOC) { if (canswap == 0) return 0; } if (restr & (CANLR|CANLD)) { flags |= quickflag(lp, flags); } else if (restr & (CANRL|CANRD)) { flags |= quickflag(rp, flags); } flags &= 0xfff; if (restr & CANLR) { if ((flags & canflag(lc,rc)) == 0) return 0; } else if (restr & CANRL) { if ((flags & canflag(rc,lc)) == 0) return 0; } else if (restr & CANRD) { if ((flags & canflag(rc,CL_DREG)) == 0) return 0; } else if (restr & CANDL) { if ((flags & canflag(CL_DREG,lc)) == 0) return 0; } else if (restr & CANLD) { if ((flags & canflag(lc,CL_DREG)) == 0) return 0; } else if (restr & CANDR) { if ((flags & canflag(CL_DREG,rc)) == 0) return 0; } else if (restr & CANDD) { if ((flags & DOPD) == 0) return 0; } return 1; } quickflag(np, flags) NODEP np; { long offs; if (np->g_token != ICON) return 0; offs = np->g_offs; if ((flags & QOPD) && np->g_offs >= 1 && np->g_offs <= 8) return IOPD; if ((flags & ONEOPM) && np->g_offs == 1) return IOPM; return 0; } /* * stuff to do field extract and field assign * Yes, this stuff can be optimized a lot more ... feel free */ fldget(np, flags) register NODEP np; { int how; how = 1; if (np->g_fldo == 0) how = 0; /* no shift needed */ else if (np->g_fldo > 8) how = 2; /* shift too big for immediate */ np->n_left->g_offs += np->g_offs; /* major HACK, hope it works */ retreg(np, ralloc(0)); addcode(np, "\tmove\tg_fldo == 0) how = 0; /* no shift needed */ else if (np->g_fldo > 8) how = 2; /* shift too big for immediate */ retreg(np, ralloc(0)); tempr(np, 0); addcode(np, "\tmove\t>A,A\n"); /* value */ if (needmask(np)) /* mask off high bits */ addcode(np, "\tand\t#W,A\n"); if (how) /* shift into position */ addcode(np, how==1 ? "\tlsl\t#Y,A\n" : "\tlsl\t#8,A\n\tlsl\t#Z,A\n"); addcode(np, "\tmove\tn_left; if (np->g_fldw + np->g_fldo >= 16) return 0; if (lp->g_token != ICON) return 1; if ((int)lp->g_offs & ~ones(np->g_fldw)) { warn("value too big for field"); return 1; } return 0; }