[llvm] SelectionDAG: Support nofpclass(nan/qnan/snan) in arguments (PR #130051)
YunQiang Su via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 9 17:55:27 PDT 2025
https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/130051
>From 92938f49ed1a66ae26c53167c61bb19ab1b3879d Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Thu, 6 Mar 2025 18:09:56 +0800
Subject: [PATCH 1/2] SelectionDAG: Support nofpclass(nan/qnan/snan)
SelectionDAGISel::LowerArguments: Pass NoNaN Flags to InVals.
`nofpclass` support values nan, snan, qnan, where nan=snan|qnan.
So let's use NoSNaNs and NoQNaNs in SDNodeFlags.
Thus, we can use it in isKnownNeverNaN.
---
llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 25 +-
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 7 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 10 +
.../AArch64/fp-maximumnum-minimumnum.ll | 973 ++++++++++++++++++
.../LoongArch/fp-maximumnum-minimumnum.ll | 241 +++++
.../CodeGen/Mips/fp-maximumnum-minimumnum.ll | 73 ++
6 files changed, 1322 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 2283f99202e2f..5fc670ac4d022 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -397,7 +397,7 @@ struct SDNodeFlags {
Exact = 1 << 2,
Disjoint = 1 << 3,
NonNeg = 1 << 4,
- NoNaNs = 1 << 5,
+ // 1 << 5 was used as NoNaNs
NoInfs = 1 << 6,
NoSignedZeros = 1 << 7,
AllowReciprocal = 1 << 8,
@@ -416,13 +416,18 @@ struct SDNodeFlags {
// Compare instructions which may carry the samesign flag.
SameSign = 1 << 14,
+ NoSNaNs = 1 << 15,
+ NoQNaNs = 1 << 16,
+
// NOTE: Please update LargestValue in LLVM_DECLARE_ENUM_AS_BITMASK below
// the class definition when adding new flags.
PoisonGeneratingFlags = NoUnsignedWrap | NoSignedWrap | Exact | Disjoint |
NonNeg | NoNaNs | NoInfs | SameSign,
- FastMathFlags = NoNaNs | NoInfs | NoSignedZeros | AllowReciprocal |
- AllowContract | ApproximateFuncs | AllowReassociation,
+ FastMathFlags = NoSNaNs | NoQNaNs | NoInfs | NoSignedZeros |
+ AllowReciprocal | AllowContract | ApproximateFuncs |
+ AllowReassociation,
+>>>>>>> 3a271aeff00e (SelectionDAG: Support nofpclass(nan/qnan/snan))
};
/// Default constructor turns off all optimization flags.
@@ -430,7 +435,8 @@ struct SDNodeFlags {
/// Propagate the fast-math-flags from an IR FPMathOperator.
void copyFMF(const FPMathOperator &FPMO) {
- setNoNaNs(FPMO.hasNoNaNs());
+ setNoSNaNs(FPMO.hasNoNaNs());
+ setNoQNaNs(FPMO.hasNoNaNs());
setNoInfs(FPMO.hasNoInfs());
setNoSignedZeros(FPMO.hasNoSignedZeros());
setAllowReciprocal(FPMO.hasAllowReciprocal());
@@ -446,7 +452,12 @@ struct SDNodeFlags {
void setDisjoint(bool b) { setFlag<Disjoint>(b); }
void setSameSign(bool b) { setFlag<SameSign>(b); }
void setNonNeg(bool b) { setFlag<NonNeg>(b); }
- void setNoNaNs(bool b) { setFlag<NoNaNs>(b); }
+ void setNoNaNs(bool b) {
+ setFlag<NoSNaNs>(b);
+ setFlag<NoQNaNs>(b);
+ }
+ void setNoSNaNs(bool b) { setFlag<NoSNaNs>(b); }
+ void setNoQNaNs(bool b) { setFlag<NoQNaNs>(b); }
void setNoInfs(bool b) { setFlag<NoInfs>(b); }
void setNoSignedZeros(bool b) { setFlag<NoSignedZeros>(b); }
void setAllowReciprocal(bool b) { setFlag<AllowReciprocal>(b); }
@@ -463,7 +474,9 @@ struct SDNodeFlags {
bool hasDisjoint() const { return Flags & Disjoint; }
bool hasSameSign() const { return Flags & SameSign; }
bool hasNonNeg() const { return Flags & NonNeg; }
- bool hasNoNaNs() const { return Flags & NoNaNs; }
+ bool hasNoNaNs() const { return (Flags & NoSNaNs) && (Flags & NoQNaNs); }
+ bool hasNoSNaNs() const { return Flags & NoSNaNs; }
+ bool hasNoQNaNs() const { return Flags & NoQNaNs; }
bool hasNoInfs() const { return Flags & NoInfs; }
bool hasNoSignedZeros() const { return Flags & NoSignedZeros; }
bool hasAllowReciprocal() const { return Flags & AllowReciprocal; }
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index df30148b78b65..7fc97fadeff09 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5613,7 +5613,12 @@ bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth) const {
// If we're told that NaNs won't happen, assume they won't.
- if (getTarget().Options.NoNaNsFPMath || Op->getFlags().hasNoNaNs())
+ if (getTarget().Options.NoNaNsFPMath)
+ return true;
+ SDNodeFlags OpFlags = Op->getFlags();
+ if (SNaN && OpFlags.hasNoSNaNs())
+ return true;
+ if (OpFlags.hasNoSNaNs() && OpFlags.hasNoQNaNs())
return true;
if (Depth >= MaxRecursionDepth)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 66dc86cd13e2d..9942bbfbe9389 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11891,6 +11891,16 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
AssertOp = ISD::AssertSext;
else if (Arg.hasAttribute(Attribute::ZExt))
AssertOp = ISD::AssertZext;
+ if (Arg.hasAttribute(Attribute::NoFPClass)) {
+ SDNodeFlags InValFlags = InVals[i]->getFlags();
+ bool NoSNaN = ((Arg.getNoFPClass() & llvm::fcSNan) == llvm::fcSNan);
+ bool NoQNaN = ((Arg.getNoFPClass() & llvm::fcQNan) == llvm::fcQNan);
+ InValFlags.setNoSNaNs(NoSNaN);
+ InValFlags.setNoQNaNs(NoQNaN);
+ InValFlags.setNoInfs((Arg.getNoFPClass() & llvm::fcInf) ==
+ llvm::fcInf);
+ InVals[i]->setFlags(InValFlags);
+ }
ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
PartVT, VT, nullptr, NewRoot,
diff --git a/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
index bb3f9a3e52a16..2ef6d17f657b2 100644
--- a/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
@@ -1,5 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=aarch64 --mattr=+fullfp16 < %s | FileCheck %s --check-prefix=AARCH64
+; FIXME: nofpclass with length more than 128bit, may emit unnecessary instructions.
;;;;;;;;;;;;;;;; max_f64
define double @max_nnan_f64(double %a, double %b) {
@@ -1032,3 +1033,975 @@ entry:
%c = call <16 x half> @llvm.minimumnum.v16f16(<16 x half> %a, <16 x half> %b)
ret <16 x half> %c
}
+;;;;;;;;;;;;;;;; max_f64
+define double @max_nofpclass_f64(double nofpclass(nan) %a, double nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.maximumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @max_nofpclass_v2f64(<2 x double> nofpclass(nan) %a, <2 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @max_nofpclass_v3f64(<3 x double> nofpclass(nan) %a, <3 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fmaxnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.maximumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @max_nofpclass_v4f64(<4 x double> nofpclass(nan) %a, <4 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fmaxnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.maximumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+;;;;;;;;;;;;;;;;;; max_f32
+define float @max_nofpclass_f32(float nofpclass(nan) %a, float nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm s0, s0, s1
+; AARCH64-NEXT: ret
+entry:
+ %c = call float @llvm.maximumnum.f32(float %a, float %b)
+ ret float %c
+}
+
+define <2 x float> @max_nofpclass_v2f32(<2 x float> nofpclass(nan) %a, <2 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @max_nofpclass_v3f32(<3 x float> nofpclass(nan) %a, <3 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.maximumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @max_nofpclass_v4f32(<4 x float> nofpclass(nan) %a, <4 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @max_nofpclass_v5f32(<5 x float> nofpclass(nan) %a, <5 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fmaxnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.maximumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @max_nofpclass_v8f32(<8 x float> nofpclass(nan) %a, <8 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fmaxnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.maximumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+define <2 x half> @max_nofpclass_v2f16(<2 x half> nofpclass(nan) %a, <2 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.maximumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @max_nofpclass_v4f16(<4 x half> nofpclass(nan) %a, <4 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @max_nofpclass_v8f16(<8 x half> nofpclass(nan) %a, <8 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.maximumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @max_nofpclass_v9f16(<9 x half> nofpclass(nan) %a, <9 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fmaxnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.maximumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @max_nofpclass_v16f16(<16 x half> nofpclass(nan) %a, <16 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: max_nofpclass_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fmaxnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.maximumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
+
+;;;;;;;;;;;;;;;; min_f64
+define double @min_nofpclass_f64(double nofpclass(nan) %a, double nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.minimumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @min_nofpclass_v2f64(<2 x double> nofpclass(nan) %a, <2 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @min_nofpclass_v3f64(<3 x double> nofpclass(nan) %a, <3 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.minimumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @min_nofpclass_v4f64(<4 x double> nofpclass(nan) %a, <4 x double> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.minimumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+define <2 x float> @min_nofpclass_v2f32(<2 x float> nofpclass(nan) %a, <2 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @min_nofpclass_v3f32(<3 x float> nofpclass(nan) %a, <3 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.minimumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @min_nofpclass_v4f32(<4 x float> nofpclass(nan) %a, <4 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @min_nofpclass_v5f32(<5 x float> nofpclass(nan) %a, <5 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.minimumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @min_nofpclass_v8f32(<8 x float> nofpclass(nan) %a, <8 x float> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.minimumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+;;;;;;;;;;;;;;;;;; min_f16
+define half @min_nofpclass_f16(half nofpclass(nan) %a, half nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm h0, h0, h1
+; AARCH64-NEXT: ret
+entry:
+ %c = call half @llvm.minimumnum.f16(half %a, half %b)
+ ret half %c
+}
+
+define <2 x half> @min_nofpclass_v2f16(<2 x half> nofpclass(nan) %a, <2 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @min_nofpclass_v4f16(<4 x half> nofpclass(nan) %a, <4 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.minimumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @min_nofpclass_v8f16(<8 x half> nofpclass(nan) %a, <8 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.minimumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @min_nofpclass_v9f16(<9 x half> nofpclass(nan) %a, <9 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.minimumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @min_nofpclass_v16f16(<16 x half> nofpclass(nan) %a, <16 x half> nofpclass(nan) %b) {
+; AARCH64-LABEL: min_nofpclass_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.minimumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
+
+
+;;;;;;;;;;;;;;;; max_f64
+define double @max_nofpclass_s_f64(double nofpclass(snan) %a, double nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.maximumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @max_nofpclass_s_v2f64(<2 x double> nofpclass(snan) %a, <2 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @max_nofpclass_s_v3f64(<3 x double> nofpclass(snan) %a, <3 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fmaxnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.maximumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @max_nofpclass_s_v4f64(<4 x double> nofpclass(snan) %a, <4 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fmaxnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.maximumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+;;;;;;;;;;;;;;;;;; max_f32
+define float @max_nofpclass_s_f32(float nofpclass(snan) %a, float nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm s0, s0, s1
+; AARCH64-NEXT: ret
+entry:
+ %c = call float @llvm.maximumnum.f32(float %a, float %b)
+ ret float %c
+}
+
+define <2 x float> @max_nofpclass_s_v2f32(<2 x float> nofpclass(snan) %a, <2 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @max_nofpclass_s_v3f32(<3 x float> nofpclass(snan) %a, <3 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.maximumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @max_nofpclass_s_v4f32(<4 x float> nofpclass(snan) %a, <4 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @max_nofpclass_s_v5f32(<5 x float> nofpclass(snan) %a, <5 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fmaxnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.maximumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @max_nofpclass_s_v8f32(<8 x float> nofpclass(snan) %a, <8 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fmaxnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.maximumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+define <2 x half> @max_nofpclass_s_v2f16(<2 x half> nofpclass(snan) %a, <2 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.maximumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @max_nofpclass_s_v4f16(<4 x half> nofpclass(snan) %a, <4 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @max_nofpclass_s_v8f16(<8 x half> nofpclass(snan) %a, <8 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.maximumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @max_nofpclass_s_v9f16(<9 x half> nofpclass(snan) %a, <9 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fmaxnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.maximumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @max_nofpclass_s_v16f16(<16 x half> nofpclass(snan) %a, <16 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: max_nofpclass_s_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fmaxnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.maximumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
+
+;;;;;;;;;;;;;;;; min_f64
+define double @min_nofpclass_s_f64(double nofpclass(snan) %a, double nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.minimumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @min_nofpclass_s_v2f64(<2 x double> nofpclass(snan) %a, <2 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @min_nofpclass_s_v3f64(<3 x double> nofpclass(snan) %a, <3 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.minimumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @min_nofpclass_s_v4f64(<4 x double> nofpclass(snan) %a, <4 x double> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.minimumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+define <2 x float> @min_nofpclass_s_v2f32(<2 x float> nofpclass(snan) %a, <2 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @min_nofpclass_s_v3f32(<3 x float> nofpclass(snan) %a, <3 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.minimumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @min_nofpclass_s_v4f32(<4 x float> nofpclass(snan) %a, <4 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @min_nofpclass_s_v5f32(<5 x float> nofpclass(snan) %a, <5 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.minimumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @min_nofpclass_s_v8f32(<8 x float> nofpclass(snan) %a, <8 x float> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.minimumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+;;;;;;;;;;;;;;;;;; min_f16
+define half @min_nofpclass_s_f16(half nofpclass(snan) %a, half nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm h0, h0, h1
+; AARCH64-NEXT: ret
+entry:
+ %c = call half @llvm.minimumnum.f16(half %a, half %b)
+ ret half %c
+}
+
+define <2 x half> @min_nofpclass_s_v2f16(<2 x half> nofpclass(snan) %a, <2 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @min_nofpclass_s_v4f16(<4 x half> nofpclass(snan) %a, <4 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.minimumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @min_nofpclass_s_v8f16(<8 x half> nofpclass(snan) %a, <8 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.minimumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @min_nofpclass_s_v9f16(<9 x half> nofpclass(snan) %a, <9 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.minimumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @min_nofpclass_s_v16f16(<16 x half> nofpclass(snan) %a, <16 x half> nofpclass(snan) %b) {
+; AARCH64-LABEL: min_nofpclass_s_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.minimumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
diff --git a/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
index b4fdd954b856c..b8b47218c9670 100644
--- a/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
@@ -100,6 +100,54 @@ define float @maximumnum_float_nnan(float %x, float %y) {
ret float %z
}
+define float @maximumnum_float_nofpclass(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; LA32F-LABEL: maximumnum_float_nofpclass:
+; LA32F: # %bb.0:
+; LA32F-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: maximumnum_float_nofpclass:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: maximumnum_float_nofpclass:
+; LA64F: # %bb.0:
+; LA64F-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: maximumnum_float_nofpclass:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call float @llvm.maximumnum.f32(float %x, float %y)
+ ret float %z
+}
+
+define float @maximumnum_float_nofpclass_s(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; LA32F-LABEL: maximumnum_float_nofpclass_s:
+; LA32F: # %bb.0:
+; LA32F-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: maximumnum_float_nofpclass_s:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: maximumnum_float_nofpclass_s:
+; LA64F: # %bb.0:
+; LA64F-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: maximumnum_float_nofpclass_s:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call float @llvm.maximumnum.f32(float %x, float %y)
+ ret float %z
+}
+
define double @maximumnum_double(double %x, double %y) {
;
@@ -220,6 +268,79 @@ define double @maximumnum_double_nnan(double %x, double %y) {
ret double %z
}
+define double @maximumnum_double_nofpclass(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; LA32F-LABEL: maximumnum_double_nofpclass:
+; LA32F: # %bb.0:
+; LA32F-NEXT: addi.w $sp, $sp, -16
+; LA32F-NEXT: .cfi_def_cfa_offset 16
+; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT: .cfi_offset 1, -4
+; LA32F-NEXT: bl %plt(fmaximum_num)
+; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT: addi.w $sp, $sp, 16
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: maximumnum_double_nofpclass:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: maximumnum_double_nofpclass:
+; LA64F: # %bb.0:
+; LA64F-NEXT: addi.d $sp, $sp, -16
+; LA64F-NEXT: .cfi_def_cfa_offset 16
+; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT: .cfi_offset 1, -8
+; LA64F-NEXT: bl %plt(fmaximum_num)
+; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT: addi.d $sp, $sp, 16
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: maximumnum_double_nofpclass:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call double @llvm.maximumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+define double @maximumnum_double_nofpclass_s(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; LA32F-LABEL: maximumnum_double_nofpclass_s:
+; LA32F: # %bb.0:
+; LA32F-NEXT: addi.w $sp, $sp, -16
+; LA32F-NEXT: .cfi_def_cfa_offset 16
+; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT: .cfi_offset 1, -4
+; LA32F-NEXT: bl %plt(fmaximum_num)
+; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT: addi.w $sp, $sp, 16
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: maximumnum_double_nofpclass_s:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: maximumnum_double_nofpclass_s:
+; LA64F: # %bb.0:
+; LA64F-NEXT: addi.d $sp, $sp, -16
+; LA64F-NEXT: .cfi_def_cfa_offset 16
+; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT: .cfi_offset 1, -8
+; LA64F-NEXT: bl %plt(fmaximum_num)
+; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT: addi.d $sp, $sp, 16
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: maximumnum_double_nofpclass_s:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call double @llvm.maximumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+
define float @minimumnum_float(float %x, float %y) {
;
; LA32F-LABEL: minimumnum_float:
@@ -311,6 +432,54 @@ define float @minimumnum_float_nnan(float %x, float %y) {
ret float %z
}
+define float @minimumnum_float_nofpclass(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; LA32F-LABEL: minimumnum_float_nofpclass:
+; LA32F: # %bb.0:
+; LA32F-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: minimumnum_float_nofpclass:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: minimumnum_float_nofpclass:
+; LA64F: # %bb.0:
+; LA64F-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: minimumnum_float_nofpclass:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call float @llvm.minimumnum.f32(float %x, float %y)
+ ret float %z
+}
+
+define float @minimumnum_float_nofpclass_s(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; LA32F-LABEL: minimumnum_float_nofpclass_s:
+; LA32F: # %bb.0:
+; LA32F-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: minimumnum_float_nofpclass_s:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: minimumnum_float_nofpclass_s:
+; LA64F: # %bb.0:
+; LA64F-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: minimumnum_float_nofpclass_s:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmin.s $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call float @llvm.minimumnum.f32(float %x, float %y)
+ ret float %z
+}
+
define double @minimumnum_double(double %x, double %y) {
;
; LA32F-LABEL: minimumnum_double:
@@ -429,3 +598,75 @@ define double @minimumnum_double_nnan(double %x, double %y) {
%z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
ret double %z
}
+
+define double @minimumnum_double_nofpclass(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; LA32F-LABEL: minimumnum_double_nofpclass:
+; LA32F: # %bb.0:
+; LA32F-NEXT: addi.w $sp, $sp, -16
+; LA32F-NEXT: .cfi_def_cfa_offset 16
+; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT: .cfi_offset 1, -4
+; LA32F-NEXT: bl %plt(fminimum_num)
+; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT: addi.w $sp, $sp, 16
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: minimumnum_double_nofpclass:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: minimumnum_double_nofpclass:
+; LA64F: # %bb.0:
+; LA64F-NEXT: addi.d $sp, $sp, -16
+; LA64F-NEXT: .cfi_def_cfa_offset 16
+; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT: .cfi_offset 1, -8
+; LA64F-NEXT: bl %plt(fminimum_num)
+; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT: addi.d $sp, $sp, 16
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: minimumnum_double_nofpclass:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call double @llvm.minimumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+define double @minimumnum_double_nofpclass_s(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; LA32F-LABEL: minimumnum_double_nofpclass_s:
+; LA32F: # %bb.0:
+; LA32F-NEXT: addi.w $sp, $sp, -16
+; LA32F-NEXT: .cfi_def_cfa_offset 16
+; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT: .cfi_offset 1, -4
+; LA32F-NEXT: bl %plt(fminimum_num)
+; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT: addi.w $sp, $sp, 16
+; LA32F-NEXT: ret
+;
+; LA32D-LABEL: minimumnum_double_nofpclass_s:
+; LA32D: # %bb.0:
+; LA32D-NEXT: fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT: ret
+;
+; LA64F-LABEL: minimumnum_double_nofpclass_s:
+; LA64F: # %bb.0:
+; LA64F-NEXT: addi.d $sp, $sp, -16
+; LA64F-NEXT: .cfi_def_cfa_offset 16
+; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT: .cfi_offset 1, -8
+; LA64F-NEXT: bl %plt(fminimum_num)
+; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT: addi.d $sp, $sp, 16
+; LA64F-NEXT: ret
+;
+; LA64D-LABEL: minimumnum_double_nofpclass_s:
+; LA64D: # %bb.0:
+; LA64D-NEXT: fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT: ret
+ %z = call double @llvm.minimumnum.f64(double %x, double %y)
+ ret double %z
+}
diff --git a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
index bc81966ca0f5c..4e79cd5a635bd 100644
--- a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
@@ -37,6 +37,24 @@ define float @maximumnum_float_nnan(float %x, float %y) {
ret float %z
}
+define float @maximumnum_float_nofpclass(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_nofpclass:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: max.s $f0, $f12, $f14
+ %z = call float @llvm.maximumnum.f32(float %x, float %y)
+ ret float %z
+}
+
+define float @maximumnum_float_nofpclass_s(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_nofpclass_s:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: max.s $f0, $f12, $f14
+ %z = call float @llvm.maximumnum.f32(float %x, float %y)
+ ret float %z
+}
+
define double @maximumnum_double(double %x, double %y) {
; MIPS32R6-LABEL: maximumnum_double:
@@ -69,6 +87,25 @@ define double @maximumnum_double_nnan(double %x, double %y) {
ret double %z
}
+define double @maximumnum_double_nofpclass(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_nofpclass:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: max.d $f0, $f12, $f14
+ %z = call double @llvm.maximumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+define double @maximumnum_double_nofpclass_s(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_nofpclass_s:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: max.d $f0, $f12, $f14
+ %z = call double @llvm.maximumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+
define float @minimumnum_float(float %x, float %y) {
; MIPS32R6-LABEL: minimumnum_float:
; MIPS32R6: # %bb.0:
@@ -100,6 +137,24 @@ define float @minimumnum_float_nnan(float %x, float %y) {
ret float %z
}
+define float @minimumnum_float_nofpclass(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_nofpclass:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: min.s $f0, $f12, $f14
+ %z = call float @llvm.minimumnum.f32(float %x, float %y)
+ ret float %z
+}
+
+define float @minimumnum_float_nofpclass_s(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_nofpclass_s:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: min.s $f0, $f12, $f14
+ %z = call float @llvm.minimumnum.f32(float %x, float %y)
+ ret float %z
+}
+
define double @minimumnum_double(double %x, double %y) {
; MIPS32R6-LABEL: minimumnum_double:
; MIPS32R6: # %bb.0:
@@ -130,3 +185,21 @@ define double @minimumnum_double_nnan(double %x, double %y) {
%z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
ret double %z
}
+
+define double @minimumnum_double_nofpclass(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_nofpclass:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: min.d $f0, $f12, $f14
+ %z = call double @llvm.minimumnum.f64(double %x, double %y)
+ ret double %z
+}
+
+define double @minimumnum_double_nofpclass_s(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_nofpclass_s:
+; MIPS32R6: # %bb.0:
+; MIPS32R6-NEXT: jr $ra
+; MIPS32R6-NEXT: min.d $f0, $f12, $f14
+ %z = call double @llvm.minimumnum.f64(double %x, double %y)
+ ret double %z
+}
>From 32f4676f36d630c990ff184dea6e45476a245283 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 10 Mar 2025 08:49:59 +0800
Subject: [PATCH 2/2] support ISD::AssertFPNoClass
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 6 +++++
.../include/llvm/Target/TargetSelectionDAG.td | 1 +
.../SelectionDAG/LegalizeVectorTypes.cpp | 3 +++
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 4 ++++
.../SelectionDAG/SelectionDAGBuilder.cpp | 24 ++++++++++---------
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
.../CodeGen/SelectionDAG/SelectionDAGISel.cpp | 1 +
7 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 59f31f8443947..bd2ec13e9313e 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -67,6 +67,12 @@ enum NodeType {
/// poisoned the assertion will not be true for that value.
AssertAlign,
+ /// AssertNoFPClass - These nodes record if a register contains a float
+ /// value that is known to be not some type.
+ /// NOTE: In case of the source value (or any vector element value) is
+ /// poisoned the assertion will not be true for that value.
+ AssertNoFPClass,
+
/// Various leaf nodes.
BasicBlock,
VALUETYPE,
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 42a5fbec95174..40585e8fa2d30 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -859,6 +859,7 @@ def SDT_assert : SDTypeProfile<1, 1,
[SDTCisInt<0>, SDTCisInt<1>, SDTCisSameAs<1, 0>]>;
def assertsext : SDNode<"ISD::AssertSext", SDT_assert>;
def assertzext : SDNode<"ISD::AssertZext", SDT_assert>;
+def assernofpclass : SDNode<"ISD::AssertNoFPClass", SDTFPUnaryOp>;
def assertalign : SDNode<"ISD::AssertAlign", SDT_assert>;
def convergencectrl_anchor : SDNode<"ISD::CONVERGENCECTRL_ANCHOR",
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 9d42ec2fdf859..eb097b40e5206 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -128,6 +128,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
case ISD::UINT_TO_FP:
case ISD::ZERO_EXTEND:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
R = ScalarizeVecRes_UnaryOp(N);
break;
case ISD::ADDRSPACECAST:
@@ -1276,6 +1277,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
case ISD::UINT_TO_FP:
case ISD::VP_UINT_TO_FP:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
SplitVecRes_UnaryOp(N, Lo, Hi);
break;
case ISD::ADDRSPACECAST:
@@ -4843,6 +4845,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
case ISD::FREEZE:
case ISD::ARITH_FENCE:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
Res = WidenVecRes_Unary(N);
break;
case ISD::FMA: case ISD::VP_FMA:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 7fc97fadeff09..63265be2171ca 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7384,6 +7384,10 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
N2.getOpcode() == ISD::TargetConstant && "Invalid FP_ROUND!");
if (N1.getValueType() == VT) return N1; // noop conversion.
break;
+ case ISD::AssertNoFPClass:
+ assert(N1.getValueType().isFloatingPoint() &&
+ "AssertNoFPClass is used for a non-floating type");
+ return N1;
case ISD::AssertSext:
case ISD::AssertZext: {
EVT EVT = cast<VTSDNode>(N2)->getVT();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 9942bbfbe9389..50284bb776797 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11891,20 +11891,22 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
AssertOp = ISD::AssertSext;
else if (Arg.hasAttribute(Attribute::ZExt))
AssertOp = ISD::AssertZext;
- if (Arg.hasAttribute(Attribute::NoFPClass)) {
- SDNodeFlags InValFlags = InVals[i]->getFlags();
+ SDValue OutVal =
+ getCopyFromParts(DAG, dl, &InVals[i], NumParts, PartVT, VT, nullptr,
+ NewRoot, F.getCallingConv(), AssertOp);
+ if (Arg.hasAttribute(Attribute::NoFPClass) &&
+ OutVal.getValueType().isFloatingPoint()) {
+ SDNodeFlags OutValFlags = OutVal->getFlags();
bool NoSNaN = ((Arg.getNoFPClass() & llvm::fcSNan) == llvm::fcSNan);
bool NoQNaN = ((Arg.getNoFPClass() & llvm::fcQNan) == llvm::fcQNan);
- InValFlags.setNoSNaNs(NoSNaN);
- InValFlags.setNoQNaNs(NoQNaN);
- InValFlags.setNoInfs((Arg.getNoFPClass() & llvm::fcInf) ==
- llvm::fcInf);
- InVals[i]->setFlags(InValFlags);
+ bool NoInf = ((Arg.getNoFPClass() & llvm::fcInf) == llvm::fcInf);
+ OutValFlags.setNoSNaNs(NoSNaN);
+ OutValFlags.setNoQNaNs(NoQNaN);
+ OutValFlags.setNoInfs(NoInf);
+ OutVal =
+ DAG.getNode(ISD::AssertNoFPClass, dl, VT, OutVal, OutValFlags);
}
-
- ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
- PartVT, VT, nullptr, NewRoot,
- F.getCallingConv(), AssertOp));
+ ArgValues.push_back(OutVal);
}
i += NumParts;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 64ecff8d71f98..6a34ae6b1b772 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -118,6 +118,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::TokenFactor: return "TokenFactor";
case ISD::AssertSext: return "AssertSext";
case ISD::AssertZext: return "AssertZext";
+ case ISD::AssertNoFPClass: return "AssertNoFPClass";
case ISD::AssertAlign: return "AssertAlign";
case ISD::BasicBlock: return "BasicBlock";
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 63ee2d78cfa1b..657ddce115649 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3262,6 +3262,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
return;
case ISD::AssertSext:
case ISD::AssertZext:
+ case ISD::AssertNoFPClass:
case ISD::AssertAlign:
ReplaceUses(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0));
CurDAG->RemoveDeadNode(NodeToMatch);
More information about the llvm-commits
mailing list