[llvm] [ARM] Improve i16 zext-load equality compares (PR #196862)

via llvm-commits llvm-commits at lists.llvm.org
Sun May 10 18:22:42 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: LumioseSil (LumioseSil)

<details>
<summary>Changes</summary>

Ported from aarch64

---
Full diff: https://github.com/llvm/llvm-project/pull/196862.diff


3 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+1-1) 
- (modified) llvm/lib/Target/ARM/ARMISelLowering.cpp (+34) 
- (added) llvm/test/CodeGen/ARM/cmpwithshort.ll (+127) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 8dd94e1418400..7c9d76e116cf6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -4299,7 +4299,7 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
     // >
     // ldrsh w0, [x0, #0]
     // cmn w0, #1
-    // Fundamental, we're relying on the property that (zext LHS) == (zext RHS)
+    // Fundamentally, we're relying on the property that (zext LHS) == (zext RHS)
     // if and only if (sext LHS) == (sext RHS). The checks are in place to
     // ensure both the LHS and RHS are truly zero extended and to make sure the
     // transformation is profitable.
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 259467f78afb4..b716a82f5c367 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -4580,6 +4580,40 @@ SDValue ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
     return Shift.getValue(1);
   }
 
+  if (isIntEqualitySetCC(CC) && isa<ConstantSDNode>(RHS)) {
+    const ConstantSDNode *RHSC = cast<ConstantSDNode>(RHS);
+    // The imm operand of ADDS is an unsigned immediate, in the range 0 to 4095.
+    // For the i8 operand, the largest immediate is 255, so this can be easily
+    // encoded in the compare instruction. For the i16 operand, however, the
+    // largest immediate cannot be encoded in the compare.
+    // Therefore, use a sign extending load and cmn to avoid materializing the
+    // -1 constant. For example (ARMv6T2+; lower cores may load 0xffff differently),
+    // movw r1, #65535
+    // ldrh r0, [r0]
+    // cmp r0, r1
+    // >
+    // ldrsh r0, [r0]
+    // cmn r0, #1
+    // Fundamentally, we're relying on the property that (zext LHS) == (zext RHS)
+    // if and only if (sext LHS) == (sext RHS). The checks are in place to
+    // ensure both the LHS and RHS are truly zero extended and to make sure the
+    // transformation is profitable.
+    if ((RHSC->getZExtValue() >> 16 == 0) && isa<LoadSDNode>(LHS) &&
+        cast<LoadSDNode>(LHS)->getExtensionType() == ISD::ZEXTLOAD &&
+        cast<LoadSDNode>(LHS)->getMemoryVT() == MVT::i16 &&
+        LHS.getNode()->hasNUsesOfValue(1, 0)) {
+      int16_t ValueofRHS = RHS->getAsZExtVal();
+      if (ValueofRHS < 0 && isLegalICmpImmediate(-ValueofRHS)) {
+        SDValue SExt =
+            DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, MVT::i32, LHS,
+                        DAG.getValueType(MVT::i16));
+
+        LHS = SExt;
+        RHS = DAG.getSignedConstant(ValueofRHS, dl, MVT::i32);
+      }
+    }
+  }
+
   ARMCC::CondCodes CondCode = IntCCToARMCC(CC);
 
   // If the RHS is a constant zero then the V (overflow) flag will never be
diff --git a/llvm/test/CodeGen/ARM/cmpwithshort.ll b/llvm/test/CodeGen/ARM/cmpwithshort.ll
new file mode 100644
index 0000000000000..a2f8b31eaa935
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/cmpwithshort.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O3 -mtriple=armv7-linux-gnueabihf | FileCheck %s --check-prefix=ARM
+; RUN: llc < %s -O3 -mtriple=thumbv7-linux-gnueabihf | FileCheck %s --check-prefix=THUMBV7
+; RUN: llc < %s -O3 -mtriple=thumbv5-none-eabi | FileCheck %s --check-prefix=THUMBV5
+
+define i16 @test_1cmp_signed_1(ptr %ptr1) {
+; ARM-LABEL: test_1cmp_signed_1:
+; ARM:       @ %bb.0: @ %entry
+; ARM-NEXT:    ldrsh r0, [r0]
+; ARM-NEXT:    add r0, r0, #1
+; ARM-NEXT:    clz r0, r0
+; ARM-NEXT:    lsr r0, r0, #5
+; ARM-NEXT:    bx lr
+;
+; THUMBV7-LABEL: test_1cmp_signed_1:
+; THUMBV7:       @ %bb.0: @ %entry
+; THUMBV7-NEXT:    ldrsh.w r0, [r0]
+; THUMBV7-NEXT:    adds r0, #1
+; THUMBV7-NEXT:    clz r0, r0
+; THUMBV7-NEXT:    lsrs r0, r0, #5
+; THUMBV7-NEXT:    bx lr
+;
+; THUMBV5-LABEL: test_1cmp_signed_1:
+; THUMBV5:       @ %bb.0: @ %entry
+; THUMBV5-NEXT:    ldrh r0, [r0]
+; THUMBV5-NEXT:    lsls r0, r0, #16
+; THUMBV5-NEXT:    asrs r0, r0, #16
+; THUMBV5-NEXT:    adds r0, r0, #1
+; THUMBV5-NEXT:    beq .LBB0_2
+; THUMBV5-NEXT:  @ %bb.1: @ %if.then
+; THUMBV5-NEXT:    movs r0, #0
+; THUMBV5-NEXT:    bx lr
+; THUMBV5-NEXT:  .LBB0_2: @ %if
+; THUMBV5-NEXT:    movs r0, #1
+; THUMBV5-NEXT:    bx lr
+entry:
+  %val = load i16, ptr %ptr1, align 2
+  %cmp = icmp eq i16 %val, -1
+  br i1 %cmp, label %if, label %if.then
+if:
+  ret i16 1
+if.then:
+  ret i16 0
+}
+
+define i16 @test_1cmp_signed_2(ptr %ptr1) {
+; ARM-LABEL: test_1cmp_signed_2:
+; ARM:       @ %bb.0: @ %entry
+; ARM-NEXT:    ldrsh r1, [r0]
+; ARM-NEXT:    mov r0, #0
+; ARM-NEXT:    cmn r1, #2
+; ARM-NEXT:    movwgt r0, #1
+; ARM-NEXT:    bx lr
+;
+; THUMBV7-LABEL: test_1cmp_signed_2:
+; THUMBV7:       @ %bb.0: @ %entry
+; THUMBV7-NEXT:    ldrsh.w r1, [r0]
+; THUMBV7-NEXT:    movs r0, #0
+; THUMBV7-NEXT:    cmn.w r1, #2
+; THUMBV7-NEXT:    it gt
+; THUMBV7-NEXT:    movgt r0, #1
+; THUMBV7-NEXT:    bx lr
+;
+; THUMBV5-LABEL: test_1cmp_signed_2:
+; THUMBV5:       @ %bb.0: @ %entry
+; THUMBV5-NEXT:    movs r1, #0
+; THUMBV5-NEXT:    mvns r1, r1
+; THUMBV5-NEXT:    ldrh r0, [r0]
+; THUMBV5-NEXT:    lsls r0, r0, #16
+; THUMBV5-NEXT:    asrs r0, r0, #16
+; THUMBV5-NEXT:    cmp r0, r1
+; THUMBV5-NEXT:    blt .LBB1_2
+; THUMBV5-NEXT:  @ %bb.1: @ %if
+; THUMBV5-NEXT:    movs r0, #1
+; THUMBV5-NEXT:    bx lr
+; THUMBV5-NEXT:  .LBB1_2: @ %if.then
+; THUMBV5-NEXT:    movs r0, #0
+; THUMBV5-NEXT:    bx lr
+entry:
+  %val = load i16, ptr %ptr1, align 2
+  %cmp = icmp sge i16 %val, -1
+  br i1 %cmp, label %if, label %if.then
+if:
+  ret i16 1
+if.then:
+  ret i16 0
+}
+
+define i16 @test_1cmp_unsigned_1(ptr %ptr1) {
+; ARM-LABEL: test_1cmp_unsigned_1:
+; ARM:       @ %bb.0: @ %entry
+; ARM-NEXT:    ldrsh r0, [r0]
+; ARM-NEXT:    add r0, r0, #1
+; ARM-NEXT:    clz r0, r0
+; ARM-NEXT:    lsr r0, r0, #5
+; ARM-NEXT:    bx lr
+;
+; THUMBV7-LABEL: test_1cmp_unsigned_1:
+; THUMBV7:       @ %bb.0: @ %entry
+; THUMBV7-NEXT:    ldrsh.w r0, [r0]
+; THUMBV7-NEXT:    adds r0, #1
+; THUMBV7-NEXT:    clz r0, r0
+; THUMBV7-NEXT:    lsrs r0, r0, #5
+; THUMBV7-NEXT:    bx lr
+;
+; THUMBV5-LABEL: test_1cmp_unsigned_1:
+; THUMBV5:       @ %bb.0: @ %entry
+; THUMBV5-NEXT:    ldrh r0, [r0]
+; THUMBV5-NEXT:    lsls r0, r0, #16
+; THUMBV5-NEXT:    asrs r0, r0, #16
+; THUMBV5-NEXT:    adds r0, r0, #1
+; THUMBV5-NEXT:    bne .LBB2_2
+; THUMBV5-NEXT:  @ %bb.1: @ %if
+; THUMBV5-NEXT:    movs r0, #1
+; THUMBV5-NEXT:    bx lr
+; THUMBV5-NEXT:  .LBB2_2: @ %if.then
+; THUMBV5-NEXT:    movs r0, #0
+; THUMBV5-NEXT:    bx lr
+entry:
+  %val = load i16, ptr %ptr1, align 2
+  %cmp = icmp uge i16 %val, -1
+  br i1 %cmp, label %if, label %if.then
+if:
+  ret i16 1
+if.then:
+  ret i16 0
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/196862


More information about the llvm-commits mailing list