cmd/compile: learn transitive proofs for safe positive signed adds

I've split this into it's own CL to make git bisect more effective.

Change-Id: I3fbb42ec7d29169a29f7f55ef2c188317512f532
Reviewed-on: https://go-review.googlesource.com/c/go/+/685819
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Jorropo 2025-07-04 09:23:21 +02:00 committed by Gopher Robot
parent e5f202bb60
commit 1a72920f09
3 changed files with 111 additions and 14 deletions

View file

@ -2148,6 +2148,22 @@ func unsignedAddOverflows(a, b uint64, t *types.Type) bool {
}
}
func signedAddOverflowsOrUnderflows(a, b int64, t *types.Type) bool {
r := a + b
switch t.Size() {
case 8:
return (a >= 0 && b >= 0 && r < 0) || (a < 0 && b < 0 && r >= 0)
case 4:
return r < math.MinInt32 || math.MaxInt32 < r
case 2:
return r < math.MinInt16 || math.MaxInt16 < r
case 1:
return r < math.MinInt8 || math.MaxInt8 < r
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
@ -2182,6 +2198,20 @@ func addLocalFacts(ft *factsTable, b *Block) {
}
ft.update(b, v, v.Args[0], unsigned, r)
}
if x.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
r := gt
if !x.nonzero() {
r |= eq
}
ft.update(b, v, v.Args[1], signed, r)
}
if y.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
r := gt
if !y.nonzero() {
r |= eq
}
ft.update(b, v, v.Args[0], signed, 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)