diff --git a/src/cmd/compile/internal/ssa/fuse_branchredirect.go b/src/cmd/compile/internal/ssa/fuse_branchredirect.go
index 153c2a56b7..a431c0ece9 100644
--- a/src/cmd/compile/internal/ssa/fuse_branchredirect.go
+++ b/src/cmd/compile/internal/ssa/fuse_branchredirect.go
@@ -28,7 +28,7 @@ package ssa
// contradiction is found then redirect p to another successor of b.
func fuseBranchRedirect(f *Func) bool {
ft := newFactsTable(f)
- ft.checkpoint()
+ ft.checkpoint(nil)
changed := false
for i := len(f.Blocks) - 1; i >= 0; i-- {
@@ -54,13 +54,13 @@ func fuseBranchRedirect(f *Func) bool {
if pk.i == 1 {
pbranch = negative
}
- ft.checkpoint()
+ ft.checkpoint(nil)
// Assume branch p->b is taken.
addBranchRestrictions(ft, p, pbranch)
// Check if any outgoing branch is unreachable based on the above condition.
parent := b
for j, bbranch := range [...]branch{positive, negative} {
- ft.checkpoint()
+ ft.checkpoint(nil)
// Try to update relationship b->child, and check if the contradiction occurs.
addBranchRestrictions(ft, parent, bbranch)
unsat := ft.unsat
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 6f21432711..8e154923bb 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -507,6 +507,8 @@ type ordering struct {
// by the facts table is effective for real code while remaining very
// efficient.
type factsTable struct {
+ currentlyDescending *Block
+
// unsat is true if facts contains a contradiction.
//
// Note that the factsTable logic is incomplete, so if unsat
@@ -677,8 +679,10 @@ func (ft *factsTable) newLimit(v *Value, newLim limit) {
ft.recurseCheck[v.ID] = false
}()
- // Record undo information.
- ft.limitStack = append(ft.limitStack, limitFact{v.ID, oldLim})
+ if v.Block != ft.currentlyDescending {
+ // Record undo information.
+ ft.limitStack = append(ft.limitStack, limitFact{v.ID, oldLim})
+ }
// Record new information.
ft.limits[v.ID] = lim
if v.Block.Func.pass.debug > 2 {
@@ -1264,7 +1268,11 @@ func (ft *factsTable) isNonNegative(v *Value) bool {
// checkpoint saves the current state of known relations.
// Called when descending on a branch.
-func (ft *factsTable) checkpoint() {
+// descending is used to ignore checkpointing facts learned
+// in the current block as they will be always be true in
+// dominated users. Can be nil.
+func (ft *factsTable) checkpoint(descending *Block) {
+ ft.currentlyDescending = descending
if ft.unsat {
ft.unsatDepth++
}
@@ -1598,7 +1606,7 @@ func prove(f *Func) {
}
ft := newFactsTable(f)
- ft.checkpoint()
+ ft.checkpoint(nil)
// Find length and capacity ops.
for _, b := range f.Blocks {
@@ -1673,7 +1681,7 @@ func prove(f *Func) {
switch node.state {
case descend:
- ft.checkpoint()
+ ft.checkpoint(node.block)
// Entering the block, add facts about the induction variable
// that is bound to this block.
@@ -3031,7 +3039,7 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
}
// For edges to other blocks, this can trim a branch
// even if we couldn't get rid of the child itself.
- ft.checkpoint()
+ ft.checkpoint(nil)
addBranchRestrictions(ft, parent, branch)
unsat := ft.unsat
ft.restore()