[llvm] [AArch64][SelectionDAG] Snap -32 and 32 to 31 snd -31 for ccmn (PR #192879)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 19 15:42:04 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: SiliconA-Z
<details>
<summary>Changes</summary>
This is so we can encode it.
---
Full diff: https://github.com/llvm/llvm-project/pull/192879.diff
2 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+42-1)
- (modified) llvm/test/CodeGen/AArch64/cmp-chains.ll (+89)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 9b34d9b385b4e..ec193e74c328b 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3853,6 +3853,43 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
/// can only implement 1 of the inner (not) operations, but not both!
/// @{
+/// CCMP/CCMN Wi/Xi immediates are restricted to 0..31. When lowering a
+/// \em conditional compare (not the leading CMP in a chain), snap RHS
+/// constants at ±32 to ±31 where equivalent so the CCMP/CCMN immediate form
+/// applies. Plain CMP;CCMP can use a separate \p mov for \p #32; only the
+/// conditional step needs this rewrite.
+static void snapCCmpImmEncodingBounds(SDValue &RHS, ISD::CondCode &CC,
+ SelectionDAG &DAG, const SDLoc &DL,
+ EVT VT) {
+ auto *C = dyn_cast<ConstantSDNode>(RHS);
+ if (!C)
+ return;
+ APInt Imm = C->getAPIntValue();
+
+ // x < 32 <=> x <= 31 ; x <u 32 <=> x <=u 31
+ if (Imm == 32) {
+ if (CC == ISD::SETLT) {
+ CC = ISD::SETLE;
+ RHS = DAG.getConstant(31, DL, VT);
+ } else if (CC == ISD::SETULT) {
+ CC = ISD::SETULE;
+ RHS = DAG.getConstant(31, DL, VT);
+ }
+ return;
+ }
+
+ // x > -32 <=> x >= -31
+ if (Imm.getSExtValue() == -32) {
+ if (CC == ISD::SETGT) {
+ CC = ISD::SETGE;
+ RHS = DAG.getSignedConstant(-31, DL, VT);
+ } else if (CC == ISD::SETUGT) {
+ CC = ISD::SETUGE;
+ RHS = DAG.getSignedConstant(-31, DL, VT);
+ }
+ }
+}
+
/// Create a conditional comparison; Use CCMP, CCMN or FCCMP as appropriate.
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
ISD::CondCode CC, SDValue CCOp,
@@ -4000,6 +4037,10 @@ static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val,
SDLoc DL(Val);
// Determine OutCC and handle FP special case.
if (isInteger) {
+ // Immediate snap only for conditional CCMP/CCMN; leading CMP uses
+ // emitComparison and does not share the 0..31 Wi/Xi restriction.
+ if (CCOp)
+ snapCCmpImmEncodingBounds(RHS, CC, DAG, DL, LHS.getValueType());
OutCC = changeIntCCToAArch64CC(CC, RHS);
} else {
assert(LHS.getValueType().isFloatingPoint());
@@ -4009,7 +4050,7 @@ static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val,
// code. Construct an additional comparison in this case.
if (ExtraCC != AArch64CC::AL) {
SDValue ExtraCmp;
- if (!CCOp.getNode())
+ if (!CCOp)
ExtraCmp = emitComparison(LHS, RHS, CC, DL, DAG);
else
ExtraCmp = emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate,
diff --git a/llvm/test/CodeGen/AArch64/cmp-chains.ll b/llvm/test/CodeGen/AArch64/cmp-chains.ll
index 3620444a6aad6..4bf443c9cc910 100644
--- a/llvm/test/CodeGen/AArch64/cmp-chains.ll
+++ b/llvm/test/CodeGen/AArch64/cmp-chains.ll
@@ -501,3 +501,92 @@ entry:
%land.ext = zext i1 %0 to i32
ret i32 %land.ext
}
+
+; Boundary immediates (±32) in the second conjunct of select-with-and chains.
+define i32 @compare_with_neg_32(i32 %a, i32 %b, i32 %c) {
+; CHECK-SD-LABEL: compare_with_neg_32:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: cmp w0, w2
+; CHECK-SD-NEXT: ccmn w1, #31, #8, lt
+; CHECK-SD-NEXT: csel w0, w1, w0, ge
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: compare_with_neg_32:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov w8, #-32 // =0xffffffe0
+; CHECK-GI-NEXT: cmp w0, w2
+; CHECK-GI-NEXT: ccmp w1, w8, #4, lt
+; CHECK-GI-NEXT: csel w0, w1, w0, gt
+; CHECK-GI-NEXT: ret
+ %cmp = icmp sgt i32 %b, -32
+ %cmp1 = icmp slt i32 %a, %c
+ %or.cond = and i1 %cmp, %cmp1
+ %cond = select i1 %or.cond, i32 %b, i32 %a
+ ret i32 %cond
+}
+
+define i32 @compare_with_32(i32 %a, i32 %b, i32 %c) {
+; CHECK-SD-LABEL: compare_with_32:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: cmp w0, w2
+; CHECK-SD-NEXT: ccmp w1, #31, #0, lt
+; CHECK-SD-NEXT: csel w0, w1, w0, le
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: compare_with_32:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov w8, #32 // =0x20
+; CHECK-GI-NEXT: cmp w0, w2
+; CHECK-GI-NEXT: ccmp w1, w8, #0, lt
+; CHECK-GI-NEXT: csel w0, w1, w0, lt
+; CHECK-GI-NEXT: ret
+ %cmp = icmp slt i32 %b, 32
+ %cmp1 = icmp slt i32 %a, %c
+ %or.cond = and i1 %cmp, %cmp1
+ %cond = select i1 %or.cond, i32 %b, i32 %a
+ ret i32 %cond
+}
+
+define i32 @compare_with_neg_32_unsigned(i32 %a, i32 %b, i32 %c) {
+; CHECK-SD-LABEL: compare_with_neg_32_unsigned:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: cmp w0, w2
+; CHECK-SD-NEXT: ccmn w1, #31, #0, lo
+; CHECK-SD-NEXT: csel w0, w1, w0, hs
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: compare_with_neg_32_unsigned:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov w8, #-32 // =0xffffffe0
+; CHECK-GI-NEXT: cmp w0, w2
+; CHECK-GI-NEXT: ccmp w1, w8, #0, lo
+; CHECK-GI-NEXT: csel w0, w1, w0, hi
+; CHECK-GI-NEXT: ret
+ %cmp = icmp ugt i32 %b, -32
+ %cmp1 = icmp ult i32 %a, %c
+ %or.cond = and i1 %cmp, %cmp1
+ %cond = select i1 %or.cond, i32 %b, i32 %a
+ ret i32 %cond
+}
+
+define i32 @compare_with_32_unsigned(i32 %a, i32 %b, i32 %c) {
+; CHECK-SD-LABEL: compare_with_32_unsigned:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: cmp w0, w2
+; CHECK-SD-NEXT: ccmp w1, #31, #2, lo
+; CHECK-SD-NEXT: csel w0, w1, w0, ls
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: compare_with_32_unsigned:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov w8, #32 // =0x20
+; CHECK-GI-NEXT: cmp w0, w2
+; CHECK-GI-NEXT: ccmp w1, w8, #2, lo
+; CHECK-GI-NEXT: csel w0, w1, w0, lo
+; CHECK-GI-NEXT: ret
+ %cmp = icmp ult i32 %b, 32
+ %cmp1 = icmp ult i32 %a, %c
+ %or.cond = and i1 %cmp, %cmp1
+ %cond = select i1 %or.cond, i32 %b, i32 %a
+ ret i32 %cond
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/192879
More information about the llvm-commits
mailing list