Skip to content

Commit 5c3b36b

Browse files
committed
Clang: Add minnum/maxnum builtin functions support
With #112852, we claimed that llvm.minnum and llvm.maxnum should treat +0.0>-0.0, while libc doesn't require fmin(3)/fmax(3) for it. To make llvm.minnum/llvm.maxnum easy to use, we define the builtin functions for them, include __builtin_minnum __builtin_elementwise_minnum __builtin_minnum __builtin_elementwise_minnum __builtin_minnum __builtin_elementwise_minnum __builtin_minnum __builtin_maxnum __builtin_elementwise_maxnum __builtin_maxnum __builtin_elementwise_maxnum __builtin_maxnum __builtin_elementwise_maxnum __builtin_maxnum All of them support _Float16, float, double, long double.
1 parent 2e39533 commit 5c3b36b

File tree

5 files changed

+365
-0
lines changed

5 files changed

+365
-0
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,18 @@ def FmaxF16F128 : Builtin, F16F128MathTemplate {
209209
let Prototype = "T(T, T)";
210210
}
211211

212+
def MinNum : Builtin {
213+
let Spellings = ["__builtin_minnum"];
214+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, CustomTypeChecking, Constexpr];
215+
let Prototype = "void(...)";
216+
}
217+
218+
def MaxNum : Builtin {
219+
let Spellings = ["__builtin_maxnum"];
220+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, CustomTypeChecking, Constexpr];
221+
let Prototype = "void(...)";
222+
}
223+
212224
def FminF16F128 : Builtin, F16F128MathTemplate {
213225
let Spellings = ["__builtin_fmin"];
214226
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
@@ -1304,6 +1316,18 @@ def ElementwiseMin : Builtin {
13041316
let Prototype = "void(...)";
13051317
}
13061318

1319+
def ElementwiseMaxNum : Builtin {
1320+
let Spellings = ["__builtin_elementwise_maxnum"];
1321+
let Attributes = [NoThrow, Const, CustomTypeChecking];
1322+
let Prototype = "void(...)";
1323+
}
1324+
1325+
def ElementwiseMinNum : Builtin {
1326+
let Spellings = ["__builtin_elementwise_minnum"];
1327+
let Attributes = [NoThrow, Const, CustomTypeChecking];
1328+
let Prototype = "void(...)";
1329+
}
1330+
13071331
def ElementwiseMaximum : Builtin {
13081332
let Spellings = ["__builtin_elementwise_maximum"];
13091333
let Attributes = [NoThrow, Const, CustomTypeChecking];

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,7 @@ class Sema final : public SemaBase {
25822582
ExprResult AtomicOpsOverloaded(ExprResult TheCallResult,
25832583
AtomicExpr::AtomicOp Op);
25842584

2585+
bool BuiltinMaxNumMinNumMath(CallExpr *TheCall);
25852586
/// \param FPOnly restricts the arguments to floating-point types.
25862587
bool BuiltinElementwiseMath(CallExpr *TheCall,
25872588
EltwiseBuiltinArgTyRestriction ArgTyRestr =

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,6 +3238,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
32383238
Intrinsic::minnum,
32393239
Intrinsic::experimental_constrained_minnum));
32403240

3241+
case Builtin::BI__builtin_maxnum:
3242+
return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(
3243+
*this, E, Intrinsic::maxnum,
3244+
Intrinsic::experimental_constrained_maxnum));
3245+
3246+
case Builtin::BI__builtin_minnum:
3247+
return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(
3248+
*this, E, Intrinsic::minnum,
3249+
Intrinsic::experimental_constrained_minnum));
3250+
32413251
case Builtin::BIfmaximum_num:
32423252
case Builtin::BIfmaximum_numf:
32433253
case Builtin::BIfmaximum_numl:
@@ -4429,6 +4439,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
44294439
return RValue::get(Result);
44304440
}
44314441

4442+
case Builtin::BI__builtin_elementwise_maxnum: {
4443+
Value *Op0 = EmitScalarExpr(E->getArg(0));
4444+
Value *Op1 = EmitScalarExpr(E->getArg(1));
4445+
Value *Result = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::maxnum, Op0,
4446+
Op1, nullptr, "elt.maxnum");
4447+
return RValue::get(Result);
4448+
}
4449+
4450+
case Builtin::BI__builtin_elementwise_minnum: {
4451+
Value *Op0 = EmitScalarExpr(E->getArg(0));
4452+
Value *Op1 = EmitScalarExpr(E->getArg(1));
4453+
Value *Result = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::minnum, Op0,
4454+
Op1, nullptr, "elt.minnum");
4455+
return RValue::get(Result);
4456+
}
4457+
44324458
case Builtin::BI__builtin_elementwise_maximum: {
44334459
Value *Op0 = EmitScalarExpr(E->getArg(0));
44344460
Value *Op1 = EmitScalarExpr(E->getArg(1));

clang/lib/Sema/SemaChecking.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,8 +2757,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
27572757
return ExprError();
27582758
break;
27592759

2760+
case Builtin::BI__builtin_minnum:
2761+
case Builtin::BI__builtin_maxnum: {
2762+
if (BuiltinMaxNumMinNumMath(TheCall))
2763+
return ExprError();
2764+
break;
2765+
}
2766+
27602767
// These builtins restrict the element type to floating point
27612768
// types only, and take in two arguments.
2769+
case Builtin::BI__builtin_elementwise_minnum:
2770+
case Builtin::BI__builtin_elementwise_maxnum:
27622771
case Builtin::BI__builtin_elementwise_minimum:
27632772
case Builtin::BI__builtin_elementwise_maximum:
27642773
case Builtin::BI__builtin_elementwise_atan2:
@@ -15276,6 +15285,42 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
1527615285
return false;
1527715286
}
1527815287

15288+
bool Sema::BuiltinMaxNumMinNumMath(CallExpr *TheCall) {
15289+
if (checkArgCount(TheCall, 2))
15290+
return true;
15291+
15292+
ExprResult OrigArg0 = TheCall->getArg(0);
15293+
ExprResult OrigArg1 = TheCall->getArg(1);
15294+
15295+
// Do standard promotions between the two arguments, returning their common
15296+
// type.
15297+
QualType Res = UsualArithmeticConversions(
15298+
OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison);
15299+
if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
15300+
return true;
15301+
15302+
// Make sure any conversions are pushed back into the call; this is
15303+
// type safe since unordered compare builtins are declared as "_Bool
15304+
// foo(...)".
15305+
TheCall->setArg(0, OrigArg0.get());
15306+
TheCall->setArg(1, OrigArg1.get());
15307+
15308+
if (!OrigArg0.get()->isTypeDependent() && OrigArg1.get()->isTypeDependent())
15309+
return true;
15310+
15311+
// If the common type isn't a real floating type, then the arguments were
15312+
// invalid for this operation.
15313+
if (Res.isNull() || !Res->isRealFloatingType())
15314+
return Diag(OrigArg0.get()->getBeginLoc(),
15315+
diag::err_typecheck_call_invalid_ordered_compare)
15316+
<< OrigArg0.get()->getType() << OrigArg1.get()->getType()
15317+
<< SourceRange(OrigArg0.get()->getBeginLoc(),
15318+
OrigArg1.get()->getEndLoc());
15319+
15320+
TheCall->setType(Res);
15321+
return false;
15322+
}
15323+
1527915324
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
1528015325
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1528115326
if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {

0 commit comments

Comments
 (0)