[llvm] [DAGCombiner] add fold (xor (smin(x, C), C)) and fold (xor (smax(x, C), C)) (PR #155141)
guan jian via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 24 00:50:33 PDT 2025
https://github.com/rez5427 updated https://github.com/llvm/llvm-project/pull/155141
>From f8575c96d83f9040c05d788492edf7a4ac5392a8 Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Sun, 24 Aug 2025 13:34:01 +0800
Subject: [PATCH] [DAGCombiner] add fold (xor (smin(x, C), C)) -> select (x <
C), xor(x, C), 0
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 42 +++++++++++
llvm/test/CodeGen/AArch64/xor-smin-smax.ll | 75 +++++++++++++++++++
2 files changed, 117 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/xor-smin-smax.ll
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index cee593def653c..2d4d74935e1bc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10086,6 +10086,48 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
if (SDValue Combined = combineCarryDiamond(DAG, TLI, N0, N1, N))
return Combined;
+ // fold (xor (smin(x, C), C)) -> select (x < C), xor(x, C), 0
+ // fold (xor (smin(C, x), C)) -> select (x < C), xor(x, C), 0
+ if (N0.getOpcode() == ISD::SMIN && N0.hasOneUse()) {
+ SDValue Op0 = N0.getOperand(0);
+ SDValue Op1 = N0.getOperand(1);
+
+ if (Op1 != N1) {
+ std::swap(Op0, Op1);
+ }
+
+ if (Op1 == N1) {
+ if (isa<ConstantSDNode>(N1)) {
+ EVT CCVT = getSetCCResultType(VT);
+ SDValue Cmp = DAG.getSetCC(SDLoc(N), CCVT, Op0, N1, ISD::SETLT);
+ SDValue XorXC = DAG.getNode(ISD::XOR, SDLoc(N), VT, Op0, N1);
+ SDValue Zero = DAG.getConstant(0, SDLoc(N), VT);
+ return DAG.getSelect(SDLoc(N), VT, Cmp, XorXC, Zero);
+ }
+ }
+ }
+
+ // fold (xor (smax(x, C), C)) -> select (x > C), xor(x, C), 0
+ // fold (xor (smax(C, x), C)) -> select (x > C), xor(x, C), 0
+ if (N0.getOpcode() == ISD::SMAX && N0.hasOneUse()) {
+ SDValue Op0 = N0.getOperand(0);
+ SDValue Op1 = N0.getOperand(1);
+
+ if (Op1 != N1) {
+ std::swap(Op0, Op1);
+ }
+
+ if (Op1 == N1) {
+ if (isa<ConstantSDNode>(N1)) {
+ EVT CCVT = getSetCCResultType(VT);
+ SDValue Cmp = DAG.getSetCC(SDLoc(N), CCVT, Op0, N1, ISD::SETGT);
+ SDValue XorXC = DAG.getNode(ISD::XOR, SDLoc(N), VT, Op0, N1);
+ SDValue Zero = DAG.getConstant(0, SDLoc(N), VT);
+ return DAG.getSelect(SDLoc(N), VT, Cmp, XorXC, Zero);
+ }
+ }
+ }
+
return SDValue();
}
diff --git a/llvm/test/CodeGen/AArch64/xor-smin-smax.ll b/llvm/test/CodeGen/AArch64/xor-smin-smax.ll
new file mode 100644
index 0000000000000..cfdec2da61c7a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/xor-smin-smax.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=aarch64-unknown-unknown | FileCheck %s
+
+; Test for DAGCombiner optimization: fold (xor (smin(x, C), C)) -> select (x < C), xor (x, C), 0
+
+define i64 @test_smin_neg_one(i64 %a) {
+; CHECK-LABEL: test_smin_neg_one:
+; CHECK: // %bb.0:
+; CHECK-NEXT: cmn x0, #1
+; CHECK-NEXT: csinv x0, xzr, x0, ge
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smin.i64(i64 %a, i64 -1)
+ %retval.0 = xor i64 %1, -1
+ ret i64 %retval.0
+}
+
+define i64 @test_smin_zero(i64 %a) {
+; CHECK-LABEL: test_smin_zero:
+; CHECK: // %bb.0:
+; CHECK-NEXT: and x0, x0, x0, asr #63
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smin.i64(i64 %a, i64 0)
+ %retval.0 = xor i64 %1, 0
+ ret i64 %retval.0
+}
+
+define i64 @test_smin_constant(i64 %a) {
+; CHECK-LABEL: test_smin_constant:
+; CHECK: // %bb.0:
+; CHECK-NEXT: eor x8, x0, #0x8
+; CHECK-NEXT: cmp x0, #8
+; CHECK-NEXT: csel x0, x8, xzr, lt
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smin.i64(i64 %a, i64 8)
+ %retval.0 = xor i64 %1, 8
+ ret i64 %retval.0
+}
+
+; Test for DAGCombiner optimization: fold (xor (smax(x, C), C)) -> select (x > C), xor (x, C), 0
+
+define i64 @test_smax_neg_one(i64 %a) {
+; CHECK-LABEL: test_smax_neg_one:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mvn x8, x0
+; CHECK-NEXT: bic x0, x8, x0, asr #63
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smax.i64(i64 %a, i64 -1)
+ %retval.0 = xor i64 %1, -1
+ ret i64 %retval.0
+}
+
+define i64 @test_smax_zero(i64 %a) {
+; CHECK-LABEL: test_smax_zero:
+; CHECK: // %bb.0:
+; CHECK-NEXT: bic x0, x0, x0, asr #63
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smax.i64(i64 %a, i64 0)
+ %retval.0 = xor i64 %1, 0
+ ret i64 %retval.0
+}
+
+define i64 @test_smax_constant(i64 %a) {
+; CHECK-LABEL: test_smax_constant:
+; CHECK: // %bb.0:
+; CHECK-NEXT: eor x8, x0, #0x8
+; CHECK-NEXT: cmp x0, #8
+; CHECK-NEXT: csel x0, x8, xzr, gt
+; CHECK-NEXT: ret
+ %1 = tail call i64 @llvm.smax.i64(i64 %a, i64 8)
+ %retval.0 = xor i64 %1, 8
+ ret i64 %retval.0
+}
+
+declare i64 @llvm.smin.i64(i64, i64)
+declare i64 @llvm.smax.i64(i64, i64)
\ No newline at end of file
More information about the llvm-commits
mailing list