Skip to content

Commit d5e1515

Browse files
committed
Intrinsic: introduce minimumnum and maximumnum
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
1 parent 6a3982f commit d5e1515

File tree

78 files changed

+1697
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1697
-176
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];
@@ -3636,6 +3648,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
36363648
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
36373649
}
36383650

3651+
def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
3652+
let Spellings = ["fmaximum_num"];
3653+
let Attributes = [NoThrow, Const];
3654+
let Prototype = "T(T, T)";
3655+
let AddBuiltinPrefixedAlias = 1;
3656+
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
3657+
}
3658+
3659+
def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
3660+
let Spellings = ["fminimum_num"];
3661+
let Attributes = [NoThrow, Const];
3662+
let Prototype = "T(T, T)";
3663+
let AddBuiltinPrefixedAlias = 1;
3664+
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
3665+
}
3666+
36393667
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
36403668
let Spellings = ["hypot"];
36413669
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,6 +2786,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
27862786
Intrinsic::minnum,
27872787
Intrinsic::experimental_constrained_minnum));
27882788

2789+
case Builtin::BIfmaximum_num:
2790+
case Builtin::BIfmaximum_numf:
2791+
case Builtin::BIfmaximum_numl:
2792+
case Builtin::BI__builtin_fmaximum_num:
2793+
case Builtin::BI__builtin_fmaximum_numf:
2794+
case Builtin::BI__builtin_fmaximum_numf16:
2795+
case Builtin::BI__builtin_fmaximum_numl:
2796+
case Builtin::BI__builtin_fmaximum_numf128:
2797+
return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
2798+
Intrinsic::maximumnum,
2799+
Intrinsic::experimental_constrained_maximumnum));
2800+
2801+
case Builtin::BIfminimum_num:
2802+
case Builtin::BIfminimum_numf:
2803+
case Builtin::BIfminimum_numl:
2804+
case Builtin::BI__builtin_fminimum_num:
2805+
case Builtin::BI__builtin_fminimum_numf:
2806+
case Builtin::BI__builtin_fminimum_numf16:
2807+
case Builtin::BI__builtin_fminimum_numl:
2808+
case Builtin::BI__builtin_fminimum_numf128:
2809+
return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
2810+
Intrinsic::minnum,
2811+
Intrinsic::experimental_constrained_minimumnum));
2812+
27892813
// fmod() is a special-case. It maps to the frem instruction rather than an
27902814
// LLVM intrinsic.
27912815
case Builtin::BIfmod:

clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ SYMBOL(fmaxl, None, <math.h>)
475475
SYMBOL(fmin, None, <math.h>)
476476
SYMBOL(fminf, None, <math.h>)
477477
SYMBOL(fminl, None, <math.h>)
478+
SYMBOL(fmaximum_num, None, <math.h>)
479+
SYMBOL(fmaximum_numf, None, <math.h>)
480+
SYMBOL(fmaximum_numfl, None, <math.h>)
481+
SYMBOL(fminimum_num, None, <math.h>)
482+
SYMBOL(fminimum_numf, None, <math.h>)
483+
SYMBOL(fminimum_numl, None, <math.h>)
478484
SYMBOL(fmod, None, <math.h>)
479485
SYMBOL(fmodf, None, <math.h>)
480486
SYMBOL(fmodl, None, <math.h>)

clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,24 @@ SYMBOL(fminf, None, <math.h>)
12951295
SYMBOL(fminl, std::, <cmath>)
12961296
SYMBOL(fminl, None, <cmath>)
12971297
SYMBOL(fminl, None, <math.h>)
1298+
SYMBOL(fmaximum_num, std::, <cmath>)
1299+
SYMBOL(fmaximum_num, None, <cmath>)
1300+
SYMBOL(fmaximum_num, None, <math.h>)
1301+
SYMBOL(fmaximum_numf, std::, <cmath>)
1302+
SYMBOL(fmaximum_numf, None, <cmath>)
1303+
SYMBOL(fmaximum_numf, None, <math.h>)
1304+
SYMBOL(fmaximum_numl, std::, <cmath>)
1305+
SYMBOL(fmaximum_numl, None, <cmath>)
1306+
SYMBOL(fmaximum_numl, None, <math.h>)
1307+
SYMBOL(fminimum_num, std::, <cmath>)
1308+
SYMBOL(fminimum_num, None, <cmath>)
1309+
SYMBOL(fminimum_num, None, <math.h>)
1310+
SYMBOL(fminimum_numf, std::, <cmath>)
1311+
SYMBOL(fminimum_numf, None, <cmath>)
1312+
SYMBOL(fminimum_numf, None, <math.h>)
1313+
SYMBOL(fminimum_numl, std::, <cmath>)
1314+
SYMBOL(fminimum_numl, None, <cmath>)
1315+
SYMBOL(fminimum_numl, None, <math.h>)
12981316
SYMBOL(fmod, std::, <cmath>)
12991317
SYMBOL(fmod, None, <cmath>)
13001318
SYMBOL(fmod, None, <math.h>)

clang/test/CodeGen/builtins.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,24 @@ void test_float_builtin_ops(float F, double D, long double LD) {
353353
resld = __builtin_fmaxl(LD, LD);
354354
// CHECK: call x86_fp80 @llvm.maxnum.f80
355355

356+
resf = __builtin_fminimum_numf(F, F);
357+
// CHECK: call float @llvm.minimumnum.f32
358+
359+
resd = __builtin_fminimum_num(D, D);
360+
// CHECK: call double @llvm.minimumnum.f64
361+
362+
resld = __builtin_fminimum_numl(LD, LD);
363+
// CHECK: call x86_fp80 @llvm.minimumnum.f80
364+
365+
resf = __builtin_fmaximum_numf(F, F);
366+
// CHECK: call float @llvm.maximumnum.f32
367+
368+
resd = __builtin_fmaximum_num(D, D);
369+
// CHECK: call double @llvm.maximumnum.f64
370+
371+
resld = __builtin_fmaximum_numl(LD, LD);
372+
// CHECK: call x86_fp80 @llvm.maximumnum.f80
373+
356374
resf = __builtin_fabsf(F);
357375
// CHECK: call float @llvm.fabs.f32
358376

clang/test/CodeGen/math-libcalls.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,31 @@ 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(f,f); fmaximum_numf(f,f); fmaximum_numl(f,f);
376+
377+
// NO__ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
378+
// NO__ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
379+
// NO__ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
380+
// HAS_ERRNO: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
381+
// HAS_ERRNO: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
382+
// HAS_ERRNO: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
383+
// HAS_MAYTRAP: declare double @llvm.experimental.constrained.maximumnum.f64(
384+
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.maximumnum.f32(
385+
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.maximumnum.f80(
386+
387+
fminimum_num(f,f); fminimum_numf(f,f); fminimum_numl(f,f);
388+
389+
// NO__ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
390+
// NO__ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
391+
// NO__ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
392+
// HAS_ERRNO: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
393+
// HAS_ERRNO: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
394+
// HAS_ERRNO: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
395+
// HAS_MAYTRAP: declare double @llvm.experimental.constrained.minimumnum.f64(
396+
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minimumnum.f32(
397+
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minimumnum.f80(
398+
399+
375400
hypot(f,f); hypotf(f,f); hypotl(f,f);
376401

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

llvm/docs/LangRef.rst

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16049,6 +16049,84 @@ of the two arguments. -0.0 is considered to be less than +0.0 for this
1604916049
intrinsic. Note that these are the semantics specified in the draft of
1605016050
IEEE 754-2019.
1605116051

16052+
.. _i_minimumnum:
16053+
16054+
'``llvm.minimumnum.*``' Intrinsic
16055+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16056+
16057+
Syntax:
16058+
"""""""
16059+
16060+
This is an overloaded intrinsic. You can use ``llvm.minimumnum`` on any
16061+
floating-point or vector of floating-point type. Not all targets support
16062+
all types however.
16063+
16064+
::
16065+
16066+
declare float @llvm.minimumnum.f32(float %Val0, float %Val1)
16067+
declare double @llvm.minimumnum.f64(double %Val0, double %Val1)
16068+
declare x86_fp80 @llvm.minimumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
16069+
declare fp128 @llvm.minimumnum.f128(fp128 %Val0, fp128 %Val1)
16070+
declare ppc_fp128 @llvm.minimumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
16071+
16072+
Overview:
16073+
"""""""""
16074+
16075+
The '``llvm.minimumnum.*``' intrinsics return the minimum of the two
16076+
arguments, not propagating NaNs and treating -0.0 as less than +0.0.
16077+
16078+
16079+
Arguments:
16080+
""""""""""
16081+
16082+
The arguments and return value are floating-point numbers of the same
16083+
type.
16084+
16085+
Semantics:
16086+
""""""""""
16087+
If both operands are NaNs, returns qNaN. Otherwise returns the lesser
16088+
of the two arguments. -0.0 is considered to be less than +0.0 for this
16089+
intrinsic. Note that these are the semantics specified in IEEE 754-2019.
16090+
16091+
.. _i_maximumnum:
16092+
16093+
'``llvm.maximumnum.*``' Intrinsic
16094+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16095+
16096+
Syntax:
16097+
"""""""
16098+
16099+
This is an overloaded intrinsic. You can use ``llvm.maximumnum`` on any
16100+
floating-point or vector of floating-point type. Not all targets support
16101+
all types however.
16102+
16103+
::
16104+
16105+
declare float @llvm.maximumnum.f32(float %Val0, float %Val1)
16106+
declare double @llvm.maximumnum.f64(double %Val0, double %Val1)
16107+
declare x86_fp80 @llvm.maximumnum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
16108+
declare fp128 @llvm.maximumnum.f128(fp128 %Val0, fp128 %Val1)
16109+
declare ppc_fp128 @llvm.maximumnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
16110+
16111+
Overview:
16112+
"""""""""
16113+
16114+
The '``llvm.maximumnum.*``' intrinsics return the maximum of the two
16115+
arguments, not propagating NaNs and treating -0.0 as less than +0.0.
16116+
16117+
16118+
Arguments:
16119+
""""""""""
16120+
16121+
The arguments and return value are floating-point numbers of the same
16122+
type.
16123+
16124+
Semantics:
16125+
""""""""""
16126+
If both operands are NaNs, returns qNaN. Otherwise returns the greater
16127+
of the two arguments. -0.0 is considered to be less than +0.0 for this
16128+
intrinsic. Note that these are the semantics specified in IEEE 754-2019.
16129+
1605216130
.. _int_copysign:
1605316131

1605416132
'``llvm.copysign.*``' Intrinsic

llvm/include/llvm/ADT/APFloat.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,16 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
14421442
return A.isNegative() ? A : B;
14431443
return B < A ? B : A;
14441444
}
1445+
LLVM_READONLY
1446+
inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
1447+
if (A.isNaN())
1448+
return B.isNaN() ? B.makeQuiet() : B;
1449+
if (B.isNaN())
1450+
return A;
1451+
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1452+
return A.isNegative() ? A : B;
1453+
return B < A ? B : A;
1454+
}
14451455

14461456
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
14471457
/// arguments, propagating NaNs and treating -0 as less than +0.
@@ -1455,6 +1465,16 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
14551465
return A.isNegative() ? B : A;
14561466
return A < B ? B : A;
14571467
}
1468+
LLVM_READONLY
1469+
inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
1470+
if (A.isNaN())
1471+
return B.isNaN() ? B.makeQuiet() : B;
1472+
if (B.isNaN())
1473+
return A;
1474+
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1475+
return A.isNegative() ? B : A;
1476+
return A < B ? B : A;
1477+
}
14581478

14591479
// We want the following functions to be available in the header for inlining.
14601480
// We cannot define them inline in the class definition of `DoubleAPFloat`

llvm/include/llvm/Analysis/IVDescriptors.h

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,29 @@ class StoreInst;
3232

3333
/// These are the kinds of recurrences that we support.
3434
enum class RecurKind {
35-
None, ///< Not a recurrence.
36-
Add, ///< Sum of integers.
37-
Mul, ///< Product of integers.
38-
Or, ///< Bitwise or logical OR of integers.
39-
And, ///< Bitwise or logical AND of integers.
40-
Xor, ///< Bitwise or logical XOR of integers.
41-
SMin, ///< Signed integer min implemented in terms of select(cmp()).
42-
SMax, ///< Signed integer max implemented in terms of select(cmp()).
43-
UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
44-
UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
45-
FAdd, ///< Sum of floats.
46-
FMul, ///< Product of floats.
47-
FMin, ///< FP min implemented in terms of select(cmp()).
48-
FMax, ///< FP max implemented in terms of select(cmp()).
49-
FMinimum, ///< FP min with llvm.minimum semantics
50-
FMaximum, ///< FP max with llvm.maximum semantics
51-
FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
52-
IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
53-
///< loop invariant, and both x and y are integer type.
54-
FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
55-
///< loop invariant, and both x and y are integer type.
35+
None, ///< Not a recurrence.
36+
Add, ///< Sum of integers.
37+
Mul, ///< Product of integers.
38+
Or, ///< Bitwise or logical OR of integers.
39+
And, ///< Bitwise or logical AND of integers.
40+
Xor, ///< Bitwise or logical XOR of integers.
41+
SMin, ///< Signed integer min implemented in terms of select(cmp()).
42+
SMax, ///< Signed integer max implemented in terms of select(cmp()).
43+
UMin, ///< Unsigned integer min implemented in terms of select(cmp()).
44+
UMax, ///< Unsigned integer max implemented in terms of select(cmp()).
45+
FAdd, ///< Sum of floats.
46+
FMul, ///< Product of floats.
47+
FMin, ///< FP min implemented in terms of select(cmp()).
48+
FMax, ///< FP max implemented in terms of select(cmp()).
49+
FMinimum, ///< FP min with llvm.minimum semantics
50+
FMaximum, ///< FP max with llvm.maximum semantics
51+
FMinimumnum, ///< FP min with llvm.minimumnum semantics
52+
FMaximumnum, ///< FP max with llvm.maximumnum semantics
53+
FMulAdd, ///< Sum of float products with llvm.fmuladd(a * b + sum).
54+
IAnyOf, ///< Any_of reduction with select(icmp(),x,y) where one of (x,y) is
55+
///< loop invariant, and both x and y are integer type.
56+
FAnyOf ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
57+
///< loop invariant, and both x and y are integer type.
5658
// TODO: Any_of reduction need not be restricted to integer type only.
5759
};
5860

@@ -226,7 +228,8 @@ class RecurrenceDescriptor {
226228
/// Returns true if the recurrence kind is a floating-point min/max kind.
227229
static bool isFPMinMaxRecurrenceKind(RecurKind Kind) {
228230
return Kind == RecurKind::FMin || Kind == RecurKind::FMax ||
229-
Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum;
231+
Kind == RecurKind::FMinimum || Kind == RecurKind::FMaximum ||
232+
Kind == RecurKind::FMinimumnum || Kind == RecurKind::FMaximumnum;
230233
}
231234

232235
/// Returns true if the recurrence kind is any min/max kind.

llvm/include/llvm/Analysis/TargetLibraryInfo.def

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,39 @@ TLI_DEFINE_ENUM_INTERNAL(fminl)
13471347
TLI_DEFINE_STRING_INTERNAL("fminl")
13481348
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
13491349

1350+
// Calls to fmaximum_num and fminimum_num library functions expand to the llvm.maximumnum and
1351+
// llvm.minimumnum intrinsics with the correct parameter types for the arguments
1352+
// (all types must match).
1353+
/// double fmaximum_num(double x, double y);
1354+
TLI_DEFINE_ENUM_INTERNAL(fmaximum_num)
1355+
TLI_DEFINE_STRING_INTERNAL("fmaximum_num")
1356+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1357+
1358+
/// float fmaximum_numf(float x, float y);
1359+
TLI_DEFINE_ENUM_INTERNAL(fmaximum_numf)
1360+
TLI_DEFINE_STRING_INTERNAL("fmaximum_numf")
1361+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1362+
1363+
/// long double fmaximum_numl(long double x, long double y);
1364+
TLI_DEFINE_ENUM_INTERNAL(fmaximum_numl)
1365+
TLI_DEFINE_STRING_INTERNAL("fmaximum_numl")
1366+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1367+
1368+
/// double fminimum_num(double x, double y);
1369+
TLI_DEFINE_ENUM_INTERNAL(fminimum_num)
1370+
TLI_DEFINE_STRING_INTERNAL("fminimum_num")
1371+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1372+
1373+
/// float fminimum_numf(float x, float y);
1374+
TLI_DEFINE_ENUM_INTERNAL(fminimum_numf)
1375+
TLI_DEFINE_STRING_INTERNAL("fminimum_numf")
1376+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1377+
1378+
/// long double fminimum_numl(long double x, long double y);
1379+
TLI_DEFINE_ENUM_INTERNAL(fminimum_numl)
1380+
TLI_DEFINE_STRING_INTERNAL("fminimum_numl")
1381+
TLI_DEFINE_SIG_INTERNAL(Floating, Same, Same)
1382+
13501383
/// double fmod(double x, double y);
13511384
TLI_DEFINE_ENUM_INTERNAL(fmod)
13521385
TLI_DEFINE_STRING_INTERNAL("fmod")

0 commit comments

Comments
 (0)