[llvm] [AArch64] Snap 32 and -32 to 31 and -31 if possible for ccmp and ccmn (PR #150640)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 26 08:10:17 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/150640
>From 38b94f879f4a01183153c2039f60faf7dfd4733d Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Fri, 25 Jul 2025 11:41:19 -0400
Subject: [PATCH 1/2] Pre-commit test (NFC)
---
llvm/test/CodeGen/AArch64/cmp-chains.ll | 92 +++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/cmp-chains.ll b/llvm/test/CodeGen/AArch64/cmp-chains.ll
index 4b816df75a730..7cf82cb52a48c 100644
--- a/llvm/test/CodeGen/AArch64/cmp-chains.ll
+++ b/llvm/test/CodeGen/AArch64/cmp-chains.ll
@@ -501,3 +501,95 @@ entry:
%land.ext = zext i1 %0 to i32
ret i32 %land.ext
}
+
+define i32 @compare_with_neg_32(i32 %a, i32 %b, i32 %c) {
+; SDISEL-LABEL: compare_with_neg_32:
+; SDISEL: // %bb.0:
+; SDISEL-NEXT: cmp w0, w2
+; SDISEL-NEXT: mov w8, #-32 // =0xffffffe0
+; SDISEL-NEXT: ccmp w1, w8, #4, lt
+; SDISEL-NEXT: csel w0, w1, w0, gt
+; SDISEL-NEXT: ret
+;
+; GISEL-LABEL: compare_with_neg_32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: mov w8, #-32 // =0xffffffe0
+; GISEL-NEXT: cmp w0, w2
+; GISEL-NEXT: ccmp w1, w8, #4, lt
+; GISEL-NEXT: csel w0, w1, w0, gt
+; GISEL-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) {
+; SDISEL-LABEL: compare_with_32:
+; SDISEL: // %bb.0:
+; SDISEL-NEXT: cmp w0, w2
+; SDISEL-NEXT: mov w8, #32 // =0x20
+; SDISEL-NEXT: ccmp w1, w8, #0, lt
+; SDISEL-NEXT: csel w0, w1, w0, lt
+; SDISEL-NEXT: ret
+;
+; GISEL-LABEL: compare_with_32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: mov w8, #32 // =0x20
+; GISEL-NEXT: cmp w0, w2
+; GISEL-NEXT: ccmp w1, w8, #0, lt
+; GISEL-NEXT: csel w0, w1, w0, lt
+; GISEL-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) {
+; SDISEL-LABEL: compare_with_neg_32_unsigned:
+; SDISEL: // %bb.0:
+; SDISEL-NEXT: cmp w0, w2
+; SDISEL-NEXT: mov w8, #-32 // =0xffffffe0
+; SDISEL-NEXT: ccmp w1, w8, #0, lo
+; SDISEL-NEXT: csel w0, w1, w0, hi
+; SDISEL-NEXT: ret
+;
+; GISEL-LABEL: compare_with_neg_32_unsigned:
+; GISEL: // %bb.0:
+; GISEL-NEXT: mov w8, #-32 // =0xffffffe0
+; GISEL-NEXT: cmp w0, w2
+; GISEL-NEXT: ccmp w1, w8, #0, lo
+; GISEL-NEXT: csel w0, w1, w0, hi
+; GISEL-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) {
+; SDISEL-LABEL: compare_with_32_unsigned:
+; SDISEL: // %bb.0:
+; SDISEL-NEXT: cmp w0, w2
+; SDISEL-NEXT: mov w8, #32 // =0x20
+; SDISEL-NEXT: ccmp w1, w8, #2, lo
+; SDISEL-NEXT: csel w0, w1, w0, lo
+; SDISEL-NEXT: ret
+;
+; GISEL-LABEL: compare_with_32_unsigned:
+; GISEL: // %bb.0:
+; GISEL-NEXT: mov w8, #32 // =0x20
+; GISEL-NEXT: cmp w0, w2
+; GISEL-NEXT: ccmp w1, w8, #2, lo
+; GISEL-NEXT: csel w0, w1, w0, lo
+; GISEL-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
+}
>From 0f714b9c0c1617d4ab5dfe1caec0dd82696fadf2 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Fri, 25 Jul 2025 11:42:01 -0400
Subject: [PATCH 2/2] [AArch64] Snap 32 and -32 to 31 and -31 if possible for
ccmp and ccmn
This lets us encode the immediate in the instruction.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 45 +++++++++-
.../GISel/AArch64InstructionSelector.cpp | 55 +++++++++++-
llvm/test/CodeGen/AArch64/cmp-chains.ll | 84 ++++++-------------
3 files changed, 118 insertions(+), 66 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7b49754ee7e1f..2c11776323e02 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3646,7 +3646,7 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
ISD::CondCode CC, SDValue CCOp,
AArch64CC::CondCode Predicate,
- AArch64CC::CondCode OutCC,
+ AArch64CC::CondCode &OutCC,
const SDLoc &DL, SelectionDAG &DAG) {
unsigned Opcode = 0;
const bool FullFP16 = DAG.getSubtarget<AArch64Subtarget>().hasFullFP16();
@@ -3661,7 +3661,48 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
Opcode = AArch64ISD::FCCMP;
} else if (ConstantSDNode *Const = dyn_cast<ConstantSDNode>(RHS)) {
APInt Imm = Const->getAPIntValue();
- if (Imm.isNegative() && Imm.sgt(-32)) {
+ if (Imm.getZExtValue() == 32 && (CC == ISD::SETLT || CC == ISD::SETGE ||
+ CC == ISD::SETULT || CC == ISD::SETUGE)) {
+ Opcode = AArch64ISD::CCMP;
+ RHS = DAG.getConstant(31, DL, Const->getValueType(0));
+ switch (CC) {
+ case ISD::SETLT:
+ OutCC = AArch64CC::LE;
+ break;
+ case ISD::SETGE:
+ OutCC = AArch64CC::GT;
+ break;
+ case ISD::SETULT:
+ OutCC = AArch64CC::LS;
+ break;
+ case ISD::SETUGE:
+ OutCC = AArch64CC::HI;
+ break;
+ default:
+ llvm_unreachable("Cannot adjust 32 to 31");
+ }
+ } else if (Imm.getSExtValue() == -32 &&
+ (CC == ISD::SETLE || CC == ISD::SETGT || CC == ISD::SETULE ||
+ CC == ISD::SETUGT)) {
+ Opcode = AArch64ISD::CCMN;
+ RHS = DAG.getConstant(31, DL, Const->getValueType(0));
+ switch (CC) {
+ case ISD::SETLE:
+ OutCC = AArch64CC::LT;
+ break;
+ case ISD::SETGT:
+ OutCC = AArch64CC::GE;
+ break;
+ case ISD::SETULE:
+ OutCC = AArch64CC::LO;
+ break;
+ case ISD::SETUGT:
+ OutCC = AArch64CC::HS;
+ break;
+ default:
+ llvm_unreachable("Cannot adjust -32 to -31");
+ }
+ } else if (Imm.isNegative() && Imm.sgt(-32)) {
Opcode = AArch64ISD::CCMN;
RHS = DAG.getConstant(Imm.abs(), DL, Const->getValueType(0));
}
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 1381a9b70df87..b1a2d9ebe7fc2 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -352,7 +352,7 @@ class AArch64InstructionSelector : public InstructionSelector {
MachineInstr *emitConditionalComparison(Register LHS, Register RHS,
CmpInst::Predicate CC,
AArch64CC::CondCode Predicate,
- AArch64CC::CondCode OutCC,
+ AArch64CC::CondCode &OutCC,
MachineIRBuilder &MIB) const;
MachineInstr *emitConjunctionRec(Register Val, AArch64CC::CondCode &OutCC,
bool Negate, Register CCOp,
@@ -4868,16 +4868,61 @@ static bool canEmitConjunction(Register Val, bool &CanNegate, bool &MustBeFirst,
MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
Register LHS, Register RHS, CmpInst::Predicate CC,
- AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC,
+ AArch64CC::CondCode Predicate, AArch64CC::CondCode &OutCC,
MachineIRBuilder &MIB) const {
auto &MRI = *MIB.getMRI();
LLT OpTy = MRI.getType(LHS);
unsigned CCmpOpc;
std::optional<ValueAndVReg> C;
+ bool Adjusted = false;
if (CmpInst::isIntPredicate(CC)) {
assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
C = getIConstantVRegValWithLookThrough(RHS, MRI);
- if (!C || C->Value.sgt(31) || C->Value.slt(-31))
+ if (!C) {
+ CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
+ } else if (C->Value.getZExtValue() == 32 &&
+ (CC == CmpInst::ICMP_SLT || CC == CmpInst::ICMP_SGE ||
+ CC == CmpInst::ICMP_ULT || CC == CmpInst::ICMP_UGE)) {
+ CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
+ switch (CC) {
+ case CmpInst::ICMP_SLT:
+ OutCC = AArch64CC::LE;
+ break;
+ case CmpInst::ICMP_SGE:
+ OutCC = AArch64CC::GT;
+ break;
+ case CmpInst::ICMP_ULT:
+ OutCC = AArch64CC::LS;
+ break;
+ case CmpInst::ICMP_UGE:
+ OutCC = AArch64CC::HI;
+ break;
+ default:
+ llvm_unreachable("Cannot adjust 32 to 31");
+ }
+ Adjusted = true;
+ } else if (C->Value.getSExtValue() == -32 &&
+ (CC == CmpInst::ICMP_SLE || CC == CmpInst::ICMP_SGT ||
+ CC == CmpInst::ICMP_ULE || CC == CmpInst::ICMP_UGT)) {
+ CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
+ switch (CC) {
+ case CmpInst::ICMP_SLE:
+ OutCC = AArch64CC::LT;
+ break;
+ case CmpInst::ICMP_SGT:
+ OutCC = AArch64CC::GE;
+ break;
+ case CmpInst::ICMP_ULE:
+ OutCC = AArch64CC::LO;
+ break;
+ case CmpInst::ICMP_UGT:
+ OutCC = AArch64CC::HS;
+ break;
+ default:
+ llvm_unreachable("Cannot adjust -32 to -31");
+ }
+ Adjusted = true;
+ } else if (C->Value.sgt(31) || C->Value.slt(-31))
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
else if (C->Value.ule(31))
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
@@ -4905,7 +4950,9 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
unsigned NZCV = AArch64CC::getNZCVToSatisfyCondCode(InvOutCC);
auto CCmp =
MIB.buildInstr(CCmpOpc, {}, {LHS});
- if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
+ if (Adjusted) {
+ CCmp.addImm(31);
+ } else if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
CCmp.addImm(C->Value.getZExtValue());
else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
CCmp.addImm(C->Value.abs().getZExtValue());
diff --git a/llvm/test/CodeGen/AArch64/cmp-chains.ll b/llvm/test/CodeGen/AArch64/cmp-chains.ll
index 7cf82cb52a48c..45aa2cc6bf4f4 100644
--- a/llvm/test/CodeGen/AArch64/cmp-chains.ll
+++ b/llvm/test/CodeGen/AArch64/cmp-chains.ll
@@ -503,21 +503,12 @@ entry:
}
define i32 @compare_with_neg_32(i32 %a, i32 %b, i32 %c) {
-; SDISEL-LABEL: compare_with_neg_32:
-; SDISEL: // %bb.0:
-; SDISEL-NEXT: cmp w0, w2
-; SDISEL-NEXT: mov w8, #-32 // =0xffffffe0
-; SDISEL-NEXT: ccmp w1, w8, #4, lt
-; SDISEL-NEXT: csel w0, w1, w0, gt
-; SDISEL-NEXT: ret
-;
-; GISEL-LABEL: compare_with_neg_32:
-; GISEL: // %bb.0:
-; GISEL-NEXT: mov w8, #-32 // =0xffffffe0
-; GISEL-NEXT: cmp w0, w2
-; GISEL-NEXT: ccmp w1, w8, #4, lt
-; GISEL-NEXT: csel w0, w1, w0, gt
-; GISEL-NEXT: ret
+; CHECK-LABEL: compare_with_neg_32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp w0, w2
+; CHECK-NEXT: ccmn w1, #31, #8, lt
+; CHECK-NEXT: csel w0, w1, w0, ge
+; CHECK-NEXT: ret
%cmp = icmp sgt i32 %b, -32
%cmp1 = icmp slt i32 %a, %c
%or.cond = and i1 %cmp, %cmp1
@@ -526,21 +517,12 @@ define i32 @compare_with_neg_32(i32 %a, i32 %b, i32 %c) {
}
define i32 @compare_with_32(i32 %a, i32 %b, i32 %c) {
-; SDISEL-LABEL: compare_with_32:
-; SDISEL: // %bb.0:
-; SDISEL-NEXT: cmp w0, w2
-; SDISEL-NEXT: mov w8, #32 // =0x20
-; SDISEL-NEXT: ccmp w1, w8, #0, lt
-; SDISEL-NEXT: csel w0, w1, w0, lt
-; SDISEL-NEXT: ret
-;
-; GISEL-LABEL: compare_with_32:
-; GISEL: // %bb.0:
-; GISEL-NEXT: mov w8, #32 // =0x20
-; GISEL-NEXT: cmp w0, w2
-; GISEL-NEXT: ccmp w1, w8, #0, lt
-; GISEL-NEXT: csel w0, w1, w0, lt
-; GISEL-NEXT: ret
+; CHECK-LABEL: compare_with_32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp w0, w2
+; CHECK-NEXT: ccmp w1, #31, #0, lt
+; CHECK-NEXT: csel w0, w1, w0, le
+; CHECK-NEXT: ret
%cmp = icmp slt i32 %b, 32
%cmp1 = icmp slt i32 %a, %c
%or.cond = and i1 %cmp, %cmp1
@@ -549,21 +531,12 @@ define i32 @compare_with_32(i32 %a, i32 %b, i32 %c) {
}
define i32 @compare_with_neg_32_unsigned(i32 %a, i32 %b, i32 %c) {
-; SDISEL-LABEL: compare_with_neg_32_unsigned:
-; SDISEL: // %bb.0:
-; SDISEL-NEXT: cmp w0, w2
-; SDISEL-NEXT: mov w8, #-32 // =0xffffffe0
-; SDISEL-NEXT: ccmp w1, w8, #0, lo
-; SDISEL-NEXT: csel w0, w1, w0, hi
-; SDISEL-NEXT: ret
-;
-; GISEL-LABEL: compare_with_neg_32_unsigned:
-; GISEL: // %bb.0:
-; GISEL-NEXT: mov w8, #-32 // =0xffffffe0
-; GISEL-NEXT: cmp w0, w2
-; GISEL-NEXT: ccmp w1, w8, #0, lo
-; GISEL-NEXT: csel w0, w1, w0, hi
-; GISEL-NEXT: ret
+; CHECK-LABEL: compare_with_neg_32_unsigned:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp w0, w2
+; CHECK-NEXT: ccmn w1, #31, #0, lo
+; CHECK-NEXT: csel w0, w1, w0, hs
+; CHECK-NEXT: ret
%cmp = icmp ugt i32 %b, -32
%cmp1 = icmp ult i32 %a, %c
%or.cond = and i1 %cmp, %cmp1
@@ -572,21 +545,12 @@ define i32 @compare_with_neg_32_unsigned(i32 %a, i32 %b, i32 %c) {
}
define i32 @compare_with_32_unsigned(i32 %a, i32 %b, i32 %c) {
-; SDISEL-LABEL: compare_with_32_unsigned:
-; SDISEL: // %bb.0:
-; SDISEL-NEXT: cmp w0, w2
-; SDISEL-NEXT: mov w8, #32 // =0x20
-; SDISEL-NEXT: ccmp w1, w8, #2, lo
-; SDISEL-NEXT: csel w0, w1, w0, lo
-; SDISEL-NEXT: ret
-;
-; GISEL-LABEL: compare_with_32_unsigned:
-; GISEL: // %bb.0:
-; GISEL-NEXT: mov w8, #32 // =0x20
-; GISEL-NEXT: cmp w0, w2
-; GISEL-NEXT: ccmp w1, w8, #2, lo
-; GISEL-NEXT: csel w0, w1, w0, lo
-; GISEL-NEXT: ret
+; CHECK-LABEL: compare_with_32_unsigned:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp w0, w2
+; CHECK-NEXT: ccmp w1, #31, #2, lo
+; CHECK-NEXT: csel w0, w1, w0, ls
+; CHECK-NEXT: ret
%cmp = icmp ult i32 %b, 32
%cmp1 = icmp ult i32 %a, %c
%or.cond = and i1 %cmp, %cmp1
More information about the llvm-commits
mailing list