summaryrefslogtreecommitdiff
path: root/src/cmd/5g/reg.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
committerOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
commit505c19580e0f43fe5224431459cacb7c21edd93d (patch)
tree79e2634c253d60afc0cc0b2f510dc7dcbb48497b /src/cmd/5g/reg.c
parent1336a7c91e596c423a49d1194ea42d98bca0d958 (diff)
downloadgolang-505c19580e0f43fe5224431459cacb7c21edd93d.tar.gz
Imported Upstream version 1upstream/1
Diffstat (limited to 'src/cmd/5g/reg.c')
-rw-r--r--src/cmd/5g/reg.c177
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");
+ }
+}