mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: check domination of loop return in both controls
Fixes #74473 Change-Id: I72ff6b95955ae9407271508aa80f230dcf1b6c74 Reviewed-on: https://go-review.googlesource.com/c/go/+/685816 Reviewed-by: Mark Freeman <mark@golang.org> Auto-Submit: Jorropo <jorropo.pgm@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
cefaed0de0
commit
8cd85e602a
2 changed files with 36 additions and 10 deletions
|
|
@ -37,19 +37,20 @@ type indVar struct {
|
||||||
// - the minimum bound
|
// - the minimum bound
|
||||||
// - the increment value
|
// - the increment value
|
||||||
// - the "next" value (SSA value that is Phi'd into the induction variable every loop)
|
// - the "next" value (SSA value that is Phi'd into the induction variable every loop)
|
||||||
|
// - the header's edge returning from the body
|
||||||
//
|
//
|
||||||
// Currently, we detect induction variables that match (Phi min nxt),
|
// Currently, we detect induction variables that match (Phi min nxt),
|
||||||
// with nxt being (Add inc ind).
|
// with nxt being (Add inc ind).
|
||||||
// If it can't parse the induction variable correctly, it returns (nil, nil, nil).
|
// If it can't parse the induction variable correctly, it returns (nil, nil, nil).
|
||||||
func parseIndVar(ind *Value) (min, inc, nxt *Value) {
|
func parseIndVar(ind *Value) (min, inc, nxt *Value, loopReturn Edge) {
|
||||||
if ind.Op != OpPhi {
|
if ind.Op != OpPhi {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if n := ind.Args[0]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
|
if n := ind.Args[0]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
|
||||||
min, nxt = ind.Args[1], n
|
min, nxt, loopReturn = ind.Args[1], n, ind.Block.Preds[0]
|
||||||
} else if n := ind.Args[1]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
|
} else if n := ind.Args[1]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
|
||||||
min, nxt = ind.Args[0], n
|
min, nxt, loopReturn = ind.Args[0], n, ind.Block.Preds[1]
|
||||||
} else {
|
} else {
|
||||||
// Not a recognized induction variable.
|
// Not a recognized induction variable.
|
||||||
return
|
return
|
||||||
|
|
@ -111,13 +112,13 @@ func findIndVar(f *Func) []indVar {
|
||||||
|
|
||||||
// See if this is really an induction variable
|
// See if this is really an induction variable
|
||||||
less := true
|
less := true
|
||||||
init, inc, nxt := parseIndVar(ind)
|
init, inc, nxt, loopReturn := parseIndVar(ind)
|
||||||
if init == nil {
|
if init == nil {
|
||||||
// We failed to parse the induction variable. Before punting, we want to check
|
// We failed to parse the induction variable. Before punting, we want to check
|
||||||
// whether the control op was written with the induction variable on the RHS
|
// whether the control op was written with the induction variable on the RHS
|
||||||
// instead of the LHS. This happens for the downwards case, like:
|
// instead of the LHS. This happens for the downwards case, like:
|
||||||
// for i := len(n)-1; i >= 0; i--
|
// for i := len(n)-1; i >= 0; i--
|
||||||
init, inc, nxt = parseIndVar(limit)
|
init, inc, nxt, loopReturn = parseIndVar(limit)
|
||||||
if init == nil {
|
if init == nil {
|
||||||
// No recognized induction variable on either operand
|
// No recognized induction variable on either operand
|
||||||
continue
|
continue
|
||||||
|
|
@ -145,6 +146,20 @@ func findIndVar(f *Func) []indVar {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// startBody is the edge that eventually returns to the loop header.
|
||||||
|
var startBody Edge
|
||||||
|
switch {
|
||||||
|
case sdom.IsAncestorEq(b.Succs[0].b, loopReturn.b):
|
||||||
|
startBody = b.Succs[0]
|
||||||
|
case sdom.IsAncestorEq(b.Succs[1].b, loopReturn.b):
|
||||||
|
// if x { goto exit } else { goto entry } is identical to if !x { goto entry } else { goto exit }
|
||||||
|
startBody = b.Succs[1]
|
||||||
|
less = !less
|
||||||
|
inclusive = !inclusive
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Increment sign must match comparison direction.
|
// Increment sign must match comparison direction.
|
||||||
// When incrementing, the termination comparison must be ind </<= limit.
|
// When incrementing, the termination comparison must be ind </<= limit.
|
||||||
// When decrementing, the termination comparison must be ind >/>= limit.
|
// When decrementing, the termination comparison must be ind >/>= limit.
|
||||||
|
|
@ -172,14 +187,14 @@ func findIndVar(f *Func) []indVar {
|
||||||
// First condition: loop entry has a single predecessor, which
|
// First condition: loop entry has a single predecessor, which
|
||||||
// is the header block. This implies that b.Succs[0] is
|
// is the header block. This implies that b.Succs[0] is
|
||||||
// reached iff ind < limit.
|
// reached iff ind < limit.
|
||||||
if len(b.Succs[0].b.Preds) != 1 {
|
if len(startBody.b.Preds) != 1 {
|
||||||
// b.Succs[1] must exit the loop.
|
// the other successor must exit the loop.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second condition: b.Succs[0] dominates nxt so that
|
// Second condition: startBody.b dominates nxt so that
|
||||||
// nxt is computed when inc < limit.
|
// nxt is computed when inc < limit.
|
||||||
if !sdom.IsAncestorEq(b.Succs[0].b, nxt.Block) {
|
if !sdom.IsAncestorEq(startBody.b, nxt.Block) {
|
||||||
// inc+ind can only be reached through the branch that enters the loop.
|
// inc+ind can only be reached through the branch that enters the loop.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -298,7 +313,7 @@ func findIndVar(f *Func) []indVar {
|
||||||
nxt: nxt,
|
nxt: nxt,
|
||||||
min: min,
|
min: min,
|
||||||
max: max,
|
max: max,
|
||||||
entry: b.Succs[0].b,
|
entry: startBody.b,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
})
|
})
|
||||||
b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)
|
b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)
|
||||||
|
|
|
||||||
|
|
@ -2319,6 +2319,17 @@ func resliceBytes(b []byte) byte {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func issue74473(s []uint) {
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
if i >= len(s) { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ = s[i] // ERROR "Proved IsInBounds$"
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func useInt(a int) {
|
func useInt(a int) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue