From 03fcb33c0ef76ebbdfa5e9ff483e26d5a250abd5 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Wed, 26 Nov 2025 09:27:45 +0100 Subject: [PATCH] cmd/compile: add tests bruteforcing limit negation and improve limit addition I had to improve addition to make the tests pass. Change-Id: I4daba2ee0f24a0dbc3929bf9afadd2116e16efae Reviewed-on: https://go-review.googlesource.com/c/go/+/724600 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Auto-Submit: Keith Randall Auto-Submit: Jorropo Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/prove.go | 52 +++++++++++++++- src/cmd/compile/internal/ssa/prove_test.go | 69 ++++++++++++++++++++++ 2 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/prove_test.go diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 536965a0a0..1aab7e3eb7 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -250,9 +250,51 @@ func fitsInBitsU(x uint64, b uint) bool { return x>>b == 0 } +func noLimitForBitsize(bitsize uint) limit { + return limit{min: -(1 << (bitsize - 1)), max: 1<<(bitsize-1) - 1, umin: 0, umax: 1< realBiggest { + realBiggest = result + } + } + + l := limit{int64(min), int64(max), 0, math.MaxUint64} + l = op(l, 8) + l = l.intersect(sizeLimit) // We assume this is gonna be used by newLimit which is seeded by the op size already. + + if l.min != int64(realSmallest) || l.max != int64(realBiggest) { + t.Errorf("%s(%d..%d) = %d..%d; want %d..%d", opName, min, max, l.min, l.max, realSmallest, realBiggest) + } + } + } +} + +func testLimitUnaryOpUnsigned8(t *testing.T, opName string, op func(l limit, bitsize uint) limit, opImpl func(uint8) uint8) { + sizeLimit := noLimitForBitsize(8) + for min := 0; min <= math.MaxUint8; min++ { + for max := min; max <= math.MaxUint8; max++ { + realSmallest, realBiggest := uint8(math.MaxUint8), uint8(0) + for i := min; i <= max; i++ { + result := opImpl(uint8(i)) + if result < realSmallest { + realSmallest = result + } + if result > realBiggest { + realBiggest = result + } + } + + l := limit{math.MinInt64, math.MaxInt64, uint64(min), uint64(max)} + l = op(l, 8) + l = l.intersect(sizeLimit) // We assume this is gonna be used by newLimit which is seeded by the op size already. + + if l.umin != uint64(realSmallest) || l.umax != uint64(realBiggest) { + t.Errorf("%s(%d..%d) = %d..%d; want %d..%d", opName, min, max, l.umin, l.umax, realSmallest, realBiggest) + } + } + } +} + +func TestLimitNegSigned(t *testing.T) { + testLimitUnaryOpSigned8(t, "neg", limit.neg, func(x int8) int8 { return -x }) +} +func TestLimitNegUnsigned(t *testing.T) { + testLimitUnaryOpUnsigned8(t, "neg", limit.neg, func(x uint8) uint8 { return -x }) +} -- 2.52.0