[llvm] Use umin for x != 0 when +cssc is enabled (PR #169159)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 22 07:59:14 PST 2025
https://github.com/clingfei updated https://github.com/llvm/llvm-project/pull/169159
>From 51d75337f6dd3a008529ca306e56d6921eef0abe Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Sat, 22 Nov 2025 18:36:17 +0800
Subject: [PATCH 1/3] Use umin for x != 0 when +cssc is enabled
---
.../Target/AArch64/AArch64ISelLowering.cpp | 10 ++-
.../test/CodeGen/AArch64/aarch64-isel-umin.ll | 82 +++++++++++++++++++
llvm/test/CodeGen/AArch64/arm64-popcnt.ll | 4 +-
3 files changed, 92 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index ac3745ea5c274..fdea0d2dfd268 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -26375,7 +26375,8 @@ performVecReduceBitwiseCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
static SDValue performSETCCCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
- SelectionDAG &DAG) {
+ SelectionDAG &DAG,
+ const AArch64Subtarget *Subtarget) {
assert(N->getOpcode() == ISD::SETCC && "Unexpected opcode!");
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
@@ -26417,6 +26418,11 @@ static SDValue performSETCCCombine(SDNode *N,
return DAG.getNode(ISD::SETCC, DL, VT, TST, RHS, N->getOperand(2));
}
}
+ if (Subtarget->hasCSSC() && Cond == ISD::SETNE && isNullConstant(RHS)) {
+ SDValue One = DAG.getConstant(1, DL, LHS.getValueType());
+ auto UMin = DAG.getNode(ISD::UMIN, DL, LHS.getValueType(), LHS, One);
+ return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, UMin);
+ }
// setcc (iN (bitcast (vNi1 X))), 0, (eq|ne)
// ==> setcc (iN (zext (i1 (vecreduce_or (vNi1 X))))), 0, (eq|ne)
@@ -28180,7 +28186,7 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::VSELECT:
return performVSelectCombine(N, DCI.DAG);
case ISD::SETCC:
- return performSETCCCombine(N, DCI, DAG);
+ return performSETCCCombine(N, DCI, DAG, Subtarget);
case ISD::LOAD:
return performLOADCombine(N, DCI, DAG, Subtarget);
case ISD::STORE:
diff --git a/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll b/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
new file mode 100644
index 0000000000000..87b827aaaa3db
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
@@ -0,0 +1,82 @@
+; RUN: llc -mtriple=aarch64-- -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc -mtriple=aarch64-- -mattr=+cssc -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-CSSC
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux-gnu"
+
+; auto icmpi64(long x0) { return x0 != 0; }
+define i1 @icmpi64(i64 noundef %0) {
+; CHECK-SD-LABEL: icmpi64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp x0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: icmpi64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin x0, x0, #1
+; CHECK-CSSC-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %2 = icmp ne i64 %0, 0
+ ret i1 %2
+}
+
+; auto icmpi32(int x0) { return x0 != 0; }
+define i1 @icmpi32(i32 noundef %0) {
+; CHECK-SD-LABEL: icmpi32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp w0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: icmpi32:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin w0, w0, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %2 = icmp ne i32 %0, 0
+ ret i1 %2
+}
+
+; auto icmpi16(short x0) { return x0 != 0; }
+define i1 @icmpi16(i16 noundef %0) {
+; CHECK-SD-LABEL: icmpi16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: tst w0, #0xffff
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: icmpi16:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: and w8, w0, #0xffff
+; CHECK-CSSC-NEXT: umin w0, w8, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %2 = icmp ne i16 %0, 0
+ ret i1 %2
+}
+
+; auto icmpi8(char x0) { return x0 != 0; }
+define i1 @icmpi8(i8 noundef %0) {
+; CHECK-SD-LABEL: icmpi8:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: tst w0, #0xff
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: icmpi8:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: and w8, w0, #0xff
+; CHECK-CSSC-NEXT: umin w0, w8, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %2 = icmp ne i8 %0, 0
+ ret i1 %2
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/AArch64/arm64-popcnt.ll b/llvm/test/CodeGen/AArch64/arm64-popcnt.ll
index d06e42f5405ef..3d6cc814d157d 100644
--- a/llvm/test/CodeGen/AArch64/arm64-popcnt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-popcnt.ll
@@ -414,8 +414,8 @@ define i1 @ctpop32_ne_one_nonzero(i32 %x) {
; CHECK-CSSC-LABEL: ctpop32_ne_one_nonzero:
; CHECK-CSSC: // %bb.0: // %entry
; CHECK-CSSC-NEXT: sub w8, w0, #1
-; CHECK-CSSC-NEXT: tst w0, w8
-; CHECK-CSSC-NEXT: cset w0, ne
+; CHECK-CSSC-NEXT: and w8, w0, w8
+; CHECK-CSSC-NEXT: umin w0, w8, #1
; CHECK-CSSC-NEXT: ret
;
; CHECK-BE-LABEL: ctpop32_ne_one_nonzero:
>From 6ae4bc20abd6f43d9ef943f2718217744266a62e Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Sat, 22 Nov 2025 22:44:18 +0800
Subject: [PATCH 2/3] use the SETCC's VT as new DAG node's type, and add more
tests
---
.../Target/AArch64/AArch64ISelLowering.cpp | 2 +-
.../test/CodeGen/AArch64/aarch64-isel-umin.ll | 241 +++++++++++++++++-
2 files changed, 238 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index fdea0d2dfd268..5c84142152b68 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -26421,7 +26421,7 @@ static SDValue performSETCCCombine(SDNode *N,
if (Subtarget->hasCSSC() && Cond == ISD::SETNE && isNullConstant(RHS)) {
SDValue One = DAG.getConstant(1, DL, LHS.getValueType());
auto UMin = DAG.getNode(ISD::UMIN, DL, LHS.getValueType(), LHS, One);
- return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, UMin);
+ return DAG.getNode(ISD::TRUNCATE, DL, VT, UMin);
}
// setcc (iN (bitcast (vNi1 X))), 0, (eq|ne)
diff --git a/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll b/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
index 87b827aaaa3db..ec60387223f3d 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-isel-umin.ll
@@ -1,5 +1,5 @@
-; RUN: llc -mtriple=aarch64-- -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc -mtriple=aarch64-- -mattr=+cssc -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-CSSC
+; RUN: llc -mtriple=aarch64-- -o - < %s | FileCheck %s --check-prefix=CHECK-SD
+; RUN: llc -mtriple=aarch64-- -mattr=+cssc -o - < %s | FileCheck %s --check-prefix=CHECK-CSSC
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-gnu"
@@ -78,5 +78,238 @@ entry:
%2 = icmp ne i8 %0, 0
ret i1 %2
}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
\ No newline at end of file
+
+; unsigned long icmpi64i8(char x0) { return x0 != 0; }
+define i64 @icmpi64i8(i8 noundef %0) {
+; CHECK-SD-LABEL: icmpi64i8:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: tst w0, #0xff
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: icmpi64i8:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: and w8, w0, #0xff
+; CHECK-CSSC-NEXT: umin w0, w8, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %1 = icmp ne i8 %0, 0
+ %2 = zext i1 %1 to i64
+ ret i64 %2
+}
+
+; unsigned long setcc_i8_i64(char x0) { return x0 != 0; }
+define i8 @setcc_i8_i64(i64 %x) {
+; CHECK-SD-LABEL: setcc_i8_i64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp x0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_i8_i64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin x0, x0, #1
+; CHECK-CSSC-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne i64 %x, 0
+ %conv = zext i1 %cmp to i8
+ ret i8 %conv
+}
+
+; short setcc_i16_i32(int x0) { return x0 != 0; }
+define i16 @setcc_i16_i32(i32 %x) {
+; CHECK-SD-LABEL: setcc_i16_i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp w0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_i16_i32:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin w0, w0, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne i32 %x, 0
+ %conv = zext i1 %cmp to i16
+ ret i16 %conv
+}
+
+; int setcc_i32_i64(unsigned long x0) { return x0 != 0; }
+define i32 @setcc_i32_i64(i64 %x) {
+; CHECK-SD-LABEL: setcc_i32_i64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp x0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_i32_i64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin x0, x0, #1
+; CHECK-CSSC-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne i64 %x, 0
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+}
+
+; unsigned long setcc_i64_i64(unsigned long x0) { return x0 != 0; }
+define i64 @setcc_i64_i64(i64 %x) {
+; CHECK-SD-LABEL: setcc_i64_i64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmp x0, #0
+; CHECK-SD-NEXT: cset w0, ne
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_i64_i64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: umin x0, x0, #1
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne i64 %x, 0
+ %conv = zext i1 %cmp to i64
+ ret i64 %conv
+}
+
+define <2 x i1> @setcc_v2i1_v2i64(<2 x i64> %x) {
+; CHECK-SD-LABEL: setcc_v2i1_v2i64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.2d, v0.2d, v0.2d
+; CHECK-SD-NEXT: xtn v0.2s, v0.2d
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v2i1_v2i64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.2d, v0.2d, v0.2d
+; CHECK-CSSC-NEXT: xtn v0.2s, v0.2d
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <2 x i64> %x, zeroinitializer
+ ret <2 x i1> %cmp
+}
+
+define <4 x i1> @setcc_v4i1_v4i32(<4 x i32> %x) {
+; CHECK-SD-LABEL: setcc_v4i1_v4i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.4s, v0.4s, v0.4s
+; CHECK-SD-NEXT: xtn v0.4h, v0.4s
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v4i1_v4i32:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.4s, v0.4s, v0.4s
+; CHECK-CSSC-NEXT: xtn v0.4h, v0.4s
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <4 x i32> %x, zeroinitializer
+ ret <4 x i1> %cmp
+}
+
+define <8 x i1> @setcc_v8i1_v8i16(<8 x i16> %x) {
+; CHECK-SD-LABEL: setcc_v8i1_v8i16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: xtn v0.8b, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v8i1_v8i16:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.8h, v0.8h, v0.8h
+; CHECK-CSSC-NEXT: xtn v0.8b, v0.8h
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <8 x i16> %x, zeroinitializer
+ ret <8 x i1> %cmp
+}
+
+define <16 x i1> @setcc_v16i1_v16i8(<16 x i8> %x) {
+; CHECK-SD-LABEL: setcc_v16i1_v16i8:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.16b, v0.16b, v0.16b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v16i1_v16i8:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.16b, v0.16b, v0.16b
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <16 x i8> %x, zeroinitializer
+ ret <16 x i1> %cmp
+}
+
+define <2 x i8> @setcc_v2i8_v2i64(<2 x i64> %x) {
+; CHECK-SD-LABEL: setcc_v2i8_v2i64:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.2d, v0.2d, v0.2d
+; CHECK-SD-NEXT: movi v1.2s, #1
+; CHECK-SD-NEXT: xtn v0.2s, v0.2d
+; CHECK-SD-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v2i8_v2i64:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.2d, v0.2d, v0.2d
+; CHECK-CSSC-NEXT: movi v1.2s, #1
+; CHECK-CSSC-NEXT: xtn v0.2s, v0.2d
+; CHECK-CSSC-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <2 x i64> %x, zeroinitializer
+ %conv = zext <2 x i1> %cmp to <2 x i8>
+ ret <2 x i8> %conv
+}
+
+define <4 x i16> @setcc_v4i16_v4i32(<4 x i32> %x) {
+; CHECK-SD-LABEL: setcc_v4i16_v4i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: cmtst v0.4s, v0.4s, v0.4s
+; CHECK-SD-NEXT: movi v1.4h, #1
+; CHECK-SD-NEXT: xtn v0.4h, v0.4s
+; CHECK-SD-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v4i16_v4i32:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: cmtst v0.4s, v0.4s, v0.4s
+; CHECK-CSSC-NEXT: movi v1.4h, #1
+; CHECK-CSSC-NEXT: xtn v0.4h, v0.4s
+; CHECK-CSSC-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <4 x i32> %x, zeroinitializer
+ %conv = zext <4 x i1> %cmp to <4 x i16>
+ ret <4 x i16> %conv
+}
+
+define <4 x i32> @setcc_v4i32_v4i32(<4 x i32> %x) {
+; CHECK-SD-LABEL: setcc_v4i32_v4i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: movi v1.4s, #1
+; CHECK-SD-NEXT: cmeq v0.4s, v0.4s, #0
+; CHECK-SD-NEXT: bic v0.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-CSSC-LABEL: setcc_v4i32_v4i32:
+; CHECK-CSSC: // %bb.0: // %entry
+; CHECK-CSSC-NEXT: movi v1.4s, #1
+; CHECK-CSSC-NEXT: cmeq v0.4s, v0.4s, #0
+; CHECK-CSSC-NEXT: bic v0.16b, v1.16b, v0.16b
+; CHECK-CSSC-NEXT: ret
+;
+entry:
+ %cmp = icmp ne <4 x i32> %x, zeroinitializer
+ %conv = zext <4 x i1> %cmp to <4 x i32>
+ ret <4 x i32> %conv
+}
>From ad2311da9ffa91a26cb75471929e4cd27eb93205 Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Sat, 22 Nov 2025 23:59:00 +0800
Subject: [PATCH 3/3] check whether SETCC is vectortype
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 5c84142152b68..814f71d3fdec7 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -26418,7 +26418,7 @@ static SDValue performSETCCCombine(SDNode *N,
return DAG.getNode(ISD::SETCC, DL, VT, TST, RHS, N->getOperand(2));
}
}
- if (Subtarget->hasCSSC() && Cond == ISD::SETNE && isNullConstant(RHS)) {
+ if (Subtarget->hasCSSC() && Cond == ISD::SETNE && isNullConstant(RHS) && !VT.isVector()) {
SDValue One = DAG.getConstant(1, DL, LHS.getValueType());
auto UMin = DAG.getNode(ISD::UMIN, DL, LHS.getValueType(), LHS, One);
return DAG.getNode(ISD::TRUNCATE, DL, VT, UMin);
More information about the llvm-commits
mailing list