From 0a36b58888cc41b276362673f70be87efd7e55ad Mon Sep 17 00:00:00 2001 From: Jorropo Date: Sun, 29 Mar 2026 05:19:58 +0200 Subject: cmd/compile: extend all the cmov into math generic rules with their contrary If the bool comes from a local operation this is foldable into the comparison. if a == b { } else { x++ } becomes: x += !(a == b) becomes: x += a != b If the bool is passed in or loaded rather than being locally computed this adds an extra XOR ^1 to invert it. But at worst it should make the math equal to the compute + CMP + CMOV which is a tie on modern CPUs which can execute CMOV on all int ALUs and a win on the cheaper or older ones which can't. Change-Id: Idd2566c7a3826ec432ebfbba7b3898aa0db4b812 Reviewed-on: https://go-review.googlesource.com/c/go/+/760922 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Jorropo Reviewed-by: Keith Randall Reviewed-by: Junyang Shao --- test/codegen/condmove.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'test/codegen') diff --git a/test/codegen/condmove.go b/test/codegen/condmove.go index 6d1bba4c70..ec1b971ed7 100644 --- a/test/codegen/condmove.go +++ b/test/codegen/condmove.go @@ -464,6 +464,16 @@ func cmovmathadd(a uint, b bool) uint { // wasm:"I64Add" -"Select" return a } +func cmovmathaddelse(a uint, b bool) uint { + if !b { + a++ + } + // amd64:"ADDQ" -"CMOV" + // arm64:"CSINC" -"CSEL" + // ppc64x:"ADD" -"ISEL" + // wasm:"I64Add" -"Select" + return a +} func cmovmathsub(a uint, b bool) uint { if b { @@ -475,6 +485,16 @@ func cmovmathsub(a uint, b bool) uint { // wasm:"I64Sub" -"Select" return a } +func cmovmathsubelse(a uint, b bool) uint { + if !b { + a-- + } + // amd64:"SUBQ" -"CMOV" + // arm64:"SUB" -"CSEL" + // ppc64x:"SUB" -"ISEL" + // wasm:"I64Sub" -"Select" + return a +} func cmovmathdouble(a uint, b bool) uint { if b { @@ -486,6 +506,16 @@ func cmovmathdouble(a uint, b bool) uint { // wasm:"I64Shl" -"Select" return a } +func cmovmathdoubleelse(a uint, b bool) uint { + if !b { + a *= 2 + } + // amd64:"SHL" -"CMOV" + // amd64/v3:"SHL" -"CMOV" -"MOV" + // arm64:"LSL" -"CSEL" + // wasm:"I64Shl" -"Select" + return a +} func cmovmathhalvei(a int, b bool) int { if b { @@ -498,6 +528,17 @@ func cmovmathhalvei(a int, b bool) int { // wasm:-"Select" return a } +func cmovmathhalveielse(a int, b bool) int { + if !b { + // For some reason the compiler attributes the shift to inside this block rather than where the Phi node is. + // arm64:"ASR" -"CSEL" + // wasm:"I64ShrS" -"Select" + a /= 2 + } + // arm64:-"CSEL" + // wasm:-"Select" + return a +} func cmovmathhalveu(a uint, b bool) uint { if b { @@ -509,6 +550,16 @@ func cmovmathhalveu(a uint, b bool) uint { // wasm:"I64ShrU" -"Select" return a } +func cmovmathhalveuelse(a uint, b bool) uint { + if !b { + a /= 2 + } + // amd64:"SHR" -"CMOV" + // amd64/v3:"SHR" -"CMOV" -"MOV" + // arm64:"LSR" -"CSEL" + // wasm:"I64ShrU" -"Select" + return a +} func cmovmathor(a uint, b bool) uint { if b { @@ -520,6 +571,16 @@ func cmovmathor(a uint, b bool) uint { // wasm:"I64Or" -"Select" return a } +func cmovmathorelse(a uint, b bool) uint { + if !b { + a |= 1 + } + // amd64:"ORQ" -"CMOV" + // arm64:"ORR" -"CSEL" + // ppc64x:"OR" -"ISEL" + // wasm:"I64Or" -"Select" + return a +} func cmovmathxor(a uint, b bool) uint { if b { @@ -531,6 +592,16 @@ func cmovmathxor(a uint, b bool) uint { // wasm:"I64Xor" -"Select" return a } +func cmovmathxorelse(a uint, b bool) uint { + if !b { + a ^= 1 + } + // amd64:"XORQ" -"CMOV" + // arm64:"EOR" -"CSEL" + // ppc64x:"XOR" -"ISEL" + // wasm:"I64Xor" -"Select" + return a +} func branchlessBoolToUint8(b bool) (r uint8) { if b { -- cgit v1.3-5-g9baa