diff options
Diffstat (limited to 'src/cmd/6g/reg.c')
-rw-r--r-- | src/cmd/6g/reg.c | 190 |
1 files changed, 160 insertions, 30 deletions
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 4d4263047..bed9f8da6 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -28,9 +28,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> +#include <libc.h> #include "gg.h" -#undef EXTERN -#define EXTERN #include "opt.h" #define NREGVAR 32 /* 16 general + 16 floating */ @@ -89,8 +89,8 @@ setoutvar(void) ovar.b[z] |= bit.b[z]; t = structnext(&save); } -//if(bany(b)) -//print("ovars = %Q\n", &ovar); +//if(bany(&ovar)) +//print("ovars = %Q\n", ovar); } static void @@ -98,19 +98,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; } } @@ -151,6 +151,8 @@ static char* regname[] = { ".X15", }; +static void fixjmp(Prog*); + void regopt(Prog *firstp) { @@ -166,6 +168,8 @@ regopt(Prog *firstp) first = 0; } + fixjmp(firstp); + // count instructions nr = 0; for(p=firstp; p!=P; p=p->link) @@ -179,7 +183,6 @@ regopt(Prog *firstp) r1 = R; firstr = R; lastr = R; - nvar = 0; /* * control flow is more complicated in generated go code @@ -189,7 +192,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(D_SP); for(z=0; z<BITS; z++) { @@ -801,9 +804,9 @@ brk: if(ostats.ndelmov) print(" %4d delmov\n", ostats.ndelmov); if(ostats.nvar) - print(" %4d delmov\n", ostats.nvar); + print(" %4d var\n", ostats.nvar); if(ostats.naddr) - print(" %4d delmov\n", ostats.naddr); + print(" %4d addr\n", ostats.naddr); memset(&ostats, 0, sizeof(ostats)); } @@ -832,12 +835,12 @@ addmove(Reg *r, int bn, int rn, int f) v = var + bn; a = &p1->to; - a->sym = v->sym; a->offset = v->offset; a->etype = v->etype; a->type = v->name; a->gotype = v->gotype; a->node = v->node; + a->sym = v->node->sym; // need to clean this up with wptr and // some of the defaults @@ -933,7 +936,7 @@ mkvar(Reg *r, Adr *a) uint32 regu; int32 o; Bits bit; - Sym *s; + Node *node; /* * mark registers used @@ -969,10 +972,14 @@ mkvar(Reg *r, Adr *a) n = t; 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; @@ -981,7 +988,7 @@ mkvar(Reg *r, Adr *a) flag = 0; 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) @@ -995,11 +1002,6 @@ mkvar(Reg *r, Adr *a) } } } - if(a->pun) { -// print("disable pun %s\n", s->name); - flag = 1; - - } switch(et) { case 0: case TFUNC: @@ -1007,25 +1009,24 @@ mkvar(Reg *r, Adr *a) } if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - fatal("variable not optimized: %D", a); + if(debug['w'] > 1 && node != N) + fatal("variable not optimized: %#N", node); goto none; } i = nvar; nvar++; 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 %S %D\n", i, et, w, s, a); + print("bit=%2d et=%2d w=%d %#N %D\n", i, et, w, node, a); ostats.nvar++; bit = blsh(i); @@ -1084,6 +1085,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]) | @@ -1220,10 +1228,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; } @@ -1628,7 +1638,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)) @@ -1688,3 +1698,123 @@ noreturn(Prog *p) return 1; return 0; } + +/* + * the code generator depends on being able to write out JMP + * 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 == AJMP && 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->reg != dead) + break; + p->reg = alive; + if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch) + mark(p->to.branch); + if(p->as == AJMP || p->as == ARET || (p->as == ACALL && 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 AJMP, 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 != ACALL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AJMP) { + p->to.branch = chasejmp(p->to.branch, &jmploop); + if(debug['R'] && debug['v']) + print("->%P\n", p); + } + p->reg = 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->reg == 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 == AJMP && 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"); + } +} |