Skip to content

[C++23] [CLANG] Adding C++23 constexpr math functions: fmin, fmax and frexp. #88978

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

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3acc848
Adding C23 constexpr math functions fmin and frexp.
zahiraam Apr 16, 2024
d7050b5
Addressed review comments.
zahiraam Apr 22, 2024
625028a
Responded to review comments.
zahiraam May 1, 2024
319fdd0
Added code to store the exponent in Pointer. Edited LIT tests
zahiraam May 8, 2024
da06dba
Added fmax function and function IsinRange function.
zahiraam May 9, 2024
1793cf0
Addressed review comments.
zahiraam May 10, 2024
42d7d4c
Added a fix for failing LIT test.
zahiraam May 15, 2024
9f4d632
Fixed aix-builtin-mapping.c test.
zahiraam May 17, 2024
efeec9b
Merge remote-tracking branch 'origin/main' into C23ConstExpr
zahiraam May 17, 2024
e384a05
Addressed review comments.
zahiraam Jun 11, 2024
5f67645
Put back CodeGen/aix-builtin-mapping.c how it was originally written.
zahiraam Jun 11, 2024
49186b9
Fix build issue in flang.
zahiraam Jul 26, 2024
cf2814d
Merge remote-tracking branch 'origin/main' into C23ConstExpr
zahiraam Jul 26, 2024
1c2912c
Merge remote-tracking branch 'origin/main' into C23ConstExpr
zahiraam Jul 26, 2024
d32737e
Rewrote isInFrexpResultRange according to review comments and fixed
zahiraam Jul 26, 2024
bd536f5
Fix format.
zahiraam Jul 26, 2024
32b788a
Addressed missed review comments.
zahiraam Jul 29, 2024
501e39a
Addressed review comments. Remove StoreExponent function and fixed LIT
zahiraam Aug 5, 2024
0cc61eb
Replaced ConstexpSince by Constexpr for FrexpF16F128.
zahiraam Aug 13, 2024
c615b22
Removed builtin attribute ConstExprSince and replaced it with a member
zahiraam Aug 22, 2024
5eec2db
Fix format.
zahiraam Aug 22, 2024
299df9a
Fix LIT failures.
zahiraam Aug 23, 2024
1507a33
Merge remote-tracking branch 'origin/main' into C23ConstExpr
zahiraam Aug 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion clang/include/clang/Basic/Builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_BASIC_BUILTINS_H
#define LLVM_CLANG_BASIC_BUILTINS_H

#include "LangStandard.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -74,6 +75,7 @@ struct Info {
const char *Features;
HeaderDesc Header;
LanguageID Langs;
LangStandard UnprefixedOnlyConstexprSince;
};

/// Holds information about both target-independent and
Expand Down Expand Up @@ -161,6 +163,12 @@ class Context {
return strchr(getRecord(ID).Attributes, 'f') != nullptr;
}

clang::LangStandard::Kind isBuiltinConstant(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 'O') != nullptr
? LangStandard::lang_cxx23
: LangStandard::lang_cxx20; // Not constexpr
}

/// Returns true if this builtin requires appropriate header in other
/// compilers. In Clang it will work even without including it, but we can emit
/// a warning about missing header.
Expand Down Expand Up @@ -277,7 +285,8 @@ class Context {

/// Return true if this function can be constant evaluated by Clang frontend.
bool isConstantEvaluated(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 'E') != nullptr;
return (strchr(getRecord(ID).Attributes, 'E') != nullptr ||
strchr(getRecord(ID).Attributes, 'O') != nullptr);
}

/// Returns true if this is an immediate (consteval) function
Expand Down
24 changes: 15 additions & 9 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,10 @@ def FmodF16F128 : F16F128MathTemplate, Builtin {

def FrexpF16F128 : F16F128MathTemplate, Builtin {
let Spellings = ["__builtin_frexp"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, ConstexprSince];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frexp family of functions cannot be marked const because they modify the object pointed to by the pointer parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

let Prototype = "T(T, int*)";
let BuiltinPrefixedAliasIsConstexpr = 1;
let UnprefixedOnlyConstexprSince = "lang_cxx23";
}

def HugeVal : Builtin, FPMathWithF128Template {
Expand Down Expand Up @@ -3461,15 +3463,15 @@ def Copysign : FPMathTemplate, LibBuiltin<"math.h"> {
let Attributes = [NoThrow, Const];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
}

def Fabs : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fabs"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
}

def Finite : FPMathTemplate, GNULibBuiltin<"math.h"> {
Expand All @@ -3494,9 +3496,11 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> {

def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a separate FrexpF16F128 that should probably also be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added UnprefixedOnlyConstexprSince to the class LIBBUILTIN so it will be unknow if I add it to this def. I will wait to see if the changes I made were correct and update this rule accordingly.

let Spellings = ["frexp"];
let Attributes = [NoThrow];
let Attributes = [NoThrow, Const, ConstexprSince];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
let UnprefixedOnlyConstexprSince = "lang_cxx23";
}

def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> {
Expand All @@ -3518,7 +3522,7 @@ def Nan : FPMathTemplate, LibBuiltin<"math.h"> {
let Attributes = [Pure, NoThrow];
let Prototype = "T(char const*)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
}

def Pow : FPMathTemplate, LibBuiltin<"math.h"> {
Expand Down Expand Up @@ -3664,18 +3668,20 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> {

def Fmax : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmax"];
let Attributes = [NoThrow, Const];
let Attributes = [NoThrow, Const, ConstexprSince];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
let UnprefixedOnlyConstexprSince = "lang_cxx23";
}

def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmin"];
let Attributes = [NoThrow, Const];
let Attributes = [NoThrow, Const, ConstexprSince];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
let UnprefixedOnlyConstexprSince = "lang_cxx23";
}

def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Basic/BuiltinsBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class VScanfFormat<int I> : IndexedAttribute<"S", I>;

// Builtin can be constant evaluated
def Constexpr : Attribute<"E">;
def ConstexprSince : Attribute<"O">;
// Builtin is immediate and must be constant evaluated. Implies Constexpr, and will only be supported in C++20 mode.
def Consteval : Attribute<"EG">;

Expand All @@ -84,6 +85,8 @@ class Builtin {
// On some platforms, some functions are actually macros. In that case we need
// to #undef them.
bit RequiresUndef = 0;
bit BuiltinPrefixedAliasIsConstexpr = 0;
string UnprefixedOnlyConstexprSince = "";
}

class CustomEntry {
Expand All @@ -99,7 +102,8 @@ class LibBuiltin<string header, string languages = "ALL_LANGUAGES"> : Builtin {
string Header = header;
string Languages = languages;
bit AddBuiltinPrefixedAlias = 0;
bit OnlyBuiltinPrefixedAliasIsConstexpr = 0;
bit BuiltinPrefixedAliasIsConstexpr = 0;
string UnprefixedOnlyConstexprSince = "";
}

class MSLibBuiltin<string header> : LibBuiltin<header, "ALL_MS_LANGUAGES">;
Expand Down
68 changes: 68 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14718,6 +14718,8 @@ class FloatExprEvaluator
return true;
}

void StoreExponent(LValue Pointer, int exp);

bool VisitCallExpr(const CallExpr *E);

bool VisitUnaryOperator(const UnaryOperator *E);
Expand Down Expand Up @@ -14775,6 +14777,29 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,

return true;
}
// Checks that the value x is in the range (-1;-0.5], [0.5; 1)
static bool isInFrexpResultRange(const llvm::APFloat &x) {
llvm::APFloat AbsX = abs(x);

llvm::APFloat half(x.getSemantics(), "0.5");
llvm::APFloat one(x.getSemantics(), "1.0");

return (AbsX.compare(half) != llvm::APFloat::cmpLessThan &&
AbsX.compare(one) == llvm::APFloat::cmpLessThan);
}

void FloatExprEvaluator::StoreExponent(LValue Pointer, int exp) {
const APValue::LValueBase Base = Pointer.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
if (auto *VarD = dyn_cast<VarDecl>(VD)) {
clang::IntegerLiteral *IL =
clang::IntegerLiteral::Create(Info.Ctx, llvm::APSInt(32, exp),
Info.Ctx.IntTy, clang::SourceLocation());
VarD->setInit(IL);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See use of handleAssignment for __builtin_add_overflow:

if (!handleAssignment(Info, E, ResultLValue, ResultType, APV))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure what I should be looking at here. Are you objecting to the way StoreExponent is written?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure what I should be looking at here. Are you objecting to the way StoreExponent is written?

Sorry for the late response. Yes, I am objecting to the way StoreExponent() is written. It tries to change the initializer of a variable to give it a value, but that approach is wrong. There does not need to be a variable in the first place (the pointer can point to a member of a temporary class object). Please see handleAssignment().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

} else {
llvm_unreachable("expecting a VarDecl for an exponent");
}
}

bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
Expand All @@ -14784,6 +14809,33 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;

case Builtin::BIfrexp:
case Builtin::BIfrexpf:
case Builtin::BIfrexpl:
case Builtin::BI__builtin_frexp:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-__builtin_-prefixed cases need to be added in as per @philnik777's comment (#88978 (comment)). Same for the other two function families.

Some more thought is needed on how to handle the non-__builtin_-prefixed cases under non-C++23-or-higher language modes. The specific implications of those functions being non-constexpr under said modes (as required, for C++, by https://wg21.link/constexpr.functions) may determine the solution to apply in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the non-`_builtin prefixed cases.

case Builtin::BI__builtin_frexpf:
case Builtin::BI__builtin_frexpl:
case Builtin::BI__builtin_frexpf16:
case Builtin::BI__builtin_frexpf128: {
const auto *FDecl = E->getDirectCallee();
Builtin::Context BTC = Info.Ctx.BuiltinInfo;
if (BTC.isBuiltinConstant(FDecl->getBuiltinID()) >
Info.Ctx.getLangOpts().LangStd)
return false;
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
return false;
int FrexpExp;
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
Result = llvm::frexp(Result, FrexpExp, RM);
assert((Result.isZero() || Result.isNaN() || Result.isInfinity() ||
isInFrexpResultRange(Result)) &&
"The value is not in the expected range for frexp.");
StoreExponent(Pointer, FrexpExp);
return true;
}

case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
case Builtin::BI__builtin_huge_vall:
Expand Down Expand Up @@ -14857,12 +14909,20 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}

case Builtin::BIfmax:
case Builtin::BIfmaxf:
case Builtin::BIfmaxl:
case Builtin::BI__builtin_fmax:
case Builtin::BI__builtin_fmaxf:
case Builtin::BI__builtin_fmaxl:
case Builtin::BI__builtin_fmaxf16:
case Builtin::BI__builtin_fmaxf128: {
// TODO: Handle sNaN.
const auto *FDecl = E->getDirectCallee();
Builtin::Context BTC = Info.Ctx.BuiltinInfo;
if (BTC.isBuiltinConstant(FDecl->getBuiltinID()) >
Info.Ctx.getLangOpts().LangStd)
return false;
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
Expand All @@ -14875,12 +14935,20 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}

case Builtin::BIfmin:
case Builtin::BIfminf:
Comment on lines +15093 to +15094
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make these evaluate in constexpr. Not only does this extend C (not a stated intent of the patch), it will cause accidental dependencies that break when -fno-builtin is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These have to be made constexpr, at least in C++23. C++ stdlibs can't override them to make them call the __builtin_ versions, so Clang has to handle that.

This comment was marked as resolved.

This comment was marked as resolved.

This comment was marked as resolved.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll be missing at least "pedantic" diagnostics if we don't restrict the constexpr-ness to C++23 and up. So we do need that restriction.

The interaction with -fno-builtin[-*] may need more discussion. At least the documentation for that option would need to be updated if the C++23 constexpr math would break with it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the Clang C/C++ Language Workgroup call on 2024-05-15, it was agreed that -fno-builtin[-*] should remain capable of disabling built-in treatment even when that treatment would be required for conformance w.r.t. constexpr behaviour of functions shared with C.

For me, the first expectation for this PR (on that subject) is an update to the documentation of -fno-builtin[-*].

@AaronBallman @ldionne, I am no sure how we want to handle this w.r.t. documenting the C++23 implementation status. Does it go in both the Clang documentation (for the functions shared with C) and the libc++ documentation (for the overloads added by C++)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think anything should happen to the libc++ documentation in this patch. We can update the implementation to behave the same across the different overloads in a follow-up and update our documentation then.

case Builtin::BIfminl:
case Builtin::BI__builtin_fmin:
case Builtin::BI__builtin_fminf:
case Builtin::BI__builtin_fminl:
case Builtin::BI__builtin_fminf16:
case Builtin::BI__builtin_fminf128: {
// TODO: Handle sNaN.
const auto *FDecl = E->getDirectCallee();
Builtin::Context BTC = Info.Ctx.BuiltinInfo;
if (BTC.isBuiltinConstant(FDecl->getBuiltinID()) >
Info.Ctx.getLangOpts().LangStd)
return false;
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
Expand Down
106 changes: 106 additions & 0 deletions clang/test/CodeGenCXX/constexpr-math.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4

// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
// RUN: -emit-llvm -o - %s | FileCheck %s

#define NAN (__builtin_nanf(""))
#define INFINITY (__builtin_inff())

// CHECK-LABEL: define dso_local noundef i32 @_Z4funcv(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[MIN1:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MIN2:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MIN3:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MIN4:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MIN5:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MIN6:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MIN7:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MIN8:%.*]] = alloca x86_fp80, align 16
// CHECK-NEXT: [[MAX1:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MAX2:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MAX3:%.*]] = alloca double, align 8
// CHECK-NEXT: [[MAX4:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MAX5:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MAX6:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MAX7:%.*]] = alloca float, align 4
// CHECK-NEXT: [[MAX8:%.*]] = alloca x86_fp80, align 16
// CHECK-NEXT: [[FREXP1:%.*]] = alloca double, align 8
// CHECK-NEXT: [[FREXP2:%.*]] = alloca double, align 8
// CHECK-NEXT: [[FREXP3:%.*]] = alloca double, align 8
// CHECK-NEXT: [[FREXP4:%.*]] = alloca float, align 4
// CHECK-NEXT: [[FREXP5:%.*]] = alloca float, align 4
// CHECK-NEXT: [[FREXP6:%.*]] = alloca float, align 4
// CHECK-NEXT: [[FREXP7:%.*]] = alloca float, align 4
// CHECK-NEXT: [[FREXP8:%.*]] = alloca x86_fp80, align 16
// CHECK-NEXT: [[FREXP9:%.*]] = alloca float, align 4
// CHECK-NEXT: [[FREXP10:%.*]] = alloca x86_fp80, align 16
// CHECK-NEXT: store i32 0, ptr [[I]], align 4
// CHECK-NEXT: store double 1.300000e+00, ptr [[MIN1]], align 8
// CHECK-NEXT: store double -0.000000e+00, ptr [[MIN2]], align 8
// CHECK-NEXT: store double -0.000000e+00, ptr [[MIN3]], align 8
// CHECK-NEXT: store float 0x7FF8000000000000, ptr [[MIN4]], align 4
// CHECK-NEXT: store float -1.000000e+00, ptr [[MIN5]], align 4
// CHECK-NEXT: store float 0xFFF0000000000000, ptr [[MIN6]], align 4
// CHECK-NEXT: store float 0.000000e+00, ptr [[MIN7]], align 4
// CHECK-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[MIN8]], align 16
// CHECK-NEXT: store double 1.524000e+01, ptr [[MAX1]], align 8
// CHECK-NEXT: store double 0.000000e+00, ptr [[MAX2]], align 8
// CHECK-NEXT: store double 0.000000e+00, ptr [[MAX3]], align 8
// CHECK-NEXT: store float -1.000000e+00, ptr [[MAX4]], align 4
// CHECK-NEXT: store float 0x7FF0000000000000, ptr [[MAX5]], align 4
// CHECK-NEXT: store float 0.000000e+00, ptr [[MAX6]], align 4
// CHECK-NEXT: store float 0x7FF8000000000000, ptr [[MAX7]], align 4
// CHECK-NEXT: store x86_fp80 0xK4008C540C49BA5E353F8, ptr [[MAX8]], align 16
// CHECK-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[FREXP1]], align 8
// CHECK-NEXT: store double 0.000000e+00, ptr [[FREXP2]], align 8
// CHECK-NEXT: store double -0.000000e+00, ptr [[FREXP3]], align 8
// CHECK-NEXT: store float 0x7FF8000000000000, ptr [[FREXP4]], align 4
// CHECK-NEXT: store float 0xFFF8000000000000, ptr [[FREXP5]], align 4
// CHECK-NEXT: store float 0x7FF0000000000000, ptr [[FREXP6]], align 4
// CHECK-NEXT: store float 0xFFF0000000000000, ptr [[FREXP7]], align 4
// CHECK-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
// CHECK-NEXT: store float 8.750000e-01, ptr [[FREXP9]], align 4
// CHECK-NEXT: store x86_fp80 0xK3FFEEAC7AE147AE14800, ptr [[FREXP10]], align 16
// CHECK-NEXT: ret i32 0
//
int func()
{
int i;

// fmin
constexpr double min1 = __builtin_fmin(15.24, 1.3);
constexpr double min2 = __builtin_fmin(-0.0, +0.0);
constexpr double min3 = __builtin_fmin(+0.0, -0.0);
constexpr float min4 = __builtin_fminf(NAN, NAN);
constexpr float min5 = __builtin_fminf(NAN, -1);
constexpr float min6 = __builtin_fminf(-INFINITY, 0);
constexpr float min7 = __builtin_fminf(INFINITY, 0);
constexpr long double min8 = __builtin_fminl(123.456L, 789.012L);

// fmax
constexpr double max1 = __builtin_fmax(15.24, 1.3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting nit:

Suggested change
constexpr double max1 = __builtin_fmax(15.24, 1.3);
constexpr double max1 = __builtin_fmax(15.24, 1.3);

constexpr double max2 = __builtin_fmax(-0.0, +0.0);
constexpr double max3 = __builtin_fmax(+0.0, -0.0);
constexpr float max4 = __builtin_fmaxf(NAN, -1);
constexpr float max5 = __builtin_fmaxf(+INFINITY, 0);
constexpr float max6 = __builtin_fmaxf(-INFINITY, 0);
constexpr float max7 = __builtin_fmaxf(NAN, NAN);
constexpr long double max8 = __builtin_fmaxl(123.456L, 789.012L);

// frexp
constexpr double frexp1 = __builtin_frexp(123.45, &i);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zahiraam, to be explicit, these tests (as-is) will fail once the comment re: StoreExponent() is addressed.

This will probably work:

Suggested change
constexpr double frexp1 = __builtin_frexp(123.45, &i);
constexpr double frexp1 = __builtin_frexp(123.45, (int [1]){});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

constexpr double frexp2 = __builtin_frexp(0.0, &i);
constexpr double frexp3 = __builtin_frexp(-0.0, &i);
constexpr float frexp4 = __builtin_frexpf(NAN, &i);
constexpr float frexp5 = __builtin_frexpf(-NAN, &i);
constexpr float frexp6 = __builtin_frexpf(+INFINITY, &i);
constexpr float frexp7 = __builtin_frexpf(-INFINITY, &i);
constexpr long double frexp8 = __builtin_frexpl(259.328L, &i);
constexpr float frexp9 = __builtin_frexpf16(3.5, &i);
constexpr long double frexp10 = __builtin_frexpf128(234.78, &i);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constexpr float frexp9 = __builtin_frexpf16(3.5, &i);
constexpr long double frexp10 = __builtin_frexpf128(234.78, &i);
constexpr __fp16 frexp9 = __builtin_frexpf16(3.5, &i);
constexpr __float128 frexp10 = __builtin_frexpf128(234.78, &i);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


return 0;
}

Loading