ft.checkpoint()
var lensVars map[*Block][]*Value
+ var logicVars map[*Block][]*Value
// Find length and capacity ops.
for _, b := range f.Blocks {
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,
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
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)