cmd/internal/gc: cache ProgInfo in Prog
The ProgInfo is loaded many times during each analysis pass.
Load it once at the beginning (in Flowstart if using that, or explicitly,
as in plive.go) and then refer to the cached copy.
Removes many calls to proginfo.
Makes Prog a little bigger, but the previous CL more than compensates.
Change-Id: If90a12fc6729878fdae10444f9c3bedc8d85026e
Reviewed-on: https://go-review.googlesource.com/7745
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index dbc8adc..b88f77e 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -737,12 +737,6 @@
/*
* interface to back end
*/
-type ProgInfo struct {
- Flags uint32 // the bits below
- Reguse uint64 // registers implicitly used by this instruction
- Regset uint64 // registers implicitly set by this instruction
- Regindex uint64 // registers used by addressing mode
-}
const (
// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
@@ -823,7 +817,7 @@
Igen func(*Node, *Node, *Node)
Linkarchinit func()
Peep func(*obj.Prog)
- Proginfo func(*obj.Prog) ProgInfo
+ Proginfo func(*obj.Prog) // fills in Prog.Info
Regalloc func(*Node, *Type, *Node)
Regfree func(*Node)
Regtyp func(*obj.Addr) bool
diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go
index e0f85f9..4cbeca0 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/internal/gc/plive.go
@@ -422,6 +422,7 @@
bb := newblock(firstp)
cfg = append(cfg, bb)
for p := firstp; p != nil; p = p.Link {
+ Thearch.Proginfo(p)
if p.To.Type == obj.TYPE_BRANCH {
if p.To.Val == nil {
Fatal("prog branch to nil")
@@ -561,7 +562,6 @@
bvresetall(varkill)
bvresetall(avarinit)
- info := Thearch.Proginfo(prog)
if prog.As == obj.ARET {
// Return instructions implicitly read all the arguments. For
// the sake of correctness, out arguments must be read. For the
@@ -612,7 +612,7 @@
return
}
- if info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
+ if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
from := &prog.From
if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Curfn == Curfn {
switch ((from.Node).(*Node)).Class &^ PHEAP {
@@ -629,10 +629,10 @@
if ((from.Node).(*Node)).Addrtaken {
bvset(avarinit, pos)
} else {
- if info.Flags&(LeftRead|LeftAddr) != 0 {
+ if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
bvset(uevar, pos)
}
- if info.Flags&LeftWrite != 0 {
+ if prog.Info.Flags&LeftWrite != 0 {
if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
bvset(varkill, pos)
}
@@ -643,7 +643,7 @@
}
Next:
- if info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
+ if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
to := &prog.To
if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Curfn == Curfn {
switch ((to.Node).(*Node)).Class &^ PHEAP {
@@ -673,10 +673,10 @@
// It is not a read. It is equivalent to RightWrite except that
// having the RightAddr bit set keeps the registerizer from
// trying to substitute a register for the memory location.
- if (info.Flags&RightRead != 0) || info.Flags&(RightAddr|RightWrite) == RightAddr {
+ if (prog.Info.Flags&RightRead != 0) || prog.Info.Flags&(RightAddr|RightWrite) == RightAddr {
bvset(uevar, pos)
}
- if info.Flags&RightWrite != 0 {
+ if prog.Info.Flags&RightWrite != 0 {
if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
bvset(varkill, pos)
}
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/internal/gc/popt.go
index 9070007..8dcd1df 100644
--- a/src/cmd/internal/gc/popt.go
+++ b/src/cmd/internal/gc/popt.go
@@ -355,15 +355,13 @@
var flowmark int
func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
- var info ProgInfo
-
// Count and mark instructions to annotate.
nf := 0
for p := firstp; p != nil; p = p.Link {
p.Opt = nil // should be already, but just in case
- info = Thearch.Proginfo(p)
- if info.Flags&Skip != 0 {
+ Thearch.Proginfo(p)
+ if p.Info.Flags&Skip != 0 {
continue
}
p.Opt = &flowmark
@@ -409,8 +407,7 @@
var p *obj.Prog
for f := start; f != nil; f = f.Link {
p = f.Prog
- info = Thearch.Proginfo(p)
- if info.Flags&Break == 0 {
+ if p.Info.Flags&Break == 0 {
f1 = f.Link
f.S1 = f1
f1.P1 = f
@@ -442,6 +439,7 @@
func Flowend(graph *Graph) {
for f := graph.Start; f != nil; f = f.Link {
+ f.Prog.Info.Flags = 0 // drop cached proginfo
f.Prog.Opt = nil
}
}
@@ -714,12 +712,8 @@
// We assume that the earliest reference to a temporary is its definition.
// This is not true of variables in general but our temporaries are all
// single-use (that's why we have so many!).
- var p *obj.Prog
- var info ProgInfo
for f := g.Start; f != nil; f = f.Link {
- p = f.Prog
- info = Thearch.Proginfo(p)
-
+ p := f.Prog
if p.From.Node != nil && ((p.From.Node).(*Node)).Opt != nil && p.To.Node != nil && ((p.To.Node).(*Node)).Opt != nil {
Fatal("double node %v", p)
}
@@ -740,7 +734,7 @@
}
f.Data = v.use
v.use = f
- if n == p.From.Node && (info.Flags&LeftAddr != 0) {
+ if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
v.addr = 1
}
}
@@ -753,9 +747,6 @@
nkill := 0
// Special case.
- var p1 *obj.Prog
- var info1 ProgInfo
- var f *Flow
for i := 0; i < len(var_); i++ {
v = &var_[i]
if v.addr != 0 {
@@ -763,11 +754,10 @@
}
// Used in only one instruction, which had better be a write.
- f = v.use
+ f := v.use
if f != nil && f.Data.(*Flow) == nil {
- p = f.Prog
- info = Thearch.Proginfo(p)
- if p.To.Node == v.node && (info.Flags&RightWrite != 0) && info.Flags&RightRead == 0 {
+ p := f.Prog
+ if p.To.Node == v.node && (p.Info.Flags&RightWrite != 0) && p.Info.Flags&RightRead == 0 {
p.As = obj.ANOP
p.To = obj.Addr{}
v.removed = 1
@@ -785,14 +775,12 @@
// no jumps to the next instruction. Happens mainly in 386 compiler.
f = v.use
if f != nil && f.Link == f.Data.(*Flow) && (f.Data.(*Flow)).Data.(*Flow) == nil && Uniqp(f.Link) == f {
- p = f.Prog
- info = Thearch.Proginfo(p)
- p1 = f.Link.Prog
- info1 = Thearch.Proginfo(p1)
+ p := f.Prog
+ p1 := f.Link.Prog
const (
SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
)
- if p.From.Node == v.node && p1.To.Node == v.node && (info.Flags&Move != 0) && (info.Flags|info1.Flags)&(LeftAddr|RightAddr) == 0 && info.Flags&SizeAny == info1.Flags&SizeAny {
+ if p.From.Node == v.node && p1.To.Node == v.node && (p.Info.Flags&Move != 0) && (p.Info.Flags|p1.Info.Flags)&(LeftAddr|RightAddr) == 0 && p.Info.Flags&SizeAny == p1.Info.Flags&SizeAny {
p1.From = p.From
Thearch.Excise(f)
v.removed = 1
@@ -814,12 +802,12 @@
for i := 0; i < len(var_); i++ {
v = &var_[i]
gen++
- for f = v.use; f != nil; f = f.Data.(*Flow) {
+ for f := v.use; f != nil; f = f.Data.(*Flow) {
mergewalk(v, f, uint32(gen))
}
if v.addr != 0 {
gen++
- for f = v.use; f != nil; f = f.Data.(*Flow) {
+ for f := v.use; f != nil; f = f.Data.(*Flow) {
varkillwalk(v, f, uint32(gen))
}
}
@@ -935,7 +923,7 @@
// Update node references to use merged temporaries.
for f := g.Start; f != nil; f = f.Link {
- p = f.Prog
+ p := f.Prog
n, _ = p.From.Node.(*Node)
if n != nil {
v, _ = n.Opt.(*TempVar)
@@ -1109,13 +1097,9 @@
}
func nilwalkback(fcheck *Flow) {
- var p *obj.Prog
- var info ProgInfo
-
for f := fcheck; f != nil; f = Uniqp(f) {
- p = f.Prog
- info = Thearch.Proginfo(p)
- if (info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
+ p := f.Prog
+ if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
// Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked.
return
@@ -1146,8 +1130,7 @@
if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
break;
- thearch.proginfo(&info, p);
- if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
+ if((p.Info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
// Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked.
fcheck->kill = 0;
@@ -1168,10 +1151,8 @@
for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
nilwalkback(fcheck, f2, gen);
*/
-func nilwalkfwd(fcheck *Flow) {
- var p *obj.Prog
- var info ProgInfo
+func nilwalkfwd(fcheck *Flow) {
// If the path down from rcheck dereferences the address
// (possibly with a small offset) before writing to memory
// and before any subsequent checks, it's okay to wait for
@@ -1179,18 +1160,16 @@
// avoid problems like:
// _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible
+
var last *Flow
-
for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
- p = f.Prog
- info = Thearch.Proginfo(p)
-
- if (info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
+ p := f.Prog
+ if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
fcheck.Data = &killed
return
}
- if (info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
+ if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
fcheck.Data = &killed
return
}
@@ -1201,12 +1180,12 @@
}
// Stop if value is lost.
- if (info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
+ if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
return
}
// Stop if memory write.
- if (info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
+ if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
return
}
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/internal/gc/reg.go
index d613bd1..d1aa343 100644
--- a/src/cmd/internal/gc/reg.go
+++ b/src/cmd/internal/gc/reg.go
@@ -972,17 +972,11 @@
firstf = g.Start
- var r *Reg
- var info ProgInfo
- var p *obj.Prog
- var bit Bits
- var z int
for f := firstf; f != nil; f = f.Link {
- p = f.Prog
+ p := f.Prog
if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
continue
}
- info = Thearch.Proginfo(p)
// Avoid making variables for direct-called functions.
if p.As == obj.ACALL && p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_EXTERN {
@@ -990,30 +984,29 @@
}
// from vs to doesn't matter for registers.
- r = f.Data.(*Reg)
+ r := f.Data.(*Reg)
+ r.use1.b[0] |= p.Info.Reguse | p.Info.Regindex
+ r.set.b[0] |= p.Info.Regset
- r.use1.b[0] |= info.Reguse | info.Regindex
- r.set.b[0] |= info.Regset
-
- bit = mkvar(f, &p.From)
+ bit := mkvar(f, &p.From)
if bany(&bit) {
- if info.Flags&LeftAddr != 0 {
+ if p.Info.Flags&LeftAddr != 0 {
setaddrs(bit)
}
- if info.Flags&LeftRead != 0 {
- for z = 0; z < BITS; z++ {
+ if p.Info.Flags&LeftRead != 0 {
+ for z := 0; z < BITS; z++ {
r.use1.b[z] |= bit.b[z]
}
}
- if info.Flags&LeftWrite != 0 {
- for z = 0; z < BITS; z++ {
+ if p.Info.Flags&LeftWrite != 0 {
+ for z := 0; z < BITS; z++ {
r.set.b[z] |= bit.b[z]
}
}
}
// Compute used register for reg
- if info.Flags&RegRead != 0 {
+ if p.Info.Flags&RegRead != 0 {
r.use1.b[0] |= Thearch.RtoB(int(p.Reg))
}
@@ -1025,16 +1018,16 @@
bit = mkvar(f, &p.To)
if bany(&bit) {
- if info.Flags&RightAddr != 0 {
+ if p.Info.Flags&RightAddr != 0 {
setaddrs(bit)
}
- if info.Flags&RightRead != 0 {
- for z = 0; z < BITS; z++ {
+ if p.Info.Flags&RightRead != 0 {
+ for z := 0; z < BITS; z++ {
r.use2.b[z] |= bit.b[z]
}
}
- if info.Flags&RightWrite != 0 {
- for z = 0; z < BITS; z++ {
+ if p.Info.Flags&RightWrite != 0 {
+ for z := 0; z < BITS; z++ {
r.set.b[z] |= bit.b[z]
}
}
@@ -1044,8 +1037,8 @@
for i := 0; i < nvar; i++ {
v := &var_[i]
if v.addr != 0 {
- bit = blsh(uint(i))
- for z = 0; z < BITS; z++ {
+ bit := blsh(uint(i))
+ for z := 0; z < BITS; z++ {
addrs.b[z] |= bit.b[z]
}
}
@@ -1080,12 +1073,12 @@
for f := firstf; f != nil; f = f.Link {
f.Active = 0
- r = f.Data.(*Reg)
+ r := f.Data.(*Reg)
r.act = zbits
}
for f := firstf; f != nil; f = f.Link {
- p = f.Prog
+ p := f.Prog
if p.As == obj.AVARDEF && Isfat(((p.To.Node).(*Node)).Type) && ((p.To.Node).(*Node)).Opt != nil {
active++
walkvardef(p.To.Node.(*Node), f, active)
@@ -1161,7 +1154,7 @@
*/
mask := uint64((1 << uint(nreg)) - 1)
for f := firstf; f != nil; f = f.Link {
- r = f.Data.(*Reg)
+ r := f.Data.(*Reg)
r.regu = (r.refbehind.b[0] | r.set.b[0]) & mask
r.set.b[0] &^= mask
r.use1.b[0] &^= mask
@@ -1185,6 +1178,7 @@
*/
f = firstf
+ var bit Bits
if f != nil {
r := f.Data.(*Reg)
for z := 0; z < BITS; z++ {
@@ -1205,8 +1199,8 @@
nregion = 0
var rgp *Rgn
for f := firstf; f != nil; f = f.Link {
- r = f.Data.(*Reg)
- for z = 0; z < BITS; z++ {
+ r := f.Data.(*Reg)
+ for z := 0; z < BITS; z++ {
bit.b[z] = r.set.b[z] &^ (r.refahead.b[z] | r.calahead.b[z] | addrs.b[z])
}
if bany(&bit) && f.Refset == 0 {
@@ -1217,7 +1211,7 @@
Thearch.Excise(f)
}
- for z = 0; z < BITS; z++ {
+ for z := 0; z < BITS; z++ {
bit.b[z] = LOAD(r, z) &^ (r.act.b[z] | addrs.b[z])
}
for bany(&bit) {
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 3b286af..92fd7c4 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -225,6 +225,18 @@
Printed uint8
Width int8
Mode int8
+
+ Info ProgInfo
+}
+
+// ProgInfo holds information about the instruction for use
+// by clients such as the compiler. The exact meaning of this
+// data is up to the client and is not interpreted by the cmd/internal/obj/... packages.
+type ProgInfo struct {
+ Flags uint32 // flag bits
+ Reguse uint64 // registers implicitly used by this instruction
+ Regset uint64 // registers implicitly set by this instruction
+ Regindex uint64 // registers used by addressing mode
}
// Prog.as opcodes.