package ssa
import (
+ "cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
"math"
}
}
+func unsignedAddOverflows(a, b uint64, t *types.Type) bool {
+ switch t.Size() {
+ case 8:
+ return a+b < a
+ case 4:
+ return a+b > math.MaxUint32
+ case 2:
+ return a+b > math.MaxUint16
+ case 1:
+ return a+b > math.MaxUint8
+ default:
+ panic("unreachable")
+ }
+}
+
func addLocalFacts(ft *factsTable, b *Block) {
// Propagate constant ranges among values in this block.
// We do this before the second loop so that we have the
// FIXME(go.dev/issue/68857): this loop only set up limits properly when b.Values is in topological order.
// flowLimit can also depend on limits given by this loop which right now is not handled.
switch v.Op {
+ case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
+ x := ft.limits[v.Args[0].ID]
+ y := ft.limits[v.Args[1].ID]
+ if !unsignedAddOverflows(x.umax, y.umax, v.Type) {
+ r := gt
+ if !x.nonzero() {
+ r |= eq
+ }
+ ft.update(b, v, v.Args[1], unsigned, r)
+ r = gt
+ if !y.nonzero() {
+ r |= eq
+ }
+ ft.update(b, v, v.Args[0], unsigned, r)
+ }
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
ft.update(b, v, v.Args[0], unsigned, lt|eq)
ft.update(b, v, v.Args[1], unsigned, lt|eq)
return a[c] // ERROR "Proved IsInBounds$"
}
+func transitiveProofsThroughNonOverflowingUnsignedAdd(x, y, z uint64) {
+ x &= 1<<63 - 1
+ y &= 1<<63 - 1
+
+ a := x + y
+ if a > z {
+ return
+ }
+
+ if x > z { // ERROR "Disproved Less64U$"
+ return
+ }
+ if y > z { // ERROR "Disproved Less64U$"
+ return
+ }
+ if a == x {
+ return
+ }
+ if a == y {
+ return
+ }
+
+ x |= 1
+ y |= 1
+ a = x + y
+ if a == x { // ERROR "Disproved Eq64$"
+ return
+ }
+ if a == y { // ERROR "Disproved Eq64$"
+ return
+ }
+}
+
+func transitiveProofsThroughOverflowingUnsignedAdd(x, y, z uint64) {
+ a := x + y
+ if a > z {
+ return
+ }
+
+ if x > z {
+ return
+ }
+ if y > z {
+ return
+ }
+ if a == x {
+ return
+ }
+ if a == y {
+ return
+ }
+
+ x |= 1
+ y |= 1
+ a = x + y
+ if a == x {
+ return
+ }
+ if a == y {
+ return
+ }
+}
+
//go:noinline
func useInt(a int) {
}