| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- #include "all.h"
- #include <limits.h>
- /* For x86_64, do the following:
- *
- * - check that constants are used only in
- * places allowed
- * - ensure immediates always fit in 32b
- * - expose machine register contraints
- * on instructions like division.
- * - implement fast locals (the streak of
- * constant allocX in the first basic block)
- * - recognize complex addressing modes
- *
- * Invariant: the use counts that are used
- * in sel() must be sound. This
- * is not so trivial, maybe the
- * dce should be moved out...
- */
- static int amatch(Addr *, Num *, Ref, Fn *);
- static int
- noimm(Ref r, Fn *fn)
- {
- int64_t val;
- if (rtype(r) != RCon)
- return 0;
- switch (fn->con[r.val].type) {
- case CAddr:
- /* we only support the 'small'
- * code model of the ABI, this
- * means that we can always
- * address data with 32bits
- */
- return 0;
- case CBits:
- val = fn->con[r.val].bits.i;
- return (val < INT32_MIN || val > INT32_MAX);
- default:
- die("invalid constant");
- }
- }
- static int
- rslot(Ref r, Fn *fn)
- {
- if (rtype(r) != RTmp)
- return -1;
- return fn->tmp[r.val].slot;
- }
- static int
- hascon(Ref r, Con **pc, Fn *fn)
- {
- switch (rtype(r)) {
- case RCon:
- *pc = &fn->con[r.val];
- return 1;
- case RMem:
- *pc = &fn->mem[r.val].offset;
- return 1;
- default:
- return 0;
- }
- }
- static void
- fixarg(Ref *r, int k, Ins *i, Fn *fn)
- {
- char buf[32];
- Addr a, *m;
- Con cc, *c;
- Ref r0, r1, r2, r3;
- int s, n, op;
- r1 = r0 = *r;
- s = rslot(r0, fn);
- op = i ? i->op : Ocopy;
- if (KBASE(k) == 1 && rtype(r0) == RCon) {
- /* load floating points from memory
- * slots, they can't be used as
- * immediates
- */
- r1 = MEM(fn->nmem);
- vgrow(&fn->mem, ++fn->nmem);
- memset(&a, 0, sizeof a);
- a.offset.type = CAddr;
- n = stashbits(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
- /* quote the name so that we do not
- * add symbol prefixes on the apple
- * target variant
- */
- sprintf(buf, "\"%sfp%d\"", T.asloc, n);
- a.offset.sym.id = intern(buf);
- fn->mem[fn->nmem-1] = a;
- }
- else if (op != Ocopy && k == Kl && noimm(r0, fn)) {
- /* load constants that do not fit in
- * a 32bit signed integer into a
- * long temporary
- */
- r1 = newtmp("isel", Kl, fn);
- emit(Ocopy, Kl, r1, r0, R);
- }
- else if (s != -1) {
- /* load fast locals' addresses into
- * temporaries right before the
- * instruction
- */
- r1 = newtmp("isel", Kl, fn);
- emit(Oaddr, Kl, r1, SLOT(s), R);
- }
- else if (T.apple && hascon(r0, &c, fn)
- && c->type == CAddr && c->sym.type == SThr) {
- r1 = newtmp("isel", Kl, fn);
- if (c->bits.i) {
- r2 = newtmp("isel", Kl, fn);
- cc = (Con){.type = CBits};
- cc.bits.i = c->bits.i;
- r3 = newcon(&cc, fn);
- emit(Oadd, Kl, r1, r2, r3);
- } else
- r2 = r1;
- emit(Ocopy, Kl, r2, TMP(RAX), R);
- r2 = newtmp("isel", Kl, fn);
- r3 = newtmp("isel", Kl, fn);
- emit(Ocall, 0, R, r3, CALL(17));
- emit(Ocopy, Kl, TMP(RDI), r2, R);
- emit(Oload, Kl, r3, r2, R);
- cc = *c;
- cc.bits.i = 0;
- r3 = newcon(&cc, fn);
- emit(Oload, Kl, r2, r3, R);
- if (rtype(r0) == RMem) {
- m = &fn->mem[r0.val];
- m->offset.type = CUndef;
- m->base = r1;
- r1 = r0;
- }
- }
- else if (!(isstore(op) && r == &i->arg[1])
- && !isload(op) && op != Ocall && rtype(r0) == RCon
- && fn->con[r0.val].type == CAddr) {
- /* apple as does not support 32-bit
- * absolute addressing, use a rip-
- * relative leaq instead
- */
- r1 = newtmp("isel", Kl, fn);
- emit(Oaddr, Kl, r1, r0, R);
- }
- else if (rtype(r0) == RMem) {
- /* eliminate memory operands of
- * the form $foo(%rip, ...)
- */
- m = &fn->mem[r0.val];
- if (req(m->base, R))
- if (m->offset.type == CAddr) {
- r0 = newtmp("isel", Kl, fn);
- emit(Oaddr, Kl, r0, newcon(&m->offset, fn), R);
- m->offset.type = CUndef;
- m->base = r0;
- }
- }
- *r = r1;
- }
- static void
- seladdr(Ref *r, Num *tn, Fn *fn)
- {
- Addr a;
- Ref r0;
- r0 = *r;
- if (rtype(r0) == RTmp) {
- memset(&a, 0, sizeof a);
- if (!amatch(&a, tn, r0, fn))
- return;
- if (!req(a.base, R))
- if (a.offset.type == CAddr) {
- /* apple as does not support
- * $foo(%r0, %r1, M); try to
- * rewrite it or bail out if
- * impossible
- */
- if (!req(a.index, R) || rtype(a.base) != RTmp)
- return;
- else {
- a.index = a.base;
- a.scale = 1;
- a.base = R;
- }
- }
- chuse(r0, -1, fn);
- vgrow(&fn->mem, ++fn->nmem);
- fn->mem[fn->nmem-1] = a;
- chuse(a.base, +1, fn);
- chuse(a.index, +1, fn);
- *r = MEM(fn->nmem-1);
- }
- }
- static int
- cmpswap(Ref arg[2], int op)
- {
- switch (op) {
- case NCmpI+Cflt:
- case NCmpI+Cfle:
- return 1;
- case NCmpI+Cfgt:
- case NCmpI+Cfge:
- return 0;
- }
- return rtype(arg[0]) == RCon;
- }
- static void
- selcmp(Ref arg[2], int k, int swap, Fn *fn)
- {
- Ref r;
- Ins *icmp;
- if (swap) {
- r = arg[1];
- arg[1] = arg[0];
- arg[0] = r;
- }
- emit(Oxcmp, k, R, arg[1], arg[0]);
- icmp = curi;
- if (rtype(arg[0]) == RCon) {
- assert(k != Kw);
- icmp->arg[1] = newtmp("isel", k, fn);
- emit(Ocopy, k, icmp->arg[1], arg[0], R);
- fixarg(&curi->arg[0], k, curi, fn);
- }
- fixarg(&icmp->arg[0], k, icmp, fn);
- fixarg(&icmp->arg[1], k, icmp, fn);
- }
- static void
- sel(Ins i, Num *tn, Fn *fn)
- {
- Ref r0, r1, tmp[7];
- int x, j, k, kc, sh, swap;
- Ins *i0, *i1;
- if (rtype(i.to) == RTmp)
- if (!isreg(i.to) && !isreg(i.arg[0]) && !isreg(i.arg[1]))
- if (fn->tmp[i.to.val].nuse == 0) {
- chuse(i.arg[0], -1, fn);
- chuse(i.arg[1], -1, fn);
- return;
- }
- i0 = curi;
- k = i.cls;
- switch (i.op) {
- case Odiv:
- case Orem:
- case Oudiv:
- case Ourem:
- if (KBASE(k) == 1)
- goto Emit;
- if (i.op == Odiv || i.op == Oudiv)
- r0 = TMP(RAX), r1 = TMP(RDX);
- else
- r0 = TMP(RDX), r1 = TMP(RAX);
- emit(Ocopy, k, i.to, r0, R);
- emit(Ocopy, k, R, r1, R);
- if (rtype(i.arg[1]) == RCon) {
- /* immediates not allowed for
- * divisions in x86
- */
- r0 = newtmp("isel", k, fn);
- } else
- r0 = i.arg[1];
- if (fn->tmp[r0.val].slot != -1)
- err("unlikely argument %%%s in %s",
- fn->tmp[r0.val].name, optab[i.op].name);
- if (i.op == Odiv || i.op == Orem) {
- emit(Oxidiv, k, R, r0, R);
- emit(Osign, k, TMP(RDX), TMP(RAX), R);
- } else {
- emit(Oxdiv, k, R, r0, R);
- emit(Ocopy, k, TMP(RDX), CON_Z, R);
- }
- emit(Ocopy, k, TMP(RAX), i.arg[0], R);
- fixarg(&curi->arg[0], k, curi, fn);
- if (rtype(i.arg[1]) == RCon)
- emit(Ocopy, k, r0, i.arg[1], R);
- break;
- case Osar:
- case Oshr:
- case Oshl:
- r0 = i.arg[1];
- if (rtype(r0) == RCon)
- goto Emit;
- if (fn->tmp[r0.val].slot != -1)
- err("unlikely argument %%%s in %s",
- fn->tmp[r0.val].name, optab[i.op].name);
- i.arg[1] = TMP(RCX);
- emit(Ocopy, Kw, R, TMP(RCX), R);
- emiti(i);
- i1 = curi;
- emit(Ocopy, Kw, TMP(RCX), r0, R);
- fixarg(&i1->arg[0], argcls(&i, 0), i1, fn);
- break;
- case Ouwtof:
- r0 = newtmp("utof", Kl, fn);
- emit(Osltof, k, i.to, r0, R);
- emit(Oextuw, Kl, r0, i.arg[0], R);
- fixarg(&curi->arg[0], k, curi, fn);
- break;
- case Oultof:
- /* %mask =l and %arg.0, 1
- * %isbig =l shr %arg.0, 63
- * %divided =l shr %arg.0, %isbig
- * %or =l or %mask, %divided
- * %float =d sltof %or
- * %cast =l cast %float
- * %addend =l shl %isbig, 52
- * %sum =l add %cast, %addend
- * %result =d cast %sum
- */
- r0 = newtmp("utof", k, fn);
- if (k == Ks)
- kc = Kw, sh = 23;
- else
- kc = Kl, sh = 52;
- for (j=0; j<4; j++)
- tmp[j] = newtmp("utof", Kl, fn);
- for (; j<7; j++)
- tmp[j] = newtmp("utof", kc, fn);
- emit(Ocast, k, i.to, tmp[6], R);
- emit(Oadd, kc, tmp[6], tmp[4], tmp[5]);
- emit(Oshl, kc, tmp[5], tmp[1], getcon(sh, fn));
- emit(Ocast, kc, tmp[4], r0, R);
- emit(Osltof, k, r0, tmp[3], R);
- emit(Oor, Kl, tmp[3], tmp[0], tmp[2]);
- emit(Oshr, Kl, tmp[2], i.arg[0], tmp[1]);
- sel(*curi++, 0, fn);
- emit(Oshr, Kl, tmp[1], i.arg[0], getcon(63, fn));
- fixarg(&curi->arg[0], Kl, curi, fn);
- emit(Oand, Kl, tmp[0], i.arg[0], getcon(1, fn));
- fixarg(&curi->arg[0], Kl, curi, fn);
- break;
- case Ostoui:
- i.op = Ostosi;
- kc = Ks;
- tmp[4] = getcon(0xdf000000, fn);
- goto Oftoui;
- case Odtoui:
- i.op = Odtosi;
- kc = Kd;
- tmp[4] = getcon(0xc3e0000000000000, fn);
- Oftoui:
- if (k == Kw) {
- r0 = newtmp("ftou", Kl, fn);
- emit(Ocopy, Kw, i.to, r0, R);
- i.cls = Kl;
- i.to = r0;
- goto Emit;
- }
- /* %try0 =l {s,d}tosi %fp
- * %mask =l sar %try0, 63
- *
- * mask is all ones if the first
- * try was oob, all zeroes o.w.
- *
- * %fps ={s,d} sub %fp, (1<<63)
- * %try1 =l {s,d}tosi %fps
- *
- * %tmp =l and %mask, %try1
- * %res =l or %tmp, %try0
- */
- r0 = newtmp("ftou", kc, fn);
- for (j=0; j<4; j++)
- tmp[j] = newtmp("ftou", Kl, fn);
- emit(Oor, Kl, i.to, tmp[0], tmp[3]);
- emit(Oand, Kl, tmp[3], tmp[2], tmp[1]);
- emit(i.op, Kl, tmp[2], r0, R);
- emit(Oadd, kc, r0, tmp[4], i.arg[0]);
- i1 = curi; /* fixarg() can change curi */
- fixarg(&i1->arg[0], kc, i1, fn);
- fixarg(&i1->arg[1], kc, i1, fn);
- emit(Osar, Kl, tmp[1], tmp[0], getcon(63, fn));
- emit(i.op, Kl, tmp[0], i.arg[0], R);
- fixarg(&curi->arg[0], Kl, curi, fn);
- break;
- case Onop:
- break;
- case Ostored:
- case Ostores:
- case Ostorel:
- case Ostorew:
- case Ostoreh:
- case Ostoreb:
- if (rtype(i.arg[0]) == RCon) {
- if (i.op == Ostored)
- i.op = Ostorel;
- if (i.op == Ostores)
- i.op = Ostorew;
- }
- seladdr(&i.arg[1], tn, fn);
- goto Emit;
- case_Oload:
- seladdr(&i.arg[0], tn, fn);
- goto Emit;
- case Odbgloc:
- case Ocall:
- case Osalloc:
- case Ocopy:
- case Oadd:
- case Osub:
- case Oneg:
- case Omul:
- case Oand:
- case Oor:
- case Oxor:
- case Oxtest:
- case Ostosi:
- case Odtosi:
- case Oswtof:
- case Osltof:
- case Oexts:
- case Otruncd:
- case Ocast:
- case_OExt:
- Emit:
- emiti(i);
- i1 = curi; /* fixarg() can change curi */
- fixarg(&i1->arg[0], argcls(&i, 0), i1, fn);
- fixarg(&i1->arg[1], argcls(&i, 1), i1, fn);
- break;
- case Oalloc4:
- case Oalloc8:
- case Oalloc16:
- salloc(i.to, i.arg[0], fn);
- break;
- default:
- if (isext(i.op))
- goto case_OExt;
- if (isload(i.op))
- goto case_Oload;
- if (iscmp(i.op, &kc, &x)) {
- switch (x) {
- case NCmpI+Cfeq:
- /* zf is set when operands are
- * unordered, so we may have to
- * check pf
- */
- r0 = newtmp("isel", Kw, fn);
- r1 = newtmp("isel", Kw, fn);
- emit(Oand, Kw, i.to, r0, r1);
- emit(Oflagfo, k, r1, R, R);
- i.to = r0;
- break;
- case NCmpI+Cfne:
- r0 = newtmp("isel", Kw, fn);
- r1 = newtmp("isel", Kw, fn);
- emit(Oor, Kw, i.to, r0, r1);
- emit(Oflagfuo, k, r1, R, R);
- i.to = r0;
- break;
- }
- swap = cmpswap(i.arg, x);
- if (swap)
- x = cmpop(x);
- emit(Oflag+x, k, i.to, R, R);
- selcmp(i.arg, kc, swap, fn);
- break;
- }
- die("unknown instruction %s", optab[i.op].name);
- }
- while (i0>curi && --i0) {
- assert(rslot(i0->arg[0], fn) == -1);
- assert(rslot(i0->arg[1], fn) == -1);
- }
- }
- static Ins *
- flagi(Ins *i0, Ins *i)
- {
- while (i>i0) {
- i--;
- if (amd64_op[i->op].zflag)
- return i;
- if (amd64_op[i->op].lflag)
- continue;
- return 0;
- }
- return 0;
- }
- static void
- seljmp(Blk *b, Fn *fn)
- {
- Ref r;
- int c, k, swap;
- Ins *fi;
- Tmp *t;
- if (b->jmp.type == Jret0
- || b->jmp.type == Jjmp
- || b->jmp.type == Jhlt)
- return;
- assert(b->jmp.type == Jjnz);
- r = b->jmp.arg;
- t = &fn->tmp[r.val];
- b->jmp.arg = R;
- assert(rtype(r) == RTmp);
- if (b->s1 == b->s2) {
- chuse(r, -1, fn);
- b->jmp.type = Jjmp;
- b->s2 = 0;
- return;
- }
- fi = flagi(b->ins, &b->ins[b->nins]);
- if (!fi || !req(fi->to, r)) {
- selcmp((Ref[2]){r, CON_Z}, Kw, 0, fn);
- b->jmp.type = Jjf + Cine;
- }
- else if (iscmp(fi->op, &k, &c)
- && c != NCmpI+Cfeq /* see sel() */
- && c != NCmpI+Cfne) {
- swap = cmpswap(fi->arg, c);
- if (swap)
- c = cmpop(c);
- if (t->nuse == 1) {
- selcmp(fi->arg, k, swap, fn);
- *fi = (Ins){.op = Onop};
- }
- b->jmp.type = Jjf + c;
- }
- else if (fi->op == Oand && t->nuse == 1
- && (rtype(fi->arg[0]) == RTmp ||
- rtype(fi->arg[1]) == RTmp)) {
- fi->op = Oxtest;
- fi->to = R;
- b->jmp.type = Jjf + Cine;
- if (rtype(fi->arg[1]) == RCon) {
- r = fi->arg[1];
- fi->arg[1] = fi->arg[0];
- fi->arg[0] = r;
- }
- }
- else {
- /* since flags are not tracked in liveness,
- * the result of the flag-setting instruction
- * has to be marked as live
- */
- if (t->nuse == 1)
- emit(Ocopy, Kw, R, r, R);
- b->jmp.type = Jjf + Cine;
- }
- }
- enum {
- Pob,
- Pbis,
- Pois,
- Pobis,
- Pbi1,
- Pobi1,
- };
- /* mgen generated code
- *
- * (with-vars (o b i s)
- * (patterns
- * (ob (add (con o) (tmp b)))
- * (bis (add (tmp b) (mul (tmp i) (con s 1 2 4 8))))
- * (ois (add (con o) (mul (tmp i) (con s 1 2 4 8))))
- * (obis (add (con o) (tmp b) (mul (tmp i) (con s 1 2 4 8))))
- * (bi1 (add (tmp b) (tmp i)))
- * (obi1 (add (con o) (tmp b) (tmp i)))
- * ))
- */
- static int
- opn(int op, int l, int r)
- {
- static uchar Oaddtbl[91] = {
- 2,
- 2,2,
- 4,4,5,
- 6,6,8,8,
- 4,4,9,10,9,
- 7,7,5,8,9,5,
- 4,4,12,10,12,12,12,
- 4,4,9,10,9,9,12,9,
- 11,11,5,8,9,5,12,9,5,
- 7,7,5,8,9,5,12,9,5,5,
- 11,11,5,8,9,5,12,9,5,5,5,
- 4,4,9,10,9,9,12,9,9,9,9,9,
- 7,7,5,8,9,5,12,9,5,5,5,9,5,
- };
- int t;
- if (l < r)
- t = l, l = r, r = t;
- switch (op) {
- case Omul:
- if (2 <= l)
- if (r == 0) {
- return 3;
- }
- return 2;
- case Oadd:
- return Oaddtbl[(l + l*l)/2 + r];
- default:
- return 2;
- }
- }
- static int
- refn(Ref r, Num *tn, Con *con)
- {
- int64_t n;
- switch (rtype(r)) {
- case RTmp:
- if (!tn[r.val].n)
- tn[r.val].n = 2;
- return tn[r.val].n;
- case RCon:
- if (con[r.val].type != CBits)
- return 1;
- n = con[r.val].bits.i;
- if (n == 8 || n == 4 || n == 2 || n == 1)
- return 0;
- return 1;
- default:
- return INT_MIN;
- }
- }
- static bits match[13] = {
- [4] = BIT(Pob),
- [5] = BIT(Pbi1),
- [6] = BIT(Pob) | BIT(Pois),
- [7] = BIT(Pob) | BIT(Pobi1),
- [8] = BIT(Pbi1) | BIT(Pbis),
- [9] = BIT(Pbi1) | BIT(Pobi1),
- [10] = BIT(Pbi1) | BIT(Pbis) | BIT(Pobi1) | BIT(Pobis),
- [11] = BIT(Pob) | BIT(Pobi1) | BIT(Pobis),
- [12] = BIT(Pbi1) | BIT(Pobi1) | BIT(Pobis),
- };
- static uchar *matcher[] = {
- [Pbi1] = (uchar[]){
- 1,3,1,3,2,0
- },
- [Pbis] = (uchar[]){
- 5,1,8,5,27,1,5,1,2,5,13,3,1,1,3,3,3,2,0,1,
- 3,3,3,2,3,1,0,1,29
- },
- [Pob] = (uchar[]){
- 1,3,0,3,1,0
- },
- [Pobi1] = (uchar[]){
- 5,3,9,9,10,33,12,35,45,1,5,3,11,9,7,9,4,9,
- 17,1,3,0,3,1,3,2,0,3,1,1,3,0,34,1,37,1,5,2,
- 5,7,2,7,8,37,29,1,3,0,1,32
- },
- [Pobis] = (uchar[]){
- 5,2,10,7,11,19,49,1,1,3,3,3,2,1,3,0,3,1,0,
- 1,3,0,5,1,8,5,25,1,5,1,2,5,13,3,1,1,3,3,3,
- 2,0,1,3,3,3,2,26,1,51,1,5,1,6,5,9,1,3,0,51,
- 3,1,1,3,0,45
- },
- [Pois] = (uchar[]){
- 1,3,0,1,3,3,3,2,0
- },
- };
- /* end of generated code */
- static void
- anumber(Num *tn, Blk *b, Con *con)
- {
- Ins *i;
- Num *n;
- for (i=b->ins; i<&b->ins[b->nins]; i++) {
- if (rtype(i->to) != RTmp)
- continue;
- n = &tn[i->to.val];
- n->l = i->arg[0];
- n->r = i->arg[1];
- n->nl = refn(n->l, tn, con);
- n->nr = refn(n->r, tn, con);
- n->n = opn(i->op, n->nl, n->nr);
- }
- }
- static Ref
- adisp(Con *c, Num *tn, Ref r, Fn *fn, int s)
- {
- Ref v[2];
- int n;
- while (!req(r, R)) {
- assert(rtype(r) == RTmp);
- n = refn(r, tn, fn->con);
- if (!(match[n] & BIT(Pob)))
- break;
- runmatch(matcher[Pob], tn, r, v);
- assert(rtype(v[0]) == RCon);
- addcon(c, &fn->con[v[0].val], s);
- r = v[1];
- }
- return r;
- }
- static int
- amatch(Addr *a, Num *tn, Ref r, Fn *fn)
- {
- static int pat[] = {Pobis, Pobi1, Pbis, Pois, Pbi1, -1};
- Ref ro, rb, ri, rs, v[4];
- Con *c, co;
- int s, n, *p;
- if (rtype(r) != RTmp)
- return 0;
- n = refn(r, tn, fn->con);
- memset(v, 0, sizeof v);
- for (p=pat; *p>=0; p++)
- if (match[n] & BIT(*p)) {
- runmatch(matcher[*p], tn, r, v);
- break;
- }
- if (*p < 0)
- v[1] = r;
- memset(&co, 0, sizeof co);
- ro = v[0];
- rb = adisp(&co, tn, v[1], fn, 1);
- ri = v[2];
- rs = v[3];
- s = 1;
- if (*p < 0 && co.type != CUndef)
- if (amatch(a, tn, rb, fn))
- return addcon(&a->offset, &co, 1);
- if (!req(ro, R)) {
- assert(rtype(ro) == RCon);
- c = &fn->con[ro.val];
- if (!addcon(&co, c, 1))
- return 0;
- }
- if (!req(rs, R)) {
- assert(rtype(rs) == RCon);
- c = &fn->con[rs.val];
- assert(c->type = CBits);
- s = c->bits.i;
- }
- ri = adisp(&co, tn, ri, fn, s);
- *a = (Addr){co, rb, ri, s};
- if (rtype(ri) == RTmp)
- if (fn->tmp[ri.val].slot != -1) {
- if (a->scale != 1
- || fn->tmp[rb.val].slot != -1)
- return 0;
- a->base = ri;
- a->index = rb;
- }
- if (!req(a->base, R)) {
- assert(rtype(a->base) == RTmp);
- s = fn->tmp[a->base.val].slot;
- if (s != -1)
- a->base = SLOT(s);
- }
- return 1;
- }
- /* instruction selection
- * requires use counts (as given by parsing)
- */
- void
- amd64_isel(Fn *fn)
- {
- Blk *b, **sb;
- Ins *i;
- Phi *p;
- uint a;
- int n, al;
- int64_t sz;
- Num *num;
- /* assign slots to fast allocs */
- b = fn->start;
- /* specific to NAlign == 3 */ /* or change n=4 and sz /= 4 below */
- for (al=Oalloc, n=4; al<=Oalloc1; al++, n*=2)
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- if (i->op == al) {
- if (rtype(i->arg[0]) != RCon)
- break;
- sz = fn->con[i->arg[0].val].bits.i;
- if (sz < 0 || sz >= INT_MAX-15)
- err("invalid alloc size %"PRId64, sz);
- sz = (sz + n-1) & -n;
- sz /= 4;
- if (sz > INT_MAX - fn->slot)
- die("alloc too large");
- fn->tmp[i->to.val].slot = fn->slot;
- fn->slot += sz;
- *i = (Ins){.op = Onop};
- }
- /* process basic blocks */
- n = fn->ntmp;
- num = emalloc(n * sizeof num[0]);
- for (b=fn->start; b; b=b->link) {
- curi = &insb[NIns];
- for (sb=(Blk*[3]){b->s1, b->s2, 0}; *sb; sb++)
- for (p=(*sb)->phi; p; p=p->link) {
- for (a=0; p->blk[a] != b; a++)
- assert(a+1 < p->narg);
- fixarg(&p->arg[a], p->cls, 0, fn);
- }
- memset(num, 0, n * sizeof num[0]);
- anumber(num, b, fn->con);
- seljmp(b, fn);
- for (i=&b->ins[b->nins]; i!=b->ins;)
- sel(*--i, num, fn);
- b->nins = &insb[NIns] - curi;
- idup(&b->ins, curi, b->nins);
- }
- free(num);
- if (debug['I']) {
- fprintf(stderr, "\n> After instruction selection:\n");
- printfn(fn, stderr);
- }
- }
|