[llvm] [PowerPC] Enable custom lowering for bswap64 builtin on Power8 64 bits with improved parallelism (PR #187259)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 22:59:10 PDT 2026
https://github.com/Himadhith updated https://github.com/llvm/llvm-project/pull/187259
>From 2c1b11ca3d4c5417ee132bbdb5406aa7942ae0eb Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Wed, 18 Mar 2026 08:32:00 -0400
Subject: [PATCH 1/3] [PowerPC] Enable custom lowering for bswap64 builtin on
Power8 64 bits with improved parallelism
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 61 ++++++++++++++++++++-
llvm/test/CodeGen/PowerPC/bswap64.ll | 26 ++++-----
2 files changed, 69 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 753306a8d365b..e2d63dfcbd1bb 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -485,8 +485,11 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::BSWAP, MVT::i64, Legal);
} else {
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
- setOperationAction(ISD::BSWAP, MVT::i64,
- (Subtarget.hasP9Vector() && isPPC64) ? Custom : Expand);
+ setOperationAction(
+ ISD::BSWAP, MVT::i64,
+ ((Subtarget.hasP9Vector() || Subtarget.hasP8Vector()) && isPPC64)
+ ? Custom
+ : Expand);
}
// CTPOP or CTTZ were introduced in P8/P9 respectively
@@ -11622,6 +11625,60 @@ SDValue PPCTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
if (!Subtarget.isPPC64())
return Op;
+
+ // Apply the optimization to Power8 and 64-bits which allows parallelism for
+ // rotate instructions which should make the bswap64 builtin faster.
+ if (Subtarget.hasP8Vector() && !Subtarget.hasP9Vector()) {
+ SDValue Input = Op.getOperand(0);
+
+ // Extract high and low 32 bits
+ SDValue Hi32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32,
+ DAG.getNode(ISD::SRL, dl, MVT::i64, Input,
+ DAG.getConstant(32, dl, MVT::i64)));
+ SDValue Lo32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Input);
+
+ // Swap high 32 bits using: rotl + 2x rlwimi
+ SDValue HiRot = DAG.getNode(ISD::ROTL, dl, MVT::i32, Hi32,
+ DAG.getConstant(8, dl, MVT::i32));
+ SDValue HiSwap =
+ SDValue(DAG.getMachineNode(PPC::RLWIMI, dl, MVT::i32,
+ {HiRot, Hi32,
+ DAG.getTargetConstant(24, dl, MVT::i32),
+ DAG.getTargetConstant(0, dl, MVT::i32),
+ DAG.getTargetConstant(7, dl, MVT::i32)}),
+ 0);
+ HiSwap = SDValue(DAG.getMachineNode(
+ PPC::RLWIMI, dl, MVT::i32,
+ {HiSwap, Hi32, DAG.getTargetConstant(24, dl, MVT::i32),
+ DAG.getTargetConstant(16, dl, MVT::i32),
+ DAG.getTargetConstant(23, dl, MVT::i32)}),
+ 0);
+
+ SDValue LoRot = DAG.getNode(ISD::ROTL, dl, MVT::i32, Lo32,
+ DAG.getConstant(8, dl, MVT::i32));
+ SDValue LoSwap =
+ SDValue(DAG.getMachineNode(PPC::RLWIMI, dl, MVT::i32,
+ {LoRot, Lo32,
+ DAG.getTargetConstant(24, dl, MVT::i32),
+ DAG.getTargetConstant(0, dl, MVT::i32),
+ DAG.getTargetConstant(7, dl, MVT::i32)}),
+ 0);
+ LoSwap = SDValue(DAG.getMachineNode(
+ PPC::RLWIMI, dl, MVT::i32,
+ {LoSwap, Lo32, DAG.getTargetConstant(24, dl, MVT::i32),
+ DAG.getTargetConstant(16, dl, MVT::i32),
+ DAG.getTargetConstant(23, dl, MVT::i32)}),
+ 0);
+
+ // Combine: (LoSwap << 32) | HiSwap using rldimi
+ HiSwap = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, HiSwap);
+ LoSwap = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, LoSwap);
+ return SDValue(DAG.getMachineNode(PPC::RLDIMI, dl, MVT::i64,
+ {HiSwap, LoSwap,
+ DAG.getTargetConstant(32, dl, MVT::i32),
+ DAG.getTargetConstant(0, dl, MVT::i32)}),
+ 0);
+ }
// MTVSRDD
Op = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v2i64, Op.getOperand(0),
Op.getOperand(0));
diff --git a/llvm/test/CodeGen/PowerPC/bswap64.ll b/llvm/test/CodeGen/PowerPC/bswap64.ll
index 5a8eca0fba9d4..b16c9b434b0fd 100644
--- a/llvm/test/CodeGen/PowerPC/bswap64.ll
+++ b/llvm/test/CodeGen/PowerPC/bswap64.ll
@@ -14,25 +14,19 @@
declare i64 @llvm.bswap.i64(i64)
-; For now both the set of instructions for P8 are unoptimized versions.
-; A future patch will leverage parallelism and improve the
-; efficiency and performance.
+; This patch verifies that the compiler generates optimized assembly for Power 8 64-bit
+; byte swap operations that enables instruction-level parallelism.
define i64 @bswap64(i64 %x) {
; POWER-8-LABEL: bswap64:
; POWER-8: # %bb.0: # %entry
-; POWER-8-NEXT: rotldi 5, 3, 16
-; POWER-8-NEXT: rotldi 4, 3, 8
-; POWER-8-NEXT: rldimi 4, 5, 8, 48
-; POWER-8-NEXT: rotldi 5, 3, 24
-; POWER-8-NEXT: rldimi 4, 5, 16, 40
-; POWER-8-NEXT: rotldi 5, 3, 32
-; POWER-8-NEXT: rldimi 4, 5, 24, 32
-; POWER-8-NEXT: rotldi 5, 3, 48
-; POWER-8-NEXT: rldimi 4, 5, 40, 16
-; POWER-8-NEXT: rotldi 5, 3, 56
-; POWER-8-NEXT: rldimi 4, 5, 48, 8
-; POWER-8-NEXT: rldimi 4, 3, 56, 0
-; POWER-8-NEXT: mr 3, 4
+; POWER-8-NEXT: rotlwi 4, 3, 8
+; POWER-8-NEXT: rldicl 5, 3, 32, 32
+; POWER-8-NEXT: rlwimi 4, 3, 24, 0, 7
+; POWER-8-NEXT: rlwimi 4, 3, 24, 16, 23
+; POWER-8-NEXT: rotlwi 3, 5, 8
+; POWER-8-NEXT: rlwimi 3, 5, 24, 0, 7
+; POWER-8-NEXT: rlwimi 3, 5, 24, 16, 23
+; POWER-8-NEXT: rldimi 3, 4, 32, 0
; POWER-8-NEXT: blr
;
; POWER-8-NO-ALTIVEC-LABEL: bswap64:
>From e3a67c6a04f39d60e7dd40680c6c660056dac95b Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Tue, 31 Mar 2026 09:12:20 -0400
Subject: [PATCH 2/3] Refactoring using lambda and adding affected test
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 52 ++++++++-------------
llvm/test/CodeGen/PowerPC/pr35402.ll | 18 +++----
2 files changed, 28 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index e2d63dfcbd1bb..d8a9f7b82236e 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -11631,46 +11631,32 @@ SDValue PPCTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
if (Subtarget.hasP8Vector() && !Subtarget.hasP9Vector()) {
SDValue Input = Op.getOperand(0);
- // Extract high and low 32 bits
- SDValue Hi32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32,
- DAG.getNode(ISD::SRL, dl, MVT::i64, Input,
- DAG.getConstant(32, dl, MVT::i64)));
- SDValue Lo32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Input);
-
- // Swap high 32 bits using: rotl + 2x rlwimi
- SDValue HiRot = DAG.getNode(ISD::ROTL, dl, MVT::i32, Hi32,
+ auto Swap32 = [&](SDValue Val32) -> SDValue {
+ SDValue Rot = DAG.getNode(ISD::ROTL, dl, MVT::i32, Val32,
DAG.getConstant(8, dl, MVT::i32));
- SDValue HiSwap =
- SDValue(DAG.getMachineNode(PPC::RLWIMI, dl, MVT::i32,
- {HiRot, Hi32,
- DAG.getTargetConstant(24, dl, MVT::i32),
- DAG.getTargetConstant(0, dl, MVT::i32),
- DAG.getTargetConstant(7, dl, MVT::i32)}),
- 0);
- HiSwap = SDValue(DAG.getMachineNode(
+ SDValue Swap =
+ SDValue(DAG.getMachineNode(PPC::RLWIMI, dl, MVT::i32,
+ {Rot, Val32,
+ DAG.getTargetConstant(24, dl, MVT::i32),
+ DAG.getTargetConstant(0, dl, MVT::i32),
+ DAG.getTargetConstant(7, dl, MVT::i32)}),
+ 0);
+ return SDValue(DAG.getMachineNode(
PPC::RLWIMI, dl, MVT::i32,
- {HiSwap, Hi32, DAG.getTargetConstant(24, dl, MVT::i32),
+ {Swap, Val32, DAG.getTargetConstant(24, dl, MVT::i32),
DAG.getTargetConstant(16, dl, MVT::i32),
DAG.getTargetConstant(23, dl, MVT::i32)}),
0);
+ };
- SDValue LoRot = DAG.getNode(ISD::ROTL, dl, MVT::i32, Lo32,
- DAG.getConstant(8, dl, MVT::i32));
- SDValue LoSwap =
- SDValue(DAG.getMachineNode(PPC::RLWIMI, dl, MVT::i32,
- {LoRot, Lo32,
- DAG.getTargetConstant(24, dl, MVT::i32),
- DAG.getTargetConstant(0, dl, MVT::i32),
- DAG.getTargetConstant(7, dl, MVT::i32)}),
- 0);
- LoSwap = SDValue(DAG.getMachineNode(
- PPC::RLWIMI, dl, MVT::i32,
- {LoSwap, Lo32, DAG.getTargetConstant(24, dl, MVT::i32),
- DAG.getTargetConstant(16, dl, MVT::i32),
- DAG.getTargetConstant(23, dl, MVT::i32)}),
- 0);
+ SDValue Hi32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32,
+ DAG.getNode(ISD::SRL, dl, MVT::i64, Input,
+ DAG.getConstant(32, dl, MVT::i64)));
+ SDValue Lo32 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Input);
+
+ SDValue HiSwap = Swap32(Hi32);
+ SDValue LoSwap = Swap32(Lo32);
- // Combine: (LoSwap << 32) | HiSwap using rldimi
HiSwap = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, HiSwap);
LoSwap = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, LoSwap);
return SDValue(DAG.getMachineNode(PPC::RLDIMI, dl, MVT::i64,
diff --git a/llvm/test/CodeGen/PowerPC/pr35402.ll b/llvm/test/CodeGen/PowerPC/pr35402.ll
index bcbae3bbbb973..015b7fbcb96fc 100644
--- a/llvm/test/CodeGen/PowerPC/pr35402.ll
+++ b/llvm/test/CodeGen/PowerPC/pr35402.ll
@@ -5,17 +5,17 @@ target triple = "powerpc64le-linux-gnu"
define void @test(ptr %p, i64 %data) {
; CHECK-LABEL: test:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: rotldi 5, 4, 16
-; CHECK-NEXT: rldicl 6, 4, 8, 56
-; CHECK-NEXT: rldimi 6, 5, 8, 48
-; CHECK-NEXT: rotldi 5, 4, 24
-; CHECK-NEXT: rldimi 6, 5, 16, 40
-; CHECK-NEXT: rotldi 5, 4, 32
-; CHECK-NEXT: rldimi 6, 5, 24, 32
-; CHECK-NEXT: rlwinm 5, 4, 8, 24, 31
+; CHECK-NEXT: rotlwi 5, 4, 8
+; CHECK-NEXT: rlwimi 5, 4, 24, 0, 7
; CHECK-NEXT: rlwimi 5, 4, 24, 16, 23
+; CHECK-NEXT: rldicl 4, 4, 32, 32
+; CHECK-NEXT: rotlwi 6, 4, 8
+; CHECK-NEXT: rlwimi 6, 4, 24, 0, 7
+; CHECK-NEXT: rlwimi 6, 4, 24, 16, 23
+; CHECK-NEXT: rldimi 6, 5, 32, 0
+; CHECK-NEXT: rldicl 4, 6, 32, 32
; CHECK-NEXT: stw 6, 0(3)
-; CHECK-NEXT: sth 5, 4(3)
+; CHECK-NEXT: sth 4, 4(3)
; CHECK-NEXT: blr
entry:
%0 = tail call i64 @llvm.bswap.i64(i64 %data)
>From 8453b9aa615257a28a2992869d554285c54adec6 Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Tue, 31 Mar 2026 11:53:35 -0400
Subject: [PATCH 3/3] Minor change
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index d8a9f7b82236e..26a033b5cf9a8 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -485,11 +485,9 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::BSWAP, MVT::i64, Legal);
} else {
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
- setOperationAction(
- ISD::BSWAP, MVT::i64,
- ((Subtarget.hasP9Vector() || Subtarget.hasP8Vector()) && isPPC64)
- ? Custom
- : Expand);
+ setOperationAction(ISD::BSWAP, MVT::i64,
+ ((Subtarget.hasP8Vector()) && isPPC64) ? Custom
+ : Expand);
}
// CTPOP or CTTZ were introduced in P8/P9 respectively
@@ -11628,7 +11626,7 @@ SDValue PPCTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
// Apply the optimization to Power8 and 64-bits which allows parallelism for
// rotate instructions which should make the bswap64 builtin faster.
- if (Subtarget.hasP8Vector() && !Subtarget.hasP9Vector()) {
+ if (!Subtarget.hasP9Vector()) {
SDValue Input = Op.getOperand(0);
auto Swap32 = [&](SDValue Val32) -> SDValue {
More information about the llvm-commits
mailing list