diff options
Diffstat (limited to 'amd64/isel.c')
| -rw-r--r-- | amd64/isel.c | 660 |
1 files changed, 0 insertions, 660 deletions
diff --git a/amd64/isel.c b/amd64/isel.c deleted file mode 100644 index a0c913c..0000000 --- a/amd64/isel.c +++ /dev/null @@ -1,660 +0,0 @@ -#include "all.h" -#include "../endian.h" - -enum flag { - ZF = 1 << 0, - SF = 1 << 1, - CF = 1 << 2, - OF = 1 << 3, - CLOBF = 1 << 4, -}; - -/* flags modified by each integer op */ -static const uchar opflags[NOPER] = { - [Oneg] = ZF|CLOBF, - [Oadd] = ZF|CLOBF, - [Osub] = ZF|CLOBF, - [Omul] = CLOBF, - [Odiv] = CLOBF, - [Oudiv] = CLOBF, - [Orem] = CLOBF, - [Ourem] = CLOBF, - [Oand] = ZF|CLOBF, - [Oior] = ZF|CLOBF, - [Oxor] = ZF|CLOBF, - [Oshl] = ZF|CLOBF, - [Osar] = ZF|CLOBF, - [Oslr] = ZF|CLOBF, - [Oequ] = ZF|CLOBF, - [Oneq] = ZF|CLOBF, - [Olth] = ZF|CLOBF, - [Ogth] = ZF|CLOBF, - [Olte] = ZF|CLOBF, - [Ogte] = ZF|CLOBF, - [Oulth] = ZF|CLOBF, - [Ougth] = ZF|CLOBF, - [Oulte] = ZF|CLOBF, - [Ougte] = ZF|CLOBF, - [Ocall] = CLOBF, -}; - -static int iflagsrc = -1; - -static void -picfixsym(union ref *r, struct block *blk, int *curi) -{ - if (!ccopt.pic || !isaddrcon(*r,0)) return; - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = *r)); -} - -/* map alloca tmp -> stack frame displacement (0 if not alloca) */ -static ushort *stkslots; -static uint nstkslots; - -#define isstkslot(r) ((r).t == RTMP && (r).i < nstkslots && stkslots[(r).i]) - -static void -fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) -{ - int sh; - enum op op = ins ? ins->op : 0; - - if (r->t == RXCON) { - struct xcon *con = &conht[r->i]; - if (in_range(op, Oshl, Oslr) && r == &ins->r) { - sh = con->i; - goto ShiftImm; - } else if (in_range(op, Oadd, Osub) && con->i == 2147483648 && r == &ins->r) { - /* add X, INT32MAX+1 -> sub X, INT32MIN */ - ins->op = Oadd + (op == Oadd); - *r = mkintcon(KI32, -2147483648); - } else if (kisflt(con->cls) && con->i == 0) { - /* copy of positive float zero -> regular zero, that emit() will turn into xor x,x */ - if (in_range(op, Ocopy, Omove) || op == Ophi) - *r = ZEROREF; - else - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, con->cls, ZEROREF)); - } else if (con->cls >= KI64) { - /* float immediates & 64bit immediates are loaded from memory */ - uchar data[8]; - uint ksiz = cls2siz[con->cls]; - union type ctype; - /* can't use memory arg in rhs if lhs is memory */ - bool docopy = &ins->l != r && (oisstore(ins->op) || ins->l.t == RADDR); - if (con->cls <= KPTR && in_range(ins->op, Ocopy, Omove)) /* in this case we can use movabs */ - return; - else if (!docopy || con->cls >= KF32) { - if (con->cls != KF32) { - wr64le(data, con->i); - ctype = mktype(con->cls == KF64 ? TYDOUBLE : TYVLONG); - } else { - union { float f; int i; } pun = { con->f }; - wr32le(data, pun.i); - ctype = mktype(TYFLOAT); - } - *r = mkdatref(NULL, ctype, ksiz, /*align*/ksiz, data, ksiz, /*deref*/1); - } - if (docopy) - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, con->cls, *r)); - } else if (ins->op != Omove && con->issym && r == &ins->r) { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, mkaddr((struct addr){*r}))); - } else if (in_range(op, Odiv, Ourem) && kisint(ins->cls)) - goto DivImm; - } else if (r->t == RICON && in_range(op, Odiv, Ourem) && kisint(ins->cls) && r == &ins->r) { - DivImm: /* there is no division by immediate, must be copied to a register */ - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ins->cls, *r)); - } else if (r->t == RICON && in_range(op, Oshl, Oslr) && r == &ins->r) { - sh = r->i; - ShiftImm: /* shift immediate is always 8bit */ - *r = mkref(RICON, sh & 255); - } else if (isstkslot(*r)) { - struct instr adr = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkintcon(KI32, -stkslots[r->i])); - if (in_range(op, Ocopy, Omove)) - *ins = adr; - else - *r = insertinstr(blk, (*curi)++, adr); - } - picfixsym(r, blk, curi); -} - -#define isimm32(r) (iscon(r) && concls(r) == KI32) - -static void -selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) -{ - const struct call *call = &calltab.p[ins->r.i]; - int iarg = *curi - 1; - enum irclass cls; - uint argstksiz = alignup(call->argstksiz, 16); - - for (int i = call->narg - 1; i >= 0; --i) { - struct abiarg abi = call->abiarg[i]; - struct instr *arg; - for (;; --iarg) { - assert(iarg >= 0 && i >= 0 && "arg?"); - if ((arg = &instrtab[blk->ins.p[iarg]])->op == Oarg) - break; - } - - if (!abi.isstk) { - assert(!abi.ty.isagg); - *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, abi.reg), arg->r); - } else { - union ref adr = mkaddr((struct addr){mkref(RREG, RSP), .disp = abi.stk}); - int iargsave = iarg; - if (!abi.ty.isagg) { /* scalar arg in stack */ - *arg = mkinstr(Ostore8+ilog2(cls2siz[abi.ty.cls]), 0, adr, arg->r); - if (isaddrcon(arg->r,1) || arg->r.t == RADDR) - arg->r = insertinstr(blk, iarg++, mkinstr(Ocopy, abi.ty.cls, arg->r)); - else - fixarg(&ins->r, ins, blk, &iarg); - } else { /* aggregate arg in stack, callee stack frame destination address */ - *arg = mkinstr(Ocopy, KPTR, adr); - } - *curi += iarg - iargsave; - } - } - if (call->argstksiz) { - union ref disp = mkref(RICON, argstksiz); - insertinstr(blk, iarg--, (struct instr){Osub, KPTR, .keep=1, .reg = RSP+1, .l=mkref(RREG,RSP), disp}); - ++*curi; - insertinstr(blk, *curi+1, (struct instr){Oadd, KPTR, .keep=1, .reg = RSP+1, .l=mkref(RREG,RSP), disp}); - } - if (isimm32(ins->l)) - ins->l = mkaddr((struct addr){.base = ins->l}); - else if (isintcon(ins->l)) - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->l)); - - if (call->vararg >= 0 && ins->l.t == RTMP) { - /* variadic calls write number of sse regs used to AL, so mark it as clobbered such that - * the function pointer of an indirect calls does not get allocated to RAX by regalloc */ - insertinstr(blk, (*curi)++, mkinstr(Omove, KPTR, mkref(RREG, RAX), mkref(RREG, RAX))); - } - cls = ins->cls; - ins->cls = 0; - if (cls) { - /* duplicate to reuse same TMP ref */ - insertinstr(blk, (*curi)++, *ins); - *ins = mkinstr(Ocopy, cls, mkref(RREG, call->abiret[0].reg)); - for (int i = 1; i <= 2; ++i) { - if (*curi + i >= blk->ins.n) break; - if (instrtab[blk->ins.p[*curi + i]].op == Ocall2r) { - ins = &instrtab[blk->ins.p[*curi += i]]; - *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, call->abiret[1].reg)); - break; - } - } - } -} - -static bool -aimm(struct addr *addr, int disp) -{ - vlong a = addr->disp; - a += disp; - if ((int)a == a) { - addr->disp = a; - return 1; - } - return 0; -} - -static bool -acon(struct addr *addr, union ref r) -{ - vlong a = addr->disp; - assert(isintcon(r)); - a += intconval(r); - if ((int)a == a) { - addr->disp = a; - return 1; - } - return 0; -} - -static bool -ascale(struct addr *addr, union ref a, union ref b) -{ - if (b.t != RICON) return 0; - if (addr->index.bits) return 0; - if ((unsigned)b.i > 3) return 0; - if (a.t == RREG) { - Scaled: - addr->index = a; - addr->shift = b.i; - return 1; - } else if (a.t == RTMP) { - struct instr *ins = &instrtab[a.i]; - /* factor out shifted immediate from 'shl {add %x, imm}, s' */ - /* XXX maybe we shouldn't do this here because it should be done by a generic - * arithemetic optimization pass ? */ - if (ins->op == Oadd && (ins->l.t == RREG || ins->l.t == RTMP) && isintcon(ins->r)) { - vlong a = ((vlong) addr->disp + intconval(ins->r)) * (1 << b.i); - if (a != (int) a) return 0; - addr->disp = a; - addr->index = ins->l; - addr->shift = b.i; - return 1; - } else { - goto Scaled; - } - } - return 0; -} - -static bool -aadd(struct addr *addr, struct block *blk, int *curi, union ref r) -{ - if (isstkslot(r)) { - if (addr->base.bits || !aimm(addr, -stkslots[r.i])) goto Ref; - addr->base = mkref(RREG, RBP); - } else if (r.t == RTMP) { - struct instr *ins = &instrtab[r.i]; - if (ins->op == Oadd) { - if (!aadd(addr, blk, curi, ins->l)) goto Ref; - if (!aadd(addr, blk, curi, ins->r)) goto Ref; - ins->skip = 1; - } else if (ins->op == Oshl) { - if (!ascale(addr, ins->l, ins->r)) goto Ref; - ins->skip = 1; - } else if (ins->op == Ocopy && ins->l.t == RADDR) { - struct addr save = *addr, *addr2 = &addrht[ins->l.i]; - if ((!addr2->base.bits || aadd(addr, blk, curi, addr2->base)) - && aimm(addr, addr2->disp) - && (!addr2->index.bits || ascale(addr, addr2->index, mkref(RICON, addr2->shift)))) - { - ins->skip = 1; - } else { - *addr = save; - goto Ref; - } - } else if (ins->op == Ocopy) { - if (!aadd(addr, blk, curi, ins->l)) goto Ref; - ins->skip = 1; - } else goto Ref; - } else if (isnumcon(r)) { - return acon(addr, r); - } else if (isaddrcon(r,1)) { - if (!addr->base.bits && !isaddrcon(addr->index,1)) addr->base = r; - else return 0; - } else if (r.t == RREG) { - /* temporaries are single assignment, but register aren't, so they can't be * - * safely hoisted into an address value, unless they have global lifetime */ - if (!rstest(mctarg->rglob, r.i)) return 0; - Ref: - if (isstkslot(r) && (addr->base.bits || addr->index.bits)) { - r = insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -stkslots[r.i]))); - } - if (!addr->base.bits) addr->base = r; - else if (!addr->index.bits) addr->index = r; - else return 0; - } else return 0; - return 1; -} - -static bool -fuseaddr(union ref *r, struct block *blk, int *curi) -{ - struct addr addr = { 0 }; - - if (isaddrcon(*r,1)) return 1; - if (r->t == RADDR) { - const struct addr *a0 = &addrht[r->i]; - if (aadd(&addr, blk, curi, a0->base) - && (!addr.index.bits || ascale(&addr, a0->index, mkref(RICON, a0->shift))) - && aadd(&addr, blk, curi, mkintcon(KPTR, a0->disp))) { - *r = mkaddr(addr); - } - return 1; - } - if (r->t != RTMP) return 0; - if (!aadd(&addr, blk, curi, *r)) return 0; - - if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits))) { - /* pic needs to load from GOT */ - /* pie cannot encode RIP-relative address with index register */ - /* first load symbol address into a temp register */ - union ref temp = mkaddr((struct addr){.base = addr.base, .disp = ccopt.pic ? 0 : addr.disp}); - addr.base = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = temp)); - if (!ccopt.pic) addr.disp = 0; - } - - if (!addr.base.bits) { - /* absolute int address in disp */ - if (addr.index.bits) return 0; - addr.base = mkintcon(KPTR, addr.disp); - addr.disp = 0; - } - - *r = mkaddr(addr); - return 1; -} - -/* is add instruction with this arg a candidate to transform into efective addr? */ -static bool -addarg4addrp(union ref r) -{ - struct instr *ins; - if (r.t == RXCON && !conht[r.i].cls && !conht[r.i].deref) return 1; /* sym or dat ref */ - if (r.t != RTMP) return 0; - if (isstkslot(r)) return 1; - ins = &instrtab[r.i]; - return ins->op == Oshl || (ins->op == Ocopy && ins->l.t == RADDR) || ins->op == Oadd; -} - -static void -loadstoreaddr(struct block *blk, union ref *r, int *curi) -{ - if (isimm32(*r)) { - *r = mkaddr((struct addr){.base = *r}); - } else if (isaddrcon(*r, 0)) { - picfixsym(r, blk, curi); - } else if (r->t == RTMP) { - if (addarg4addrp(*r)) fuseaddr(r, blk, curi); - } else if (r->t != RREG) { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, *r)); - } -} - -static bool -arithfold(struct instr *ins) -{ - if (isnumcon(ins->l) && (!ins->r.t || isnumcon(ins->r))) { - union ref r; - bool ok = ins->r.t ? foldbinop(&r, ins->op, ins->cls, ins->l, ins->r) : foldunop(&r, ins->op, ins->cls, ins->l); - assert(ok && "fold?"); - *ins = mkinstr(Ocopy, insrescls(*ins), r); - return 1; - } - return 0; -} - -static void -sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) -{ - uint siz, alignlog2; - int t = ins - instrtab; - struct instr temp = {0}; - enum op op = ins->op; - - if (oisarith(ins->op) && arithfold(ins)) { - fixarg(&ins->l, ins, blk, curi); - return; - } - - switch (op) { - default: assert(0); - case Onop: break; - case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16: - alignlog2 = ins->op - Oalloca1; - assert(ins->l.i > 0); - siz = ins->l.i << alignlog2; - fn->stksiz += siz; - fn->stksiz = alignup(fn->stksiz, 1 << alignlog2); - if (fn->stksiz > (1<<16)-1) error(NULL, "'%s' stack frame too big", fn->name); - stkslots[t] = fn->stksiz; - *ins = mkinstr(Onop,0,); - break; - case Oparam: - assert(ins->l.t == RICON && ins->l.i < fn->nabiarg); - if (!fn->abiarg[ins->l.i].isstk) - *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, fn->abiarg[ins->l.i].reg)); - else /* stack */ - *ins = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, 16+fn->abiarg[ins->l.i].stk)); - break; - case Oarg: - fixarg(&ins->r, ins, blk, curi); - break; - case Ocall: - selcall(fn, ins, blk, curi); - break; - case Ocall2r: assert(0); - case Ointrin: - break; - case Oshl: case Osar: case Oslr: - if (!iscon(ins->r)) { - /* shift amount register is always CL */ - insertinstr(blk, (*curi)++, mkinstr(Omove, KI32, mkref(RREG, RCX), ins->r)); - ins->r = mkref(RREG, RCX); - } - goto ALU; - case Oequ: case Oneq: - case Olth: case Ogth: case Olte: case Ogte: - case Oulth: case Ougth: case Oulte: case Ougte: - if (iscon(ins->l)) { - /* lth imm, x -> gth x, imm */ - if (!in_range(ins->op, Oequ, Oneq)) - ins->op = ((op - Olth) ^ 1) + Olth; - rswap(ins->l, ins->r); - } - if (ins->l.t != RTMP && ins->l.t != RREG) - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ins->cls, ins->l)); - else - fixarg(&ins->l, ins, blk, curi); - fixarg(&ins->r, ins, blk, curi); - break; - case Odiv: case Oudiv: case Orem: case Ourem: - if (kisflt(ins->cls)) goto ALU; - /* TODO fuse div/rem pair */ - - /* (I)DIV dividend is always in RDX:RAX, output also in those regs */ - insertinstr(blk, (*curi)++, mkinstr(Omove, ins->cls, mkref(RREG, RAX), ins->l)); - /* mark RDX as clobbered. sign/zero-extending RAX into RDX is handled in emit() */ - insertinstr(blk, (*curi)++, mkinstr(Omove, ins->cls, mkref(RREG, RDX), mkref(RREG, RDX))); - fixarg(&ins->r, ins, blk, curi); /* make sure rhs is memory or reg */ - ins->l = mkref(RREG, RAX); - ins->keep = 1; - if (op == Orem) ins->op = Odiv; - else if (op == Ourem) ins->op = Oudiv; - insertinstr(blk, (*curi)++, *ins); /* duplicate ins to reuse tmp ref */ - *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, op < Orem ? RAX : RDX)); /* get output */ - temp = mkinstr(Ocopy, ins->cls, mkref(RREG, op < Orem ? RDX : RAX)); /* clobber other reg*/ - insertinstr(blk, ++(*curi), temp); - /* swap instrs so that clobber goes first */ - t = blk->ins.p[*curi - 1]; - blk->ins.p[*curi - 1] = blk->ins.p[*curi - 0]; - blk->ins.p[*curi - 0] = t; - break; - case Osub: - if (isintcon(ins->l)) { - /* sub imm, x -> sub x, imm; neg x */ - fixarg(&ins->l, ins, blk, curi); - ins->inplace = 1; - struct instr sub = *ins; - rswap(sub.l, sub.r); - ins->op = op = Oneg; - ins->l = insertinstr(blk, (*curi)++, sub); - ins->r = NOREF; - goto ALU; - } else if (kisint(ins->cls) && isintcon(ins->r)) { - ins->op = op = Oadd; - ins->r = mkintcon(concls(ins->r), -intconval(ins->r)); - } else { - goto ALU; - } - /* fallthru */ - case Oadd: - if (kisint(ins->cls)) { - if ((addarg4addrp(ins->l) || addarg4addrp(ins->r))) { - temp.op = Ocopy; - temp.cls = ins->cls; - temp.l = mkref(RTMP, t); - if (fuseaddr(&temp.l, blk, curi)) { - *ins = temp; - break; - } - } - } - /* fallthru */ - case Omul: - case Oand: case Oxor: case Oior: - /* commutative ops */ - if (iscon(ins->l)) - rswap(ins->l, ins->r); - goto ALU; - case Oneg: - if (kisflt(ins->cls)) { - /* flip sign bit with XORPS/D */ - static const uvlong sd[2] = {0x8000000000000000,0x8000000000000000}; - static const uint sf[4] = {0x80000000,80000000,0x80000000,80000000}; - ins->op = Oxor; - ins->r = mkdatref(NULL, mktype(ins->cls == KF32 ? TYFLOAT : TYDOUBLE), /*siz*/16, - /*align*/16, ins->cls == KF32 ? (void *)sf : sd, /*siz*/16, /*deref*/1); - } - /* fallthru */ - case Onot: - ALU: - if (!(op == Oadd && kisint(ins->cls))) /* 3-address add is lea */ - if (!(op == Omul && kisint(ins->cls) && isimm32(ins->r))) /* for (I)MUL r,r/m,imm */ - ins->inplace = 1; - if (iscon(ins->l)) { - fixarg(&ins->l, ins, blk, curi); - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ins->cls, ins->l)); - } - if (ins->r.bits) - case Omove: - fixarg(&ins->r, ins, blk, curi); - if (op == Oadd && isaddrcon(ins->r,1)) /* no 3-address add if rhs is mem */ - ins->inplace = 1; - break; - case Oloads8: case Oloadu8: case Oloads16: case Oloadu16: - case Oloads32: case Oloadu32: case Oloadi64: case Oloadf32: case Oloadf64: - loadstoreaddr(blk, &ins->l, curi); - break; - case Ostore8: case Ostore16: case Ostore32: case Ostore64: - loadstoreaddr(blk, &ins->l, curi); - if (isaddrcon(ins->r,1) || ins->r.t == RADDR) - ins->r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->r)); - else - fixarg(&ins->r, ins, blk, curi); - break; - case Ocvtu32f: - fixarg(&ins->l, ins, blk, curi); - ins->l = insertinstr(blk, (*curi)++, mkinstr(Oextu32, KI64, ins->l)); - ins->op = Ocvts64f; - break; - case Ocvtf32u: case Ocvtf64u: - fixarg(&ins->l, ins, blk, curi); - if (ins->cls == KI32) { - ins->l = insertinstr(blk, (*curi)++, mkinstr(ins->op == Ocvtf32u ? Ocvtf32s : Ocvtf64s, KI64, ins->l)); - ins->op = Oextu32; - } else assert(!"nyi flt -> u64"); - break; - case Ocvtf32f64: case Ocvtf64f32: case Ocvtf32s: case Ocvtf64s: case Ocvts32f: case Ocvts64f: - case Ocvtu64f: - case Oexts8: case Oextu8: case Oexts16: case Oextu16: case Oexts32: case Oextu32: - if (isnumcon(ins->l)) { - union ref it; - bool ok = foldunop(&it, ins->op, ins->cls, ins->l); - assert(ok); - ins->op = Ocopy; - ins->l = it; - break; - } - case Ocopy: - fixarg(&ins->l, ins, blk, curi); - break; - case Oxvaprologue: - fuseaddr(&ins->l, blk, curi); - assert(ins->l.t == RADDR); - /* !this must be the first instruction */ - assert(*curi == 1); - assert(blk == fn->entry); - t = blk->ins.p[0]; - blk->ins.p[0] = blk->ins.p[1]; - blk->ins.p[1] = t; - break; - } -} - -static void -seljmp(struct function *fn, struct block *blk) -{ - if (blk->jmp.t == Jb && blk->jmp.arg[0].bits) { - int curi = blk->ins.n; - fixarg(&blk->jmp.arg[0], NULL, blk, &curi); - union ref c = blk->jmp.arg[0]; - if (c.t != RTMP) { - enum irclass cls = c.t == RICON ? KI32 : c.t == RXCON && conht[c.i].cls ? conht[c.i].cls : KPTR; - int curi = blk->ins.n; - - c = insertinstr(blk, blk->ins.n, mkinstr(Ocopy, cls, c)); - sel(fn, &instrtab[c.i], blk, &curi); - } - if (iflagsrc == c.i /* test cmp */ - && (oiscmp(instrtab[c.i].op) || instrtab[c.i].op == Oand || instrtab[c.i].op == Osub)) { - instrtab[c.i].keep = 1; - } else { - if (!(opflags[instrtab[c.i].op] & ZF) || blk->ins.n == 0 || c.i != blk->ins.p[blk->ins.n - 1]) { - struct instr *ins; - int curi = blk->ins.n; - blk->jmp.arg[0] = insertinstr(blk, blk->ins.n, mkinstr(Oneq, instrtab[c.i].cls, c, ZEROREF)); - ins = &instrtab[blk->jmp.arg[0].i]; - if (kisflt(ins->cls)) { - ins->r = insertinstr(blk, curi, mkinstr(Ocopy, ins->cls, ZEROREF)); - } - ins->keep = 1; - } else if (instrtab[c.i].op == Oadd) { - /* prevent a 3-address add whose flag results are used from becoming a LEA */ - instrtab[c.i].inplace = 1; - } - } - } else if (blk->jmp.t == Jret) { - if (blk->jmp.arg[0].bits) { - int curi; - union ref r = mkref(RREG, fn->abiret[0].reg); - struct instr *ins = &instrtab[insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[0].ty.cls, r , blk->jmp.arg[0])).i]; - curi = blk->ins.n; - fixarg(&ins->r, ins, blk, &curi); - blk->jmp.arg[0] = r; - if (blk->jmp.arg[1].bits) { - r = mkref(RREG, fn->abiret[1].reg); - ins = &instrtab[insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[1].ty.cls, r, blk->jmp.arg[1])).i]; - curi = blk->ins.n; - fixarg(&ins->r, ins, blk, &curi); - blk->jmp.arg[1] = r; - } - } - } -} - -void -amd64_isel(struct function *fn) -{ - extern int ninstr; - struct block *blk = fn->entry; - - fn->stksiz = 0; - stkslots = xcalloc((nstkslots = ninstr) * sizeof *stkslots); - do { - int i; - for (i = 0; i < blk->phi.n; ++i) { - struct instr *ins = &instrtab[blk->phi.p[i]]; - union ref *phi = phitab.p[ins->l.i]; - for (int i = 0; i < blk->npred; ++i) { - int curi = blkpred(blk, i)->ins.n; - fixarg(&phi[i], ins, blkpred(blk, i), &curi); - } - } - iflagsrc = -1; - for (i = 0; i < blk->ins.n; ++i) { - struct instr *ins = &instrtab[blk->ins.p[i]]; - sel(fn, ins, blk, &i); - if (ins->op < countof(opflags) && kisint(insrescls(*ins))) { - if (opflags[ins->op] & ZF) iflagsrc = ins - instrtab; - else if (opflags[ins->op] & CLOBF) iflagsrc = -1; - } - } - seljmp(fn, blk); - } while ((blk = blk->lnext) != fn->entry); - free(stkslots); - - if (ccopt.dbg.i) { - bfmt(ccopt.dbgout, "<< After isel >>\n"); - irdump(fn); - } - - fn->prop = 0; -} - -/* vim:set ts=3 sw=3 expandtab: */ |