[llvm] [ARM] Avoid materializing constant 1 when generating cneg instructions (PR #146591)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 1 12:06:20 PDT 2025


https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/146591

Port to ARM.

>From b22b3b870008e83fe0ac9dbd990ab15b13d2d1ae Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 1 Jul 2025 14:59:12 -0400
Subject: [PATCH 1/2] [Thumb2] Pre-commit tests (NFC)

---
 llvm/test/CodeGen/Thumb2/csel.ll | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/llvm/test/CodeGen/Thumb2/csel.ll b/llvm/test/CodeGen/Thumb2/csel.ll
index d786bc076aff9..e96b46e845d45 100644
--- a/llvm/test/CodeGen/Thumb2/csel.ll
+++ b/llvm/test/CodeGen/Thumb2/csel.ll
@@ -379,3 +379,17 @@ entry:
   %t = add i32 %s, %b
   ret i32 %t
 }
+
+; Rather than use a CNEG, use a CSINV to transform "a == 1 ? 1 : -1" toAdd commentMore actions
+; "a == 1 ? a : -1" to avoid materializing a constant.
+define i32 @test_cneg(i32 %x) {
+; CHECK-LABEL: test_cneg:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    movs r1, #1
+; CHECK-NEXT:    cmp r0, #1
+; CHECK-NEXT:    cneg r0, r1, ne
+; CHECK-NEXT:    bx lr
+  %cmp = icmp eq i32 %x, 1
+  %res = select i1 %cmp, i32 1, i32 -1
+  ret i32 %res
+}

>From 8ad3063397eb7d5eca882c958ffbf6fdb393cf05 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 1 Jul 2025 15:05:48 -0400
Subject: [PATCH 2/2] [ARM] Avoid materializing constant 1 when generating cneg
 instructions

Port to ARM
---
 llvm/lib/Target/ARM/ARMISelLowering.cpp | 12 ++++++++++++
 llvm/test/CodeGen/Thumb2/csel.ll        |  3 +--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 2f89e23993385..d9bea6c646ccf 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -5530,6 +5530,18 @@ SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
       CC = ISD::getSetCCInverse(CC, LHS.getValueType());
     }
 
+    ConstantSDNode *RHSVal = dyn_cast<ConstantSDNode>(RHS);
+    if (Opcode == ARMISD::CSNEG && RHSVal && RHSVal->isOne()) {
+      assert(CTVal && CFVal && "Expected constant operands for CSNEG.");
+      // Use a CSINV to transform "a == C ? 1 : -1" to "a == C ? a : -1" to
+      // avoid materializing C.
+      if (CTVal == RHSVal && CC == ISD::SETEQ) {
+        Opcode = ARMISD::CSINV;
+        TrueVal = LHS;
+        FalseVal = DAG.getConstant(0, dl, FalseVal.getValueType());
+      }
+    }
+
     if (Opcode) {
       // If one of the constants is cheaper than another, materialise the
       // cheaper one and let the csel generate the other.
diff --git a/llvm/test/CodeGen/Thumb2/csel.ll b/llvm/test/CodeGen/Thumb2/csel.ll
index e96b46e845d45..4a40c79edad41 100644
--- a/llvm/test/CodeGen/Thumb2/csel.ll
+++ b/llvm/test/CodeGen/Thumb2/csel.ll
@@ -385,9 +385,8 @@ entry:
 define i32 @test_cneg(i32 %x) {
 ; CHECK-LABEL: test_cneg:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    movs r1, #1
 ; CHECK-NEXT:    cmp r0, #1
-; CHECK-NEXT:    cneg r0, r1, ne
+; CHECK-NEXT:    cinv r0, r0, ne
 ; CHECK-NEXT:    bx lr
   %cmp = icmp eq i32 %x, 1
   %res = select i1 %cmp, i32 1, i32 -1



More information about the llvm-commits mailing list