aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/ssa/loopbce.go65
1 files changed, 37 insertions, 28 deletions
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
index 2ab05711ad..8ab1a0c695 100644
--- a/src/cmd/compile/internal/ssa/loopbce.go
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -15,15 +15,15 @@ const (
type indVar struct {
ind *Value // induction variable
- inc *Value // increment, a constant
- nxt *Value // ind+inc variable
min *Value // minimum value, inclusive/exclusive depends on flags
max *Value // maximum value, inclusive/exclusive depends on flags
entry *Block // entry block in the loop.
flags indVarFlags
- // Invariants: for all blocks dominated by entry:
- // min <= ind < max
- // min <= nxt <= max
+ // Invariant: for all blocks strictly dominated by entry:
+ // min <= ind < max [if flags == 0]
+ // min < ind < max [if flags == indVarMinExc]
+ // min <= ind <= max [if flags == indVarMaxInc]
+ // min < ind <= max [if flags == indVarMinExc|indVarMaxInc]
}
// findIndVar finds induction variables in a function.
@@ -49,7 +49,6 @@ func findIndVar(f *Func) []indVar {
var iv []indVar
sdom := f.sdom()
-nextb:
for _, b := range f.Blocks {
if b.Kind != BlockIf || len(b.Preds) != 2 {
continue
@@ -57,7 +56,6 @@ nextb:
var flags indVarFlags
var ind, max *Value // induction, and maximum
- entry := -1 // which successor of b enters the loop
// Check thet the control if it either ind </<= max or max >/>= ind.
// TODO: Handle 32-bit comparisons.
@@ -66,21 +64,21 @@ nextb:
flags |= indVarMaxInc
fallthrough
case OpLess64:
- entry = 0
ind, max = b.Control.Args[0], b.Control.Args[1]
case OpGeq64:
flags |= indVarMaxInc
fallthrough
case OpGreater64:
- entry = 0
ind, max = b.Control.Args[1], b.Control.Args[0]
default:
- continue nextb
+ continue
}
// See if the arguments are reversed (i < len() <=> len() > i)
+ less := true
if max.Op == OpPhi {
ind, max = max, ind
+ less = false
}
// Check that the induction variable is a phi that depends on itself.
@@ -108,22 +106,35 @@ nextb:
panic("unreachable") // one of the cases must be true from the above.
}
- // Expect the increment to be a constant.
+ // Expect the increment to be a nonzero constant.
if inc.Op != OpConst64 {
continue
}
+ step := inc.AuxInt
+ if step == 0 {
+ continue
+ }
+
+ // Increment sign must match comparison direction.
+ // When incrementing, the termination comparison must be ind </<= max.
+ // When decrementing, the termination comparison must be ind >/>= max.
+ // See issue 26116.
+ if step > 0 && !less {
+ continue
+ }
+ if step < 0 && less {
+ continue
+ }
// If the increment is negative, swap min/max and their flags
- if inc.AuxInt <= 0 {
+ if step < 0 {
min, max = max, min
oldf := flags
- flags = 0
+ flags = indVarMaxInc
if oldf&indVarMaxInc == 0 {
flags |= indVarMinExc
}
- if oldf&indVarMinExc == 0 {
- flags |= indVarMaxInc
- }
+ step = -step
}
// Up to now we extracted the induction variable (ind),
@@ -140,26 +151,26 @@ nextb:
// as an induction variable.
// First condition: loop entry has a single predecessor, which
- // is the header block. This implies that b.Succs[entry] is
+ // is the header block. This implies that b.Succs[0] is
// reached iff ind < max.
- if len(b.Succs[entry].b.Preds) != 1 {
- // b.Succs[1-entry] must exit the loop.
+ if len(b.Succs[0].b.Preds) != 1 {
+ // b.Succs[1] must exit the loop.
continue
}
- // Second condition: b.Succs[entry] dominates nxt so that
+ // Second condition: b.Succs[0] dominates nxt so that
// nxt is computed when inc < max, meaning nxt <= max.
- if !sdom.isAncestorEq(b.Succs[entry].b, nxt.Block) {
+ if !sdom.isAncestorEq(b.Succs[0].b, nxt.Block) {
// inc+ind can only be reached through the branch that enters the loop.
continue
}
// We can only guarantee that the loops runs within limits of induction variable
// if the increment is ±1 or when the limits are constants.
- if inc.AuxInt != 1 && inc.AuxInt != -1 {
+ if step != 1 {
ok := false
- if min.Op == OpConst64 && max.Op == OpConst64 && inc.AuxInt != 0 {
- if max.AuxInt > min.AuxInt && max.AuxInt%inc.AuxInt == min.AuxInt%inc.AuxInt { // handle overflow
+ if min.Op == OpConst64 && max.Op == OpConst64 {
+ if max.AuxInt > min.AuxInt && max.AuxInt%step == min.AuxInt%step { // handle overflow
ok = true
}
}
@@ -169,16 +180,14 @@ nextb:
}
if f.pass.debug >= 1 {
- printIndVar(b, ind, min, max, inc.AuxInt, flags)
+ printIndVar(b, ind, min, max, step, flags)
}
iv = append(iv, indVar{
ind: ind,
- inc: inc,
- nxt: nxt,
min: min,
max: max,
- entry: b.Succs[entry].b,
+ entry: b.Succs[0].b,
flags: flags,
})
b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)