arrayadd(to->pred, &from);
}
-// Inserts a new instruction ahead of an existing instruction in the instruction
+// Inserts prev before curr in the instruction
// stream. Any control flow, such as branches or fall throughs, that target the
// existing instruction are adjusted to target the new instruction.
static void
splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr)
{
- Prog *p;
+ Prog *next, tmp;
- prev->opt = curr->opt;
- curr->opt = prev;
- prev->link = curr;
- if(prev->opt != nil)
- ((Prog*)prev->opt)->link = prev;
- else
- bb->first = prev;
- for(p = lv->ptxt; p != nil; p = p->link) {
- if(p != prev) {
- if(p->link == curr)
- p->link = prev;
- if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch == curr)
- p->to.u.branch = prev;
- }
- }
+ USED(lv);
+
+ // There may be other instructions pointing at curr,
+ // and we want them to now point at prev. Instead of
+ // trying to find all such instructions, swap the contents
+ // so that the problem becomes inserting next after curr.
+ // The "opt" field is the backward link in the linked list.
+
+ // Overwrite curr's data with prev, but keep the list links.
+ tmp = *curr;
+ *curr = *prev;
+ curr->opt = tmp.opt;
+ curr->link = tmp.link;
+
+ // Overwrite prev (now next) with curr's old data.
+ next = prev;
+ *next = tmp;
+ next->opt = nil;
+ next->link = nil;
+
+ // Now insert next after curr.
+ next->link = curr->link;
+ next->opt = curr;
+ curr->link = next;
+ if(next->link && next->link->opt == curr)
+ next->link->opt = next;
+
+ if(bb->last == curr)
+ bb->last = next;
}
// A pretty printer for basic blocks.
}
}
+// NOTE: The bitmap for a specific type t should be cached in t after the first run
+// and then simply copied into bv at the correct offset on future calls with
+// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
+// accounts for 40% of the 6g execution time.
static void
twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
{
vlong o;
Type *t1;
- if(t->align > 0 && (*xoffset % t->align) != 0)
+ if(t->align > 0 && (*xoffset & (t->align - 1)) != 0)
fatal("twobitwalktype1: invalid initial alignment, %T", t);
switch(t->etype) {
case TFUNC:
case TCHAN:
case TMAP:
- if(*xoffset % widthptr != 0)
+ if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
*xoffset += t->width;
case TSTRING:
// struct { byte *str; intgo len; }
- if(*xoffset % widthptr != 0)
+ if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
*xoffset += t->width;
// struct { Itab *tab; union { void *ptr, uintptr val } data; }
// or, when isnilinter(t)==true:
// struct { Type *type; union { void *ptr, uintptr val } data; }
- if(*xoffset % widthptr != 0)
+ if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1);
if(isnilinter(t))
fatal("twobitwalktype1: invalid bound, %T", t);
if(isslice(t)) {
// struct { byte *array; uintgo len; uintgo cap; }
- if(*xoffset % widthptr != 0)
+ if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
*xoffset += t->width;
Bvec *varkill;
Bvec *args;
Bvec *locals;
- Prog *p;
+ Prog *p, *next;
int32 i;
int32 nvars;
int32 pos;
fatal("livenessepilogue");
}
- for(p = bb->last; p != nil; p = p->opt) {
+ for(p = bb->last; p != nil; p = next) {
+ next = p->opt; // splicebefore modifies p->opt
// Propagate liveness information
progeffects(p, lv->vars, uevar, varkill);
bvcopy(liveout, livein);