[llvm] [AArch64] Recombine SETCCCARRY for legalized unsigned compares (PR #204504)
Cheng Lingfei via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 24 06:40:08 PDT 2026
https://github.com/clingfei updated https://github.com/llvm/llvm-project/pull/204504
>From 075500d1c90a6012b27419ca9b10a2a5ef52727f Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Thu, 18 Jun 2026 10:33:27 +0800
Subject: [PATCH 1/3] [AArch64] Recombine SETCCCARRY for legalized unsigned
compares
Type legalization can turn wide unsigned compares into SETCCCARRY nodes fed
by USUBO carry results, hiding the original high/low compare shape from the
existing CCMP conjunction/disjunction lowering.
Add an AArch64 DAG combine for SETCCCARRY that recognizes these legalized
wide-compare patterns and rebuilds them as SETCC plus AND/OR, exposing them
to the existing CCMP lowering.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 67ef911117eff..15c5089cdb507 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1157,6 +1157,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
// Try and combine setcc/select_cc with csel and bool-vector bitcasts.
setTargetDAGCombine(ISD::SETCC);
setTargetDAGCombine(ISD::SELECT_CC);
+ setTargetDAGCombine(ISD::SETCCCARRY);
setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN);
@@ -28078,6 +28079,41 @@ static SDValue performSETCCCombine(SDNode *N,
return SDValue();
}
+static SDValue performSETCCCARRYCombine(SDNode *N, SelectionDAG &DAG) {
+ assert(N->getOpcode() == ISD::SETCCCARRY && "Unexpected opcode!");
+
+ // Rebuild narrow high/low compares from type-legalized wide unsigned compares
+ // so the existing CCMP conjunction/disjunction lowering can handle them.
+ SDValue HiLHS = N->getOperand(0);
+ SDValue HiRHS = N->getOperand(1);
+ SDValue Carry = N->getOperand(2);
+ ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(3))->get();
+ if (Cond != ISD::SETULT || Carry.getOpcode() != ISD::USUBO ||
+ Carry.getResNo() != 1)
+ return SDValue();
+
+ if (!isNullConstant(HiLHS) && !isNullConstant(HiRHS))
+ return SDValue();
+
+ SDValue LoLHS = Carry.getOperand(0);
+ SDValue LoRHS = Carry.getOperand(1);
+ if (!isa<ConstantSDNode>(LoLHS) && !isa<ConstantSDNode>(LoRHS))
+ return SDValue();
+
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ SDValue LoCmp = DAG.getSetCC(DL, VT, LoLHS, LoRHS, ISD::SETULT);
+ if (isNullConstant(HiRHS)) {
+ SDValue HiEq = DAG.getSetCC(DL, VT, HiLHS, HiRHS, ISD::SETEQ);
+ return DAG.getNode(ISD::AND, DL, VT, HiEq, LoCmp);
+ }
+
+ SDValue HiNe = DAG.getSetCC(
+ DL, VT, HiRHS, DAG.getConstant(0, DL, HiRHS.getValueType()), ISD::SETNE);
+ return DAG.getNode(ISD::OR, DL, VT, HiNe, LoCmp);
+}
+
static SDValue performSELECT_CCCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG) {
@@ -30010,6 +30046,8 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
return performVSelectCombine(N, DCI, Subtarget);
case ISD::SETCC:
return performSETCCCombine(N, DCI, DAG);
+ case ISD::SETCCCARRY:
+ return performSETCCCARRYCombine(N, DAG);
case ISD::LOAD:
return performLOADCombine(N, DCI, DAG, Subtarget);
case ISD::STORE:
>From 578ebbb2e5da3b2c23d518d99108acec5f4c2561 Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Thu, 18 Jun 2026 10:33:27 +0800
Subject: [PATCH 2/3] [AArch64] Recombine SETCCCARRY for legalized unsigned
compares
Type legalization can turn wide unsigned compares into SETCCCARRY nodes fed
by USUBO carry results, hiding the original high/low compare shape from the
existing CCMP conjunction/disjunction lowering.
Add an AArch64 DAG combine for SETCCCARRY that recognizes these legalized
wide-compare patterns and rebuilds them as SETCC plus AND/OR, exposing them
to the existing CCMP lowering.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 38 ++++++++++++++
llvm/test/CodeGen/AArch64/i128-cmp.ll | 49 +++++++++++++++++++
2 files changed, 87 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 67ef911117eff..15c5089cdb507 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1157,6 +1157,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
// Try and combine setcc/select_cc with csel and bool-vector bitcasts.
setTargetDAGCombine(ISD::SETCC);
setTargetDAGCombine(ISD::SELECT_CC);
+ setTargetDAGCombine(ISD::SETCCCARRY);
setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN);
@@ -28078,6 +28079,41 @@ static SDValue performSETCCCombine(SDNode *N,
return SDValue();
}
+static SDValue performSETCCCARRYCombine(SDNode *N, SelectionDAG &DAG) {
+ assert(N->getOpcode() == ISD::SETCCCARRY && "Unexpected opcode!");
+
+ // Rebuild narrow high/low compares from type-legalized wide unsigned compares
+ // so the existing CCMP conjunction/disjunction lowering can handle them.
+ SDValue HiLHS = N->getOperand(0);
+ SDValue HiRHS = N->getOperand(1);
+ SDValue Carry = N->getOperand(2);
+ ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(3))->get();
+ if (Cond != ISD::SETULT || Carry.getOpcode() != ISD::USUBO ||
+ Carry.getResNo() != 1)
+ return SDValue();
+
+ if (!isNullConstant(HiLHS) && !isNullConstant(HiRHS))
+ return SDValue();
+
+ SDValue LoLHS = Carry.getOperand(0);
+ SDValue LoRHS = Carry.getOperand(1);
+ if (!isa<ConstantSDNode>(LoLHS) && !isa<ConstantSDNode>(LoRHS))
+ return SDValue();
+
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ SDValue LoCmp = DAG.getSetCC(DL, VT, LoLHS, LoRHS, ISD::SETULT);
+ if (isNullConstant(HiRHS)) {
+ SDValue HiEq = DAG.getSetCC(DL, VT, HiLHS, HiRHS, ISD::SETEQ);
+ return DAG.getNode(ISD::AND, DL, VT, HiEq, LoCmp);
+ }
+
+ SDValue HiNe = DAG.getSetCC(
+ DL, VT, HiRHS, DAG.getConstant(0, DL, HiRHS.getValueType()), ISD::SETNE);
+ return DAG.getNode(ISD::OR, DL, VT, HiNe, LoCmp);
+}
+
static SDValue performSELECT_CCCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG) {
@@ -30010,6 +30046,8 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
return performVSelectCombine(N, DCI, Subtarget);
case ISD::SETCC:
return performSETCCCombine(N, DCI, DAG);
+ case ISD::SETCCCARRY:
+ return performSETCCCARRYCombine(N, DAG);
case ISD::LOAD:
return performLOADCombine(N, DCI, DAG, Subtarget);
case ISD::STORE:
diff --git a/llvm/test/CodeGen/AArch64/i128-cmp.ll b/llvm/test/CodeGen/AArch64/i128-cmp.ll
index 9c23b3a603d10..c878cc5f1e6a6 100644
--- a/llvm/test/CodeGen/AArch64/i128-cmp.ll
+++ b/llvm/test/CodeGen/AArch64/i128-cmp.ll
@@ -323,3 +323,52 @@ exit:
ret void
}
+define i1 @cmp_i128_ult_small_const(i128 %a) {
+; CHECK-LABEL: cmp_i128_ult_small_const:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp x1, #0
+; CHECK-NEXT: ccmp x0, #7, #2, eq
+; CHECK-NEXT: cset w0, lo
+; CHECK-NEXT: ret
+ %cmp = icmp ult i128 %a, 7
+ ret i1 %cmp
+}
+
+define i1 @cmp_i128_small_const_ult(i128 %a) {
+; CHECK-LABEL: cmp_i128_small_const_ult:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp x1, #0
+; CHECK-NEXT: ccmp x0, #7, #2, eq
+; CHECK-NEXT: cset w0, hi
+; CHECK-NEXT: ret
+ %cmp = icmp ult i128 7, %a
+ ret i1 %cmp
+}
+
+define i1 @cmp_i128_ult_small_const_and_i64(i128 %a, i64 %b) {
+; CHECK-LABEL: cmp_i128_ult_small_const_and_i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp x0, #7
+; CHECK-NEXT: ccmp x2, #11, #2, lo
+; CHECK-NEXT: ccmp x1, #0, #0, lo
+; CHECK-NEXT: cset w0, eq
+; CHECK-NEXT: ret
+ %wide = icmp ult i128 %a, 7
+ %narrow = icmp ult i64 %b, 11
+ %cmp = and i1 %wide, %narrow
+ ret i1 %cmp
+}
+
+define i1 @cmp_i128_small_const_ult_or_i64(i128 %a, i64 %b) {
+; CHECK-LABEL: cmp_i128_small_const_ult_or_i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmp x1, #0
+; CHECK-NEXT: ccmp x0, #7, #2, eq
+; CHECK-NEXT: ccmp x2, #11, #0, ls
+; CHECK-NEXT: cset w0, lo
+; CHECK-NEXT: ret
+ %wide = icmp ult i128 7, %a
+ %narrow = icmp ult i64 %b, 11
+ %cmp = or i1 %wide, %narrow
+ ret i1 %cmp
+}
>From 809eb5632363878bc8909d398f71702ea2128bc5 Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Wed, 24 Jun 2026 21:39:35 +0800
Subject: [PATCH 3/3] Use HiLHS instead
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 6ae80bbc999f3..d33e88caa2d2c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -28215,8 +28215,7 @@ static SDValue performSETCCCARRYCombine(SDNode *N, SelectionDAG &DAG) {
return DAG.getNode(ISD::AND, DL, VT, HiEq, LoCmp);
}
- SDValue HiNe = DAG.getSetCC(
- DL, VT, HiRHS, DAG.getConstant(0, DL, HiRHS.getValueType()), ISD::SETNE);
+ SDValue HiNe = DAG.getSetCC(DL, VT, HiRHS, HiLHS, ISD::SETNE);
return DAG.getNode(ISD::OR, DL, VT, HiNe, LoCmp);
}
More information about the llvm-commits
mailing list