mirror of
https://github.com/golang/go
synced 2024-11-11 19:51:37 -07:00
cmd/compile: get more bounds info from logic operators in prove pass
Currently, the prove pass can get knowledge from some specific logic operators only before the CFG is explored, which means that the bounds information of the branch will be ignored. This CL updates the facts table by the logic operators in every branch. Combined with the branch information, this will be helpful for BCE in some circumstances. Fixes #57243 Change-Id: I0bd164f1b47804ccfc37879abe9788740b016fd5 Reviewed-on: https://go-review.googlesource.com/c/go/+/419555 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Eric Fang <eric.fang@arm.com> Reviewed-by: Keith Randall <khr@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
4f4a9c7fff
commit
9be533a8ee
@ -802,6 +802,7 @@ func prove(f *Func) {
|
||||
ft.checkpoint()
|
||||
|
||||
var lensVars map[*Block][]*Value
|
||||
var logicVars map[*Block][]*Value
|
||||
|
||||
// Find length and capacity ops.
|
||||
for _, b := range f.Blocks {
|
||||
@ -856,6 +857,16 @@ func prove(f *Func) {
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
||||
for i := 0; i < 2; i++ {
|
||||
if isNonNegative(v.Args[i]) {
|
||||
ft.update(b, v, v.Args[i], signed, lt|eq)
|
||||
ft.update(b, v, ft.zero, signed, gt|eq)
|
||||
}
|
||||
}
|
||||
if logicVars == nil {
|
||||
logicVars = make(map[*Block][]*Value)
|
||||
}
|
||||
logicVars[b] = append(logicVars[b], v)
|
||||
case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u,
|
||||
OpRsh8Ux64, OpRsh8Ux32, OpRsh8Ux16, OpRsh8Ux8,
|
||||
OpRsh16Ux64, OpRsh16Ux32, OpRsh16Ux16, OpRsh16Ux8,
|
||||
@ -982,6 +993,21 @@ func prove(f *Func) {
|
||||
|
||||
if branch != unknown {
|
||||
addBranchRestrictions(ft, parent, branch)
|
||||
// After we add the branch restriction, re-check the logic operations in the parent block,
|
||||
// it may give us more info to omit some branches
|
||||
if logic, ok := logicVars[parent]; ok {
|
||||
for _, v := range logic {
|
||||
// we only have OpAnd for now
|
||||
ft.update(parent, v, v.Args[1], unsigned, lt|eq)
|
||||
ft.update(parent, v, v.Args[0], unsigned, lt|eq)
|
||||
for i := 0; i < 2; i++ {
|
||||
if isNonNegative(v.Args[i]) {
|
||||
ft.update(parent, v, v.Args[i], signed, lt|eq)
|
||||
ft.update(parent, v, ft.zero, signed, gt|eq)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ft.unsat {
|
||||
// node.block is unreachable.
|
||||
// Remove it and don't visit
|
||||
|
@ -235,7 +235,7 @@ func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
||||
// arm64:`CMN\sR[0-9]+<<3,\sR[0-9]+`
|
||||
c8 := e+(f<<3) < 0
|
||||
// arm64:`TST\sR[0-9],\sR[0-9]+`
|
||||
c9 := e&17 < 0
|
||||
c9 := e&(-19) < 0
|
||||
if c0 {
|
||||
return 1
|
||||
} else if c1 {
|
||||
|
@ -1038,6 +1038,25 @@ func divShiftClean32(n int32) int32 {
|
||||
return n / int32(16) // ERROR "Proved Rsh32x64 shifts to zero"
|
||||
}
|
||||
|
||||
// Bounds check elimination
|
||||
|
||||
func sliceBCE1(p []string, h uint) string {
|
||||
if len(p) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
i := h & uint(len(p)-1)
|
||||
return p[i] // ERROR "Proved IsInBounds$"
|
||||
}
|
||||
|
||||
func sliceBCE2(p []string, h int) string {
|
||||
if len(p) == 0 {
|
||||
return ""
|
||||
}
|
||||
i := h & (len(p) - 1)
|
||||
return p[i] // ERROR "Proved IsInBounds$"
|
||||
}
|
||||
|
||||
func and(p []byte) ([]byte, []byte) { // issue #52563
|
||||
const blocksize = 16
|
||||
fullBlocks := len(p) &^ (blocksize - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user