diff options
| author | Jorropo <jorropo.pgm@gmail.com> | 2025-12-06 17:33:06 +0100 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-02-27 23:30:54 -0800 |
| commit | e0c8676edde3e4b9560490d1a944a5d692bd1136 (patch) | |
| tree | 1acd3ba7b98114f9cffd7ffd521ea4e8eaf76b26 /src/cmd | |
| parent | fea0300499d7164a37b418ad47e2d8b3d4b16c01 (diff) | |
| download | go-e0c8676edde3e4b9560490d1a944a5d692bd1136.tar.xz | |
cmd/compile: canonicalize [0,1] == 1 & [0,1] != 1 → != 0 & == 0
Here are all the hits while building go:
archive/zip/reader.go:585:8: Rewrote v126 (Eq64) v37 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/aes/gcm/ghash.go:115:8: Rewrote v21 (Eq64) v11 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/mldsa/mldsa.go:68:86: Rewrote v89 (Eq64) v86 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/nistec/p256_asm.go:162:25: Rewrote v80 (Neq64) v76 argument is boolean-like; rewrote to Eq64 against 0
crypto/internal/fips140/nistec/p256_asm.go:266:22: Rewrote v113 (Neq64) v109 argument is boolean-like; rewrote to Eq64 against 0
crypto/internal/fips140/nistec/p256_asm.go:483:20: Rewrote v74 (Eq64) v69 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/nistec/p256_asm.go:521:20: Rewrote v76 (Eq64) v71 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/nistec/p256_asm.go:546:20: Rewrote v74 (Eq64) v69 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/rsa/keygen.go:22:27: Rewrote v45 (Eq64) v43 argument is boolean-like; rewrote to Neq64 against 0
crypto/internal/fips140/rsa/pkcs1v22.go:469:58: Rewrote v448 (Neq64) v447 argument is boolean-like; rewrote to Eq64 against 0
math/fma.go:170:55: Rewrote v349 (Eq64) v348 argument is boolean-like; rewrote to Neq64 against 0
net/http/h2_bundle.go:12020:11: Rewrote v233 (Eq64) v307 argument is boolean-like; rewrote to Neq64 against 0
time/time.go:1864:14: Rewrote v150 (Neq64) v149 argument is boolean-like; rewrote to Eq64 against 0
It optimize things like:
if bits < 2048 || bits%2 == 1 {
to:
if bits < 2048 || bits%2 != 0 {
Change-Id: Ic72e9212a44bf8b2d267bef0138249c66798dcba
Reviewed-on: https://go-review.googlesource.com/c/go/+/727241
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Jorropo <jorropo.pgm@gmail.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/compile/internal/ssa/prove.go | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 27234b4f93..c8ce7d4c65 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -463,6 +463,17 @@ func (l limit) popcount(b uint) limit { return noLimit().unsignedMinMax(min, max) } +func (l limit) constValue() (_ int64, ok bool) { + switch { + case l.min == l.max: + return l.min, true + case l.umin == l.umax: + return int64(l.umin), true + default: + return 0, false + } +} + // a limitFact is a limit known for a particular value. type limitFact struct { vid ID @@ -2805,6 +2816,20 @@ var bytesizeToAnd = [...]Op{ 64 / 8: OpAnd64, } +var invertEqNeqOp = map[Op]Op{ + OpEq8: OpNeq8, + OpNeq8: OpEq8, + + OpEq16: OpNeq16, + OpNeq16: OpEq16, + + OpEq32: OpNeq32, + OpNeq32: OpEq32, + + OpEq64: OpNeq64, + OpNeq64: OpEq64, +} + // simplifyBlock simplifies some constant values in b and evaluates // branches to non-uniquely dominated successors of b. func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) { @@ -2974,19 +2999,47 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) { b.Func.Warnl(v.Pos, "Rewrote Mul %v into CondSelect; %v is bool", v, x) } } + case OpEq64, OpEq32, OpEq16, OpEq8, + OpNeq64, OpNeq32, OpNeq16, OpNeq8: + // Canonicalize: + // [0,1] != 1 → [0,1] == 0 + // [0,1] == 1 → [0,1] != 0 + // Comparison with zero often encode smaller. + xPos, yPos := 0, 1 + x, y := v.Args[xPos], v.Args[yPos] + xl, yl := ft.limits[x.ID], ft.limits[y.ID] + xConst, xIsConst := xl.constValue() + yConst, yIsConst := yl.constValue() + switch { + case xIsConst && yIsConst: + case xIsConst: + xPos, yPos = yPos, xPos + x, y = y, x + xl, yl = yl, xl + xConst, yConst = yConst, xConst + fallthrough + case yIsConst: + if yConst != 1 || + xl.umax > 1 { + break + } + zero := b.Func.constVal(bytesizeToConst[x.Type.Size()], x.Type, 0, true) + ft.initLimitForNewValue(zero) + oldOp := v.Op + v.Op = invertEqNeqOp[v.Op] + v.SetArg(yPos, zero) + if b.Func.pass.debug > 0 { + b.Func.Warnl(v.Pos, "Rewrote %v (%v) %v argument is boolean-like; rewrote to %v against 0", v, oldOp, x, v.Op) + } + } } // Fold provable constant results. // Helps in cases where we reuse a value after branching on its equality. for i, arg := range v.Args { lim := ft.limits[arg.ID] - var constValue int64 - switch { - case lim.min == lim.max: - constValue = lim.min - case lim.umin == lim.umax: - constValue = int64(lim.umin) - default: + constValue, ok := lim.constValue() + if !ok { continue } switch arg.Op { |
