[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