diff options
| author | George Adams <georgeadams1995@gmail.com> | 2026-03-18 09:16:54 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-20 08:51:08 -0700 |
| commit | 55de3efde3a2e7789b866a66c81a1fcd7c374f09 (patch) | |
| tree | 76358568b585ec09e23752bf76072096a47d66e4 /src/cmd/compile | |
| parent | 686b127fe865e25c1d92a78ba0b56224f3fc0acf (diff) | |
| download | go-55de3efde3a2e7789b866a66c81a1fcd7c374f09.tar.xz | |
cmd/compile: elide sign-extend after zero-extend for wasm
Add rules to eliminate sign-extension of values that have already
been zero-extended from fewer bits via an I64And mask:
(I64Extend32S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int32(c)) == c => x
(I64Extend16S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int16(c)) == c => x
(I64Extend8S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int8(c)) == c => x
When a value has been masked to fit within the non-negative range of
the sign-extension width, the upper bits are already zero and sign-
extending is a no-op. For example, (I64Extend32S (I64And x 0xff))
can be elided because 0xff fits in a signed int32, so bit 31 is
guaranteed to be zero and sign-extending from 32 bits is identity.
Cq-Include-Trybots: luci.golang.try:gotip-wasip1-wasm_wasmtime,gotip-wasip1-wasm_wazero
Change-Id: Ia54d67358756e47ca7635a6a8ca4beadb003820a
Reviewed-on: https://go-review.googlesource.com/c/go/+/756320
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile')
| -rw-r--r-- | src/cmd/compile/internal/ssa/_gen/Wasm.rules | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rewriteWasm.go | 60 |
2 files changed, 67 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/_gen/Wasm.rules b/src/cmd/compile/internal/ssa/_gen/Wasm.rules index 3fef540658..31d37db657 100644 --- a/src/cmd/compile/internal/ssa/_gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/_gen/Wasm.rules @@ -412,6 +412,13 @@ (I64Extend32S (I64Extend8S x)) => (I64Extend8S x) (I64Extend16S (I64Extend8S x)) => (I64Extend8S x) +// Sign-extend of a value already zero-extended from fewer bits is a no-op. +// E.g. (I64Extend32S (I64And x (I64Const [0xff]))) — top 33 bits are already +// zero, so sign-extending from 32 is identity. +(I64Extend32S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int32(c)) == c => x +(I64Extend16S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int16(c)) == c => x +(I64Extend8S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int8(c)) == c => x + // TODO: declare these operations as commutative and get rid of these rules? (I64Add (I64Const [x]) y) && y.Op != OpWasmI64Const => (I64Add y (I64Const [x])) (I64Mul (I64Const [x]) y) && y.Op != OpWasmI64Const => (I64Mul y (I64Const [x])) diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 80c7855a45..1c9f5073e3 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -4135,6 +4135,26 @@ func rewriteValueWasm_OpWasmI64Extend16S(v *Value) bool { v.AddArg(x) return true } + // match: (I64Extend16S x:(I64And _ (I64Const [c]))) + // cond: c >= 0 && int64(int16(c)) == c + // result: x + for { + x := v_0 + if x.Op != OpWasmI64And { + break + } + _ = x.Args[1] + x_1 := x.Args[1] + if x_1.Op != OpWasmI64Const { + break + } + c := auxIntToInt64(x_1.AuxInt) + if !(c >= 0 && int64(int16(c)) == c) { + break + } + v.copyOf(x) + return true + } return false } func rewriteValueWasm_OpWasmI64Extend32S(v *Value) bool { @@ -4172,6 +4192,26 @@ func rewriteValueWasm_OpWasmI64Extend32S(v *Value) bool { v.AddArg(x) return true } + // match: (I64Extend32S x:(I64And _ (I64Const [c]))) + // cond: c >= 0 && int64(int32(c)) == c + // result: x + for { + x := v_0 + if x.Op != OpWasmI64And { + break + } + _ = x.Args[1] + x_1 := x.Args[1] + if x_1.Op != OpWasmI64Const { + break + } + c := auxIntToInt64(x_1.AuxInt) + if !(c >= 0 && int64(int32(c)) == c) { + break + } + v.copyOf(x) + return true + } return false } func rewriteValueWasm_OpWasmI64Extend8S(v *Value) bool { @@ -4187,6 +4227,26 @@ func rewriteValueWasm_OpWasmI64Extend8S(v *Value) bool { v.AddArg(x) return true } + // match: (I64Extend8S x:(I64And _ (I64Const [c]))) + // cond: c >= 0 && int64(int8(c)) == c + // result: x + for { + x := v_0 + if x.Op != OpWasmI64And { + break + } + _ = x.Args[1] + x_1 := x.Args[1] + if x_1.Op != OpWasmI64Const { + break + } + c := auxIntToInt64(x_1.AuxInt) + if !(c >= 0 && int64(int8(c)) == c) { + break + } + v.copyOf(x) + return true + } return false } func rewriteValueWasm_OpWasmI64LeU(v *Value) bool { |
