aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2025-11-14 15:26:36 -0800
committerKeith Randall <khr@golang.org>2025-11-17 09:48:53 -0800
commitc12c33709923907348837e8131122ec4c45d2c83 (patch)
tree802fa4e2ed731eabe6ded28f92cb36605f7c87f0 /src/cmd
parentbc159638135e751a291fe6753fc8c8c3d61be863 (diff)
downloadgo-c12c33709923907348837e8131122ec4c45d2c83.tar.xz
cmd/compile: teach prove about subtract idioms
For v = x-y: if y >= 0 then v <= x if y <= x then v >= 0 (With appropriate guards against overflow/underflow.) Fixes #76304 Change-Id: I8f8f1254156c347fa97802bd057a8379676720ae Reviewed-on: https://go-review.googlesource.com/c/go/+/720740 Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jorropo <jorropo.pgm@gmail.com> Reviewed-by: Keith Randall <khr@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/ssa/prove.go43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index bbcab3efa5..4b2cedc8be 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -1945,6 +1945,7 @@ func (ft *factsTable) flowLimit(v *Value) {
ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
ft.detectMod(v)
ft.detectSliceLenRelation(v)
+ ft.detectSubRelations(v)
case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
a := ft.limits[v.Args[0].ID]
bitsize := uint(v.Type.Size()) * 8
@@ -2091,6 +2092,48 @@ func (ft *factsTable) detectSliceLenRelation(v *Value) {
}
}
+// v must be Sub{64,32,16,8}.
+func (ft *factsTable) detectSubRelations(v *Value) {
+ // v = x-y
+ x := v.Args[0]
+ y := v.Args[1]
+ if x == y {
+ ft.signedMinMax(v, 0, 0)
+ return
+ }
+ xLim := ft.limits[x.ID]
+ yLim := ft.limits[y.ID]
+
+ // Check if we might wrap around. If so, give up.
+ width := uint(v.Type.Size()) * 8
+ if _, ok := safeSub(xLim.min, yLim.max, width); !ok {
+ return // x-y might underflow
+ }
+ if _, ok := safeSub(xLim.max, yLim.min, width); !ok {
+ return // x-y might overflow
+ }
+
+ // Subtracting a positive number only makes
+ // things smaller.
+ if yLim.min >= 0 {
+ ft.update(v.Block, v, x, signed, lt|eq)
+ // TODO: is this worth it?
+ //if yLim.min > 0 {
+ // ft.update(v.Block, v, x, signed, lt)
+ //}
+ }
+
+ // Subtracting a number from a bigger one
+ // can't go below 0.
+ if ft.orderS.OrderedOrEqual(y, x) {
+ ft.setNonNegative(v)
+ // TODO: is this worth it?
+ //if ft.orderS.Ordered(y, x) {
+ // ft.signedMin(v, 1)
+ //}
+ }
+}
+
// x%d has been rewritten to x - (x/d)*d.
func (ft *factsTable) detectMod(v *Value) {
var opDiv, opDivU, opMul, opConst Op