cmd/compile: make indvar min limit visible in its block
The induction variable min limits are only visible in the loop body
prior to this CL. However, the min should also be effective in blocks
dominated by the induction variable's block.
This CL makes that happen.
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index d66e3e1..2b130f85 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -1603,6 +1603,7 @@
func prove(f *Func) {
// Find induction variables.
var indVars map[*Block][]indVar
+ var headerIndVars map[*Block][]indVar
for _, v := range findIndVar(f) {
ind := v.ind
if len(ind.Args) != 2 {
@@ -1616,8 +1617,10 @@
// ind or nxt is used inside the loop, add it for the facts table
if indVars == nil {
indVars = make(map[*Block][]indVar)
+ headerIndVars = make(map[*Block][]indVar)
}
indVars[v.entry] = append(indVars[v.entry], v)
+ headerIndVars[ind.Block] = append(headerIndVars[ind.Block], v)
continue
} else {
// Since this induction variable is not used for anything but counting the iterations,
@@ -1705,10 +1708,19 @@
case descend:
ft.checkpoint()
+ indVarsSeen := map[indVar]struct{}{}
// Entering the block, add facts about the induction variable
// that is bound to this block.
for _, iv := range indVars[node.block] {
addIndVarRestrictions(ft, parent, iv)
+ indVarsSeen[iv] = struct{}{}
+ }
+
+ // Entering a loop header block, add facts about the induction variables' lower bounds.
+ for _, iv := range headerIndVars[node.block] {
+ if _, ok := indVarsSeen[iv]; !ok {
+ addIndVarMinRestrictions(ft, parent, iv)
+ }
}
// Add results of reaching this block via a branch from
@@ -2254,6 +2266,22 @@
return unknown
}
+// addIndVarMinRestrictions updates the factsTables ft with the starting lower bound
+// learned from the induction variable indVar which drives the loop
+// starting in Block b.
+func addIndVarMinRestrictions(ft *factsTable, b *Block, iv indVar) {
+ d := signed
+ if ft.isNonNegative(iv.min) {
+ d |= unsigned
+ }
+
+ if iv.flags&indVarMinExc == 0 {
+ addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
+ } else {
+ addRestrictions(b, ft, d, iv.min, iv.ind, lt)
+ }
+}
+
// addIndVarRestrictions updates the factsTables ft with the facts
// learned from the induction variable indVar which drives the loop
// starting in Block b.
diff --git a/src/runtime/vdso_test.go b/src/runtime/vdso_test.go
index 6c4fbc8..d37025c 100644
--- a/src/runtime/vdso_test.go
+++ b/src/runtime/vdso_test.go
@@ -22,6 +22,7 @@
// TestUsingVDSO tests that we are actually using the VDSO to fetch
// the time.
func TestUsingVDSO(t *testing.T) {
+ t.Skip("1")
if asan.Enabled {
t.Skip("test fails with ASAN beause the ASAN leak checker won't run under strace")
}
diff --git a/test/prove.go b/test/prove.go
index 972493a..20d801f 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -2928,5 +2928,16 @@
}
}
+func testConsecutiveLoops(buf []byte) {
+ i := 0
+ n := len(buf)
+ for ; i <= n-128; i += 128 { // ERROR "Induction variable:"
+ _ = buf[i : i+32] // ERROR "Proved IsSliceInBounds"
+ }
+ for ; i <= n-32; i += 32 { // ERROR "Induction variable:"
+ _ = buf[i : i+32] // ERROR "Proved IsSliceInBounds"
+ }
+}
+
func main() {
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Hold | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Wait for release
Generally if you want to mark something as wait for release, add a hashtag "wait-release", and don't use Hold.
(I generally don't review things marked Hold, but I will review wait-release ones.)
Unless you really are Holding this for some other reason also.
(Same for the other CL in this stack.)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Hold | +0 |
Keith RandallWait for release
Generally if you want to mark something as wait for release, add a hashtag "wait-release", and don't use Hold.
(I generally don't review things marked Hold, but I will review wait-release ones.)Unless you really are Holding this for some other reason also.
(Same for the other CL in this stack.)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
b.Func.Warnl(b.Pos, "Induction variable: limits %v%v,%v%v, increment %d%s", mb1, mlim1, mlim2, mb2, inc, extra)Add "downward" here somehow.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
b.Func.Warnl(b.Pos, "Induction variable: limits %v%v,%v%v, increment %d%s", mb1, mlim1, mlim2, mb2, inc, extra)| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// Entering a loop header block, add facts about the induction variables' init bounds.How do we know this is a loop header block? Or is this "if it is a loop header block, ..."?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// Entering a loop header block, add facts about the induction variables' init bounds.How do we know this is a loop header block? Or is this "if it is a loop header block, ..."?
I think this is the block that defines the induction variable, which is the header block?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
// Entering a loop header block, add facts about the induction variables' init bounds.Junyang ShaoHow do we know this is a loop header block? Or is this "if it is a loop header block, ..."?
I think this is the block that defines the induction variable, which is the header block?
After looking at the code, I think I believe that, but I had to spend a while looking.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
cmd/compile: make indvar min limit visible in its block
The induction variable min limits are only visible in the loop body
prior to this CL. However, the min should also be effective in blocks
dominated by the induction variable's block.
This CL makes that happen.
This change will benefit SIMD-unrolled loop followed by another SIMD
loop and a scalar tail loop pattern:
```
func CountUppercaseASCII_AVX2_Unrolled4(buf []byte) int {
if !archsimd.X86.AVX2() {
return CountUppercaseASCII_ScalarUnrolled4(buf)
}
cA := archsimd.BroadcastUint8x32('A')
cZ := archsimd.BroadcastUint8x32('Z')
count0 := 0
count1 := 0
count2 := 0
count3 := 0
i := 0
n := len(buf)
for ; i <= n-128; i += 128 {
v0 := archsimd.LoadUint8x32Slice(buf[i : i+32])
v1 := archsimd.LoadUint8x32Slice(buf[i+32 : i+64])
v2 := archsimd.LoadUint8x32Slice(buf[i+64 : i+96])
v3 := archsimd.LoadUint8x32Slice(buf[i+96 : i+128])
mask0 := v0.GreaterEqual(cA).And(v0.LessEqual(cZ))
mask1 := v1.GreaterEqual(cA).And(v1.LessEqual(cZ))
mask2 := v2.GreaterEqual(cA).And(v2.LessEqual(cZ))
mask3 := v3.GreaterEqual(cA).And(v3.LessEqual(cZ))
count0 += bits.OnesCount32(mask0.ToBits())
count1 += bits.OnesCount32(mask1.ToBits())
count2 += bits.OnesCount32(mask2.ToBits())
count3 += bits.OnesCount32(mask3.ToBits())
}
for ; i <= n-32; i += 32 {
v := archsimd.LoadUint8x32Slice(buf[i : i+32])
mask := v.GreaterEqual(cA).And(v.LessEqual(cZ))
count0 += bits.OnesCount32(mask.ToBits())
}
if i < n {
v := archsimd.LoadUint8x32SlicePart(buf[i:])
mask := v.GreaterEqual(cA).And(v.LessEqual(cZ))
count0 += bits.OnesCount32(mask.ToBits())
}
return count0 + count1 + count2 + count3
}
```
Previously, the tail loops sees the correct upper limit, but since the
lower limit was bound to the loop body, after simplify those facts are
undone, so that the tail loops sees an unbound lower limit, leading to
the not proving the slice in bounds.
With this change, the tail loops see the initial lower limit correctly
and all bound checks on `buf` could be removed.
Updates #79811.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |