aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorJorropo <jorropo.pgm@gmail.com>2025-12-06 17:33:06 +0100
committerGopher Robot <gobot@golang.org>2026-02-27 23:30:54 -0800
commite0c8676edde3e4b9560490d1a944a5d692bd1136 (patch)
tree1acd3ba7b98114f9cffd7ffd521ea4e8eaf76b26 /src/cmd
parentfea0300499d7164a37b418ad47e2d8b3d4b16c01 (diff)
downloadgo-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.go67
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 {