cmd/compile: Repurpose old sliceopt.go for prove phase.

Adapt old test for prove's bounds check elimination.
Added missing rule to generic rules that lead to differences
between 32 and 64 bit platforms on sliceopt test.
Added debugging to prove.go that was helpful-to-necessary to
discover that missing rule.
Lowered debugging level on prove.go from 3 to 1; no idea
why it was previously 3.

Change-Id: I09de206aeb2fced9f2796efe2bfd4a59927eda0c
Reviewed-on: https://go-review.googlesource.com/23290
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
David Chase 2016-10-19 11:47:52 -04:00
parent c9517b1ffe
commit 0f29942489
6 changed files with 167 additions and 15 deletions

View file

@ -4,7 +4,10 @@
package ssa
import "math"
import (
"fmt"
"math"
)
type branch int
@ -74,6 +77,10 @@ type limit struct {
umin, umax uint64 // umin <= value <= umax, unsigned
}
func (l limit) String() string {
return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
}
var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
// a limitFact is a limit known for a particular value.
@ -191,7 +198,7 @@ func (ft *factsTable) get(v, w *Value, d domain) relation {
// update updates the set of relations between v and w in domain d
// restricting it to r.
func (ft *factsTable) update(v, w *Value, d domain, r relation) {
func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
if lessByID(w, v) {
v, w = w, v
r = reverseBits[r]
@ -293,6 +300,9 @@ func (ft *factsTable) update(v, w *Value, d domain, r relation) {
}
ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
ft.limits[v.ID] = lim
if v.Block.Func.pass.debug > 2 {
v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
}
}
}
@ -478,11 +488,11 @@ func prove(f *Func) {
if branch != unknown {
ft.checkpoint()
c := parent.Control
updateRestrictions(ft, boolean, nil, c, lt|gt, branch)
updateRestrictions(parent, ft, boolean, nil, c, lt|gt, branch)
if tr, has := domainRelationTable[parent.Control.Op]; has {
// When we branched from parent we learned a new set of
// restrictions. Update the factsTable accordingly.
updateRestrictions(ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
updateRestrictions(parent, ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
}
}
@ -538,7 +548,7 @@ func getBranch(sdom SparseTree, p *Block, b *Block) branch {
// updateRestrictions updates restrictions from the immediate
// dominating block (p) using r. r is adjusted according to the branch taken.
func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
if t == 0 || branch == unknown {
// Trivial case: nothing to do, or branch unknown.
// Shoult not happen, but just in case.
@ -550,7 +560,7 @@ func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branc
}
for i := domain(1); i <= t; i <<= 1 {
if t&i != 0 {
ft.update(v, w, i, r)
ft.update(parent, v, w, i, r)
}
}
}
@ -566,13 +576,21 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(nil, b.Control, boolean)
if m == lt|gt {
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control)
} else {
b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
}
}
return positive
}
if m == eq {
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
} else {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
}
}
return negative
}
@ -599,13 +617,21 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(a0, a1, d)
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
}
}
return positive
}
if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
}
}
return negative
}
@ -620,7 +646,11 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(a0, a1, signed)
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
}
}
return positive
}
@ -635,6 +665,9 @@ func isNonNegative(v *Value) bool {
case OpConst64:
return v.AuxInt >= 0
case OpConst32:
return int32(v.AuxInt) >= 0
case OpStringLen, OpSliceLen, OpSliceCap,
OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64:
return true