]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: get more bounds info from logic operators in prove pass
authorruinan <ruinan.sun@arm.com>
Tue, 12 Jul 2022 04:05:41 +0000 (04:05 +0000)
committerEric Fang <eric.fang@arm.com>
Fri, 7 Apr 2023 10:09:11 +0000 (10:09 +0000)
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>
src/cmd/compile/internal/ssa/prove.go
test/codegen/comparisons.go
test/prove.go

index 550eb90bedc716e54f41255b7ce65b55ae97c00f..2ca246608626e7210089e4060948b338f7e29b08 100644 (file)
@@ -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
index 99589c4ce8762819a04312975f20b8097f94f651..6ffc73482aa533058f021720a2f4ac40ae4e80ce 100644 (file)
@@ -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 {
index 00bc0a315f6c74d5654f5a7b301682ccb23dee01..abc7bfaa210b596f366294d3f1bff21f27e47715 100644 (file)
@@ -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)