]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: compute Complement's limits from argument's limits
authorJorropo <jorropo.pgm@gmail.com>
Wed, 14 Aug 2024 20:28:00 +0000 (22:28 +0200)
committerKeith Randall <khr@golang.org>
Tue, 3 Sep 2024 21:12:13 +0000 (21:12 +0000)
I was not sure this was correct so I exhaustively checked all possibilities:
https://go.dev/play/p/hjmCLm4Iagz
https://go.dev/play/p/R9RuRGKwCbN

Change-Id: I85f053df825a4d77f978de42f8a1fcaf4b881def
Reviewed-on: https://go-review.googlesource.com/c/go/+/605696
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
src/cmd/compile/internal/ssa/prove.go
test/prove.go

index 8a351545c9536a6fc6ccd7682b69b393f361734d..db0ad97ad0b4734ffe55ec87ec7df77da08e56a3 100644 (file)
@@ -341,6 +341,42 @@ func (l limit) exp2(b uint) limit {
        return r
 }
 
+// Similar to add, but computes the complement of the limit for bitsize b.
+func (l limit) com(b uint) limit {
+       switch b {
+       case 64:
+               return limit{
+                       min:  ^l.max,
+                       max:  ^l.min,
+                       umin: ^l.umax,
+                       umax: ^l.umin,
+               }
+       case 32:
+               return limit{
+                       min:  int64(^int32(l.max)),
+                       max:  int64(^int32(l.min)),
+                       umin: uint64(^uint32(l.umax)),
+                       umax: uint64(^uint32(l.umin)),
+               }
+       case 16:
+               return limit{
+                       min:  int64(^int16(l.max)),
+                       max:  int64(^int16(l.min)),
+                       umin: uint64(^uint16(l.umax)),
+                       umax: uint64(^uint16(l.umin)),
+               }
+       case 8:
+               return limit{
+                       min:  int64(^int8(l.max)),
+                       max:  int64(^int8(l.min)),
+                       umin: uint64(^uint8(l.umax)),
+                       umax: uint64(^uint8(l.umin)),
+               }
+       default:
+               panic("unreachable")
+       }
+}
+
 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
 
 // a limitFact is a limit known for a particular value.
@@ -1714,6 +1750,9 @@ func (ft *factsTable) flowLimit(v *Value) bool {
                a := ft.limits[v.Args[0].ID]
                b := ft.limits[v.Args[1].ID]
                return ft.unsignedMax(v, 1<<bits.Len64(a.umax|b.umax)-1)
+       case OpCom64, OpCom32, OpCom16, OpCom8:
+               a := ft.limits[v.Args[0].ID]
+               return ft.newLimit(v, a.com(uint(v.Type.Size())*8))
 
        // Arithmetic.
        case OpAdd64:
index 16f7b7de96bef768960f37c8601c816919c0000b..fd709f119ea8c58dccc9c20e70c26d8c2aaa13a7 100644 (file)
@@ -1606,6 +1606,27 @@ func trunc64to16(a uint64, ensureAllBranchesCouldHappen func() bool) uint16 {
        return z
 }
 
+func com64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
+       a &= 0xffff
+       a |= 0xff
+
+       z := ^a
+
+       if ensureAllBranchesCouldHappen() && z > ^uint64(0xff) { // ERROR "Disproved Less64U$"
+               return 42
+       }
+       if ensureAllBranchesCouldHappen() && z <= ^uint64(0xff) { // ERROR "Proved Leq64U$"
+               return 1337
+       }
+       if ensureAllBranchesCouldHappen() && z < ^uint64(0xffff) { // ERROR "Disproved Less64U$"
+               return 42
+       }
+       if ensureAllBranchesCouldHappen() && z >= ^uint64(0xffff) { // ERROR "Proved Leq64U$"
+               return 1337
+       }
+       return z
+}
+
 //go:noinline
 func useInt(a int) {
 }