Skip to content

Commit 3302f06

Browse files
wzssyqaDanielCChen
authored andcommitted
Clang: Support minimumnum and maximumnum intrinsics (llvm#96281)
We just introduce llvm.minimumnum and llvm.maximumnum intrinsics support to llvm. Let's support them in Clang. See: llvm#93033
1 parent e2919fb commit 3302f06

File tree

9 files changed

+327
-7
lines changed

9 files changed

+327
-7
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
215215
let Prototype = "T(T, T)";
216216
}
217217

218+
def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
219+
let Spellings = ["__builtin_fmaximum_num"];
220+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
221+
let Prototype = "T(T, T)";
222+
}
223+
224+
def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
225+
let Spellings = ["__builtin_fminimum_num"];
226+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
227+
let Prototype = "T(T, T)";
228+
}
229+
218230
def Atan2F128 : Builtin {
219231
let Spellings = ["__builtin_atan2f128"];
220232
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
@@ -3728,6 +3740,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
37283740
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
37293741
}
37303742

3743+
def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
3744+
let Spellings = ["fmaximum_num"];
3745+
let Attributes = [NoThrow, Const];
3746+
let Prototype = "T(T, T)";
3747+
let AddBuiltinPrefixedAlias = 1;
3748+
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
3749+
}
3750+
3751+
def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
3752+
let Spellings = ["fminimum_num"];
3753+
let Attributes = [NoThrow, Const];
3754+
let Prototype = "T(T, T)";
3755+
let AddBuiltinPrefixedAlias = 1;
3756+
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
3757+
}
3758+
37313759
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
37323760
let Spellings = ["hypot"];
37333761
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];

clang/lib/AST/ExprConstant.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15310,6 +15310,32 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
1531015310
Result = RHS;
1531115311
return true;
1531215312
}
15313+
15314+
case Builtin::BI__builtin_fmaximum_num:
15315+
case Builtin::BI__builtin_fmaximum_numf:
15316+
case Builtin::BI__builtin_fmaximum_numl:
15317+
case Builtin::BI__builtin_fmaximum_numf16:
15318+
case Builtin::BI__builtin_fmaximum_numf128: {
15319+
APFloat RHS(0.);
15320+
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
15321+
!EvaluateFloat(E->getArg(1), RHS, Info))
15322+
return false;
15323+
Result = maximumnum(Result, RHS);
15324+
return true;
15325+
}
15326+
15327+
case Builtin::BI__builtin_fminimum_num:
15328+
case Builtin::BI__builtin_fminimum_numf:
15329+
case Builtin::BI__builtin_fminimum_numl:
15330+
case Builtin::BI__builtin_fminimum_numf16:
15331+
case Builtin::BI__builtin_fminimum_numf128: {
15332+
APFloat RHS(0.);
15333+
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
15334+
!EvaluateFloat(E->getArg(1), RHS, Info))
15335+
return false;
15336+
Result = minimumnum(Result, RHS);
15337+
return true;
15338+
}
1531315339
}
1531415340
}
1531515341

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2869,6 +2869,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
28692869
Intrinsic::minnum,
28702870
Intrinsic::experimental_constrained_minnum));
28712871

2872+
case Builtin::BIfmaximum_num:
2873+
case Builtin::BIfmaximum_numf:
2874+
case Builtin::BIfmaximum_numl:
2875+
case Builtin::BI__builtin_fmaximum_num:
2876+
case Builtin::BI__builtin_fmaximum_numf:
2877+
case Builtin::BI__builtin_fmaximum_numf16:
2878+
case Builtin::BI__builtin_fmaximum_numl:
2879+
case Builtin::BI__builtin_fmaximum_numf128:
2880+
return RValue::get(
2881+
emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::maximumnum));
2882+
2883+
case Builtin::BIfminimum_num:
2884+
case Builtin::BIfminimum_numf:
2885+
case Builtin::BIfminimum_numl:
2886+
case Builtin::BI__builtin_fminimum_num:
2887+
case Builtin::BI__builtin_fminimum_numf:
2888+
case Builtin::BI__builtin_fminimum_numf16:
2889+
case Builtin::BI__builtin_fminimum_numl:
2890+
case Builtin::BI__builtin_fminimum_numf128:
2891+
return RValue::get(
2892+
emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::minimumnum));
2893+
28722894
// fmod() is a special-case. It maps to the frem instruction rather than an
28732895
// LLVM intrinsic.
28742896
case Builtin::BIfmod:

clang/test/CodeGen/builtins.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ int main(void) {
6969
P(issignaling, (1.));
7070
P(isfpclass, (1., 1));
7171

72+
Q(fmaximum_num, (1.0, 2.0));
73+
Q(fmaximum_numf, (1.0, 2.0));
74+
Q(fmaximum_numl, (1.0, 2.0));
75+
Q(fminimum_num, (1.0, 2.0));
76+
Q(fminimum_numf, (1.0, 2.0));
77+
Q(fminimum_numl, (1.0, 2.0));
78+
7279
// Bitwise & Numeric Functions
7380

7481
P(abs, (N));
@@ -305,7 +312,7 @@ void test_float_builtins(__fp16 *H, float F, double D, long double LD) {
305312
}
306313

307314
// CHECK-LABEL: define{{.*}} void @test_float_builtin_ops
308-
void test_float_builtin_ops(float F, double D, long double LD) {
315+
void test_float_builtin_ops(float F, double D, long double LD, int I) {
309316
volatile float resf;
310317
volatile double resd;
311318
volatile long double resld;
@@ -353,6 +360,58 @@ void test_float_builtin_ops(float F, double D, long double LD) {
353360
resld = __builtin_fmaxl(LD, LD);
354361
// CHECK: call x86_fp80 @llvm.maxnum.f80
355362

363+
resf = __builtin_fminimum_numf(F, F);
364+
// CHECK: call float @llvm.minimumnum.f32
365+
366+
resf = __builtin_fminimum_numf(I, I);
367+
// CHECK: sitofp i32 {{%[0-9]+}} to float
368+
// CHECK: sitofp i32 {{%[0-9]+}} to float
369+
// CHECK: call float @llvm.minimumnum.f32
370+
371+
resf = __builtin_fminimum_numf(1.0, 2.0);
372+
// CHECK: store volatile float 1.000000e+00, ptr %resf
373+
374+
resd = __builtin_fminimum_num(D, D);
375+
// CHECK: call double @llvm.minimumnum.f64
376+
377+
resd = __builtin_fminimum_num(I, I);
378+
// CHECK: sitofp i32 {{%[0-9]+}} to double
379+
// CHECK: sitofp i32 {{%[0-9]+}} to double
380+
// CHECK: call double @llvm.minimumnum.f64
381+
382+
resd = __builtin_fminimum_num(1.0, 2.0);
383+
// CHECK: store volatile double 1.000000e+00, ptr %resd
384+
385+
//FIXME: __builtin_fminimum_numl is not supported well yet.
386+
resld = __builtin_fminimum_numl(1.0, 2.0);
387+
// CHECK: store volatile x86_fp80 0xK3FFF8000000000000000, ptr %resld, align 16
388+
389+
resf = __builtin_fmaximum_numf(F, F);
390+
// CHECK: call float @llvm.maximumnum.f32
391+
392+
resf = __builtin_fmaximum_numf(I, I);
393+
// CHECK: sitofp i32 {{%[0-9]+}} to float
394+
// CHECK: sitofp i32 {{%[0-9]+}} to float
395+
// CHECK: call float @llvm.maximumnum.f32
396+
397+
resf = __builtin_fmaximum_numf(1.0, 2.0);
398+
// CHECK: store volatile float 2.000000e+00, ptr %resf
399+
400+
resd = __builtin_fmaximum_num(D, D);
401+
// CHECK: call double @llvm.maximumnum.f64
402+
403+
resd = __builtin_fmaximum_num(I, I);
404+
// CHECK: sitofp i32 {{%[0-9]+}} to double
405+
// CHECK: sitofp i32 {{%[0-9]+}} to double
406+
// CHECK: call double @llvm.maximumnum.f64
407+
408+
resd = __builtin_fmaximum_num(1.0, 2.0);
409+
// CHECK: store volatile double 2.000000e+00, ptr %resd
410+
411+
//FIXME: __builtin_fmaximum_numl is not supported well yet.
412+
resld = __builtin_fmaximum_numl(1.0, 2.0);
413+
// CHECK: store volatile x86_fp80 0xK40008000000000000000, ptr %resld, align 16
414+
356415
resf = __builtin_fabsf(F);
357416
// CHECK: call float @llvm.fabs.f32
358417

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: not %clang_cc1 -triple x86_64 %s -fsyntax-only -verify 2>&1 | FileCheck %s --check-prefix=CHECK-ERR
2+
3+
float fminimum_numf (float, float);
4+
double fminimum_num (double, double);
5+
long double fminimum_numl (long double, long double);
6+
float fmaximum_numf (float, float);
7+
double fmaximum_num (double, double);
8+
long double fmaximum_numl (long double, long double);
9+
10+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
11+
float fmin1(char *a, char *b) {
12+
return fminimum_numf(a, b);
13+
}
14+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
15+
float fmin2(char *a, char *b) {
16+
return fminimum_num(a, b);
17+
}
18+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
19+
float fmin3(char *a, char *b) {
20+
return fminimum_numl(a, b);
21+
}
22+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
23+
float fmax1(char *a, char *b) {
24+
return fmaximum_numf(a, b);
25+
}
26+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
27+
float fmax2(char *a, char *b) {
28+
return fmaximum_num(a, b);
29+
}
30+
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
31+
float fmax3(char *a, char *b) {
32+
return fmaximum_numl(a, b);
33+
}

clang/test/CodeGen/math-libcalls.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefix=NO__ERRNO
2-
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
3-
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefix=NO__ERRNO
4-
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
5-
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefix=HAS_MAYTRAP
1+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
2+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
3+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
4+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
5+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefixes=COMMON,HAS_MAYTRAP
66
// RUN: %clang_cc1 -triple x86_64-unknown-unknown-gnu -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_GNU
77
// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_WIN
88

@@ -372,6 +372,18 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
372372
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
373373
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(
374374

375+
fmaximum_num(*d,*d); fmaximum_numf(f,f); fmaximum_numl(*l,*l);
376+
377+
// COMMON: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
378+
// COMMON: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
379+
// COMMON: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
380+
381+
fminimum_num(*d,*d); fminimum_numf(f,f); fminimum_numl(*l,*l);
382+
383+
// COMMON: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
384+
// COMMON: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
385+
// COMMON: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
386+
375387
hypot(f,f); hypotf(f,f); hypotl(f,f);
376388

377389
// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]

clang/test/Preprocessor/feature_tests.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858

5959
// Check __has_constexpr_builtin
6060
#if !__has_constexpr_builtin(__builtin_fmax) || \
61-
!__has_constexpr_builtin(__builtin_fmin)
61+
!__has_constexpr_builtin(__builtin_fmin) || \
62+
!__has_constexpr_builtin(__builtin_fmaximum_num) || \
63+
!__has_constexpr_builtin(__builtin_fminimum_num)
6264
#error Clang should have these constexpr builtins
6365
#endif
6466

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
2+
// FIXME: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
3+
// expected-no-diagnostics
4+
5+
constexpr double NaN = __builtin_nan("");
6+
constexpr double SNaN = __builtin_nans("");
7+
constexpr double Inf = __builtin_inf();
8+
constexpr double NegInf = -__builtin_inf();
9+
10+
#define FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
11+
static_assert(T(6.7890) == FUNC(T(1.2345), T(6.7890))); \
12+
static_assert(T(6.7890) == FUNC(T(6.7890), T(1.2345)));
13+
14+
#define FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
15+
static_assert(Inf == FUNC(SNaN, Inf)); \
16+
static_assert(NegInf == FUNC(NegInf, SNaN)); \
17+
static_assert(0.0 == FUNC(SNaN, 0.0)); \
18+
static_assert(-0.0 == FUNC(-0.0, SNaN)); \
19+
static_assert(T(-1.2345) == FUNC(SNaN, T(-1.2345))); \
20+
static_assert(T(1.2345) == FUNC(T(1.2345), SNaN)); \
21+
static_assert(__builtin_isnan(FUNC(SNaN, SNaN))); \
22+
static_assert(__builtin_isnan(FUNC(NaN, SNaN))); \
23+
static_assert(!__builtin_issignaling(FUNC(SNaN, SNaN))); \
24+
static_assert(!__builtin_issignaling(FUNC(NaN, SNaN)));
25+
26+
#define FMAXIMUMNUM_TEST_NAN(T, FUNC) \
27+
static_assert(Inf == FUNC(NaN, Inf)); \
28+
static_assert(NegInf == FUNC(NegInf, NaN)); \
29+
static_assert(0.0 == FUNC(NaN, 0.0)); \
30+
static_assert(-0.0 == FUNC(-0.0, NaN)); \
31+
static_assert(T(-1.2345) == FUNC(NaN, T(-1.2345))); \
32+
static_assert(T(1.2345) == FUNC(T(1.2345), NaN)); \
33+
static_assert(__builtin_isnan(FUNC(NaN, NaN)));
34+
35+
#define FMAXIMUMNUM_TEST_INF(T, FUNC) \
36+
static_assert(Inf == FUNC(NegInf, Inf)); \
37+
static_assert(Inf == FUNC(Inf, 0.0)); \
38+
static_assert(Inf == FUNC(-0.0, Inf)); \
39+
static_assert(Inf == FUNC(Inf, T(1.2345))); \
40+
static_assert(Inf == FUNC(T(-1.2345), Inf));
41+
42+
#define FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
43+
static_assert(Inf == FUNC(Inf, NegInf)); \
44+
static_assert(0.0 == FUNC(NegInf, 0.0)); \
45+
static_assert(-0.0 == FUNC(-0.0, NegInf)); \
46+
static_assert(T(-1.2345) == FUNC(NegInf, T(-1.2345))); \
47+
static_assert(T(1.2345) == FUNC(T(1.2345), NegInf));
48+
49+
#define FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC) \
50+
static_assert(__builtin_copysign(1.0, FUNC(0.0, 0.0)) == 1.0); \
51+
static_assert(__builtin_copysign(1.0, FUNC(-0.0, 0.0)) == 1.0); \
52+
static_assert(__builtin_copysign(1.0, FUNC(0.0, -0.0)) == 1.0); \
53+
static_assert(__builtin_copysign(1.0, FUNC(-0.0, -0.0)) == -1.0);
54+
55+
#define LIST_FMAXIMUMNUM_TESTS(T, FUNC) \
56+
FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
57+
FMAXIMUMNUM_TEST_NAN(T, FUNC) \
58+
FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
59+
FMAXIMUMNUM_TEST_INF(T, FUNC) \
60+
FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
61+
FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC)
62+
63+
LIST_FMAXIMUMNUM_TESTS(double, __builtin_fmaximum_num)
64+
LIST_FMAXIMUMNUM_TESTS(float, __builtin_fmaximum_numf)
65+
LIST_FMAXIMUMNUM_TESTS((long double), __builtin_fmaximum_numl)
66+
LIST_FMAXIMUMNUM_TESTS(__fp16, __builtin_fmaximum_numf16)
67+
#ifdef __FLOAT128__
68+
LIST_FMAXIMUMNUM_TESTS(__float128, __builtin_fmaximum_numf128)
69+
#endif

0 commit comments

Comments
 (0)