aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/rewrite.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/ssa/rewrite.go')
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go77
1 files changed, 76 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 9961b540b7..f9566368c0 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -1589,7 +1589,7 @@ func mergePPC64AndSrwi(m, s int64) int64 {
return encodePPC64RotateMask((32-s)&31, mask, 32)
}
-// Test if a shift right feeding into a CLRLSLDI can be merged into RLWINM.
+// Test if a word shift right feeding into a CLRLSLDI can be merged into RLWINM.
// Return the encoded RLWINM constant, or 0 if they cannot be merged.
func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
mask_1 := uint64(0xFFFFFFFF >> uint(srw))
@@ -1609,6 +1609,31 @@ func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
return encodePPC64RotateMask(int64(r_3), int64(mask_3), 32)
}
+// Test if a doubleword shift right feeding into a CLRLSLDI can be merged into RLWINM.
+// Return the encoded RLWINM constant, or 0 if they cannot be merged.
+func mergePPC64ClrlsldiSrd(sld, srd int64) int64 {
+ mask_1 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(srd)
+ // for CLRLSLDI, it's more convenient to think of it as a mask left bits then rotate left.
+ mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
+
+ // Rewrite mask to apply after the final left shift.
+ mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
+
+ r_1 := 64 - srd
+ r_2 := GetPPC64Shiftsh(sld)
+ r_3 := (r_1 + r_2) & 63 // This can wrap.
+
+ if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
+ return 0
+ }
+ // This combine only works when selecting and shifting the lower 32 bits.
+ v1 := bits.RotateLeft64(0xFFFFFFFF00000000, int(r_3))
+ if v1&mask_3 != 0 {
+ return 0
+ }
+ return encodePPC64RotateMask(int64(r_3-32), int64(mask_3), 32)
+}
+
// Test if a RLWINM feeding into a CLRLSLDI can be merged into RLWINM. Return
// the encoded RLWINM constant, or 0 if they cannot be merged.
func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
@@ -1628,6 +1653,56 @@ func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
return encodePPC64RotateMask(r_3, int64(mask_3), 32)
}
+// Test if RLWINM feeding into an ANDconst can be merged. Return the encoded RLWINM constant,
+// or 0 if they cannot be merged.
+func mergePPC64AndRlwinm(mask uint32, rlw int64) int64 {
+ r, _, _, mask_rlw := DecodePPC64RotateMask(rlw)
+ mask_out := (mask_rlw & uint64(mask))
+
+ // Verify the result is still a valid bitmask of <= 32 bits.
+ if !isPPC64WordRotateMask(int64(mask_out)) {
+ return 0
+ }
+ return encodePPC64RotateMask(r, int64(mask_out), 32)
+}
+
+// Test if AND feeding into an ANDconst can be merged. Return the encoded RLWINM constant,
+// or 0 if they cannot be merged.
+func mergePPC64RlwinmAnd(rlw int64, mask uint32) int64 {
+ r, _, _, mask_rlw := DecodePPC64RotateMask(rlw)
+
+ // Rotate the input mask, combine with the rlwnm mask, and test if it is still a valid rlwinm mask.
+ r_mask := bits.RotateLeft32(mask, int(r))
+
+ mask_out := (mask_rlw & uint64(r_mask))
+
+ // Verify the result is still a valid bitmask of <= 32 bits.
+ if !isPPC64WordRotateMask(int64(mask_out)) {
+ return 0
+ }
+ return encodePPC64RotateMask(r, int64(mask_out), 32)
+}
+
+// Test if RLWINM feeding into SRDconst can be merged. Return the encoded RLIWNM constant,
+// or 0 if they cannot be merged.
+func mergePPC64SldiRlwinm(sldi, rlw int64) int64 {
+ r_1, mb, me, mask_1 := DecodePPC64RotateMask(rlw)
+ if mb > me || mb < sldi {
+ // Wrapping masks cannot be merged as the upper 32 bits are effectively undefined in this case.
+ // Likewise, if mb is less than the shift amount, it cannot be merged.
+ return 0
+ }
+ // combine the masks, and adjust for the final left shift.
+ mask_3 := mask_1 << sldi
+ r_3 := (r_1 + sldi) & 31 // This can wrap.
+
+ // Verify the result is still a valid bitmask of <= 32 bits.
+ if uint64(uint32(mask_3)) != mask_3 {
+ return 0
+ }
+ return encodePPC64RotateMask(r_3, int64(mask_3), 32)
+}
+
// Compute the encoded RLWINM constant from combining (SLDconst [sld] (SRWconst [srw] x)),
// or return 0 if they cannot be combined.
func mergePPC64SldiSrw(sld, srw int64) int64 {