[llvm] [AArch64] Add optimizations that are not added as a result of custom lowering for min/max (PR #151880)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 3 15:17:37 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/151880
>From 8b57bbea3488361336a29cfce8e462b462d27352 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 3 Aug 2025 14:32:49 -0400
Subject: [PATCH 1/2] [AArch64] Add optimizations that are not added as a
result of custom lowering for min/max
These are taken from expandINTMinMax
---
.../Target/AArch64/AArch64ISelLowering.cpp | 30 +++++++++++-
llvm/test/CodeGen/AArch64/aarch64-minmaxv.ll | 46 +++++++++----------
2 files changed, 50 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2b6ea86ee1af5..83f6d9d1ee1ec 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -10942,6 +10942,9 @@ SDValue AArch64TargetLowering::LowerMinMax(SDValue Op,
EVT VT = Op.getValueType();
SDLoc DL(Op);
unsigned Opcode = Op.getOpcode();
+ SDValue Op0 = Op.getOperand(0);
+ SDValue Op1 = Op.getOperand(1);
+ EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
ISD::CondCode CC;
switch (Opcode) {
default:
@@ -10960,6 +10963,31 @@ SDValue AArch64TargetLowering::LowerMinMax(SDValue Op,
break;
}
+ // umax(x,1) --> sub(x,cmpeq(x,0)) iff cmp result is allbits
+ if (Opcode == ISD::UMAX && llvm::isOneOrOneSplat(Op1, true) && BoolVT == VT &&
+ getBooleanContents(VT) == ZeroOrNegativeOneBooleanContent) {
+ Op0 = DAG.getFreeze(Op0);
+ SDValue Zero = DAG.getConstant(0, DL, VT);
+ return DAG.getNode(ISD::SUB, DL, VT, Op0,
+ DAG.getSetCC(DL, VT, Op0, Zero, ISD::SETEQ));
+ }
+
+ // umin(x,y) -> sub(x,usubsat(x,y))
+ // TODO: Missing freeze(Op0)?
+ if (Opcode == ISD::UMIN && isOperationLegal(ISD::SUB, VT) &&
+ isOperationLegal(ISD::USUBSAT, VT)) {
+ return DAG.getNode(ISD::SUB, DL, VT, Op0,
+ DAG.getNode(ISD::USUBSAT, DL, VT, Op0, Op1));
+ }
+
+ // umax(x,y) -> add(x,usubsat(y,x))
+ // TODO: Missing freeze(Op0)?
+ if (Opcode == ISD::UMAX && isOperationLegal(ISD::ADD, VT) &&
+ isOperationLegal(ISD::USUBSAT, VT)) {
+ return DAG.getNode(ISD::ADD, DL, VT, Op0,
+ DAG.getNode(ISD::USUBSAT, DL, VT, Op1, Op0));
+ }
+
if (VT.isScalableVector() ||
useSVEForFixedLengthVectorVT(
VT, /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors())) {
@@ -10977,8 +11005,6 @@ SDValue AArch64TargetLowering::LowerMinMax(SDValue Op,
}
}
- SDValue Op0 = Op.getOperand(0);
- SDValue Op1 = Op.getOperand(1);
SDValue Cond = DAG.getSetCC(DL, VT, Op0, Op1, CC);
return DAG.getSelect(DL, VT, Cond, Op0, Op1);
}
diff --git a/llvm/test/CodeGen/AArch64/aarch64-minmaxv.ll b/llvm/test/CodeGen/AArch64/aarch64-minmaxv.ll
index 8a503bb65c079..2641ba4fac719 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-minmaxv.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-minmaxv.ll
@@ -1406,8 +1406,8 @@ define i64 @uminv_v2i64(<2 x i64> %a) {
; CHECK-SD-LABEL: uminv_v2i64:
; CHECK-SD: // %bb.0: // %entry
; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
-; CHECK-SD-NEXT: cmhi d2, d1, d0
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: uqsub d1, d0, d1
+; CHECK-SD-NEXT: sub d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
@@ -1434,11 +1434,11 @@ define i64 @uminv_v3i64(<3 x i64> %a) {
; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
; CHECK-SD-NEXT: mov v0.d[1], v1.d[0]
; CHECK-SD-NEXT: mov v2.d[1], x8
-; CHECK-SD-NEXT: cmhi v1.2d, v2.2d, v0.2d
-; CHECK-SD-NEXT: bif v0.16b, v2.16b, v1.16b
+; CHECK-SD-NEXT: uqsub v1.2d, v0.2d, v2.2d
+; CHECK-SD-NEXT: sub v0.2d, v0.2d, v1.2d
; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
-; CHECK-SD-NEXT: cmhi d2, d1, d0
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: uqsub d1, d0, d1
+; CHECK-SD-NEXT: sub d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
@@ -1467,11 +1467,11 @@ entry:
define i64 @uminv_v4i64(<4 x i64> %a) {
; CHECK-SD-LABEL: uminv_v4i64:
; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: cmhi v2.2d, v1.2d, v0.2d
-; CHECK-SD-NEXT: bif v0.16b, v1.16b, v2.16b
+; CHECK-SD-NEXT: uqsub v1.2d, v0.2d, v1.2d
+; CHECK-SD-NEXT: sub v0.2d, v0.2d, v1.2d
; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
-; CHECK-SD-NEXT: cmhi d2, d1, d0
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: uqsub d1, d0, d1
+; CHECK-SD-NEXT: sub d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
@@ -1762,8 +1762,8 @@ define i64 @umaxv_v2i64(<2 x i64> %a) {
; CHECK-SD-LABEL: umaxv_v2i64:
; CHECK-SD: // %bb.0: // %entry
; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
-; CHECK-SD-NEXT: cmhi d2, d0, d1
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: uqsub d1, d1, d0
+; CHECK-SD-NEXT: add d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
@@ -1785,17 +1785,15 @@ define i64 @umaxv_v3i64(<3 x i64> %a) {
; CHECK-SD-LABEL: umaxv_v3i64:
; CHECK-SD: // %bb.0: // %entry
; CHECK-SD-NEXT: // kill: def $d2 killed $d2 def $q2
-; CHECK-SD-NEXT: mov v3.16b, v2.16b
; CHECK-SD-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
; CHECK-SD-NEXT: mov v0.d[1], v1.d[0]
-; CHECK-SD-NEXT: mov v3.d[1], xzr
-; CHECK-SD-NEXT: cmhi v3.2d, v0.2d, v3.2d
-; CHECK-SD-NEXT: ext v4.16b, v3.16b, v3.16b, #8
-; CHECK-SD-NEXT: bif v0.16b, v2.16b, v3.16b
-; CHECK-SD-NEXT: and v1.8b, v1.8b, v4.8b
-; CHECK-SD-NEXT: cmhi d2, d0, d1
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: mov v2.d[1], xzr
+; CHECK-SD-NEXT: uqsub v1.2d, v2.2d, v0.2d
+; CHECK-SD-NEXT: add v0.2d, v0.2d, v1.2d
+; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; CHECK-SD-NEXT: uqsub d1, d1, d0
+; CHECK-SD-NEXT: add d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
@@ -1823,11 +1821,11 @@ entry:
define i64 @umaxv_v4i64(<4 x i64> %a) {
; CHECK-SD-LABEL: umaxv_v4i64:
; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: cmhi v2.2d, v0.2d, v1.2d
-; CHECK-SD-NEXT: bif v0.16b, v1.16b, v2.16b
+; CHECK-SD-NEXT: uqsub v1.2d, v1.2d, v0.2d
+; CHECK-SD-NEXT: add v0.2d, v0.2d, v1.2d
; CHECK-SD-NEXT: ext v1.16b, v0.16b, v0.16b, #8
-; CHECK-SD-NEXT: cmhi d2, d0, d1
-; CHECK-SD-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-SD-NEXT: uqsub d1, d1, d0
+; CHECK-SD-NEXT: add d0, d0, d1
; CHECK-SD-NEXT: fmov x0, d0
; CHECK-SD-NEXT: ret
;
>From 713b10e84c1db9ddfa934e8e2c9abb8767e93f80 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 3 Aug 2025 18:17:24 -0400
Subject: [PATCH 2/2] Update AArch64ISelLowering.cpp
---
.../Target/AArch64/AArch64ISelLowering.cpp | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 83f6d9d1ee1ec..c99b07147559e 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -10963,7 +10963,24 @@ SDValue AArch64TargetLowering::LowerMinMax(SDValue Op,
break;
}
- // umax(x,1) --> sub(x,cmpeq(x,0)) iff cmp result is allbits
+ if (VT.isScalableVector() ||
+ useSVEForFixedLengthVectorVT(
+ VT, /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors())) {
+ switch (Opcode) {
+ default:
+ llvm_unreachable("Wrong instruction");
+ case ISD::SMAX:
+ return LowerToPredicatedOp(Op, DAG, AArch64ISD::SMAX_PRED);
+ case ISD::SMIN:
+ return LowerToPredicatedOp(Op, DAG, AArch64ISD::SMIN_PRED);
+ case ISD::UMAX:
+ return LowerToPredicatedOp(Op, DAG, AArch64ISD::UMAX_PRED);
+ case ISD::UMIN:
+ return LowerToPredicatedOp(Op, DAG, AArch64ISD::UMIN_PRED);
+ }
+ }
+
+ // umax(x,1) --> sub(x,cmpeq(x,0)) iff cmp result is allbits
if (Opcode == ISD::UMAX && llvm::isOneOrOneSplat(Op1, true) && BoolVT == VT &&
getBooleanContents(VT) == ZeroOrNegativeOneBooleanContent) {
Op0 = DAG.getFreeze(Op0);
@@ -10988,23 +11005,6 @@ SDValue AArch64TargetLowering::LowerMinMax(SDValue Op,
DAG.getNode(ISD::USUBSAT, DL, VT, Op1, Op0));
}
- if (VT.isScalableVector() ||
- useSVEForFixedLengthVectorVT(
- VT, /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors())) {
- switch (Opcode) {
- default:
- llvm_unreachable("Wrong instruction");
- case ISD::SMAX:
- return LowerToPredicatedOp(Op, DAG, AArch64ISD::SMAX_PRED);
- case ISD::SMIN:
- return LowerToPredicatedOp(Op, DAG, AArch64ISD::SMIN_PRED);
- case ISD::UMAX:
- return LowerToPredicatedOp(Op, DAG, AArch64ISD::UMAX_PRED);
- case ISD::UMIN:
- return LowerToPredicatedOp(Op, DAG, AArch64ISD::UMIN_PRED);
- }
- }
-
SDValue Cond = DAG.getSetCC(DL, VT, Op0, Op1, CC);
return DAG.getSelect(DL, VT, Cond, Op0, Op1);
}
More information about the llvm-commits
mailing list