[llvm] [SelectionDAG] Allow lowering CTPOP into a libcall (PR #99752)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 21 03:00:16 PDT 2024


https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/99752

>From bb8a735facb710a07601d3bc9c45316f0de9d68d Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sat, 20 Jul 2024 13:11:56 +0300
Subject: [PATCH 1/2] [SelectionDAG] Allow lowering CTPOP into a libcall

Some in-tree targets (e.g. ARM) could benefit from this lowering,
at least in opt-size mode, but I don't know if the libcall
is available in their libgcc, so no tests.
---
 llvm/include/llvm/IR/RuntimeLibcalls.def      |  3 ++
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 38 +++++++++----------
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def
index 89aaf6d1ad83f..3dd75622b8e43 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.def
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.def
@@ -85,6 +85,9 @@ HANDLE_LIBCALL(NEG_I64, "__negdi2")
 HANDLE_LIBCALL(CTLZ_I32, "__clzsi2")
 HANDLE_LIBCALL(CTLZ_I64, "__clzdi2")
 HANDLE_LIBCALL(CTLZ_I128, "__clzti2")
+HANDLE_LIBCALL(CTPOP_I32, "__popcountsi2")
+HANDLE_LIBCALL(CTPOP_I64, "__popcountdi2")
+HANDLE_LIBCALL(CTPOP_I128, "__popcountti2")
 
 // Floating-point
 HANDLE_LIBCALL(ADD_F32, "__addsf3")
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 9f515739ee048..bfae5671d8b77 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -140,12 +140,9 @@ class SelectionDAGLegalize {
                        RTLIB::Libcall Call_F128,
                        RTLIB::Libcall Call_PPCF128,
                        SmallVectorImpl<SDValue> &Results);
-  SDValue ExpandIntLibCall(SDNode *Node, bool isSigned,
-                           RTLIB::Libcall Call_I8,
-                           RTLIB::Libcall Call_I16,
-                           RTLIB::Libcall Call_I32,
-                           RTLIB::Libcall Call_I64,
-                           RTLIB::Libcall Call_I128);
+  SDValue ExpandIntLibCall(SDNode *Node, bool IsSigned, RTLIB::Libcall Call_I8,
+                           RTLIB::Libcall Call_I16, RTLIB::Libcall Call_I32,
+                           RTLIB::Libcall Call_I64, RTLIB::Libcall Call_I128);
   void ExpandArgFPLibCall(SDNode *Node,
                           RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64,
                           RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128,
@@ -2209,7 +2206,7 @@ void SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node,
   ExpandFPLibCall(Node, LC, Results);
 }
 
-SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode* Node, bool isSigned,
+SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode *Node, bool IsSigned,
                                                RTLIB::Libcall Call_I8,
                                                RTLIB::Libcall Call_I16,
                                                RTLIB::Libcall Call_I32,
@@ -2224,7 +2221,9 @@ SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode* Node, bool isSigned,
   case MVT::i64:  LC = Call_I64; break;
   case MVT::i128: LC = Call_I128; break;
   }
-  return ExpandLibCall(LC, Node, isSigned).first;
+  assert(LC != RTLIB::UNKNOWN_LIBCALL &&
+         "LibCall explicitly requested, but not available");
+  return ExpandLibCall(LC, Node, IsSigned).first;
 }
 
 /// Expand the node to a libcall based on first argument type (for instance
@@ -4980,19 +4979,16 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
                                        RTLIB::MUL_I64, RTLIB::MUL_I128));
     break;
   case ISD::CTLZ_ZERO_UNDEF:
-    switch (Node->getSimpleValueType(0).SimpleTy) {
-    default:
-      llvm_unreachable("LibCall explicitly requested, but not available");
-    case MVT::i32:
-      Results.push_back(ExpandLibCall(RTLIB::CTLZ_I32, Node, false).first);
-      break;
-    case MVT::i64:
-      Results.push_back(ExpandLibCall(RTLIB::CTLZ_I64, Node, false).first);
-      break;
-    case MVT::i128:
-      Results.push_back(ExpandLibCall(RTLIB::CTLZ_I128, Node, false).first);
-      break;
-    }
+    Results.push_back(ExpandIntLibCall(Node, /*IsSigned=*/false,
+                                       RTLIB::UNKNOWN_LIBCALL,
+                                       RTLIB::UNKNOWN_LIBCALL, RTLIB::CTLZ_I32,
+                                       RTLIB::CTLZ_I64, RTLIB::CTLZ_I128));
+    break;
+  case ISD::CTPOP:
+    Results.push_back(ExpandIntLibCall(Node, /*IsSigned=*/false,
+                                       RTLIB::UNKNOWN_LIBCALL,
+                                       RTLIB::UNKNOWN_LIBCALL, RTLIB::CTPOP_I32,
+                                       RTLIB::CTPOP_I64, RTLIB::CTPOP_I128));
     break;
   case ISD::RESET_FPENV: {
     // It is legalized to call 'fesetenv(FE_DFL_ENV)'. On most targets

>From 437a0e5d0e6f3688bc9d7de13a412bb234d7f574 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 21 Jul 2024 12:53:02 +0300
Subject: [PATCH 2/2] [ARM] Lower 32-bit CTPOP to a libcall

---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  5 +-
 llvm/lib/Target/ARM/ARMISelLowering.cpp       |  2 +-
 llvm/test/CodeGen/ARM/popcnt.ll               | 70 +++---------------
 llvm/test/CodeGen/Thumb2/mve-ctpop.ll         | 74 +++++++------------
 4 files changed, 40 insertions(+), 111 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 140c97ccd90ba..a273fafd3f4d6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9127,8 +9127,9 @@ SDValue TargetLowering::expandCTTZ(SDNode *Node, SelectionDAG &DAG) const {
                         !isOperationLegalOrCustomOrPromote(ISD::XOR, VT)))
     return SDValue();
 
-  // Emit Table Lookup if ISD::CTLZ and ISD::CTPOP are not legal.
-  if (!VT.isVector() && isOperationExpand(ISD::CTPOP, VT) &&
+  // Emit Table Lookup if ISD::CTPOP used in the fallback path below is going
+  // to be expanded or converted to a libcall.
+  if (!VT.isVector() && !isOperationLegalOrCustomOrPromote(ISD::CTPOP, VT) &&
       !isOperationLegal(ISD::CTLZ, VT))
     if (SDValue V = CTTZTableLookup(Node, DAG, dl, VT, Op, NumBitsPerElt))
       return V;
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 2683b5741d459..2c0fd20e76d60 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1204,7 +1204,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::ROTR, VT, Expand);
   }
   setOperationAction(ISD::CTTZ,  MVT::i32, Custom);
-  setOperationAction(ISD::CTPOP, MVT::i32, Expand);
+  setOperationAction(ISD::CTPOP, MVT::i32, LibCall);
   if (!Subtarget->hasV5TOps() || Subtarget->isThumb1Only()) {
     setOperationAction(ISD::CTLZ, MVT::i32, Expand);
     setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, LibCall);
diff --git a/llvm/test/CodeGen/ARM/popcnt.ll b/llvm/test/CodeGen/ARM/popcnt.ll
index edcae5e141e73..d3d66d6d52979 100644
--- a/llvm/test/CodeGen/ARM/popcnt.ll
+++ b/llvm/test/CodeGen/ARM/popcnt.ll
@@ -324,30 +324,7 @@ define i32 @ctpop16(i16 %x) nounwind readnone {
 define i32 @ctpop32(i32 %x) nounwind readnone {
 ; CHECK-LABEL: ctpop32:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    ldr r1, .LCPI22_0
-; CHECK-NEXT:    ldr r2, .LCPI22_3
-; CHECK-NEXT:    and r1, r1, r0, lsr #1
-; CHECK-NEXT:    ldr r12, .LCPI22_1
-; CHECK-NEXT:    sub r0, r0, r1
-; CHECK-NEXT:    ldr r3, .LCPI22_2
-; CHECK-NEXT:    and r1, r0, r2
-; CHECK-NEXT:    and r0, r2, r0, lsr #2
-; CHECK-NEXT:    add r0, r1, r0
-; CHECK-NEXT:    add r0, r0, r0, lsr #4
-; CHECK-NEXT:    and r0, r0, r12
-; CHECK-NEXT:    mul r1, r0, r3
-; CHECK-NEXT:    lsr r0, r1, #24
-; CHECK-NEXT:    mov pc, lr
-; CHECK-NEXT:    .p2align 2
-; CHECK-NEXT:  @ %bb.1:
-; CHECK-NEXT:  .LCPI22_0:
-; CHECK-NEXT:    .long 1431655765 @ 0x55555555
-; CHECK-NEXT:  .LCPI22_1:
-; CHECK-NEXT:    .long 252645135 @ 0xf0f0f0f
-; CHECK-NEXT:  .LCPI22_2:
-; CHECK-NEXT:    .long 16843009 @ 0x1010101
-; CHECK-NEXT:  .LCPI22_3:
-; CHECK-NEXT:    .long 858993459 @ 0x33333333
+; CHECK-NEXT:    b __popcountsi2
   %count = tail call i32 @llvm.ctpop.i32(i32 %x)
   ret i32 %count
 }
@@ -355,42 +332,17 @@ define i32 @ctpop32(i32 %x) nounwind readnone {
 define i32 @ctpop64(i64 %x) nounwind readnone {
 ; CHECK-LABEL: ctpop64:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    .save {r4, lr}
-; CHECK-NEXT:    push {r4, lr}
-; CHECK-NEXT:    ldr r2, .LCPI23_0
-; CHECK-NEXT:    ldr r3, .LCPI23_3
-; CHECK-NEXT:    and r4, r2, r0, lsr #1
-; CHECK-NEXT:    and r2, r2, r1, lsr #1
-; CHECK-NEXT:    sub r0, r0, r4
-; CHECK-NEXT:    sub r1, r1, r2
-; CHECK-NEXT:    and r4, r0, r3
-; CHECK-NEXT:    and r2, r1, r3
-; CHECK-NEXT:    and r0, r3, r0, lsr #2
-; CHECK-NEXT:    and r1, r3, r1, lsr #2
-; CHECK-NEXT:    add r0, r4, r0
-; CHECK-NEXT:    ldr lr, .LCPI23_1
-; CHECK-NEXT:    add r1, r2, r1
-; CHECK-NEXT:    ldr r12, .LCPI23_2
-; CHECK-NEXT:    add r0, r0, r0, lsr #4
-; CHECK-NEXT:    and r0, r0, lr
-; CHECK-NEXT:    add r1, r1, r1, lsr #4
-; CHECK-NEXT:    mul r2, r0, r12
-; CHECK-NEXT:    and r0, r1, lr
-; CHECK-NEXT:    mul r1, r0, r12
-; CHECK-NEXT:    lsr r0, r2, #24
-; CHECK-NEXT:    add r0, r0, r1, lsr #24
-; CHECK-NEXT:    pop {r4, lr}
+; CHECK-NEXT:    .save {r4, r5, r11, lr}
+; CHECK-NEXT:    push {r4, r5, r11, lr}
+; CHECK-NEXT:    mov r4, r0
+; CHECK-NEXT:    mov r0, r1
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    mov r5, r0
+; CHECK-NEXT:    mov r0, r4
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    add r0, r0, r5
+; CHECK-NEXT:    pop {r4, r5, r11, lr}
 ; CHECK-NEXT:    mov pc, lr
-; CHECK-NEXT:    .p2align 2
-; CHECK-NEXT:  @ %bb.1:
-; CHECK-NEXT:  .LCPI23_0:
-; CHECK-NEXT:    .long 1431655765 @ 0x55555555
-; CHECK-NEXT:  .LCPI23_1:
-; CHECK-NEXT:    .long 252645135 @ 0xf0f0f0f
-; CHECK-NEXT:  .LCPI23_2:
-; CHECK-NEXT:    .long 16843009 @ 0x1010101
-; CHECK-NEXT:  .LCPI23_3:
-; CHECK-NEXT:    .long 858993459 @ 0x33333333
   %count = tail call i64 @llvm.ctpop.i64(i64 %x)
   %conv = trunc i64 %count to i32
   ret i32 %conv
diff --git a/llvm/test/CodeGen/Thumb2/mve-ctpop.ll b/llvm/test/CodeGen/Thumb2/mve-ctpop.ll
index 724bd4f7963b8..dcba42db886ae 100644
--- a/llvm/test/CodeGen/Thumb2/mve-ctpop.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-ctpop.ll
@@ -1,58 +1,34 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; NOTE: Assertions have been autoenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve.fp -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK
 
 define arm_aapcs_vfpcc <2 x i64> @ctpop_2i64_t(<2 x i64> %src){
 ; CHECK-LABEL: ctpop_2i64_t:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    .save {r4, r5, r7, lr}
-; CHECK-NEXT:    push {r4, r5, r7, lr}
-; CHECK-NEXT:    vmov r1, r2, d1
-; CHECK-NEXT:    mov.w lr, #1431655765
-; CHECK-NEXT:    vmov r3, r4, d0
-; CHECK-NEXT:    mov.w r12, #858993459
-; CHECK-NEXT:    vldr s1, .LCPI0_0
-; CHECK-NEXT:    vmov.f32 s3, s1
-; CHECK-NEXT:    and.w r0, lr, r2, lsr #1
-; CHECK-NEXT:    subs r0, r2, r0
-; CHECK-NEXT:    and.w r2, r12, r0, lsr #2
-; CHECK-NEXT:    bic r0, r0, #-858993460
-; CHECK-NEXT:    add r0, r2
-; CHECK-NEXT:    and.w r2, lr, r1, lsr #1
-; CHECK-NEXT:    subs r1, r1, r2
-; CHECK-NEXT:    add.w r0, r0, r0, lsr #4
-; CHECK-NEXT:    and.w r2, r12, r1, lsr #2
-; CHECK-NEXT:    bic r1, r1, #-858993460
-; CHECK-NEXT:    add r1, r2
-; CHECK-NEXT:    and.w r2, lr, r3, lsr #1
-; CHECK-NEXT:    subs r2, r3, r2
-; CHECK-NEXT:    bic r5, r0, #-252645136
-; CHECK-NEXT:    add.w r1, r1, r1, lsr #4
-; CHECK-NEXT:    mov.w r0, #16843009
-; CHECK-NEXT:    and.w r3, r12, r2, lsr #2
-; CHECK-NEXT:    bic r2, r2, #-858993460
-; CHECK-NEXT:    add r2, r3
-; CHECK-NEXT:    and.w r3, lr, r4, lsr #1
-; CHECK-NEXT:    subs r3, r4, r3
-; CHECK-NEXT:    bic r1, r1, #-252645136
-; CHECK-NEXT:    add.w r2, r2, r2, lsr #4
-; CHECK-NEXT:    muls r5, r0, r5
-; CHECK-NEXT:    and.w r4, r12, r3, lsr #2
-; CHECK-NEXT:    bic r3, r3, #-858993460
-; CHECK-NEXT:    bic r2, r2, #-252645136
-; CHECK-NEXT:    add r3, r4
-; CHECK-NEXT:    muls r1, r0, r1
-; CHECK-NEXT:    add.w r3, r3, r3, lsr #4
-; CHECK-NEXT:    muls r2, r0, r2
-; CHECK-NEXT:    bic r3, r3, #-252645136
-; CHECK-NEXT:    muls r0, r3, r0
-; CHECK-NEXT:    lsrs r1, r1, #24
-; CHECK-NEXT:    add.w r1, r1, r5, lsr #24
-; CHECK-NEXT:    lsrs r2, r2, #24
-; CHECK-NEXT:    vmov s2, r1
-; CHECK-NEXT:    add.w r0, r2, r0, lsr #24
-; CHECK-NEXT:    vmov s0, r0
-; CHECK-NEXT:    pop {r4, r5, r7, pc}
+; CHECK-NEXT:    .save {r4, r5, r6, lr}
+; CHECK-NEXT:    push {r4, r5, r6, lr}
+; CHECK-NEXT:    .vsave {d8, d9}
+; CHECK-NEXT:    vpush {d8, d9}
+; CHECK-NEXT:    vmov q4, q0
+; CHECK-NEXT:    vmov r4, r0, d9
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    mov r5, r0
+; CHECK-NEXT:    mov r0, r4
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    vmov r4, r1, d8
+; CHECK-NEXT:    adds r6, r0, r5
+; CHECK-NEXT:    vldr s17, .LCPI0_0
+; CHECK-NEXT:    mov r0, r1
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    mov r5, r0
+; CHECK-NEXT:    mov r0, r4
+; CHECK-NEXT:    vmov s18, r6
+; CHECK-NEXT:    bl __popcountsi2
+; CHECK-NEXT:    add r0, r5
+; CHECK-NEXT:    vmov.f32 s19, s17
+; CHECK-NEXT:    vmov s16, r0
+; CHECK-NEXT:    vmov q0, q4
+; CHECK-NEXT:    vpop {d8, d9}
+; CHECK-NEXT:    pop {r4, r5, r6, pc}
 ; CHECK-NEXT:    .p2align 2
 ; CHECK-NEXT:  @ %bb.1:
 ; CHECK-NEXT:  .LCPI0_0:



More information about the llvm-commits mailing list