diff options
Diffstat (limited to 'src/cmd/5g/reg.c')
-rw-r--r-- | src/cmd/5g/reg.c | 177 |
1 files changed, 157 insertions, 20 deletions
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 2d2a6d01a..93724d032 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -29,6 +29,8 @@ // THE SOFTWARE. +#include <u.h> +#include <libc.h> #include "gg.h" #include "opt.h" @@ -40,6 +42,9 @@ int noreturn(Prog *p); static int first = 0; +static void fixjmp(Prog*); + + Reg* rega(void) { @@ -90,8 +95,8 @@ setoutvar(void) ovar.b[z] |= bit.b[z]; t = structnext(&save); } -//if(bany(b)) -//print("ovars = %Q\n", &ovar); +//if(bany(ovar)) +//print("ovar = %Q\n", ovar); } void @@ -112,19 +117,19 @@ setaddrs(Bits bit) { int i, n; Var *v; - Sym *s; + Node *node; while(bany(&bit)) { // convert each bit to a variable i = bnum(bit); - s = var[i].sym; + node = var[i].node; n = var[i].name; bit.b[i/32] &= ~(1L<<(i%32)); // disable all pieces of that variable for(i=0; i<nvar; i++) { v = var+i; - if(v->sym == s && v->name == n) + if(v->node == node && v->name == n) v->addr = 2; } } @@ -169,6 +174,8 @@ regopt(Prog *firstp) if(first == 0) { fmtinstall('Q', Qconv); } + + fixjmp(firstp); first++; if(debug['K']) { @@ -202,7 +209,7 @@ regopt(Prog *firstp) nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) - var[i].sym = lookup(regname[i]); + var[i].node = newname(lookup(regname[i])); regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { @@ -750,9 +757,9 @@ addmove(Reg *r, int bn, int rn, int f) v = var + bn; a = &p1->to; - a->sym = v->sym; a->name = v->name; a->node = v->node; + a->sym = v->node->sym; a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; @@ -838,11 +845,10 @@ mkvar(Reg *r, Adr *a) int i, t, n, et, z, w, flag; int32 o; Bits bit; - Sym *s; + Node *node; // mark registers used t = a->type; - n = D_NONE; flag = 0; switch(t) { @@ -909,10 +915,13 @@ mkvar(Reg *r, Adr *a) break; } - s = a->sym; - if(s == S) + node = a->node; + if(node == N || node->op != ONAME || node->orig == N) goto none; - if(s->name[0] == '.') + node = node->orig; + if(node->orig != node) + fatal("%D: bad node", a); + if(node->sym == S || node->sym->name[0] == '.') goto none; et = a->etype; o = a->offset; @@ -920,7 +929,7 @@ mkvar(Reg *r, Adr *a) for(i=0; i<nvar; i++) { v = var+i; - if(v->sym == s && v->name == n) { + if(v->node == node && v->name == n) { if(v->offset == o) if(v->etype == et) if(v->width == w) @@ -944,7 +953,7 @@ mkvar(Reg *r, Adr *a) } if(nvar >= NVAR) { - if(debug['w'] > 1 && s) + if(debug['w'] > 1 && node) fatal("variable not optimized: %D", a); goto none; } @@ -953,17 +962,16 @@ mkvar(Reg *r, Adr *a) nvar++; //print("var %d %E %D %S\n", i, et, a, s); v = var+i; - v->sym = s; v->offset = o; v->name = n; // v->gotype = a->gotype; v->etype = et; v->width = w; v->addr = flag; // funny punning - v->node = a->node; + v->node = node; if(debug['R']) - print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr); + print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -1021,6 +1029,13 @@ prop(Reg *r, Bits ref, Bits cal) ref.b[z] = 0; } break; + + default: + // Work around for issue 1304: + // flush modified globals before each instruction. + for(z=0; z<BITS; z++) + cal.b[z] |= externs.b[z]; + break; } for(z=0; z<BITS; z++) { ref.b[z] = (ref.b[z] & ~r1->set.b[z]) | @@ -1156,10 +1171,12 @@ loopit(Reg *r, int32 nr) r1 = rpo2r[i]; me = r1->rpo; d = -1; - if(r1->p1 != R && r1->p1->rpo < me) + // rpo2r[r->rpo] == r protects against considering dead code, + // which has r->rpo == 0. + if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me) d = r1->p1->rpo; for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) - if(r1->rpo < me) + if(rpo2r[r1->rpo] == r1 && r1->rpo < me) d = rpolca(idom, d, r1->rpo); idom[i] = d; } @@ -1570,7 +1587,7 @@ dumpone(Reg *r) if(bany(&r->refahead)) print(" ra:%Q ", r->refahead); if(bany(&r->calbehind)) - print("cb:%Q ", r->calbehind); + print(" cb:%Q ", r->calbehind); if(bany(&r->calahead)) print(" ca:%Q ", r->calahead); if(bany(&r->regdiff)) @@ -1605,3 +1622,123 @@ dumpit(char *str, Reg *r0) // } } } + +/* + * the code generator depends on being able to write out JMP (B) + * instructions that it can jump to now but fill in later. + * the linker will resolve them nicely, but they make the code + * longer and more difficult to follow during debugging. + * remove them. + */ + +/* what instruction does a JMP to p eventually land on? */ +static Prog* +chasejmp(Prog *p, int *jmploop) +{ + int n; + + n = 0; + while(p != P && p->as == AB && p->to.type == D_BRANCH) { + if(++n > 10) { + *jmploop = 1; + break; + } + p = p->to.branch; + } + return p; +} + +/* + * reuse reg pointer for mark/sweep state. + * leave reg==nil at end because alive==nil. + */ +#define alive ((void*)0) +#define dead ((void*)1) + +/* mark all code reachable from firstp as alive */ +static void +mark(Prog *firstp) +{ + Prog *p; + + for(p=firstp; p; p=p->link) { + if(p->regp != dead) + break; + p->regp = alive; + if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch) + mark(p->to.branch); + if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p))) + break; + } +} + +static void +fixjmp(Prog *firstp) +{ + int jmploop; + Prog *p, *last; + + if(debug['R'] && debug['v']) + print("\nfixjmp\n"); + + // pass 1: resolve jump to B, mark all code as dead. + jmploop = 0; + for(p=firstp; p; p=p->link) { + if(debug['R'] && debug['v']) + print("%P\n", p); + if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AB) { + p->to.branch = chasejmp(p->to.branch, &jmploop); + if(debug['R'] && debug['v']) + print("->%P\n", p); + } + p->regp = dead; + } + if(debug['R'] && debug['v']) + print("\n"); + + // pass 2: mark all reachable code alive + mark(firstp); + + // pass 3: delete dead code (mostly JMPs). + last = nil; + for(p=firstp; p; p=p->link) { + if(p->regp == dead) { + if(p->link == P && p->as == ARET && last && last->as != ARET) { + // This is the final ARET, and the code so far doesn't have one. + // Let it stay. + } else { + if(debug['R'] && debug['v']) + print("del %P\n", p); + continue; + } + } + if(last) + last->link = p; + last = p; + } + last->link = P; + + // pass 4: elide JMP to next instruction. + // only safe if there are no jumps to JMPs anymore. + if(!jmploop) { + last = nil; + for(p=firstp; p; p=p->link) { + if(p->as == AB && p->to.type == D_BRANCH && p->to.branch == p->link) { + if(debug['R'] && debug['v']) + print("del %P\n", p); + continue; + } + if(last) + last->link = p; + last = p; + } + last->link = P; + } + + if(debug['R'] && debug['v']) { + print("\n"); + for(p=firstp; p; p=p->link) + print("%P\n", p); + print("\n"); + } +} |