-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Intrinsic: introduce minimumnum and maximumnum #93841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-backend-loongarch @llvm/pr-subscribers-llvm-selectiondag Author: YunQiang Su (wzssyqa) ChangesCurrently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN: When we compare sNaN vs NUM: ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber. Half-fix: #93033 Patch is 170.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93841.diff 78 Files Affected:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..b2d1ab2a8be8d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T, T)";
}
+def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fmaximum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
+def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fminimum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
def Atan2F128 : Builtin {
let Spellings = ["__builtin_atan2f128"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
@@ -3636,6 +3648,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}
+def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fmaximum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
+def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fminimum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["hypot"];
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 266bf41fd5577..f2a15dc9cf3d6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2786,6 +2786,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Intrinsic::minnum,
Intrinsic::experimental_constrained_minnum));
+ case Builtin::BIfmaximum_num:
+ case Builtin::BIfmaximum_numf:
+ case Builtin::BIfmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_num:
+ case Builtin::BI__builtin_fmaximum_numf:
+ case Builtin::BI__builtin_fmaximum_numf16:
+ case Builtin::BI__builtin_fmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::maximumnum,
+ Intrinsic::experimental_constrained_maximumnum));
+
+ case Builtin::BIfminimum_num:
+ case Builtin::BIfminimum_numf:
+ case Builtin::BIfminimum_numl:
+ case Builtin::BI__builtin_fminimum_num:
+ case Builtin::BI__builtin_fminimum_numf:
+ case Builtin::BI__builtin_fminimum_numf16:
+ case Builtin::BI__builtin_fminimum_numl:
+ case Builtin::BI__builtin_fminimum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::minnum,
+ Intrinsic::experimental_constrained_minimumnum));
+
// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
case Builtin::BIfmod:
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..af2dcb632fbb6 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -475,6 +475,12 @@ SYMBOL(fmaxl, None, <math.h>)
SYMBOL(fmin, None, <math.h>)
SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numfl, None, <math.h>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, None, <math.h>)
SYMBOL(fmodf, None, <math.h>)
SYMBOL(fmodl, None, <math.h>)
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
index b46bd2e4d7a4b..442316ce8d4ff 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
@@ -1295,6 +1295,24 @@ SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, std::, <cmath>)
SYMBOL(fminl, None, <cmath>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, std::, <cmath>)
+SYMBOL(fmaximum_num, None, <cmath>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, std::, <cmath>)
+SYMBOL(fmaximum_numf, None, <cmath>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numl, std::, <cmath>)
+SYMBOL(fmaximum_numl, None, <cmath>)
+SYMBOL(fmaximum_numl, None, <math.h>)
+SYMBOL(fminimum_num, std::, <cmath>)
+SYMBOL(fminimum_num, None, <cmath>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, std::, <cmath>)
+SYMBOL(fminimum_numf, None, <cmath>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, std::, <cmath>)
+SYMBOL(fminimum_numl, None, <cmath>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, std::, <cmath>)
SYMBOL(fmod, None, <cmath>)
SYMBOL(fmod, None, <math.h>)
diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c
index b41efb59e61db..b059346bf93d3 100644
--- a/clang/test/CodeGen/builtins.c
+++ b/clang/test/CodeGen/builtins.c
@@ -353,6 +353,24 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_fmaxl(LD, LD);
// CHECK: call x86_fp80 @llvm.maxnum.f80
+ resf = __builtin_fminimum_numf(F, F);
+ // CHECK: call float @llvm.minimumnum.f32
+
+ resd = __builtin_fminimum_num(D, D);
+ // CHECK: call double @llvm.minimumnum.f64
+
+ resld = __builtin_fminimum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.minimumnum.f80
+
+ resf = __builtin_fmaximum_numf(F, F);
+ // CHECK: call float @llvm.maximumnum.f32
+
+ resd = __builtin_fmaximum_num(D, D);
+ // CHECK: call double @llvm.maximumnum.f64
+
+ resld = __builtin_fmaximum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.maximumnum.f80
+
resf = __builtin_fabsf(F);
// CHECK: call float @llvm.fabs.f32
diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c
index 29c312ba0ecac..caf9d060fc525 100644
--- a/clang/test/CodeGen/math-libcalls.c
+++ b/clang/test/CodeGen/math-libcalls.c
@@ -372,6 +372,31 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(
+ fmaximum_num(f,f); fmaximum_numf(f,f); fmaximum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.maximumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.maximumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.maximumnum.f80(
+
+ fminimum_num(f,f); fminimum_numf(f,f); fminimum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.minimumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minimumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minimumnum.f80(
+
+
hypot(f,f); hypotf(f,f); hypotl(f,f);
// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7b64c477d13c7..0a08b01d0a2b8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16049,6 +16049,84 @@ of the two arguments. -0.0 is considered to be less than +0.0 for this
intrinsic. Note that these are the semantics specified in the draft of
IEEE 754-2019.
+.. _i_minimumnum:
+
+'``llvm.minimumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.minimumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.minimumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.minimumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.minimumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.minimumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.minimumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.minimumnum.*``' intrinsics return the minimum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the lesser
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
+.. _i_maximumnum:
+
+'``llvm.maximumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.maximumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.maximumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.maximumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.maximumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.maximumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.maximumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.maximumnum.*``' intrinsics return the maximum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the greater
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
.. _int_copysign:
'``llvm.copysign.*``' Intrinsic
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 44a301ecc9928..fcfb05263a40f 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1442,6 +1442,16 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? A : B;
return B < A ? B : A;
}
+LLVM_READONLY
+inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? A : B;
+ return B < A ? B : A;
+}
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
/// arguments, propagating NaNs and treating -0 as less than +0.
@@ -1455,6 +1465,16 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? B : A;
return A < B ? B : A;
}
+LLVM_READONLY
+inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? B : A;
+ return A < B ? B : A;
+}
// We want the following functions to be available in the header for inlining.
// We cannot define them inline in the class definition of `DoubleAPFloat`
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 5c7b613ac48c4..107c9625f4f69 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -32,27 +32,29 @@ class StoreInst;
/// These are the kinds of recurrences that we support.
enum class RecurKind {
- None, ///< Not a recurrence.
- Add, ///< Sum of integers.
- Mul, ///< Product of integers.
- Or, ///< Bitwise or logical OR of integers.
- And, ///< Bitwise or logical AND of integers.
- Xor, ///< Bitwise or logical XOR of integers.
- SMin, ///< Signed integer min implemented in terms of select(cmp()).
- SMax, ///< Signed integer max implemented in terms of select(cmp()).
- UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
- UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
- FAdd, ///< Sum of floats.
- FMul, ///< Product of floats.
- FMin, ///< FP min implemented in terms of select(cmp()).
- FMax, ///< FP max implemented in terms of select(cmp()).
- FMinimum, ///< FP min with llvm.minimum semantics
- FMaximum, ///< FP max with llvm.maximum semantics
- FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
- IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
- FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
+ None, ///< Not a recurrence.
+ Add, ///< Sum of integers.
+ Mul, ///< Product of integers.
+ Or, ///< Bitwise or logical OR of integers.
+ And, ///< Bitwise or logical AND of integers.
+ Xor, ///< Bitwise or logical XOR of integers.
+ SMin, ///< Signed integer min implemented in terms of select(cmp()).
+ SMax, ///< Signed integer max implemented in terms of select(cmp()).
+ UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
+ UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
+ FAdd, ///< Sum of floats.
+ FMul, ///< Product of floats.
+ FMin, ///< FP min implemented in terms of select(cmp()).
+ FMax, ///< FP max implemented in terms of select(cmp()).
+ FMinimum, ///< FP min with llvm.minimum semantics
+ FMaximum, ///< FP max with llvm.maximum semantics
+ FMinimumnum, ///< FP min with llvm.minimumnum semantics
+ FMaximumnum, ///< FP max with llvm.maximumnum semantics
+ FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
+ IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
+ FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
// TODO: Any_of reduction need not be restricted to integer type only.
};
@@ -226,7 +228,8 @@ class RecurrenceDescriptor {
/// Returns true if the recurrence kind is a floating-point min/max kind.
static bool isFPMinMaxRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FMin || Kind == RecurKind::FMax ||
- Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum;
+ Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum ||
+ Kind == RecurKind::FMinimumnum || Kind == RecurKind::FMaximumnum;
}
/// Returns true if the recurrence kind is any min/max kind.
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 717693a7cf63c..8b938f97a679d 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -1347,6 +1347,39 @@ TLI_DEFINE_ENUM_INTERNAL(fminl)
TLI_DEFINE_STRING_INTERNAL("fminl")
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+// Calls to fmaximum_num and fminimum_num library functions expand to the llvm.maximumnum and
+// llvm.minimumnum intrinsics with the correct parameter types for the arguments
+// (all types must match).
+/// double fmaximum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_num)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fmaximum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numf)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fmaximum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numl)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// double fminimum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_num)
+TLI_DEFINE_STRING_INTERNAL("fminimum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fminimum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numf)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fminimum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numl)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
/// double fmod(double x, double y);
TLI_DEFINE_ENUM_INTERNAL(fmod)
TLI_DEFINE_STRING_INTERNAL("fmod")
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 0584b7e29f67b..9a2250a67acdf 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1059,14 +1059,16 @@ bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root,
/// Specific patterns of select instructions we can match.
enum SelectPatternFlavor {
SPF_UNKNOWN = 0,
- SPF_SMIN, /// Signed minimum
- SPF_UMIN, /// Unsigned minimum
- SPF_SMAX, /// Signed maximum
- SPF_UMAX, /// Unsigned maximum
- SPF_FMINNUM, /// Floating point minnum
- SPF_FMAXNUM, /// Floating point maxnum
- SPF_ABS, /// Absolute value
- SPF_NABS /// Negated absolute value
+ SPF_SMIN, /// Signed minimum
+ SPF_UMIN, /// Unsigned minimum
+ SPF_SMAX, /// Signed maximum
+ SPF_UMAX, /// Unsigned maximum
+ SPF_FMINNUM, /// Floating point minnum
+ SPF_FMAXNUM, /// Floating point maxnum
+ SPF_FMINIMUMNUM, /// Floating point minnum
+ SPF_FMAXIMUMNUM, /// Floating point maxnum
+ SPF_ABS, /// Absolute value
+ SPF_NABS /// Negated absolute value
};
/// Behavior when a floating point min/max is given one NaN and one
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 2091432d4fe27..167cc2d1755a5 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1686,6 +1686,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum:
+ case Intrinsic::vector_reduce_fmaximumnum:
+ case Intrinsic::vector_reduce_fminimumnum:
case Intrinsic::vector_reduce_umax:
case Intrinsic::vector_reduce_umin: {
IntrinsicCostAttributes Attrs(IID, RetTy, Args[0]->getType(), FMF, I, 1);
@@ -2009,6 +2011,12 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::maximum:
ISD = ISD::FMAXIMUM;
break;
+ case Intrinsic::minimumnum:
+ ISD = ISD::FMINIMUMNUM;
+ break;
+ ...
[truncated]
|
@llvm/pr-subscribers-backend-risc-v Author: YunQiang Su (wzssyqa) ChangesCurrently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN: When we compare sNaN vs NUM: ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber. Half-fix: #93033 Patch is 170.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93841.diff 78 Files Affected:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..b2d1ab2a8be8d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T, T)";
}
+def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fmaximum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
+def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fminimum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
def Atan2F128 : Builtin {
let Spellings = ["__builtin_atan2f128"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
@@ -3636,6 +3648,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}
+def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fmaximum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
+def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fminimum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["hypot"];
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 266bf41fd5577..f2a15dc9cf3d6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2786,6 +2786,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Intrinsic::minnum,
Intrinsic::experimental_constrained_minnum));
+ case Builtin::BIfmaximum_num:
+ case Builtin::BIfmaximum_numf:
+ case Builtin::BIfmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_num:
+ case Builtin::BI__builtin_fmaximum_numf:
+ case Builtin::BI__builtin_fmaximum_numf16:
+ case Builtin::BI__builtin_fmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::maximumnum,
+ Intrinsic::experimental_constrained_maximumnum));
+
+ case Builtin::BIfminimum_num:
+ case Builtin::BIfminimum_numf:
+ case Builtin::BIfminimum_numl:
+ case Builtin::BI__builtin_fminimum_num:
+ case Builtin::BI__builtin_fminimum_numf:
+ case Builtin::BI__builtin_fminimum_numf16:
+ case Builtin::BI__builtin_fminimum_numl:
+ case Builtin::BI__builtin_fminimum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::minnum,
+ Intrinsic::experimental_constrained_minimumnum));
+
// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
case Builtin::BIfmod:
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..af2dcb632fbb6 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -475,6 +475,12 @@ SYMBOL(fmaxl, None, <math.h>)
SYMBOL(fmin, None, <math.h>)
SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numfl, None, <math.h>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, None, <math.h>)
SYMBOL(fmodf, None, <math.h>)
SYMBOL(fmodl, None, <math.h>)
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
index b46bd2e4d7a4b..442316ce8d4ff 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
@@ -1295,6 +1295,24 @@ SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, std::, <cmath>)
SYMBOL(fminl, None, <cmath>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, std::, <cmath>)
+SYMBOL(fmaximum_num, None, <cmath>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, std::, <cmath>)
+SYMBOL(fmaximum_numf, None, <cmath>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numl, std::, <cmath>)
+SYMBOL(fmaximum_numl, None, <cmath>)
+SYMBOL(fmaximum_numl, None, <math.h>)
+SYMBOL(fminimum_num, std::, <cmath>)
+SYMBOL(fminimum_num, None, <cmath>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, std::, <cmath>)
+SYMBOL(fminimum_numf, None, <cmath>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, std::, <cmath>)
+SYMBOL(fminimum_numl, None, <cmath>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, std::, <cmath>)
SYMBOL(fmod, None, <cmath>)
SYMBOL(fmod, None, <math.h>)
diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c
index b41efb59e61db..b059346bf93d3 100644
--- a/clang/test/CodeGen/builtins.c
+++ b/clang/test/CodeGen/builtins.c
@@ -353,6 +353,24 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_fmaxl(LD, LD);
// CHECK: call x86_fp80 @llvm.maxnum.f80
+ resf = __builtin_fminimum_numf(F, F);
+ // CHECK: call float @llvm.minimumnum.f32
+
+ resd = __builtin_fminimum_num(D, D);
+ // CHECK: call double @llvm.minimumnum.f64
+
+ resld = __builtin_fminimum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.minimumnum.f80
+
+ resf = __builtin_fmaximum_numf(F, F);
+ // CHECK: call float @llvm.maximumnum.f32
+
+ resd = __builtin_fmaximum_num(D, D);
+ // CHECK: call double @llvm.maximumnum.f64
+
+ resld = __builtin_fmaximum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.maximumnum.f80
+
resf = __builtin_fabsf(F);
// CHECK: call float @llvm.fabs.f32
diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c
index 29c312ba0ecac..caf9d060fc525 100644
--- a/clang/test/CodeGen/math-libcalls.c
+++ b/clang/test/CodeGen/math-libcalls.c
@@ -372,6 +372,31 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(
+ fmaximum_num(f,f); fmaximum_numf(f,f); fmaximum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.maximumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.maximumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.maximumnum.f80(
+
+ fminimum_num(f,f); fminimum_numf(f,f); fminimum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.minimumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minimumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minimumnum.f80(
+
+
hypot(f,f); hypotf(f,f); hypotl(f,f);
// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7b64c477d13c7..0a08b01d0a2b8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16049,6 +16049,84 @@ of the two arguments. -0.0 is considered to be less than +0.0 for this
intrinsic. Note that these are the semantics specified in the draft of
IEEE 754-2019.
+.. _i_minimumnum:
+
+'``llvm.minimumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.minimumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.minimumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.minimumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.minimumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.minimumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.minimumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.minimumnum.*``' intrinsics return the minimum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the lesser
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
+.. _i_maximumnum:
+
+'``llvm.maximumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.maximumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.maximumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.maximumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.maximumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.maximumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.maximumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.maximumnum.*``' intrinsics return the maximum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the greater
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
.. _int_copysign:
'``llvm.copysign.*``' Intrinsic
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 44a301ecc9928..fcfb05263a40f 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1442,6 +1442,16 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? A : B;
return B < A ? B : A;
}
+LLVM_READONLY
+inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? A : B;
+ return B < A ? B : A;
+}
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
/// arguments, propagating NaNs and treating -0 as less than +0.
@@ -1455,6 +1465,16 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? B : A;
return A < B ? B : A;
}
+LLVM_READONLY
+inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? B : A;
+ return A < B ? B : A;
+}
// We want the following functions to be available in the header for inlining.
// We cannot define them inline in the class definition of `DoubleAPFloat`
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 5c7b613ac48c4..107c9625f4f69 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -32,27 +32,29 @@ class StoreInst;
/// These are the kinds of recurrences that we support.
enum class RecurKind {
- None, ///< Not a recurrence.
- Add, ///< Sum of integers.
- Mul, ///< Product of integers.
- Or, ///< Bitwise or logical OR of integers.
- And, ///< Bitwise or logical AND of integers.
- Xor, ///< Bitwise or logical XOR of integers.
- SMin, ///< Signed integer min implemented in terms of select(cmp()).
- SMax, ///< Signed integer max implemented in terms of select(cmp()).
- UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
- UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
- FAdd, ///< Sum of floats.
- FMul, ///< Product of floats.
- FMin, ///< FP min implemented in terms of select(cmp()).
- FMax, ///< FP max implemented in terms of select(cmp()).
- FMinimum, ///< FP min with llvm.minimum semantics
- FMaximum, ///< FP max with llvm.maximum semantics
- FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
- IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
- FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
+ None, ///< Not a recurrence.
+ Add, ///< Sum of integers.
+ Mul, ///< Product of integers.
+ Or, ///< Bitwise or logical OR of integers.
+ And, ///< Bitwise or logical AND of integers.
+ Xor, ///< Bitwise or logical XOR of integers.
+ SMin, ///< Signed integer min implemented in terms of select(cmp()).
+ SMax, ///< Signed integer max implemented in terms of select(cmp()).
+ UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
+ UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
+ FAdd, ///< Sum of floats.
+ FMul, ///< Product of floats.
+ FMin, ///< FP min implemented in terms of select(cmp()).
+ FMax, ///< FP max implemented in terms of select(cmp()).
+ FMinimum, ///< FP min with llvm.minimum semantics
+ FMaximum, ///< FP max with llvm.maximum semantics
+ FMinimumnum, ///< FP min with llvm.minimumnum semantics
+ FMaximumnum, ///< FP max with llvm.maximumnum semantics
+ FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
+ IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
+ FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
// TODO: Any_of reduction need not be restricted to integer type only.
};
@@ -226,7 +228,8 @@ class RecurrenceDescriptor {
/// Returns true if the recurrence kind is a floating-point min/max kind.
static bool isFPMinMaxRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FMin || Kind == RecurKind::FMax ||
- Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum;
+ Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum ||
+ Kind == RecurKind::FMinimumnum || Kind == RecurKind::FMaximumnum;
}
/// Returns true if the recurrence kind is any min/max kind.
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 717693a7cf63c..8b938f97a679d 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -1347,6 +1347,39 @@ TLI_DEFINE_ENUM_INTERNAL(fminl)
TLI_DEFINE_STRING_INTERNAL("fminl")
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+// Calls to fmaximum_num and fminimum_num library functions expand to the llvm.maximumnum and
+// llvm.minimumnum intrinsics with the correct parameter types for the arguments
+// (all types must match).
+/// double fmaximum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_num)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fmaximum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numf)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fmaximum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numl)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// double fminimum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_num)
+TLI_DEFINE_STRING_INTERNAL("fminimum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fminimum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numf)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fminimum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numl)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
/// double fmod(double x, double y);
TLI_DEFINE_ENUM_INTERNAL(fmod)
TLI_DEFINE_STRING_INTERNAL("fmod")
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 0584b7e29f67b..9a2250a67acdf 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1059,14 +1059,16 @@ bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root,
/// Specific patterns of select instructions we can match.
enum SelectPatternFlavor {
SPF_UNKNOWN = 0,
- SPF_SMIN, /// Signed minimum
- SPF_UMIN, /// Unsigned minimum
- SPF_SMAX, /// Signed maximum
- SPF_UMAX, /// Unsigned maximum
- SPF_FMINNUM, /// Floating point minnum
- SPF_FMAXNUM, /// Floating point maxnum
- SPF_ABS, /// Absolute value
- SPF_NABS /// Negated absolute value
+ SPF_SMIN, /// Signed minimum
+ SPF_UMIN, /// Unsigned minimum
+ SPF_SMAX, /// Signed maximum
+ SPF_UMAX, /// Unsigned maximum
+ SPF_FMINNUM, /// Floating point minnum
+ SPF_FMAXNUM, /// Floating point maxnum
+ SPF_FMINIMUMNUM, /// Floating point minnum
+ SPF_FMAXIMUMNUM, /// Floating point maxnum
+ SPF_ABS, /// Absolute value
+ SPF_NABS /// Negated absolute value
};
/// Behavior when a floating point min/max is given one NaN and one
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 2091432d4fe27..167cc2d1755a5 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1686,6 +1686,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum:
+ case Intrinsic::vector_reduce_fmaximumnum:
+ case Intrinsic::vector_reduce_fminimumnum:
case Intrinsic::vector_reduce_umax:
case Intrinsic::vector_reduce_umin: {
IntrinsicCostAttributes Attrs(IID, RetTy, Args[0]->getType(), FMF, I, 1);
@@ -2009,6 +2011,12 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::maximum:
ISD = ISD::FMAXIMUM;
break;
+ case Intrinsic::minimumnum:
+ ISD = ISD::FMINIMUMNUM;
+ break;
+ ...
[truncated]
|
@llvm/pr-subscribers-backend-x86 Author: YunQiang Su (wzssyqa) ChangesCurrently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN: When we compare sNaN vs NUM: ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber. Half-fix: #93033 Patch is 170.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93841.diff 78 Files Affected:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..b2d1ab2a8be8d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T, T)";
}
+def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fmaximum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
+def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fminimum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
def Atan2F128 : Builtin {
let Spellings = ["__builtin_atan2f128"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
@@ -3636,6 +3648,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}
+def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fmaximum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
+def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fminimum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["hypot"];
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 266bf41fd5577..f2a15dc9cf3d6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2786,6 +2786,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Intrinsic::minnum,
Intrinsic::experimental_constrained_minnum));
+ case Builtin::BIfmaximum_num:
+ case Builtin::BIfmaximum_numf:
+ case Builtin::BIfmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_num:
+ case Builtin::BI__builtin_fmaximum_numf:
+ case Builtin::BI__builtin_fmaximum_numf16:
+ case Builtin::BI__builtin_fmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::maximumnum,
+ Intrinsic::experimental_constrained_maximumnum));
+
+ case Builtin::BIfminimum_num:
+ case Builtin::BIfminimum_numf:
+ case Builtin::BIfminimum_numl:
+ case Builtin::BI__builtin_fminimum_num:
+ case Builtin::BI__builtin_fminimum_numf:
+ case Builtin::BI__builtin_fminimum_numf16:
+ case Builtin::BI__builtin_fminimum_numl:
+ case Builtin::BI__builtin_fminimum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::minnum,
+ Intrinsic::experimental_constrained_minimumnum));
+
// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
case Builtin::BIfmod:
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..af2dcb632fbb6 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -475,6 +475,12 @@ SYMBOL(fmaxl, None, <math.h>)
SYMBOL(fmin, None, <math.h>)
SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numfl, None, <math.h>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, None, <math.h>)
SYMBOL(fmodf, None, <math.h>)
SYMBOL(fmodl, None, <math.h>)
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
index b46bd2e4d7a4b..442316ce8d4ff 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
@@ -1295,6 +1295,24 @@ SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, std::, <cmath>)
SYMBOL(fminl, None, <cmath>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, std::, <cmath>)
+SYMBOL(fmaximum_num, None, <cmath>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, std::, <cmath>)
+SYMBOL(fmaximum_numf, None, <cmath>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numl, std::, <cmath>)
+SYMBOL(fmaximum_numl, None, <cmath>)
+SYMBOL(fmaximum_numl, None, <math.h>)
+SYMBOL(fminimum_num, std::, <cmath>)
+SYMBOL(fminimum_num, None, <cmath>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, std::, <cmath>)
+SYMBOL(fminimum_numf, None, <cmath>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, std::, <cmath>)
+SYMBOL(fminimum_numl, None, <cmath>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, std::, <cmath>)
SYMBOL(fmod, None, <cmath>)
SYMBOL(fmod, None, <math.h>)
diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c
index b41efb59e61db..b059346bf93d3 100644
--- a/clang/test/CodeGen/builtins.c
+++ b/clang/test/CodeGen/builtins.c
@@ -353,6 +353,24 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_fmaxl(LD, LD);
// CHECK: call x86_fp80 @llvm.maxnum.f80
+ resf = __builtin_fminimum_numf(F, F);
+ // CHECK: call float @llvm.minimumnum.f32
+
+ resd = __builtin_fminimum_num(D, D);
+ // CHECK: call double @llvm.minimumnum.f64
+
+ resld = __builtin_fminimum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.minimumnum.f80
+
+ resf = __builtin_fmaximum_numf(F, F);
+ // CHECK: call float @llvm.maximumnum.f32
+
+ resd = __builtin_fmaximum_num(D, D);
+ // CHECK: call double @llvm.maximumnum.f64
+
+ resld = __builtin_fmaximum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.maximumnum.f80
+
resf = __builtin_fabsf(F);
// CHECK: call float @llvm.fabs.f32
diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c
index 29c312ba0ecac..caf9d060fc525 100644
--- a/clang/test/CodeGen/math-libcalls.c
+++ b/clang/test/CodeGen/math-libcalls.c
@@ -372,6 +372,31 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(
+ fmaximum_num(f,f); fmaximum_numf(f,f); fmaximum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.maximumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.maximumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.maximumnum.f80(
+
+ fminimum_num(f,f); fminimum_numf(f,f); fminimum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.minimumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minimumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minimumnum.f80(
+
+
hypot(f,f); hypotf(f,f); hypotl(f,f);
// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7b64c477d13c7..0a08b01d0a2b8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16049,6 +16049,84 @@ of the two arguments. -0.0 is considered to be less than +0.0 for this
intrinsic. Note that these are the semantics specified in the draft of
IEEE 754-2019.
+.. _i_minimumnum:
+
+'``llvm.minimumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.minimumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.minimumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.minimumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.minimumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.minimumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.minimumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.minimumnum.*``' intrinsics return the minimum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the lesser
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
+.. _i_maximumnum:
+
+'``llvm.maximumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.maximumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.maximumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.maximumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.maximumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.maximumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.maximumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.maximumnum.*``' intrinsics return the maximum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the greater
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
.. _int_copysign:
'``llvm.copysign.*``' Intrinsic
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 44a301ecc9928..fcfb05263a40f 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1442,6 +1442,16 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? A : B;
return B < A ? B : A;
}
+LLVM_READONLY
+inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? A : B;
+ return B < A ? B : A;
+}
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
/// arguments, propagating NaNs and treating -0 as less than +0.
@@ -1455,6 +1465,16 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? B : A;
return A < B ? B : A;
}
+LLVM_READONLY
+inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? B : A;
+ return A < B ? B : A;
+}
// We want the following functions to be available in the header for inlining.
// We cannot define them inline in the class definition of `DoubleAPFloat`
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 5c7b613ac48c4..107c9625f4f69 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -32,27 +32,29 @@ class StoreInst;
/// These are the kinds of recurrences that we support.
enum class RecurKind {
- None, ///< Not a recurrence.
- Add, ///< Sum of integers.
- Mul, ///< Product of integers.
- Or, ///< Bitwise or logical OR of integers.
- And, ///< Bitwise or logical AND of integers.
- Xor, ///< Bitwise or logical XOR of integers.
- SMin, ///< Signed integer min implemented in terms of select(cmp()).
- SMax, ///< Signed integer max implemented in terms of select(cmp()).
- UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
- UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
- FAdd, ///< Sum of floats.
- FMul, ///< Product of floats.
- FMin, ///< FP min implemented in terms of select(cmp()).
- FMax, ///< FP max implemented in terms of select(cmp()).
- FMinimum, ///< FP min with llvm.minimum semantics
- FMaximum, ///< FP max with llvm.maximum semantics
- FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
- IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
- FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
+ None, ///< Not a recurrence.
+ Add, ///< Sum of integers.
+ Mul, ///< Product of integers.
+ Or, ///< Bitwise or logical OR of integers.
+ And, ///< Bitwise or logical AND of integers.
+ Xor, ///< Bitwise or logical XOR of integers.
+ SMin, ///< Signed integer min implemented in terms of select(cmp()).
+ SMax, ///< Signed integer max implemented in terms of select(cmp()).
+ UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
+ UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
+ FAdd, ///< Sum of floats.
+ FMul, ///< Product of floats.
+ FMin, ///< FP min implemented in terms of select(cmp()).
+ FMax, ///< FP max implemented in terms of select(cmp()).
+ FMinimum, ///< FP min with llvm.minimum semantics
+ FMaximum, ///< FP max with llvm.maximum semantics
+ FMinimumnum, ///< FP min with llvm.minimumnum semantics
+ FMaximumnum, ///< FP max with llvm.maximumnum semantics
+ FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
+ IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
+ FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
// TODO: Any_of reduction need not be restricted to integer type only.
};
@@ -226,7 +228,8 @@ class RecurrenceDescriptor {
/// Returns true if the recurrence kind is a floating-point min/max kind.
static bool isFPMinMaxRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FMin || Kind == RecurKind::FMax ||
- Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum;
+ Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum ||
+ Kind == RecurKind::FMinimumnum || Kind == RecurKind::FMaximumnum;
}
/// Returns true if the recurrence kind is any min/max kind.
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 717693a7cf63c..8b938f97a679d 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -1347,6 +1347,39 @@ TLI_DEFINE_ENUM_INTERNAL(fminl)
TLI_DEFINE_STRING_INTERNAL("fminl")
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+// Calls to fmaximum_num and fminimum_num library functions expand to the llvm.maximumnum and
+// llvm.minimumnum intrinsics with the correct parameter types for the arguments
+// (all types must match).
+/// double fmaximum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_num)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fmaximum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numf)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fmaximum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numl)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// double fminimum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_num)
+TLI_DEFINE_STRING_INTERNAL("fminimum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fminimum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numf)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fminimum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numl)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
/// double fmod(double x, double y);
TLI_DEFINE_ENUM_INTERNAL(fmod)
TLI_DEFINE_STRING_INTERNAL("fmod")
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 0584b7e29f67b..9a2250a67acdf 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1059,14 +1059,16 @@ bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root,
/// Specific patterns of select instructions we can match.
enum SelectPatternFlavor {
SPF_UNKNOWN = 0,
- SPF_SMIN, /// Signed minimum
- SPF_UMIN, /// Unsigned minimum
- SPF_SMAX, /// Signed maximum
- SPF_UMAX, /// Unsigned maximum
- SPF_FMINNUM, /// Floating point minnum
- SPF_FMAXNUM, /// Floating point maxnum
- SPF_ABS, /// Absolute value
- SPF_NABS /// Negated absolute value
+ SPF_SMIN, /// Signed minimum
+ SPF_UMIN, /// Unsigned minimum
+ SPF_SMAX, /// Signed maximum
+ SPF_UMAX, /// Unsigned maximum
+ SPF_FMINNUM, /// Floating point minnum
+ SPF_FMAXNUM, /// Floating point maxnum
+ SPF_FMINIMUMNUM, /// Floating point minnum
+ SPF_FMAXIMUMNUM, /// Floating point maxnum
+ SPF_ABS, /// Absolute value
+ SPF_NABS /// Negated absolute value
};
/// Behavior when a floating point min/max is given one NaN and one
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 2091432d4fe27..167cc2d1755a5 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1686,6 +1686,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum:
+ case Intrinsic::vector_reduce_fmaximumnum:
+ case Intrinsic::vector_reduce_fminimumnum:
case Intrinsic::vector_reduce_umax:
case Intrinsic::vector_reduce_umin: {
IntrinsicCostAttributes Attrs(IID, RetTy, Args[0]->getType(), FMF, I, 1);
@@ -2009,6 +2011,12 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::maximum:
ISD = ISD::FMAXIMUM;
break;
+ case Intrinsic::minimumnum:
+ ISD = ISD::FMINIMUMNUM;
+ break;
+ ...
[truncated]
|
@llvm/pr-subscribers-clang-codegen Author: YunQiang Su (wzssyqa) ChangesCurrently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN: When we compare sNaN vs NUM: ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber. Half-fix: #93033 Patch is 170.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93841.diff 78 Files Affected:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..b2d1ab2a8be8d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T, T)";
}
+def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fmaximum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
+def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
+ let Spellings = ["__builtin_fminimum_num"];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
+ let Prototype = "T(T, T)";
+}
+
def Atan2F128 : Builtin {
let Spellings = ["__builtin_atan2f128"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
@@ -3636,6 +3648,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}
+def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fmaximum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
+def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
+ let Spellings = ["fminimum_num"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "T(T, T)";
+ let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+}
+
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["hypot"];
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 266bf41fd5577..f2a15dc9cf3d6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2786,6 +2786,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Intrinsic::minnum,
Intrinsic::experimental_constrained_minnum));
+ case Builtin::BIfmaximum_num:
+ case Builtin::BIfmaximum_numf:
+ case Builtin::BIfmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_num:
+ case Builtin::BI__builtin_fmaximum_numf:
+ case Builtin::BI__builtin_fmaximum_numf16:
+ case Builtin::BI__builtin_fmaximum_numl:
+ case Builtin::BI__builtin_fmaximum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::maximumnum,
+ Intrinsic::experimental_constrained_maximumnum));
+
+ case Builtin::BIfminimum_num:
+ case Builtin::BIfminimum_numf:
+ case Builtin::BIfminimum_numl:
+ case Builtin::BI__builtin_fminimum_num:
+ case Builtin::BI__builtin_fminimum_numf:
+ case Builtin::BI__builtin_fminimum_numf16:
+ case Builtin::BI__builtin_fminimum_numl:
+ case Builtin::BI__builtin_fminimum_numf128:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::minnum,
+ Intrinsic::experimental_constrained_minimumnum));
+
// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
case Builtin::BIfmod:
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..af2dcb632fbb6 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -475,6 +475,12 @@ SYMBOL(fmaxl, None, <math.h>)
SYMBOL(fmin, None, <math.h>)
SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numfl, None, <math.h>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, None, <math.h>)
SYMBOL(fmodf, None, <math.h>)
SYMBOL(fmodl, None, <math.h>)
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
index b46bd2e4d7a4b..442316ce8d4ff 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
@@ -1295,6 +1295,24 @@ SYMBOL(fminf, None, <math.h>)
SYMBOL(fminl, std::, <cmath>)
SYMBOL(fminl, None, <cmath>)
SYMBOL(fminl, None, <math.h>)
+SYMBOL(fmaximum_num, std::, <cmath>)
+SYMBOL(fmaximum_num, None, <cmath>)
+SYMBOL(fmaximum_num, None, <math.h>)
+SYMBOL(fmaximum_numf, std::, <cmath>)
+SYMBOL(fmaximum_numf, None, <cmath>)
+SYMBOL(fmaximum_numf, None, <math.h>)
+SYMBOL(fmaximum_numl, std::, <cmath>)
+SYMBOL(fmaximum_numl, None, <cmath>)
+SYMBOL(fmaximum_numl, None, <math.h>)
+SYMBOL(fminimum_num, std::, <cmath>)
+SYMBOL(fminimum_num, None, <cmath>)
+SYMBOL(fminimum_num, None, <math.h>)
+SYMBOL(fminimum_numf, std::, <cmath>)
+SYMBOL(fminimum_numf, None, <cmath>)
+SYMBOL(fminimum_numf, None, <math.h>)
+SYMBOL(fminimum_numl, std::, <cmath>)
+SYMBOL(fminimum_numl, None, <cmath>)
+SYMBOL(fminimum_numl, None, <math.h>)
SYMBOL(fmod, std::, <cmath>)
SYMBOL(fmod, None, <cmath>)
SYMBOL(fmod, None, <math.h>)
diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c
index b41efb59e61db..b059346bf93d3 100644
--- a/clang/test/CodeGen/builtins.c
+++ b/clang/test/CodeGen/builtins.c
@@ -353,6 +353,24 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_fmaxl(LD, LD);
// CHECK: call x86_fp80 @llvm.maxnum.f80
+ resf = __builtin_fminimum_numf(F, F);
+ // CHECK: call float @llvm.minimumnum.f32
+
+ resd = __builtin_fminimum_num(D, D);
+ // CHECK: call double @llvm.minimumnum.f64
+
+ resld = __builtin_fminimum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.minimumnum.f80
+
+ resf = __builtin_fmaximum_numf(F, F);
+ // CHECK: call float @llvm.maximumnum.f32
+
+ resd = __builtin_fmaximum_num(D, D);
+ // CHECK: call double @llvm.maximumnum.f64
+
+ resld = __builtin_fmaximum_numl(LD, LD);
+ // CHECK: call x86_fp80 @llvm.maximumnum.f80
+
resf = __builtin_fabsf(F);
// CHECK: call float @llvm.fabs.f32
diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c
index 29c312ba0ecac..caf9d060fc525 100644
--- a/clang/test/CodeGen/math-libcalls.c
+++ b/clang/test/CodeGen/math-libcalls.c
@@ -372,6 +372,31 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(
+ fmaximum_num(f,f); fmaximum_numf(f,f); fmaximum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.maximumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.maximumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.maximumnum.f80(
+
+ fminimum_num(f,f); fminimum_numf(f,f); fminimum_numl(f,f);
+
+// NO__ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// NO__ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_MAYTRAP: declare double @llvm.experimental.constrained.minimumnum.f64(
+// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minimumnum.f32(
+// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minimumnum.f80(
+
+
hypot(f,f); hypotf(f,f); hypotl(f,f);
// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7b64c477d13c7..0a08b01d0a2b8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16049,6 +16049,84 @@ of the two arguments. -0.0 is considered to be less than +0.0 for this
intrinsic. Note that these are the semantics specified in the draft of
IEEE 754-2019.
+.. _i_minimumnum:
+
+'``llvm.minimumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.minimumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.minimumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.minimumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.minimumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.minimumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.minimumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.minimumnum.*``' intrinsics return the minimum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the lesser
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
+.. _i_maximumnum:
+
+'``llvm.maximumnum.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.maximumnum`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.maximumnum.f32(float %Val0, float %Val1)
+ declare double @llvm.maximumnum.f64(double %Val0, double %Val1)
+ declare x86_fp80 @llvm.maximumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
+ declare fp128 @llvm.maximumnum.f128(fp128 %Val0, fp128 %Val1)
+ declare ppc_fp128 @llvm.maximumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
+
+Overview:
+"""""""""
+
+The '``llvm.maximumnum.*``' intrinsics return the maximum of the two
+arguments, not propagating NaNs and treating -0.0 as less than +0.0.
+
+
+Arguments:
+""""""""""
+
+The arguments and return value are floating-point numbers of the same
+type.
+
+Semantics:
+""""""""""
+If both operands are NaNs, returns qNaN. Otherwise returns the greater
+of the two arguments. -0.0 is considered to be less than +0.0 for this
+intrinsic. Note that these are the semantics specified in IEEE 754-2019.
+
.. _int_copysign:
'``llvm.copysign.*``' Intrinsic
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 44a301ecc9928..fcfb05263a40f 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1442,6 +1442,16 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? A : B;
return B < A ? B : A;
}
+LLVM_READONLY
+inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? A : B;
+ return B < A ? B : A;
+}
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
/// arguments, propagating NaNs and treating -0 as less than +0.
@@ -1455,6 +1465,16 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
return A.isNegative() ? B : A;
return A < B ? B : A;
}
+LLVM_READONLY
+inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? B : A;
+ return A < B ? B : A;
+}
// We want the following functions to be available in the header for inlining.
// We cannot define them inline in the class definition of `DoubleAPFloat`
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 5c7b613ac48c4..107c9625f4f69 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -32,27 +32,29 @@ class StoreInst;
/// These are the kinds of recurrences that we support.
enum class RecurKind {
- None, ///< Not a recurrence.
- Add, ///< Sum of integers.
- Mul, ///< Product of integers.
- Or, ///< Bitwise or logical OR of integers.
- And, ///< Bitwise or logical AND of integers.
- Xor, ///< Bitwise or logical XOR of integers.
- SMin, ///< Signed integer min implemented in terms of select(cmp()).
- SMax, ///< Signed integer max implemented in terms of select(cmp()).
- UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
- UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
- FAdd, ///< Sum of floats.
- FMul, ///< Product of floats.
- FMin, ///< FP min implemented in terms of select(cmp()).
- FMax, ///< FP max implemented in terms of select(cmp()).
- FMinimum, ///< FP min with llvm.minimum semantics
- FMaximum, ///< FP max with llvm.maximum semantics
- FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
- IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
- FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
- ///< loop invariant, and both x and y are integer type.
+ None, ///< Not a recurrence.
+ Add, ///< Sum of integers.
+ Mul, ///< Product of integers.
+ Or, ///< Bitwise or logical OR of integers.
+ And, ///< Bitwise or logical AND of integers.
+ Xor, ///< Bitwise or logical XOR of integers.
+ SMin, ///< Signed integer min implemented in terms of select(cmp()).
+ SMax, ///< Signed integer max implemented in terms of select(cmp()).
+ UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
+ UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
+ FAdd, ///< Sum of floats.
+ FMul, ///< Product of floats.
+ FMin, ///< FP min implemented in terms of select(cmp()).
+ FMax, ///< FP max implemented in terms of select(cmp()).
+ FMinimum, ///< FP min with llvm.minimum semantics
+ FMaximum, ///< FP max with llvm.maximum semantics
+ FMinimumnum, ///< FP min with llvm.minimumnum semantics
+ FMaximumnum, ///< FP max with llvm.maximumnum semantics
+ FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
+ IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
+ FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
+ ///< loop invariant, and both x and y are integer type.
// TODO: Any_of reduction need not be restricted to integer type only.
};
@@ -226,7 +228,8 @@ class RecurrenceDescriptor {
/// Returns true if the recurrence kind is a floating-point min/max kind.
static bool isFPMinMaxRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FMin || Kind == RecurKind::FMax ||
- Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum;
+ Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum ||
+ Kind == RecurKind::FMinimumnum || Kind == RecurKind::FMaximumnum;
}
/// Returns true if the recurrence kind is any min/max kind.
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 717693a7cf63c..8b938f97a679d 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -1347,6 +1347,39 @@ TLI_DEFINE_ENUM_INTERNAL(fminl)
TLI_DEFINE_STRING_INTERNAL("fminl")
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+// Calls to fmaximum_num and fminimum_num library functions expand to the llvm.maximumnum and
+// llvm.minimumnum intrinsics with the correct parameter types for the arguments
+// (all types must match).
+/// double fmaximum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_num)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fmaximum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numf)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fmaximum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fmaximum_numl)
+TLI_DEFINE_STRING_INTERNAL("fmaximum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// double fminimum_num(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_num)
+TLI_DEFINE_STRING_INTERNAL("fminimum_num")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// float fminimum_numf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numf)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numf")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
+/// long double fminimum_numl(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fminimum_numl)
+TLI_DEFINE_STRING_INTERNAL("fminimum_numl")
+TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
+
/// double fmod(double x, double y);
TLI_DEFINE_ENUM_INTERNAL(fmod)
TLI_DEFINE_STRING_INTERNAL("fmod")
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 0584b7e29f67b..9a2250a67acdf 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1059,14 +1059,16 @@ bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root,
/// Specific patterns of select instructions we can match.
enum SelectPatternFlavor {
SPF_UNKNOWN = 0,
- SPF_SMIN, /// Signed minimum
- SPF_UMIN, /// Unsigned minimum
- SPF_SMAX, /// Signed maximum
- SPF_UMAX, /// Unsigned maximum
- SPF_FMINNUM, /// Floating point minnum
- SPF_FMAXNUM, /// Floating point maxnum
- SPF_ABS, /// Absolute value
- SPF_NABS /// Negated absolute value
+ SPF_SMIN, /// Signed minimum
+ SPF_UMIN, /// Unsigned minimum
+ SPF_SMAX, /// Signed maximum
+ SPF_UMAX, /// Unsigned maximum
+ SPF_FMINNUM, /// Floating point minnum
+ SPF_FMAXNUM, /// Floating point maxnum
+ SPF_FMINIMUMNUM, /// Floating point minnum
+ SPF_FMAXIMUMNUM, /// Floating point maxnum
+ SPF_ABS, /// Absolute value
+ SPF_NABS /// Negated absolute value
};
/// Behavior when a floating point min/max is given one NaN and one
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 2091432d4fe27..167cc2d1755a5 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1686,6 +1686,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum:
+ case Intrinsic::vector_reduce_fmaximumnum:
+ case Intrinsic::vector_reduce_fminimumnum:
case Intrinsic::vector_reduce_umax:
case Intrinsic::vector_reduce_umin: {
IntrinsicCostAttributes Attrs(IID, RetTy, Args[0]->getType(), FMF, I, 1);
@@ -2009,6 +2011,12 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::maximum:
ISD = ISD::FMAXIMUM;
break;
+ case Intrinsic::minimumnum:
+ ISD = ISD::FMINIMUMNUM;
+ break;
+ ...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Since we need to reuse some logic of Known not working ports, will be fixed in future PRs:
Other TODOs |
Please add a table to LangRef comparing the behavior of the three versions of min/max intrinsics for various inputs. |
@peterwaller-arm I noticed that in |
TODO: implement for architectures that don't have This is the example of MIPS pre-R6:
Note, it is wrong, as -0.0 vs -0.0 will get +0.0. |
d5e1515
to
2409b9b
Compare
LibFunc_fminimum_numl LibFunc_fmaximum_numf LibFunc_fmaximum_numl
a98c64f
to
f2a340c
Compare
# DEBUG-NEXT: G_VECREDUCE_FMAXIMUMNUM (opcode 276): 2 type indices, 0 imm indices | ||
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined | ||
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined | ||
# DEBUG-NEXT: G_VECREDUCE_FMINIMUMNUM (opcode 277): 2 type indices, 0 imm indices |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The opcodes for G_VECREDUCE_FMAXIMUMNUM and G_VECREDUCE_FMINIMUMNUM should be a regex to be consistent with the rest of the test and to make it more flexible.
This hard coding is causing the test to fail on a bot: https://lab.llvm.org/buildbot/#/builders/174/builds/376
…le. (#96277) This change removes the hard coded opcode values and replaces them with regexes so that the test can deal with different opcode numbers being assigned and unbreak a ton of bots.
It looks like this PR was merged without being approved, and I also couldn't find the corresponding RFC for this addition on discourse. I've reverted it for now. |
@nikic Thanks. I submit an RFC now |
Currently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN: When we compare sNaN vs NUM: ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as +0.0 is not always greater than -0.0. MIPS/LoongArch/Generic: return NUM. LIBCALL: returns qNaN. So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber. Half-fix: llvm#93033
…exible. (llvm#96277) This change removes the hard coded opcode values and replaces them with regexes so that the test can deal with different opcode numbers being assigned and unbreak a ton of bots.
Currently, on different platform, the behaivor of llvm.minnum is different if one operand is sNaN:
When we compare sNaN vs NUM:
ARM/AArch64/PowerPC: follow the IEEE754-2008's minNUM: return qNaN. RISC-V/Hexagon follow the IEEE754-2019's minimumNumber: return NUM. X86: Returns NUM but not same with IEEE754-2019's minimumNumber as
+0.0 is not always greater than -0.0.
MIPS/LoongArch/Generic: return NUM.
LIBCALL: returns qNaN.
So, let's introduce llvm.minmumnum/llvm.maximumnum, which always follow IEEE754-2019's minimumNumber/maximumNumber.
Half-fix: #93033