| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- #include "all.h"
- #ifdef TEST_PMOV
- #undef assert
- #define assert(x) assert_test(#x, x)
- #endif
- typedef struct RMap RMap;
- struct RMap {
- int t[Tmp0];
- int r[Tmp0];
- int w[Tmp0]; /* wait list, for unmatched hints */
- BSet b[1];
- int n;
- };
- static bits regu; /* registers used */
- static Tmp *tmp; /* function temporaries */
- static Mem *mem; /* function mem references */
- static struct {
- Ref src, dst;
- int cls;
- } pm[Tmp0]; /* parallel move constructed */
- static int npm; /* size of pm */
- static int loop; /* current loop level */
- static uint stmov; /* stats: added moves */
- static uint stblk; /* stats: added blocks */
- static int *
- hint(int t)
- {
- return &tmp[phicls(t, tmp)].hint.r;
- }
- static void
- sethint(int t, int r)
- {
- Tmp *p;
- p = &tmp[phicls(t, tmp)];
- if (p->hint.r == -1 || p->hint.w > loop) {
- p->hint.r = r;
- p->hint.w = loop;
- tmp[t].visit = -1;
- }
- }
- static void
- rcopy(RMap *ma, RMap *mb)
- {
- memcpy(ma->t, mb->t, sizeof ma->t);
- memcpy(ma->r, mb->r, sizeof ma->r);
- memcpy(ma->w, mb->w, sizeof ma->w);
- bscopy(ma->b, mb->b);
- ma->n = mb->n;
- }
- static int
- rfind(RMap *m, int t)
- {
- int i;
- for (i=0; i<m->n; i++)
- if (m->t[i] == t)
- return m->r[i];
- return -1;
- }
- static Ref
- rref(RMap *m, int t)
- {
- int r, s;
- r = rfind(m, t);
- if (r == -1) {
- s = tmp[t].slot;
- assert(s != -1 && "should have spilled");
- return SLOT(s);
- } else
- return TMP(r);
- }
- static void
- radd(RMap *m, int t, int r)
- {
- assert((t >= Tmp0 || t == r) && "invalid temporary");
- assert(((T.gpr0 <= r && r < T.gpr0 + T.ngpr)
- || (T.fpr0 <= r && r < T.fpr0 + T.nfpr))
- && "invalid register");
- assert(!bshas(m->b, t) && "temporary has mapping");
- assert(!bshas(m->b, r) && "register already allocated");
- assert(m->n <= T.ngpr+T.nfpr && "too many mappings");
- bsset(m->b, t);
- bsset(m->b, r);
- m->t[m->n] = t;
- m->r[m->n] = r;
- m->n++;
- regu |= BIT(r);
- }
- static Ref
- ralloctry(RMap *m, int t, int try)
- {
- bits regs;
- int h, r, r0, r1;
- if (t < Tmp0) {
- assert(bshas(m->b, t));
- return TMP(t);
- }
- if (bshas(m->b, t)) {
- r = rfind(m, t);
- assert(r != -1);
- return TMP(r);
- }
- r = tmp[t].visit;
- if (r == -1 || bshas(m->b, r))
- r = *hint(t);
- if (r == -1 || bshas(m->b, r)) {
- if (try)
- return R;
- regs = tmp[phicls(t, tmp)].hint.m;
- regs |= m->b->t[0];
- if (KBASE(tmp[t].cls) == 0) {
- r0 = T.gpr0;
- r1 = r0 + T.ngpr;
- } else {
- r0 = T.fpr0;
- r1 = r0 + T.nfpr;
- }
- for (r=r0; r<r1; r++)
- if (!(regs & BIT(r)))
- goto Found;
- for (r=r0; r<r1; r++)
- if (!bshas(m->b, r))
- goto Found;
- die("no more regs");
- }
- Found:
- radd(m, t, r);
- sethint(t, r);
- tmp[t].visit = r;
- h = *hint(t);
- if (h != -1 && h != r)
- m->w[h] = t;
- return TMP(r);
- }
- static inline Ref
- ralloc(RMap *m, int t)
- {
- return ralloctry(m, t, 0);
- }
- static int
- rfree(RMap *m, int t)
- {
- int i, r;
- assert(t >= Tmp0 || !(BIT(t) & T.rglob));
- if (!bshas(m->b, t))
- return -1;
- for (i=0; m->t[i] != t; i++)
- assert(i+1 < m->n);
- r = m->r[i];
- bsclr(m->b, t);
- bsclr(m->b, r);
- m->n--;
- memmove(&m->t[i], &m->t[i+1], (m->n-i) * sizeof m->t[0]);
- memmove(&m->r[i], &m->r[i+1], (m->n-i) * sizeof m->r[0]);
- assert(t >= Tmp0 || t == r);
- return r;
- }
- static void
- mdump(RMap *m)
- {
- int i;
- for (i=0; i<m->n; i++)
- if (m->t[i] >= Tmp0)
- fprintf(stderr, " (%s, R%d)",
- tmp[m->t[i]].name,
- m->r[i]);
- fprintf(stderr, "\n");
- }
- static void
- pmadd(Ref src, Ref dst, int k)
- {
- if (npm == Tmp0)
- die("cannot have more moves than registers");
- pm[npm].src = src;
- pm[npm].dst = dst;
- pm[npm].cls = k;
- npm++;
- }
- enum PMStat { ToMove, Moving, Moved };
- static int
- pmrec(enum PMStat *status, int i, int *k)
- {
- int j, c;
- /* note, this routine might emit
- * too many large instructions
- */
- if (req(pm[i].src, pm[i].dst)) {
- status[i] = Moved;
- return -1;
- }
- assert(KBASE(pm[i].cls) == KBASE(*k));
- assert((Kw|Kl) == Kl && (Ks|Kd) == Kd);
- *k |= pm[i].cls;
- for (j=0; j<npm; j++)
- if (req(pm[j].dst, pm[i].src))
- break;
- switch (j == npm ? Moved : status[j]) {
- case Moving:
- c = j; /* start of cycle */
- emit(Oswap, *k, R, pm[i].src, pm[i].dst);
- break;
- case ToMove:
- status[i] = Moving;
- c = pmrec(status, j, k);
- if (c == i) {
- c = -1; /* end of cycle */
- break;
- }
- if (c != -1) {
- emit(Oswap, *k, R, pm[i].src, pm[i].dst);
- break;
- }
- /* fall through */
- case Moved:
- c = -1;
- emit(Ocopy, pm[i].cls, pm[i].dst, pm[i].src, R);
- break;
- default:
- die("unreachable");
- }
- status[i] = Moved;
- return c;
- }
- static void
- pmgen()
- {
- int i;
- enum PMStat *status;
- status = alloc(npm * sizeof status[0]);
- assert(!npm || status[npm-1] == ToMove);
- for (i=0; i<npm; i++)
- if (status[i] == ToMove)
- pmrec(status, i, (int[]){pm[i].cls});
- }
- static void
- move(int r, Ref to, RMap *m)
- {
- int n, t, r1;
- r1 = req(to, R) ? -1 : rfree(m, to.val);
- if (bshas(m->b, r)) {
- /* r is used and not by to */
- assert(r1 != r);
- for (n=0; m->r[n] != r; n++)
- assert(n+1 < m->n);
- t = m->t[n];
- rfree(m, t);
- bsset(m->b, r);
- ralloc(m, t);
- bsclr(m->b, r);
- }
- t = req(to, R) ? r : to.val;
- radd(m, t, r);
- }
- static int
- regcpy(Ins *i)
- {
- return i->op == Ocopy && isreg(i->arg[0]);
- }
- static Ins *
- dopm(Blk *b, Ins *i, RMap *m)
- {
- RMap m0;
- int n, r, r1, t, s;
- Ins *i1, *ip;
- bits def;
- m0 = *m; /* okay since we don't use m0.b */
- m0.b->t = 0;
- i1 = ++i;
- do {
- i--;
- move(i->arg[0].val, i->to, m);
- } while (i != b->ins && regcpy(i-1));
- assert(m0.n <= m->n);
- if (i != b->ins && (i-1)->op == Ocall) {
- def = T.retregs((i-1)->arg[1], 0) | T.rglob;
- for (r=0; T.rsave[r]>=0; r++)
- if (!(BIT(T.rsave[r]) & def))
- move(T.rsave[r], R, m);
- }
- for (npm=0, n=0; n<m->n; n++) {
- t = m->t[n];
- s = tmp[t].slot;
- r1 = m->r[n];
- r = rfind(&m0, t);
- if (r != -1)
- pmadd(TMP(r1), TMP(r), tmp[t].cls);
- else if (s != -1)
- pmadd(TMP(r1), SLOT(s), tmp[t].cls);
- }
- for (ip=i; ip<i1; ip++) {
- if (!req(ip->to, R))
- rfree(m, ip->to.val);
- r = ip->arg[0].val;
- if (rfind(m, r) == -1)
- radd(m, r, r);
- }
- pmgen();
- return i;
- }
- static int
- prio1(Ref r1, Ref r2)
- {
- /* trivial heuristic to begin with,
- * later we can use the distance to
- * the definition instruction
- */
- (void) r2;
- return *hint(r1.val) != -1;
- }
- static void
- insert(Ref *r, Ref **rs, int p)
- {
- int i;
- rs[i = p] = r;
- while (i-- > 0 && prio1(*r, *rs[i])) {
- rs[i+1] = rs[i];
- rs[i] = r;
- }
- }
- static void
- doblk(Blk *b, RMap *cur)
- {
- int t, x, r, rf, rt, nr;
- bits rs;
- Ins *i, *i1;
- Mem *m;
- Ref *ra[4];
- if (rtype(b->jmp.arg) == RTmp)
- b->jmp.arg = ralloc(cur, b->jmp.arg.val);
- curi = &insb[NIns];
- for (i1=&b->ins[b->nins]; i1!=b->ins;) {
- emiti(*--i1);
- i = curi;
- rf = -1;
- switch (i->op) {
- case Ocall:
- rs = T.argregs(i->arg[1], 0) | T.rglob;
- for (r=0; T.rsave[r]>=0; r++)
- if (!(BIT(T.rsave[r]) & rs))
- rfree(cur, T.rsave[r]);
- break;
- case Ocopy:
- if (regcpy(i)) {
- curi++;
- i1 = dopm(b, i1, cur);
- stmov += i+1 - curi;
- continue;
- }
- if (isreg(i->to))
- if (rtype(i->arg[0]) == RTmp)
- sethint(i->arg[0].val, i->to.val);
- /* fall through */
- default:
- if (!req(i->to, R)) {
- assert(rtype(i->to) == RTmp);
- r = i->to.val;
- if (r < Tmp0 && (BIT(r) & T.rglob))
- break;
- rf = rfree(cur, r);
- if (rf == -1) {
- assert(!isreg(i->to));
- curi++;
- continue;
- }
- i->to = TMP(rf);
- }
- break;
- }
- for (x=0, nr=0; x<2; x++)
- switch (rtype(i->arg[x])) {
- case RMem:
- m = &mem[i->arg[x].val];
- if (rtype(m->base) == RTmp)
- insert(&m->base, ra, nr++);
- if (rtype(m->index) == RTmp)
- insert(&m->index, ra, nr++);
- break;
- case RTmp:
- insert(&i->arg[x], ra, nr++);
- break;
- }
- for (r=0; r<nr; r++)
- *ra[r] = ralloc(cur, ra[r]->val);
- if (i->op == Ocopy && req(i->to, i->arg[0]))
- curi++;
- /* try to change the register of a hinted
- * temporary if rf is available */
- if (rf != -1 && (t = cur->w[rf]) != 0)
- if (!bshas(cur->b, rf) && *hint(t) == rf
- && (rt = rfree(cur, t)) != -1) {
- tmp[t].visit = -1;
- ralloc(cur, t);
- assert(bshas(cur->b, rf));
- emit(Ocopy, tmp[t].cls, TMP(rt), TMP(rf), R);
- stmov += 1;
- cur->w[rf] = 0;
- for (r=0; r<nr; r++)
- if (req(*ra[r], TMP(rt)))
- *ra[r] = TMP(rf);
- /* one could iterate this logic with
- * the newly freed rt, but in this case
- * the above loop must be changed */
- }
- }
- b->nins = &insb[NIns] - curi;
- idup(&b->ins, curi, b->nins);
- }
- /* qsort() comparison function to peel
- * loop nests from inside out */
- static int
- carve(const void *a, const void *b)
- {
- Blk *ba, *bb;
- /* todo, evaluate if this order is really
- * better than the simple postorder */
- ba = *(Blk**)a;
- bb = *(Blk**)b;
- if (ba->loop == bb->loop)
- return ba->id > bb->id ? -1 : ba->id < bb->id;
- return ba->loop > bb->loop ? -1 : +1;
- }
- /* comparison function to order temporaries
- * for allocation at the end of blocks */
- static int
- prio2(int t1, int t2)
- {
- if ((tmp[t1].visit ^ tmp[t2].visit) < 0) /* != signs */
- return tmp[t1].visit != -1 ? +1 : -1;
- if ((*hint(t1) ^ *hint(t2)) < 0)
- return *hint(t1) != -1 ? +1 : -1;
- return tmp[t1].cost - tmp[t2].cost;
- }
- /* register allocation
- * depends on rpo, phi, cost, (and obviously spill)
- */
- void
- rega(Fn *fn)
- {
- int j, t, r, x, rl[Tmp0];
- Blk *b, *b1, *s, ***ps, *blist, **blk, **bp;
- RMap *end, *beg, cur, old, *m;
- Ins *i;
- Phi *p;
- uint u, n;
- Ref src, dst;
- /* 1. setup */
- stmov = 0;
- stblk = 0;
- regu = 0;
- tmp = fn->tmp;
- mem = fn->mem;
- blk = alloc(fn->nblk * sizeof blk[0]);
- end = alloc(fn->nblk * sizeof end[0]);
- beg = alloc(fn->nblk * sizeof beg[0]);
- for (n=0; n<fn->nblk; n++) {
- bsinit(end[n].b, fn->ntmp);
- bsinit(beg[n].b, fn->ntmp);
- }
- bsinit(cur.b, fn->ntmp);
- bsinit(old.b, fn->ntmp);
- loop = INT_MAX;
- for (t=0; t<fn->ntmp; t++) {
- tmp[t].hint.r = t < Tmp0 ? t : -1;
- tmp[t].hint.w = loop;
- tmp[t].visit = -1;
- }
- for (bp=blk, b=fn->start; b; b=b->link)
- *bp++ = b;
- qsort(blk, fn->nblk, sizeof blk[0], carve);
- for (b=fn->start, i=b->ins; i<&b->ins[b->nins]; i++)
- if (i->op != Ocopy || !isreg(i->arg[0]))
- break;
- else {
- assert(rtype(i->to) == RTmp);
- sethint(i->to.val, i->arg[0].val);
- }
- /* 2. assign registers */
- for (bp=blk; bp<&blk[fn->nblk]; bp++) {
- b = *bp;
- n = b->id;
- loop = b->loop;
- cur.n = 0;
- bszero(cur.b);
- memset(cur.w, 0, sizeof cur.w);
- for (x=0, t=Tmp0; bsiter(b->out, &t); t++) {
- j = x++;
- rl[j] = t;
- while (j-- > 0 && prio2(t, rl[j]) > 0) {
- rl[j+1] = rl[j];
- rl[j] = t;
- }
- }
- for (r=0; bsiter(b->out, &r) && r<Tmp0; r++)
- radd(&cur, r, r);
- for (j=0; j<x; j++)
- ralloctry(&cur, rl[j], 1);
- for (j=0; j<x; j++)
- ralloc(&cur, rl[j]);
- rcopy(&end[n], &cur);
- doblk(b, &cur);
- bscopy(b->in, cur.b);
- for (p=b->phi; p; p=p->link)
- if (rtype(p->to) == RTmp)
- bsclr(b->in, p->to.val);
- rcopy(&beg[n], &cur);
- }
- /* 3. emit copies shared by multiple edges
- * to the same block */
- for (s=fn->start; s; s=s->link) {
- if (s->npred <= 1)
- continue;
- m = &beg[s->id];
- /* rl maps a register that is live at the
- * beginning of s to the one used in all
- * predecessors (if any, -1 otherwise) */
- memset(rl, 0, sizeof rl);
- /* to find the register of a phi in a
- * predecessor, we have to find the
- * corresponding argument */
- for (p=s->phi; p; p=p->link) {
- if (rtype(p->to) != RTmp
- || (r=rfind(m, p->to.val)) == -1)
- continue;
- for (u=0; u<p->narg; u++) {
- b = p->blk[u];
- src = p->arg[u];
- if (rtype(src) != RTmp)
- continue;
- x = rfind(&end[b->id], src.val);
- if (x == -1) /* spilled */
- continue;
- rl[r] = (!rl[r] || rl[r] == x) ? x : -1;
- }
- if (rl[r] == 0)
- rl[r] = -1;
- }
- /* process non-phis temporaries */
- for (j=0; j<m->n; j++) {
- t = m->t[j];
- r = m->r[j];
- if (rl[r] || t < Tmp0 /* todo, remove this */)
- continue;
- for (bp=s->pred; bp<&s->pred[s->npred]; bp++) {
- x = rfind(&end[(*bp)->id], t);
- if (x == -1) /* spilled */
- continue;
- rl[r] = (!rl[r] || rl[r] == x) ? x : -1;
- }
- if (rl[r] == 0)
- rl[r] = -1;
- }
- npm = 0;
- for (j=0; j<m->n; j++) {
- t = m->t[j];
- r = m->r[j];
- x = rl[r];
- assert(x != 0 || t < Tmp0 /* todo, ditto */);
- if (x > 0 && !bshas(m->b, x)) {
- pmadd(TMP(x), TMP(r), tmp[t].cls);
- m->r[j] = x;
- bsset(m->b, x);
- }
- }
- curi = &insb[NIns];
- pmgen();
- j = &insb[NIns] - curi;
- if (j == 0)
- continue;
- stmov += j;
- s->nins += j;
- i = alloc(s->nins * sizeof(Ins));
- icpy(icpy(i, curi, j), s->ins, s->nins-j);
- s->ins = i;
- }
- if (debug['R']) {
- fprintf(stderr, "\n> Register mappings:\n");
- for (n=0; n<fn->nblk; n++) {
- b = fn->rpo[n];
- fprintf(stderr, "\t%-10s beg", b->name);
- mdump(&beg[n]);
- fprintf(stderr, "\t end");
- mdump(&end[n]);
- }
- fprintf(stderr, "\n");
- }
- /* 4. emit remaining copies in new blocks */
- blist = 0;
- for (b=fn->start;; b=b->link) {
- ps = (Blk**[3]){&b->s1, &b->s2, (Blk*[1]){0}};
- for (; (s=**ps); ps++) {
- npm = 0;
- for (p=s->phi; p; p=p->link) {
- dst = p->to;
- assert(rtype(dst)==RSlot || rtype(dst)==RTmp);
- if (rtype(dst) == RTmp) {
- r = rfind(&beg[s->id], dst.val);
- if (r == -1)
- continue;
- dst = TMP(r);
- }
- for (u=0; p->blk[u]!=b; u++)
- assert(u+1 < p->narg);
- src = p->arg[u];
- if (rtype(src) == RTmp)
- src = rref(&end[b->id], src.val);
- pmadd(src, dst, p->cls);
- }
- for (t=Tmp0; bsiter(s->in, &t); t++) {
- src = rref(&end[b->id], t);
- dst = rref(&beg[s->id], t);
- pmadd(src, dst, tmp[t].cls);
- }
- curi = &insb[NIns];
- pmgen();
- if (curi == &insb[NIns])
- continue;
- b1 = newblk();
- b1->loop = (b->loop+s->loop) / 2;
- b1->link = blist;
- blist = b1;
- fn->nblk++;
- strf(b1->name, "%s_%s", b->name, s->name);
- b1->nins = &insb[NIns] - curi;
- stmov += b1->nins;
- stblk += 1;
- idup(&b1->ins, curi, b1->nins);
- b1->jmp.type = Jjmp;
- b1->s1 = s;
- **ps = b1;
- }
- if (!b->link) {
- b->link = blist;
- break;
- }
- }
- for (b=fn->start; b; b=b->link)
- b->phi = 0;
- fn->reg = regu;
- if (debug['R']) {
- fprintf(stderr, "\n> Register allocation statistics:\n");
- fprintf(stderr, "\tnew moves: %d\n", stmov);
- fprintf(stderr, "\tnew blocks: %d\n", stblk);
- fprintf(stderr, "\n> After register allocation:\n");
- printfn(fn, stderr);
- }
- }
|