cmd/compile: ppc64x fold (x+x)<<c into x<<(c+1)
Add peephole rules to the ppc64x backend.
This removes an unnecessary ADD and shortens the dependency chain for
patterns like (x + x) << c, which is equivalent to x << (c+1). Aligns
ppc64 with other architectures that already assert similar codegen
in shift.go. Safe on ppc64 and ppc64le (POWER8/9/10).
Tests: extend test/codegen/shift.go with ppc64x checks to assert a single
SLD/SLW and forbid ADD.
diff --git a/src/cmd/compile/internal/ssa/_gen/PPC64.rules b/src/cmd/compile/internal/ssa/_gen/PPC64.rules
index f5e381a..36403f8 100644
--- a/src/cmd/compile/internal/ssa/_gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/PPC64.rules
@@ -865,10 +865,14 @@
(SLDconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (64-getPPC64ShiftMaskLength(d)) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
(SLDconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(64-getPPC64ShiftMaskLength(d)) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
+// (x + x) << c → x << (c+1)
+(SLDconst [c] (ADD x x)) => (SLDconst [c+1] x)
(SLWconst [c] z:(MOVBZreg x)) && z.Uses == 1 && c < 8 => (CLRLSLWI [newPPC64ShiftAuxInt(c,24,31,32)] x)
(SLWconst [c] z:(MOVHZreg x)) && z.Uses == 1 && c < 16 => (CLRLSLWI [newPPC64ShiftAuxInt(c,16,31,32)] x)
(SLWconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d)) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
(SLWconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d)) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
+// (x + x) << c → x << (c+1)
+(SLWconst [c] (ADD x x)) => (SLWconst [c+1] x)
// special case for power9
(SL(W|D)const [c] z:(MOVWreg x)) && c < 32 && buildcfg.GOPPC64 >= 9 => (EXTSWSLconst [c] x)
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 050ace8..3ae69d7 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -12540,6 +12540,22 @@
}
break
}
+ // match: (SLDconst [c] (ADD x x))
+ // result: (SLDconst [c+1] x)
+ for {
+ c := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ADD {
+ break
+ }
+ x := v_0.Args[1]
+ if x != v_0.Args[0] {
+ break
+ }
+ v.reset(OpPPC64SLDconst)
+ v.AuxInt = int64ToAuxInt(c + 1)
+ v.AddArg(x)
+ return true
+ }
// match: (SLDconst [c] z:(MOVWreg x))
// cond: c < 32 && buildcfg.GOPPC64 >= 9
// result: (EXTSWSLconst [c] x)
@@ -12676,6 +12692,22 @@
}
break
}
+ // match: (SLWconst [c] (ADD x x))
+ // result: (SLWconst [c+1] x)
+ for {
+ c := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ADD {
+ break
+ }
+ x := v_0.Args[1]
+ if x != v_0.Args[0] {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = int64ToAuxInt(c + 1)
+ v.AddArg(x)
+ return true
+ }
// match: (SLWconst [c] z:(MOVWreg x))
// cond: c < 32 && buildcfg.GOPPC64 >= 9
// result: (EXTSWSLconst [c] x)
diff --git a/test/codegen/shift.go b/test/codegen/shift.go
index 4b0885a..2375e16 100644
--- a/test/codegen/shift.go
+++ b/test/codegen/shift.go
@@ -123,6 +123,7 @@
// amd64:"SHLL\t[$]2"
// loong64:"SLL\t[$]2"
// riscv64:"SLLI\t[$]2"
+ // ppc64x:"SLW\t[$]2"-"ADD"
return (x + x) << 1
}
@@ -130,6 +131,7 @@
// amd64:"SHLQ\t[$]2"
// loong64:"SLLV\t[$]2"
// riscv64:"SLLI\t[$]2"
+ // ppc64x:"SLD\t[$]2"-"ADD"
return (x + x) << 1
}
@@ -137,6 +139,7 @@
// amd64:"SHLL\t[$]3"
// loong64:"SLL\t[$]3"
// riscv64:"SLLI\t[$]3"
+ // ppc64x:"SLW\t[$]3"-"ADD"
return (x + x) << 2
}
@@ -144,6 +147,7 @@
// amd64:"SHLQ\t[$]3"
// loong64:"SLLV\t[$]3"
// riscv64:"SLLI\t[$]3"
+ // ppc64x:"SLD\t[$]3"-"ADD"
return (x + x) << 2
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
(SLDconst [c] (ADD x x)) => (SLDconst [c+1] x)Do you need to check if c+1 is less than 64 here?
(SLWconst [c] (ADD x x)) => (SLWconst [c+1] x)Ditto for 32.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
(SLDconst [c] (ADD x x)) => (SLDconst [c+1] x)Do you need to check if c+1 is less than 64 here?
Thanks!. I believe no extra guard is needed here.
At the boundary c = w-1 (w = bit width),
(x + x) << (w-1) = (2x) << (w-1) = x << w = 0
since 2x is always even and Go’s constant-shift semantics define x << w (shift ≥ width) as 0 for integer types.
So for 64-bit, (x+x)<<63 and x<<64 are both 0 for all x (same for 32-bit).
I can add guards (c < 63 / c < 31) if you prefer the explicit style, but they may not be required for correctness.
(SLWconst [c] (ADD x x)) => (SLWconst [c+1] x)Jayanth KrishnamurthyDitto for 32.
Acknowledged
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
(SLDconst [c] (ADD x x)) => (SLDconst [c+1] x)Jayanth KrishnamurthyDo you need to check if c+1 is less than 64 here?
Thanks!. I believe no extra guard is needed here.
At the boundary c = w-1 (w = bit width),
(x + x) << (w-1) = (2x) << (w-1) = x << w = 0since 2x is always even and Go’s constant-shift semantics define x << w (shift ≥ width) as 0 for integer types.
So for 64-bit, (x+x)<<63 and x<<64 are both 0 for all x (same for 32-bit).
I can add guards (c < 63 / c < 31) if you prefer the explicit style, but they may not be required for correctness.
Go's shift semantics aren't relevant at this point in the compiler. These rules lower the program into ppc64 instructions.
The shift amount when using the sldi instruction on ppc64 is represented using 6 bits. A shift amount of 64 will therefore either be silently truncated to 0 or an error will be raised by the assembler, I'm not sure which. Therefore I think there does need to be a check that c+1 is less than 64 for correctness.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
Jayanth KrishnamurthyDo you need to check if c+1 is less than 64 here?
Michael MundayThanks!. I believe no extra guard is needed here.
At the boundary c = w-1 (w = bit width),
(x + x) << (w-1) = (2x) << (w-1) = x << w = 0since 2x is always even and Go’s constant-shift semantics define x << w (shift ≥ width) as 0 for integer types.
So for 64-bit, (x+x)<<63 and x<<64 are both 0 for all x (same for 32-bit).
I can add guards (c < 63 / c < 31) if you prefer the explicit style, but they may not be required for correctness.
Go's shift semantics aren't relevant at this point in the compiler. These rules lower the program into ppc64 instructions.
The shift amount when using the sldi instruction on ppc64 is represented using 6 bits. A shift amount of 64 will therefore either be silently truncated to 0 or an error will be raised by the assembler, I'm not sure which. Therefore I think there does need to be a check that c+1 is less than 64 for correctness.
Thanks for the pointer on immediate ranges — I have added guards so the folded immediates stay encodable. If you suggest explicit boundary tests (to assert no fold at c=63/31), I’m happy to add them in this CL.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
// riscv64:-"SLLI","MOV\t[$]0"Can you implement a check for ppc64x here too?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
Can you implement a check for ppc64x here too?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |