aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64/isel.c
diff options
context:
space:
mode:
Diffstat (limited to 'amd64/isel.c')
-rw-r--r--amd64/isel.c660
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: */