Commit cd798dcb authored by Alexandru Moșoi's avatar Alexandru Moșoi Committed by Alexandru Moșoi

cmd/compile/internal/ssa: generalize prove to all booleans

* Refacts a bit saving and restoring parents restrictions
* Shaves ~100k from pkg/tools/linux_amd64,
but most of the savings come from the rewrite rules.
* Improves on the following artificial test case:
func f1(a4 bool, a6 bool) bool {
  return a6 || (a6 || (a6 || a4)) || (a6 || (a4 || a6 || (false || a6)))
}

Change-Id: I714000f75a37a3a6617c6e6834c75bd23674215f
Reviewed-on: https://go-review.googlesource.com/20306Reviewed-by: default avatarKeith Randall <khr@golang.org>
Run-TryBot: Alexandru Moșoi <alexandru@mosoi.ro>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 6dfcc336
...@@ -77,14 +77,19 @@ ...@@ -77,14 +77,19 @@
(Rsh8x64 (Const8 [0]) _) -> (Const8 [0]) (Rsh8x64 (Const8 [0]) _) -> (Const8 [0])
(Rsh8Ux64 (Const8 [0]) _) -> (Const8 [0]) (Rsh8Ux64 (Const8 [0]) _) -> (Const8 [0])
(IsInBounds x x) -> (ConstBool [0])
(IsInBounds (And32 (Const32 [c]) _) (Const32 [d])) && inBounds32(c, d) -> (ConstBool [1]) (IsInBounds (And32 (Const32 [c]) _) (Const32 [d])) && inBounds32(c, d) -> (ConstBool [1])
(IsInBounds (And64 (Const64 [c]) _) (Const64 [d])) && inBounds64(c, d) -> (ConstBool [1]) (IsInBounds (And64 (Const64 [c]) _) (Const64 [d])) && inBounds64(c, d) -> (ConstBool [1])
(IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(inBounds32(c,d))]) (IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(inBounds32(c,d))])
(IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(inBounds64(c,d))]) (IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(inBounds64(c,d))])
(IsSliceInBounds x x) -> (ConstBool [1])
(IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d])) && sliceInBounds32(c, d) -> (ConstBool [1]) (IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d])) && sliceInBounds32(c, d) -> (ConstBool [1])
(IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d])) && sliceInBounds64(c, d) -> (ConstBool [1]) (IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d])) && sliceInBounds64(c, d) -> (ConstBool [1])
(IsSliceInBounds (Const32 [0]) _) -> (ConstBool [1])
(IsSliceInBounds (Const64 [0]) _) -> (ConstBool [1])
(IsSliceInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(sliceInBounds32(c,d))]) (IsSliceInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(sliceInBounds32(c,d))])
(IsSliceInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(sliceInBounds64(c,d))]) (IsSliceInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(sliceInBounds64(c,d))])
(IsSliceInBounds (SliceLen x) (SliceCap x)) -> (ConstBool [1])
(Eq64 x x) -> (ConstBool [1]) (Eq64 x x) -> (ConstBool [1])
(Eq32 x x) -> (ConstBool [1]) (Eq32 x x) -> (ConstBool [1])
...@@ -547,6 +552,10 @@ ...@@ -547,6 +552,10 @@
(SlicePtr (SliceMake (Const64 <t> [c]) _ _)) -> (Const64 <t> [c]) (SlicePtr (SliceMake (Const64 <t> [c]) _ _)) -> (Const64 <t> [c])
(SliceLen (SliceMake _ (Const64 <t> [c]) _)) -> (Const64 <t> [c]) (SliceLen (SliceMake _ (Const64 <t> [c]) _)) -> (Const64 <t> [c])
(SliceCap (SliceMake _ _ (Const64 <t> [c]))) -> (Const64 <t> [c]) (SliceCap (SliceMake _ _ (Const64 <t> [c]))) -> (Const64 <t> [c])
(SlicePtr (SliceMake (SlicePtr x) _ _)) -> (SlicePtr x)
(SliceLen (SliceMake _ (SliceLen x) _)) -> (SliceLen x)
(SliceCap (SliceMake _ _ (SliceCap x))) -> (SliceCap x)
(ConstSlice) && config.PtrSize == 4 -> (ConstSlice) && config.PtrSize == 4 ->
(SliceMake (SliceMake
(ConstNil <config.fe.TypeBytePtr()>) (ConstNil <config.fe.TypeBytePtr()>)
......
This diff is collapsed.
...@@ -2487,6 +2487,18 @@ func rewriteValuegeneric_OpITab(v *Value, config *Config) bool { ...@@ -2487,6 +2487,18 @@ func rewriteValuegeneric_OpITab(v *Value, config *Config) bool {
func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool { func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b
// match: (IsInBounds x x)
// cond:
// result: (ConstBool [0])
for {
x := v.Args[0]
if v.Args[1] != x {
break
}
v.reset(OpConstBool)
v.AuxInt = 0
return true
}
// match: (IsInBounds (And32 (Const32 [c]) _) (Const32 [d])) // match: (IsInBounds (And32 (Const32 [c]) _) (Const32 [d]))
// cond: inBounds32(c, d) // cond: inBounds32(c, d)
// result: (ConstBool [1]) // result: (ConstBool [1])
...@@ -2568,6 +2580,18 @@ func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool { ...@@ -2568,6 +2580,18 @@ func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool {
func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool { func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b
// match: (IsSliceInBounds x x)
// cond:
// result: (ConstBool [1])
for {
x := v.Args[0]
if v.Args[1] != x {
break
}
v.reset(OpConstBool)
v.AuxInt = 1
return true
}
// match: (IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d])) // match: (IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d]))
// cond: sliceInBounds32(c, d) // cond: sliceInBounds32(c, d)
// result: (ConstBool [1]) // result: (ConstBool [1])
...@@ -2612,6 +2636,34 @@ func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool { ...@@ -2612,6 +2636,34 @@ func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool {
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (IsSliceInBounds (Const32 [0]) _)
// cond:
// result: (ConstBool [1])
for {
if v.Args[0].Op != OpConst32 {
break
}
if v.Args[0].AuxInt != 0 {
break
}
v.reset(OpConstBool)
v.AuxInt = 1
return true
}
// match: (IsSliceInBounds (Const64 [0]) _)
// cond:
// result: (ConstBool [1])
for {
if v.Args[0].Op != OpConst64 {
break
}
if v.Args[0].AuxInt != 0 {
break
}
v.reset(OpConstBool)
v.AuxInt = 1
return true
}
// match: (IsSliceInBounds (Const32 [c]) (Const32 [d])) // match: (IsSliceInBounds (Const32 [c]) (Const32 [d]))
// cond: // cond:
// result: (ConstBool [b2i(sliceInBounds32(c,d))]) // result: (ConstBool [b2i(sliceInBounds32(c,d))])
...@@ -2644,6 +2696,24 @@ func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool { ...@@ -2644,6 +2696,24 @@ func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool {
v.AuxInt = b2i(sliceInBounds64(c, d)) v.AuxInt = b2i(sliceInBounds64(c, d))
return true return true
} }
// match: (IsSliceInBounds (SliceLen x) (SliceCap x))
// cond:
// result: (ConstBool [1])
for {
if v.Args[0].Op != OpSliceLen {
break
}
x := v.Args[0].Args[0]
if v.Args[1].Op != OpSliceCap {
break
}
if v.Args[1].Args[0] != x {
break
}
v.reset(OpConstBool)
v.AuxInt = 1
return true
}
return false return false
} }
func rewriteValuegeneric_OpLeq16(v *Value, config *Config) bool { func rewriteValuegeneric_OpLeq16(v *Value, config *Config) bool {
...@@ -6709,6 +6779,21 @@ func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool { ...@@ -6709,6 +6779,21 @@ func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
v.AuxInt = c v.AuxInt = c
return true return true
} }
// match: (SliceCap (SliceMake _ _ (SliceCap x)))
// cond:
// result: (SliceCap x)
for {
if v.Args[0].Op != OpSliceMake {
break
}
if v.Args[0].Args[2].Op != OpSliceCap {
break
}
x := v.Args[0].Args[2].Args[0]
v.reset(OpSliceCap)
v.AddArg(x)
return true
}
return false return false
} }
func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool { func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
...@@ -6731,6 +6816,21 @@ func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool { ...@@ -6731,6 +6816,21 @@ func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
v.AuxInt = c v.AuxInt = c
return true return true
} }
// match: (SliceLen (SliceMake _ (SliceLen x) _))
// cond:
// result: (SliceLen x)
for {
if v.Args[0].Op != OpSliceMake {
break
}
if v.Args[0].Args[1].Op != OpSliceLen {
break
}
x := v.Args[0].Args[1].Args[0]
v.reset(OpSliceLen)
v.AddArg(x)
return true
}
return false return false
} }
func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool { func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
...@@ -6753,6 +6853,21 @@ func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool { ...@@ -6753,6 +6853,21 @@ func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
v.AuxInt = c v.AuxInt = c
return true return true
} }
// match: (SlicePtr (SliceMake (SlicePtr x) _ _))
// cond:
// result: (SlicePtr x)
for {
if v.Args[0].Op != OpSliceMake {
break
}
if v.Args[0].Args[0].Op != OpSlicePtr {
break
}
x := v.Args[0].Args[0].Args[0]
v.reset(OpSlicePtr)
v.AddArg(x)
return true
}
return false return false
} }
func rewriteValuegeneric_OpStore(v *Value, config *Config) bool { func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
......
...@@ -5,11 +5,11 @@ package main ...@@ -5,11 +5,11 @@ package main
func f0(a []int) int { func f0(a []int) int {
a[0] = 1 a[0] = 1
a[0] = 1 // ERROR "Proved IsInBounds$" a[0] = 1 // ERROR "Proved boolean IsInBounds$"
a[6] = 1 a[6] = 1
a[6] = 1 // ERROR "Proved IsInBounds$" a[6] = 1 // ERROR "Proved boolean IsInBounds$"
a[5] = 1 a[5] = 1
a[5] = 1 // ERROR "Proved IsInBounds$" a[5] = 1 // ERROR "Proved boolean IsInBounds$"
return 13 return 13
} }
...@@ -18,18 +18,18 @@ func f1(a []int) int { ...@@ -18,18 +18,18 @@ func f1(a []int) int {
return 18 return 18
} }
a[0] = 1 a[0] = 1
a[0] = 1 // ERROR "Proved IsInBounds$" a[0] = 1 // ERROR "Proved boolean IsInBounds$"
a[6] = 1 a[6] = 1
a[6] = 1 // ERROR "Proved IsInBounds$" a[6] = 1 // ERROR "Proved boolean IsInBounds$"
a[5] = 1 // ERROR "Proved constant IsInBounds$" a[5] = 1 // ERROR "Proved non-negative bounds IsInBounds$"
a[5] = 1 // ERROR "Proved IsInBounds$" a[5] = 1 // ERROR "Proved boolean IsInBounds$"
return 26 return 26
} }
func f2(a []int) int { func f2(a []int) int {
for i := range a { for i := range a {
a[i] = i a[i] = i
a[i] = i // ERROR "Proved IsInBounds$" a[i] = i // ERROR "Proved boolean IsInBounds$"
} }
return 34 return 34
} }
...@@ -49,13 +49,13 @@ func f4a(a, b, c int) int { ...@@ -49,13 +49,13 @@ func f4a(a, b, c int) int {
if a > b { // ERROR "Disproved Greater64$" if a > b { // ERROR "Disproved Greater64$"
return 50 return 50
} }
if a < b { // ERROR "Proved Less64$" if a < b { // ERROR "Proved boolean Less64$"
return 53 return 53
} }
if a == b { // ERROR "Disproved Eq64$" if a == b { // ERROR "Disproved boolean Eq64$"
return 56 return 56
} }
if a > b { if a > b { // ERROR "Disproved boolean Greater64$"
return 59 return 59
} }
return 61 return 61
...@@ -92,8 +92,8 @@ func f4c(a, b, c int) int { ...@@ -92,8 +92,8 @@ func f4c(a, b, c int) int {
func f4d(a, b, c int) int { func f4d(a, b, c int) int {
if a < b { if a < b {
if a < c { if a < c {
if a < b { // ERROR "Proved Less64$" if a < b { // ERROR "Proved boolean Less64$"
if a < c { // ERROR "Proved Less64$" if a < c { // ERROR "Proved boolean Less64$"
return 87 return 87
} }
return 89 return 89
...@@ -183,8 +183,8 @@ func f6e(a uint8) int { ...@@ -183,8 +183,8 @@ func f6e(a uint8) int {
func f7(a []int, b int) int { func f7(a []int, b int) int {
if b < len(a) { if b < len(a) {
a[b] = 3 a[b] = 3
if b < len(a) { // ERROR "Proved Less64$" if b < len(a) { // ERROR "Proved boolean Less64$"
a[b] = 5 // ERROR "Proved IsInBounds$" a[b] = 5 // ERROR "Proved boolean IsInBounds$"
} }
} }
return 161 return 161
...@@ -203,5 +203,55 @@ func f8(a, b uint) int { ...@@ -203,5 +203,55 @@ func f8(a, b uint) int {
return 174 return 174
} }
func f9(a, b bool) int {
if a {
return 1
}
if a || b { // ERROR "Disproved boolean Arg$"
return 2
}
return 3
}
func f10(a string) int {
n := len(a)
if a[:n>>1] == "aaa" {
return 0
}
return 1
}
func f11a(a []int, i int) {
useInt(a[i])
useInt(a[i]) // ERROR "Proved boolean IsInBounds$"
}
func f11b(a []int, i int) {
useSlice(a[i:])
useSlice(a[i:]) // ERROR "Proved boolean IsSliceInBounds$"
}
func f11c(a []int, i int) {
useSlice(a[:i])
useSlice(a[:i]) // ERROR "Proved boolean IsSliceInBounds$"
}
func f11d(a []int, i int) {
useInt(a[2*i+7])
useInt(a[2*i+7])
}
func f12(a []int, b int) {
useSlice(a[:b])
}
//go:noinline
func useInt(a int) {
}
//go:noinline
func useSlice(a []int) {
}
func main() { func main() {
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment