[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