[flang-commits] [clang] [flang] [llvm] [C++23] [CLANG] Adding C++23 constexpr math functions: fmin, fmax and frexp. (PR #88978)
Zahira Ammarguellat via flang-commits
flang-commits at lists.llvm.org
Fri Aug 23 11:22:39 PDT 2024
https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/88978
>From 3acc848f4fcc68445dfc849f9c6f8d384d3692af Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 16 Apr 2024 13:09:58 -0700
Subject: [PATCH 01/19] Adding C23 constexpr math functions fmin and frexp.
---
clang/include/clang/Basic/Builtins.td | 4 +--
clang/lib/AST/ExprConstant.cpp | 16 ++++++++-
clang/test/CodeGen/constexpr-math.cpp | 51 +++++++++++++++++++++++++++
3 files changed, 68 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CodeGen/constexpr-math.cpp
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 52c0dd52c28b11..a35c77286229ff 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3440,7 +3440,7 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> {
def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["frexp"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
}
@@ -3618,7 +3618,7 @@ def Fmax : FPMathTemplate, LibBuiltin<"math.h"> {
def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmin"];
- let Attributes = [NoThrow, Const];
+ let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5a36621dc5cce2..506621ac7e9c1b 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2922,7 +2922,7 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
// If during the evaluation of an expression, the result is not
// mathematically defined [...], the behavior is undefined.
// FIXME: C++ rules require us to not conform to IEEE 754 here.
- if (LHS.isNaN()) {
+ if (!Info.getLangOpts().CPlusPlus23 && LHS.isNaN()) {
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
return Info.noteUndefinedBehavior();
}
@@ -14547,6 +14547,18 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;
+ case Builtin::BI__builtin_frexpf:
+ case Builtin::BI__builtin_frexp: {
+ LValue Pointer;
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluatePointer(E->getArg(1), Pointer, Info))
+ return false;
+ llvm::RoundingMode RM =
+ E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).getRoundingMode();
+ int FrexpExp;
+ Result = llvm::frexp(Result, FrexpExp, RM);
+ return true;
+ }
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
case Builtin::BI__builtin_huge_vall:
@@ -14638,6 +14650,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}
+ case Builtin::BIfmin:
+ case Builtin::BIfminf:
case Builtin::BI__builtin_fmin:
case Builtin::BI__builtin_fminf:
case Builtin::BI__builtin_fminl:
diff --git a/clang/test/CodeGen/constexpr-math.cpp b/clang/test/CodeGen/constexpr-math.cpp
new file mode 100644
index 00000000000000..446bf3f4f7a504
--- /dev/null
+++ b/clang/test/CodeGen/constexpr-math.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+// RUN %clang_cc1 -x c++ -triple x86_64-linux-gnu -emit-llvm -o - %s \
+// RUN -std=c++23
+
+#define INFINITY ((float)(1e+300 * 1e+300))
+#define NAN (-(float)(INFINITY * 0.0F))
+
+//constexpr double frexp ( double num, int* exp );
+//constexpr float foo ( float num, int* exp );
+
+int func()
+{
+ int i;
+
+ // fmin
+ constexpr double f1 = __builtin_fmin(15.24, 1.3);
+ constexpr double f2 = __builtin_fmin(-0.0, +0.0);
+ constexpr double f3 = __builtin_fmin(+0.0, -0.0);
+ constexpr float f4 = __builtin_fminf(NAN, NAN);
+ constexpr float f5 = __builtin_fminf(NAN, -1);
+ constexpr float f6 = __builtin_fminf(-INFINITY, 0);
+ constexpr float f7 = __builtin_fminf(INFINITY, 0);
+
+ // frexp
+ constexpr double f8 = __builtin_frexp(123.45, &i);
+ constexpr double f9 = __builtin_frexp(0.0, &i);
+ constexpr double f10 = __builtin_frexp(-0.0, &i);
+ constexpr double f11 = __builtin_frexpf(NAN, &i);
+ constexpr double f12 = __builtin_frexpf(-NAN, &i);
+ constexpr double f13 = __builtin_frexpf(INFINITY, &i);
+ constexpr double f14 = __builtin_frexpf(INFINITY, &i);
+
+ return 0;
+}
+
+// CHECK: store double 1.300000e+00, ptr {{.*}}
+// CHECK: store double -0.000000e+00, ptr {{.*}}
+// CHECK: store double -0.000000e+00, ptr {{.*}}
+// CHECK: store float 0xFFF8000000000000, ptr {{.*}}
+// CHECK: store float -1.000000e+00, ptr {{.*}}
+// CHECK: store float 0xFFF0000000000000, ptr {{.*}}
+
+// CHECK: store double 0x3FEEDCCCCCCCCCCD, ptr {{.*}}
+// CHECK: store double 0.000000e+00, ptr {{.*}}
+// CHECK: store double -0.000000e+00, ptr {{.*}}
+// CHECK: store double 0xFFF8000000000000, ptr {{.*}}
+// CHECK: store double 0x7FF8000000000000, ptr {{.*}}
+// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
+// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
>From d7050b53a75a23024502a9e4f56b385256c4722f Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 22 Apr 2024 13:32:56 -0700
Subject: [PATCH 02/19] Addressed review comments.
---
clang/lib/AST/ExprConstant.cpp | 3 +-
.../constexpr-math.cpp | 20 ++++---
clang/test/SemaCXX/constexpr-math.cpp | 57 +++++++++++++++++++
3 files changed, 70 insertions(+), 10 deletions(-)
rename clang/test/{CodeGen => CodeGenCXX}/constexpr-math.cpp (75%)
create mode 100644 clang/test/SemaCXX/constexpr-math.cpp
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 506621ac7e9c1b..1a6abb386071c7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14553,8 +14553,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
return false;
- llvm::RoundingMode RM =
- E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).getRoundingMode();
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
int FrexpExp;
Result = llvm::frexp(Result, FrexpExp, RM);
return true;
diff --git a/clang/test/CodeGen/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
similarity index 75%
rename from clang/test/CodeGen/constexpr-math.cpp
rename to clang/test/CodeGenCXX/constexpr-math.cpp
index 446bf3f4f7a504..ad7b6779a4ae0e 100644
--- a/clang/test/CodeGen/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -1,14 +1,16 @@
// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
-// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: -DWIN -emit-llvm -o - %s | FileCheck %s --check-prefixes=WIN
-// RUN %clang_cc1 -x c++ -triple x86_64-linux-gnu -emit-llvm -o - %s \
-// RUN -std=c++23
+// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
+// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=LNX
+#ifdef WIN
#define INFINITY ((float)(1e+300 * 1e+300))
#define NAN (-(float)(INFINITY * 0.0F))
-
-//constexpr double frexp ( double num, int* exp );
-//constexpr float foo ( float num, int* exp );
+#else
+#define NAN (__builtin_nanf(""))
+#define INFINITY (__builtin_inff())
+#endif
int func()
{
@@ -38,7 +40,8 @@ int func()
// CHECK: store double 1.300000e+00, ptr {{.*}}
// CHECK: store double -0.000000e+00, ptr {{.*}}
// CHECK: store double -0.000000e+00, ptr {{.*}}
-// CHECK: store float 0xFFF8000000000000, ptr {{.*}}
+// WIN: store float 0xFFF8000000000000, ptr {{.*}}
+// LNX: store float 0x7FF8000000000000, ptr {{.*}}
// CHECK: store float -1.000000e+00, ptr {{.*}}
// CHECK: store float 0xFFF0000000000000, ptr {{.*}}
@@ -46,6 +49,7 @@ int func()
// CHECK: store double 0.000000e+00, ptr {{.*}}
// CHECK: store double -0.000000e+00, ptr {{.*}}
// CHECK: store double 0xFFF8000000000000, ptr {{.*}}
-// CHECK: store double 0x7FF8000000000000, ptr {{.*}}
+// WIN: store double 0x7FF8000000000000, ptr {{.*}}
+// LNX: store double 0xFFF8000000000000, ptr {{.*}}
// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
new file mode 100644
index 00000000000000..f51ea1bcaf7bad
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -DWIN -verify -std=c++23 -fsyntax-only %s
+// RUN: %clang_cc1 -verify -std=c++23 -fsyntax-only %s
+
+// expected-no-diagnostics
+
+
+#ifdef WIN
+#define INFINITY ((float)(1e+300 * 1e+300))
+#define NAN (-(float)(INFINITY * 0.0F))
+#else
+#define NAN (__builtin_nanf(""))
+#define INFINITY (__builtin_inff())
+#endif
+
+extern "C" void abort() noexcept;
+extern "C" int write(int, const void*, unsigned long);
+
+#define assert(condition) \
+ do { \
+ if (!(condition)) { \
+ write(2, "Assertion failed: ", 18); \
+ write(2, #condition, sizeof(#condition) - 1); \
+ write(2, "\n", 1); \
+ abort(); \
+ } \
+ } while (false)
+
+int main() {
+ int i;
+
+ // fmin
+ static_assert(__builtin_fmin(15.24, 1.3) == 1.3, "");
+ static_assert(__builtin_fmin(-0.0, +0.0) == -0.0, "");
+ static_assert(__builtin_fmin(+0.0, -0.0) == -0.0, "");
+ assert(__builtin_isnan(__builtin_fminf(NAN,NAN)));
+ assert(__builtin_isnan(__builtin_fminf(NAN, -1)));
+ assert(__builtin_isnan(__builtin_fminf(-INFINITY, 0)));
+ assert(__builtin_iszero(__builtin_fminf(+INFINITY, 0)));
+
+ // frexp
+ static_assert(__builtin_frexp(123.45, &i) == 0.96445312500000002);
+ static_assert(!__builtin_isnan(__builtin_frexp(123.45, &i)), "");
+ assert(i==0);
+ static_assert(__builtin_iszero(__builtin_frexp(0.0, &i)), "");
+ assert(i==0);
+ static_assert(__builtin_iszero(__builtin_frexp(-0.0, &i)), "");
+ assert(i==0);
+ assert(__builtin_isnan(__builtin_frexp(NAN, &i)));
+ assert(i==0);
+ assert(__builtin_isnan(__builtin_frexp(-NAN, &i)));
+ assert(i==0);
+ assert(!__builtin_isfinite(__builtin_frexp(INFINITY, &i)));
+ assert(i==0);
+ assert(!__builtin_isfinite(__builtin_frexp(-INFINITY, &i)));
+ assert(i==0);
+ return 0;
+}
>From 625028aed5ad85922f082f5192abd5ceedb0b68d Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 1 May 2024 08:44:50 -0700
Subject: [PATCH 03/19] Responded to review comments.
---
clang/include/clang/Basic/Builtins.td | 1 +
clang/lib/AST/ExprConstant.cpp | 8 +++--
clang/test/CodeGenCXX/constexpr-math.cpp | 16 ++++++----
clang/test/SemaCXX/constexpr-math.cpp | 37 ++++++------------------
4 files changed, 26 insertions(+), 36 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index a35c77286229ff..419e623c7bc04c 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3443,6 +3443,7 @@ def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
let Attributes = [NoThrow, Constexpr];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
+ let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}
def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1a6abb386071c7..4e664905969ee9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14547,15 +14547,18 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;
+ case Builtin::BI__builtin_frexp:
case Builtin::BI__builtin_frexpf:
- case Builtin::BI__builtin_frexp: {
+ case Builtin::BI__builtin_frexpl: {
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
return false;
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
int FrexpExp;
- Result = llvm::frexp(Result, FrexpExp, RM);
+ FrexpExp = ilogb(Result);
+ FrexpExp = FrexpExp == llvm::detail::IEEEFloat::IEK_Zero ? 0 : FrexpExp + 1;
+ Result = scalbn(Result, -FrexpExp, RM);
return true;
}
case Builtin::BI__builtin_huge_val:
@@ -14651,6 +14654,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BIfmin:
case Builtin::BIfminf:
+ case Builtin::BIfminl:
case Builtin::BI__builtin_fmin:
case Builtin::BI__builtin_fminf:
case Builtin::BI__builtin_fminl:
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index ad7b6779a4ae0e..a48c312d05af0a 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -24,15 +24,17 @@ int func()
constexpr float f5 = __builtin_fminf(NAN, -1);
constexpr float f6 = __builtin_fminf(-INFINITY, 0);
constexpr float f7 = __builtin_fminf(INFINITY, 0);
+ constexpr long double f8 = __builtin_fminl(123.456L, 789.012L);
// frexp
- constexpr double f8 = __builtin_frexp(123.45, &i);
- constexpr double f9 = __builtin_frexp(0.0, &i);
- constexpr double f10 = __builtin_frexp(-0.0, &i);
- constexpr double f11 = __builtin_frexpf(NAN, &i);
- constexpr double f12 = __builtin_frexpf(-NAN, &i);
- constexpr double f13 = __builtin_frexpf(INFINITY, &i);
+ constexpr double f9 = __builtin_frexp(123.45, &i);
+ constexpr double f10 = __builtin_frexp(0.0, &i);
+ constexpr double f11 = __builtin_frexp(-0.0, &i);
+ constexpr double f12 = __builtin_frexpf(NAN, &i);
+ constexpr double f13 = __builtin_frexpf(-NAN, &i);
constexpr double f14 = __builtin_frexpf(INFINITY, &i);
+ constexpr double f15 = __builtin_frexpf(INFINITY, &i);
+ constexpr long double f16 = __builtin_frexpl(259.328L, &i);
return 0;
}
@@ -44,6 +46,7 @@ int func()
// LNX: store float 0x7FF8000000000000, ptr {{.*}}
// CHECK: store float -1.000000e+00, ptr {{.*}}
// CHECK: store float 0xFFF0000000000000, ptr {{.*}}
+// CHECK: store double 1.234560e+02, ptr {{.*}}
// CHECK: store double 0x3FEEDCCCCCCCCCCD, ptr {{.*}}
// CHECK: store double 0.000000e+00, ptr {{.*}}
@@ -53,3 +56,4 @@ int func()
// LNX: store double 0xFFF8000000000000, ptr {{.*}}
// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
+// CHECK: store double 5.065000e-01, ptr {{.*}}
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index f51ea1bcaf7bad..24e5bf70e3535c 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -12,19 +12,6 @@
#define INFINITY (__builtin_inff())
#endif
-extern "C" void abort() noexcept;
-extern "C" int write(int, const void*, unsigned long);
-
-#define assert(condition) \
- do { \
- if (!(condition)) { \
- write(2, "Assertion failed: ", 18); \
- write(2, #condition, sizeof(#condition) - 1); \
- write(2, "\n", 1); \
- abort(); \
- } \
- } while (false)
-
int main() {
int i;
@@ -32,26 +19,20 @@ int main() {
static_assert(__builtin_fmin(15.24, 1.3) == 1.3, "");
static_assert(__builtin_fmin(-0.0, +0.0) == -0.0, "");
static_assert(__builtin_fmin(+0.0, -0.0) == -0.0, "");
- assert(__builtin_isnan(__builtin_fminf(NAN,NAN)));
- assert(__builtin_isnan(__builtin_fminf(NAN, -1)));
- assert(__builtin_isnan(__builtin_fminf(-INFINITY, 0)));
- assert(__builtin_iszero(__builtin_fminf(+INFINITY, 0)));
+ static_assert(__builtin_fminf(NAN, -1) == -1, "");
+ static_assert(__builtin_fminf(+INFINITY, 0) == 0, "");
+ static_assert(__builtin_isinf(__builtin_fminf(-INFINITY, 0)), "");
+ static_assert(__builtin_isnan(__builtin_fminf(NAN,NAN)), "");
// frexp
static_assert(__builtin_frexp(123.45, &i) == 0.96445312500000002);
static_assert(!__builtin_isnan(__builtin_frexp(123.45, &i)), "");
- assert(i==0);
static_assert(__builtin_iszero(__builtin_frexp(0.0, &i)), "");
- assert(i==0);
static_assert(__builtin_iszero(__builtin_frexp(-0.0, &i)), "");
- assert(i==0);
- assert(__builtin_isnan(__builtin_frexp(NAN, &i)));
- assert(i==0);
- assert(__builtin_isnan(__builtin_frexp(-NAN, &i)));
- assert(i==0);
- assert(!__builtin_isfinite(__builtin_frexp(INFINITY, &i)));
- assert(i==0);
- assert(!__builtin_isfinite(__builtin_frexp(-INFINITY, &i)));
- assert(i==0);
+ static_assert(__builtin_isnan(__builtin_frexp(NAN, &i)));
+ static_assert(__builtin_isnan(__builtin_frexp(-NAN, &i)));
+ static_assert(!__builtin_isfinite(__builtin_frexp(INFINITY, &i)));
+ static_assert(!__builtin_isfinite(__builtin_frexp(-INFINITY, &i)));
+
return 0;
}
>From 319fdd0867bdd9e7a9decfba8dc2f1be6e375a19 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 8 May 2024 10:27:54 -0700
Subject: [PATCH 04/19] Added code to store the exponent in Pointer. Edited LIT
tests as requested by reviewer.
---
clang/lib/AST/ExprConstant.cpp | 22 ++++-
clang/test/CodeGenCXX/constexpr-math.cpp | 105 ++++++++++++++++++-----
clang/test/SemaCXX/constexpr-math.cpp | 42 ++++-----
3 files changed, 123 insertions(+), 46 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4e664905969ee9..be68ef11efb38d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14481,6 +14481,8 @@ class FloatExprEvaluator
return true;
}
+ void StoreExponent(LValue Pointer, int exp);
+
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -14539,6 +14541,19 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
return true;
}
+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);
+ } else {
+ llvm_unreachable("expecting a VarDecl for an exponent");
+ }
+}
+
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -14554,11 +14569,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
return false;
- llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
int FrexpExp;
- FrexpExp = ilogb(Result);
- FrexpExp = FrexpExp == llvm::detail::IEEEFloat::IEK_Zero ? 0 : FrexpExp + 1;
- Result = scalbn(Result, -FrexpExp, RM);
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
+ Result = llvm::frexp(Result, FrexpExp, RM);
+ StoreExponent(Pointer, FrexpExp);
return true;
}
case Builtin::BI__builtin_huge_val:
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index a48c312d05af0a..039d2f288ddfa0 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -1,3 +1,4 @@
+// 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: -DWIN -emit-llvm -o - %s | FileCheck %s --check-prefixes=WIN
@@ -12,6 +13,84 @@
#define INFINITY (__builtin_inff())
#endif
+// WIN-LABEL: define dso_local noundef i32 @_Z4funcv(
+// WIN-SAME: ) #[[ATTR0:[0-9]+]] {
+// WIN-NEXT: entry:
+// WIN-NEXT: [[I:%.*]] = alloca i32, align 4
+// WIN-NEXT: [[F1:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F2:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F3:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F4:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F5:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F6:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F7:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F8:%.*]] = alloca x86_fp80, align 16
+// WIN-NEXT: [[F9:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F10:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F11:%.*]] = alloca double, align 8
+// WIN-NEXT: [[F12:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F13:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F14:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F15:%.*]] = alloca float, align 4
+// WIN-NEXT: [[F16:%.*]] = alloca x86_fp80, align 16
+// WIN-NEXT: store i32 0, ptr [[I]], align 4
+// WIN-NEXT: store double 1.300000e+00, ptr [[F1]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[F2]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[F3]], align 8
+// WIN-NEXT: store float 0xFFF8000000000000, ptr [[F4]], align 4
+// WIN-NEXT: store float -1.000000e+00, ptr [[F5]], align 4
+// WIN-NEXT: store float 0xFFF0000000000000, ptr [[F6]], align 4
+// WIN-NEXT: store float 0.000000e+00, ptr [[F7]], align 4
+// WIN-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[F8]], align 16
+// WIN-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[F9]], align 8
+// WIN-NEXT: store double 0.000000e+00, ptr [[F10]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[F11]], align 8
+// WIN-NEXT: store float 0xFFF8000000000000, ptr [[F12]], align 4
+// WIN-NEXT: store float 0x7FF8000000000000, ptr [[F13]], align 4
+// WIN-NEXT: store float 0x7FF0000000000000, ptr [[F14]], align 4
+// WIN-NEXT: store float 0x7FF0000000000000, ptr [[F15]], align 4
+// WIN-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[F16]], align 16
+// WIN-NEXT: ret i32 0
+//
+// LNX-LABEL: define dso_local noundef i32 @_Z4funcv(
+// LNX-SAME: ) #[[ATTR0:[0-9]+]] {
+// LNX-NEXT: entry:
+// LNX-NEXT: [[I:%.*]] = alloca i32, align 4
+// LNX-NEXT: [[F1:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F2:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F3:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F4:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F5:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F6:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F7:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F8:%.*]] = alloca x86_fp80, align 16
+// LNX-NEXT: [[F9:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F10:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F11:%.*]] = alloca double, align 8
+// LNX-NEXT: [[F12:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F13:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F14:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F15:%.*]] = alloca float, align 4
+// LNX-NEXT: [[F16:%.*]] = alloca x86_fp80, align 16
+// LNX-NEXT: store i32 0, ptr [[I]], align 4
+// LNX-NEXT: store double 1.300000e+00, ptr [[F1]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[F2]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[F3]], align 8
+// LNX-NEXT: store float 0x7FF8000000000000, ptr [[F4]], align 4
+// LNX-NEXT: store float -1.000000e+00, ptr [[F5]], align 4
+// LNX-NEXT: store float 0xFFF0000000000000, ptr [[F6]], align 4
+// LNX-NEXT: store float 0.000000e+00, ptr [[F7]], align 4
+// LNX-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[F8]], align 16
+// LNX-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[F9]], align 8
+// LNX-NEXT: store double 0.000000e+00, ptr [[F10]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[F11]], align 8
+// LNX-NEXT: store float 0x7FF8000000000000, ptr [[F12]], align 4
+// LNX-NEXT: store float 0xFFF8000000000000, ptr [[F13]], align 4
+// LNX-NEXT: store float 0x7FF0000000000000, ptr [[F14]], align 4
+// LNX-NEXT: store float 0x7FF0000000000000, ptr [[F15]], align 4
+// LNX-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[F16]], align 16
+// LNX-NEXT: ret i32 0
+//
int func()
{
int i;
@@ -30,30 +109,12 @@ int func()
constexpr double f9 = __builtin_frexp(123.45, &i);
constexpr double f10 = __builtin_frexp(0.0, &i);
constexpr double f11 = __builtin_frexp(-0.0, &i);
- constexpr double f12 = __builtin_frexpf(NAN, &i);
- constexpr double f13 = __builtin_frexpf(-NAN, &i);
- constexpr double f14 = __builtin_frexpf(INFINITY, &i);
- constexpr double f15 = __builtin_frexpf(INFINITY, &i);
+ constexpr float f12 = __builtin_frexpf(NAN, &i);
+ constexpr float f13 = __builtin_frexpf(-NAN, &i);
+ constexpr float f14 = __builtin_frexpf(INFINITY, &i);
+ constexpr float f15 = __builtin_frexpf(INFINITY, &i);
constexpr long double f16 = __builtin_frexpl(259.328L, &i);
return 0;
}
-// CHECK: store double 1.300000e+00, ptr {{.*}}
-// CHECK: store double -0.000000e+00, ptr {{.*}}
-// CHECK: store double -0.000000e+00, ptr {{.*}}
-// WIN: store float 0xFFF8000000000000, ptr {{.*}}
-// LNX: store float 0x7FF8000000000000, ptr {{.*}}
-// CHECK: store float -1.000000e+00, ptr {{.*}}
-// CHECK: store float 0xFFF0000000000000, ptr {{.*}}
-// CHECK: store double 1.234560e+02, ptr {{.*}}
-
-// CHECK: store double 0x3FEEDCCCCCCCCCCD, ptr {{.*}}
-// CHECK: store double 0.000000e+00, ptr {{.*}}
-// CHECK: store double -0.000000e+00, ptr {{.*}}
-// CHECK: store double 0xFFF8000000000000, ptr {{.*}}
-// WIN: store double 0x7FF8000000000000, ptr {{.*}}
-// LNX: store double 0xFFF8000000000000, ptr {{.*}}
-// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
-// CHECK: store double 0x7FF0000000000000, ptr {{.*}}
-// CHECK: store double 5.065000e-01, ptr {{.*}}
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index 24e5bf70e3535c..2c4c29c1c65425 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -12,27 +12,29 @@
#define INFINITY (__builtin_inff())
#endif
-int main() {
- int i;
+template <auto, auto> constexpr bool is_same_val = false;
+template <auto X> constexpr bool is_same_val<X, X> = true;
- // fmin
- static_assert(__builtin_fmin(15.24, 1.3) == 1.3, "");
- static_assert(__builtin_fmin(-0.0, +0.0) == -0.0, "");
- static_assert(__builtin_fmin(+0.0, -0.0) == -0.0, "");
- static_assert(__builtin_fminf(NAN, -1) == -1, "");
- static_assert(__builtin_fminf(+INFINITY, 0) == 0, "");
- static_assert(__builtin_isinf(__builtin_fminf(-INFINITY, 0)), "");
- static_assert(__builtin_isnan(__builtin_fminf(NAN,NAN)), "");
+int main() {
+ int i;
- // frexp
- static_assert(__builtin_frexp(123.45, &i) == 0.96445312500000002);
- static_assert(!__builtin_isnan(__builtin_frexp(123.45, &i)), "");
- static_assert(__builtin_iszero(__builtin_frexp(0.0, &i)), "");
- static_assert(__builtin_iszero(__builtin_frexp(-0.0, &i)), "");
- static_assert(__builtin_isnan(__builtin_frexp(NAN, &i)));
- static_assert(__builtin_isnan(__builtin_frexp(-NAN, &i)));
- static_assert(!__builtin_isfinite(__builtin_frexp(INFINITY, &i)));
- static_assert(!__builtin_isfinite(__builtin_frexp(-INFINITY, &i)));
+ // fmin
+ static_assert(is_same_val<__builtin_fmin(15.24, 1.3), 1.3>);
+ static_assert(is_same_val<__builtin_fmin(-0.0, +0.0), -0.0>);
+ static_assert(is_same_val<__builtin_fmin(+0.0, -0.0), -0.0>);
+ static_assert(is_same_val<__builtin_fminf(NAN, -1), -1.f>);
+ static_assert(is_same_val<__builtin_fminf(+INFINITY, 0), 0.f>);
+ static_assert(is_same_val<__builtin_fminf(-INFINITY, 0), -INFINITY>);
+ static_assert(is_same_val<__builtin_fminf(NAN, NAN), NAN>);
- return 0;
+ // frexp
+ static_assert(is_same_val<__builtin_frexp(123.45, &i), 123.45/128>);
+ static_assert(is_same_val<__builtin_frexp(0.0, &i), 0.0>);
+ static_assert(is_same_val<__builtin_frexp(-0.0, &i), -0.0>);
+ static_assert(is_same_val<__builtin_frexpf(NAN, &i), NAN>);
+ static_assert(is_same_val<__builtin_frexpf(-NAN, &i), -NAN>);
+ static_assert(is_same_val<__builtin_frexpf(INFINITY, &i), INFINITY>);
+ static_assert(is_same_val<__builtin_frexpf(-INFINITY, &i), -INFINITY>);
+
+ return 0;
}
>From da06dba0e58d1d6b29fe91d85104eb285bd311df Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 9 May 2024 12:02:00 -0700
Subject: [PATCH 05/19] Added fmax function and function IsinRange function.
---
clang/include/clang/Basic/Builtins.td | 2 +-
clang/lib/AST/ExprConstant.cpp | 6 +
clang/test/CodeGenCXX/constexpr-math.cpp | 202 ++++++++++++++---------
clang/test/SemaCXX/constexpr-math.cpp | 14 +-
llvm/include/llvm/ADT/APFloat.h | 13 ++
5 files changed, 155 insertions(+), 82 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 419e623c7bc04c..75a26e3cf2b58e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3611,7 +3611,7 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> {
def Fmax : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmax"];
- let Attributes = [NoThrow, Const];
+ let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index be68ef11efb38d..3a4abab8fd3369 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14572,6 +14572,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
int FrexpExp;
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
Result = llvm::frexp(Result, FrexpExp, RM);
+ if (!Result.isZero() && !Result.isNaN() && !Result.isInfinity())
+ assert(llvm::APFloat::isInRange(Result) &&
+ "The value is not in the expected range for frexp.");
StoreExponent(Pointer, FrexpExp);
return true;
}
@@ -14648,6 +14651,9 @@ 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:
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index 039d2f288ddfa0..f5546c0fcfed91 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -17,78 +17,110 @@
// WIN-SAME: ) #[[ATTR0:[0-9]+]] {
// WIN-NEXT: entry:
// WIN-NEXT: [[I:%.*]] = alloca i32, align 4
-// WIN-NEXT: [[F1:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F2:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F3:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F4:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F5:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F6:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F7:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F8:%.*]] = alloca x86_fp80, align 16
-// WIN-NEXT: [[F9:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F10:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F11:%.*]] = alloca double, align 8
-// WIN-NEXT: [[F12:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F13:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F14:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F15:%.*]] = alloca float, align 4
-// WIN-NEXT: [[F16:%.*]] = alloca x86_fp80, align 16
+// WIN-NEXT: [[MIN1:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MIN2:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MIN3:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MIN4:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MIN5:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MIN6:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MIN7:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MIN8:%.*]] = alloca x86_fp80, align 16
+// WIN-NEXT: [[MAX1:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MAX2:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MAX3:%.*]] = alloca double, align 8
+// WIN-NEXT: [[MAX4:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MAX5:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MAX6:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MAX7:%.*]] = alloca float, align 4
+// WIN-NEXT: [[MAX8:%.*]] = alloca x86_fp80, align 16
+// WIN-NEXT: [[FREXP1:%.*]] = alloca double, align 8
+// WIN-NEXT: [[FREXP2:%.*]] = alloca double, align 8
+// WIN-NEXT: [[FREXP3:%.*]] = alloca double, align 8
+// WIN-NEXT: [[FREXP4:%.*]] = alloca float, align 4
+// WIN-NEXT: [[FREXP5:%.*]] = alloca float, align 4
+// WIN-NEXT: [[FREXP6:%.*]] = alloca float, align 4
+// WIN-NEXT: [[FREXP7:%.*]] = alloca float, align 4
+// WIN-NEXT: [[FREXP8:%.*]] = alloca x86_fp80, align 16
// WIN-NEXT: store i32 0, ptr [[I]], align 4
-// WIN-NEXT: store double 1.300000e+00, ptr [[F1]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[F2]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[F3]], align 8
-// WIN-NEXT: store float 0xFFF8000000000000, ptr [[F4]], align 4
-// WIN-NEXT: store float -1.000000e+00, ptr [[F5]], align 4
-// WIN-NEXT: store float 0xFFF0000000000000, ptr [[F6]], align 4
-// WIN-NEXT: store float 0.000000e+00, ptr [[F7]], align 4
-// WIN-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[F8]], align 16
-// WIN-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[F9]], align 8
-// WIN-NEXT: store double 0.000000e+00, ptr [[F10]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[F11]], align 8
-// WIN-NEXT: store float 0xFFF8000000000000, ptr [[F12]], align 4
-// WIN-NEXT: store float 0x7FF8000000000000, ptr [[F13]], align 4
-// WIN-NEXT: store float 0x7FF0000000000000, ptr [[F14]], align 4
-// WIN-NEXT: store float 0x7FF0000000000000, ptr [[F15]], align 4
-// WIN-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[F16]], align 16
+// WIN-NEXT: store double 1.300000e+00, ptr [[MIN1]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[MIN2]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[MIN3]], align 8
+// WIN-NEXT: store float 0xFFF8000000000000, ptr [[MIN4]], align 4
+// WIN-NEXT: store float -1.000000e+00, ptr [[MIN5]], align 4
+// WIN-NEXT: store float 0xFFF0000000000000, ptr [[MIN6]], align 4
+// WIN-NEXT: store float 0.000000e+00, ptr [[MIN7]], align 4
+// WIN-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[MIN8]], align 16
+// WIN-NEXT: store double 1.524000e+01, ptr [[MAX1]], align 8
+// WIN-NEXT: store double 0.000000e+00, ptr [[MAX2]], align 8
+// WIN-NEXT: store double 0.000000e+00, ptr [[MAX3]], align 8
+// WIN-NEXT: store float -1.000000e+00, ptr [[MAX4]], align 4
+// WIN-NEXT: store float 0x7FF0000000000000, ptr [[MAX5]], align 4
+// WIN-NEXT: store float 0.000000e+00, ptr [[MAX6]], align 4
+// WIN-NEXT: store float 0xFFF8000000000000, ptr [[MAX7]], align 4
+// WIN-NEXT: store x86_fp80 0xK4008C540C49BA5E353F8, ptr [[MAX8]], align 16
+// WIN-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[FREXP1]], align 8
+// WIN-NEXT: store double 0.000000e+00, ptr [[FREXP2]], align 8
+// WIN-NEXT: store double -0.000000e+00, ptr [[FREXP3]], align 8
+// WIN-NEXT: store float 0xFFF8000000000000, ptr [[FREXP4]], align 4
+// WIN-NEXT: store float 0x7FF8000000000000, ptr [[FREXP5]], align 4
+// WIN-NEXT: store float 0x7FF0000000000000, ptr [[FREXP6]], align 4
+// WIN-NEXT: store float 0x7FF0000000000000, ptr [[FREXP7]], align 4
+// WIN-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
// WIN-NEXT: ret i32 0
//
// LNX-LABEL: define dso_local noundef i32 @_Z4funcv(
// LNX-SAME: ) #[[ATTR0:[0-9]+]] {
// LNX-NEXT: entry:
// LNX-NEXT: [[I:%.*]] = alloca i32, align 4
-// LNX-NEXT: [[F1:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F2:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F3:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F4:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F5:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F6:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F7:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F8:%.*]] = alloca x86_fp80, align 16
-// LNX-NEXT: [[F9:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F10:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F11:%.*]] = alloca double, align 8
-// LNX-NEXT: [[F12:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F13:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F14:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F15:%.*]] = alloca float, align 4
-// LNX-NEXT: [[F16:%.*]] = alloca x86_fp80, align 16
+// LNX-NEXT: [[MIN1:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MIN2:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MIN3:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MIN4:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MIN5:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MIN6:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MIN7:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MIN8:%.*]] = alloca x86_fp80, align 16
+// LNX-NEXT: [[MAX1:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MAX2:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MAX3:%.*]] = alloca double, align 8
+// LNX-NEXT: [[MAX4:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MAX5:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MAX6:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MAX7:%.*]] = alloca float, align 4
+// LNX-NEXT: [[MAX8:%.*]] = alloca x86_fp80, align 16
+// LNX-NEXT: [[FREXP1:%.*]] = alloca double, align 8
+// LNX-NEXT: [[FREXP2:%.*]] = alloca double, align 8
+// LNX-NEXT: [[FREXP3:%.*]] = alloca double, align 8
+// LNX-NEXT: [[FREXP4:%.*]] = alloca float, align 4
+// LNX-NEXT: [[FREXP5:%.*]] = alloca float, align 4
+// LNX-NEXT: [[FREXP6:%.*]] = alloca float, align 4
+// LNX-NEXT: [[FREXP7:%.*]] = alloca float, align 4
+// LNX-NEXT: [[FREXP8:%.*]] = alloca x86_fp80, align 16
// LNX-NEXT: store i32 0, ptr [[I]], align 4
-// LNX-NEXT: store double 1.300000e+00, ptr [[F1]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[F2]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[F3]], align 8
-// LNX-NEXT: store float 0x7FF8000000000000, ptr [[F4]], align 4
-// LNX-NEXT: store float -1.000000e+00, ptr [[F5]], align 4
-// LNX-NEXT: store float 0xFFF0000000000000, ptr [[F6]], align 4
-// LNX-NEXT: store float 0.000000e+00, ptr [[F7]], align 4
-// LNX-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[F8]], align 16
-// LNX-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[F9]], align 8
-// LNX-NEXT: store double 0.000000e+00, ptr [[F10]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[F11]], align 8
-// LNX-NEXT: store float 0x7FF8000000000000, ptr [[F12]], align 4
-// LNX-NEXT: store float 0xFFF8000000000000, ptr [[F13]], align 4
-// LNX-NEXT: store float 0x7FF0000000000000, ptr [[F14]], align 4
-// LNX-NEXT: store float 0x7FF0000000000000, ptr [[F15]], align 4
-// LNX-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[F16]], align 16
+// LNX-NEXT: store double 1.300000e+00, ptr [[MIN1]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[MIN2]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[MIN3]], align 8
+// LNX-NEXT: store float 0x7FF8000000000000, ptr [[MIN4]], align 4
+// LNX-NEXT: store float -1.000000e+00, ptr [[MIN5]], align 4
+// LNX-NEXT: store float 0xFFF0000000000000, ptr [[MIN6]], align 4
+// LNX-NEXT: store float 0.000000e+00, ptr [[MIN7]], align 4
+// LNX-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[MIN8]], align 16
+// LNX-NEXT: store double 1.524000e+01, ptr [[MAX1]], align 8
+// LNX-NEXT: store double 0.000000e+00, ptr [[MAX2]], align 8
+// LNX-NEXT: store double 0.000000e+00, ptr [[MAX3]], align 8
+// LNX-NEXT: store float -1.000000e+00, ptr [[MAX4]], align 4
+// LNX-NEXT: store float 0x7FF0000000000000, ptr [[MAX5]], align 4
+// LNX-NEXT: store float 0.000000e+00, ptr [[MAX6]], align 4
+// LNX-NEXT: store float 0x7FF8000000000000, ptr [[MAX7]], align 4
+// LNX-NEXT: store x86_fp80 0xK4008C540C49BA5E353F8, ptr [[MAX8]], align 16
+// LNX-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[FREXP1]], align 8
+// LNX-NEXT: store double 0.000000e+00, ptr [[FREXP2]], align 8
+// LNX-NEXT: store double -0.000000e+00, ptr [[FREXP3]], align 8
+// LNX-NEXT: store float 0x7FF8000000000000, ptr [[FREXP4]], align 4
+// LNX-NEXT: store float 0xFFF8000000000000, ptr [[FREXP5]], align 4
+// LNX-NEXT: store float 0x7FF0000000000000, ptr [[FREXP6]], align 4
+// LNX-NEXT: store float 0x7FF0000000000000, ptr [[FREXP7]], align 4
+// LNX-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
// LNX-NEXT: ret i32 0
//
int func()
@@ -96,24 +128,34 @@ int func()
int i;
// fmin
- constexpr double f1 = __builtin_fmin(15.24, 1.3);
- constexpr double f2 = __builtin_fmin(-0.0, +0.0);
- constexpr double f3 = __builtin_fmin(+0.0, -0.0);
- constexpr float f4 = __builtin_fminf(NAN, NAN);
- constexpr float f5 = __builtin_fminf(NAN, -1);
- constexpr float f6 = __builtin_fminf(-INFINITY, 0);
- constexpr float f7 = __builtin_fminf(INFINITY, 0);
- constexpr long double f8 = __builtin_fminl(123.456L, 789.012L);
+ 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);
+ 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 f9 = __builtin_frexp(123.45, &i);
- constexpr double f10 = __builtin_frexp(0.0, &i);
- constexpr double f11 = __builtin_frexp(-0.0, &i);
- constexpr float f12 = __builtin_frexpf(NAN, &i);
- constexpr float f13 = __builtin_frexpf(-NAN, &i);
- constexpr float f14 = __builtin_frexpf(INFINITY, &i);
- constexpr float f15 = __builtin_frexpf(INFINITY, &i);
- constexpr long double f16 = __builtin_frexpl(259.328L, &i);
+ constexpr double frexp1 = __builtin_frexp(123.45, &i);
+ 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);
return 0;
}
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index 2c4c29c1c65425..7ad7618f3df144 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -26,6 +26,17 @@ int main() {
static_assert(is_same_val<__builtin_fminf(+INFINITY, 0), 0.f>);
static_assert(is_same_val<__builtin_fminf(-INFINITY, 0), -INFINITY>);
static_assert(is_same_val<__builtin_fminf(NAN, NAN), NAN>);
+ static_assert(is_same_val<__builtin_fminl(123.456L, 789.012L), 123.456L>);
+
+ // fmax
+ static_assert(is_same_val<__builtin_fmax(15.24, 1.3), 15.24>);
+ static_assert(is_same_val<__builtin_fmax(-0.0, +0.0), +0.0>);
+ static_assert(is_same_val<__builtin_fmax(+0.0, -0.0), +0.0>);
+ static_assert(is_same_val<__builtin_fmaxf(NAN, -1), -1.f>);
+ static_assert(is_same_val<__builtin_fmaxf(+INFINITY, 0), INFINITY>);
+ static_assert(is_same_val<__builtin_fmaxf(-INFINITY, 0), 0.f>);
+ static_assert(is_same_val<__builtin_fmaxf(NAN, NAN), NAN>);
+ static_assert(is_same_val<__builtin_fmaxl(123.456L, 789.012L), 789.012L>);
// frexp
static_assert(is_same_val<__builtin_frexp(123.45, &i), 123.45/128>);
@@ -35,6 +46,7 @@ int main() {
static_assert(is_same_val<__builtin_frexpf(-NAN, &i), -NAN>);
static_assert(is_same_val<__builtin_frexpf(INFINITY, &i), INFINITY>);
static_assert(is_same_val<__builtin_frexpf(-INFINITY, &i), -INFINITY>);
-
+ static_assert(is_same_val<__builtin_frexpl(123.45L, &i), 123.45L/128>);
+
return 0;
}
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index deb74cb2fdeb1e..c9097b4f4e607f 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -951,6 +951,19 @@ class APFloat : public APFloatBase {
bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); }
+ // Checks that the value x is in the range (-1;-0.5], [0.5; 1)
+ static bool isInRange(const llvm::APFloat &x) {
+ llvm::APFloat minusOne(x.getSemantics(), "-1.0");
+ llvm::APFloat minusHalf(x.getSemantics(), "-0.5");
+ llvm::APFloat half(x.getSemantics(), "0.5");
+ llvm::APFloat one(x.getSemantics(), "1.0");
+
+ return ((x.compare(minusOne) == llvm::APFloat::cmpGreaterThan &&
+ x.compare(minusHalf) != llvm::APFloat::cmpGreaterThan) ||
+ (x.compare(half) != llvm::APFloat::cmpLessThan &&
+ x.compare(one) == llvm::APFloat::cmpLessThan));
+ }
+
/// Factory for Positive and Negative Zero.
///
/// \param Negative True iff the number should be negative.
>From 1793cf076c74fb7a6769674f91a3d1fb9aa19ee4 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 10 May 2024 07:14:19 -0700
Subject: [PATCH 06/19] Addressed review comments.
---
clang/lib/AST/ExprConstant.cpp | 18 +++++++++++++++---
llvm/include/llvm/ADT/APFloat.h | 13 -------------
2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3a4abab8fd3369..f82ae8ec1a8905 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14540,6 +14540,18 @@ 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 minusOne(x.getSemantics(), "-1.0");
+ llvm::APFloat minusHalf(x.getSemantics(), "-0.5");
+ llvm::APFloat half(x.getSemantics(), "0.5");
+ llvm::APFloat one(x.getSemantics(), "1.0");
+
+ return ((x.compare(minusOne) == llvm::APFloat::cmpGreaterThan &&
+ x.compare(minusHalf) != llvm::APFloat::cmpGreaterThan) ||
+ (x.compare(half) != llvm::APFloat::cmpLessThan &&
+ x.compare(one) == llvm::APFloat::cmpLessThan));
+}
void FloatExprEvaluator::StoreExponent(LValue Pointer, int exp) {
const APValue::LValueBase Base = Pointer.getLValueBase();
@@ -14572,9 +14584,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
int FrexpExp;
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
Result = llvm::frexp(Result, FrexpExp, RM);
- if (!Result.isZero() && !Result.isNaN() && !Result.isInfinity())
- assert(llvm::APFloat::isInRange(Result) &&
- "The value is not in the expected range for frexp.");
+ assert((Result.isZero() || Result.isNaN() || Result.isInfinity() ||
+ isInFrexpResultRange(Result)) &&
+ "The value is not in the expected range for frexp.");
StoreExponent(Pointer, FrexpExp);
return true;
}
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index c9097b4f4e607f..deb74cb2fdeb1e 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -951,19 +951,6 @@ class APFloat : public APFloatBase {
bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); }
- // Checks that the value x is in the range (-1;-0.5], [0.5; 1)
- static bool isInRange(const llvm::APFloat &x) {
- llvm::APFloat minusOne(x.getSemantics(), "-1.0");
- llvm::APFloat minusHalf(x.getSemantics(), "-0.5");
- llvm::APFloat half(x.getSemantics(), "0.5");
- llvm::APFloat one(x.getSemantics(), "1.0");
-
- return ((x.compare(minusOne) == llvm::APFloat::cmpGreaterThan &&
- x.compare(minusHalf) != llvm::APFloat::cmpGreaterThan) ||
- (x.compare(half) != llvm::APFloat::cmpLessThan &&
- x.compare(one) == llvm::APFloat::cmpLessThan));
- }
-
/// Factory for Positive and Negative Zero.
///
/// \param Negative True iff the number should be negative.
>From 42d7d4c55d3a163993e0f3cfde73244986e81c9f Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 15 May 2024 08:14:10 -0700
Subject: [PATCH 07/19] Added a fix for failing LIT test.
---
clang/lib/AST/ExprConstant.cpp | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f82ae8ec1a8905..b1005ed756f7e4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14574,9 +14574,17 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;
+ case Builtin::BI__builtin_frexpl:
+ // AIX library function `frexpl` has 'long double' type and not
+ // PPCDoubleDouble type. To make sure we generate the right value, don't
+ // constant evaluate it and instead defer to a libcall.
+ if (Info.Ctx.getTargetInfo().getTriple().isPPC() &&
+ (&Info.Ctx.getTargetInfo().getLongDoubleFormat() !=
+ &llvm::APFloat::PPCDoubleDouble()))
+ return false;
+ LLVM_FALLTHROUGH;
case Builtin::BI__builtin_frexp:
- case Builtin::BI__builtin_frexpf:
- case Builtin::BI__builtin_frexpl: {
+ case Builtin::BI__builtin_frexpf: {
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
@@ -14590,6 +14598,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
StoreExponent(Pointer, FrexpExp);
return true;
}
+
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
case Builtin::BI__builtin_huge_vall:
@@ -14663,9 +14672,6 @@ 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:
@@ -14684,9 +14690,6 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}
- case Builtin::BIfmin:
- case Builtin::BIfminf:
- case Builtin::BIfminl:
case Builtin::BI__builtin_fmin:
case Builtin::BI__builtin_fminf:
case Builtin::BI__builtin_fminl:
>From 9f4d6328ae03488421432fbdcba0d3166285c550 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 17 May 2024 05:17:24 -0700
Subject: [PATCH 08/19] Fixed aix-builtin-mapping.c test.
---
clang/lib/AST/ExprConstant.cpp | 12 ++----------
clang/test/CodeGen/aix-builtin-mapping.c | 8 ++++++--
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b1005ed756f7e4..6fbd46606d6272 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14574,17 +14574,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;
- case Builtin::BI__builtin_frexpl:
- // AIX library function `frexpl` has 'long double' type and not
- // PPCDoubleDouble type. To make sure we generate the right value, don't
- // constant evaluate it and instead defer to a libcall.
- if (Info.Ctx.getTargetInfo().getTriple().isPPC() &&
- (&Info.Ctx.getTargetInfo().getLongDoubleFormat() !=
- &llvm::APFloat::PPCDoubleDouble()))
- return false;
- LLVM_FALLTHROUGH;
case Builtin::BI__builtin_frexp:
- case Builtin::BI__builtin_frexpf: {
+ case Builtin::BI__builtin_frexpf:
+ case Builtin::BI__builtin_frexpl: {
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
diff --git a/clang/test/CodeGen/aix-builtin-mapping.c b/clang/test/CodeGen/aix-builtin-mapping.c
index a79218c6f1d8b9..1936f23b71d522 100644
--- a/clang/test/CodeGen/aix-builtin-mapping.c
+++ b/clang/test/CodeGen/aix-builtin-mapping.c
@@ -6,6 +6,8 @@
// RUN: %clang_cc1 -triple powerpc-ibm-aix -mlong-double-64 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
// RUN: %clang_cc1 -triple powerpc64-ibm-aix -mlong-double-64 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
+long double input = 0.0L;
+
int main()
{
int DummyInt;
@@ -13,10 +15,12 @@ int main()
long double returnValue;
returnValue = __builtin_modfl(1.0L, &DummyLongDouble);
- returnValue = __builtin_frexpl(0.0L, &DummyInt);
+ returnValue = __builtin_frexpl(input, &DummyInt);
returnValue = __builtin_ldexpl(1.0L, 1);
}
+// CHECK: @input = global double 0.000000e+00
// CHECK: %call = call double @modf(double noundef 1.000000e+00, ptr noundef %DummyLongDouble) #3
-// CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double 0.000000e+00)
+// CHECK: [[TMP0:%.*]] = load double, ptr @input
+// CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
// CHECK: %{{.+}} = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 1)
>From e384a0585c7c40475c0cf8b660ccce3dba246f12 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 11 Jun 2024 06:18:22 -0700
Subject: [PATCH 09/19] Addressed review comments.
---
clang/include/clang/Basic/Builtins.h | 11 +-
clang/include/clang/Basic/Builtins.td | 21 ++-
clang/include/clang/Basic/BuiltinsBase.td | 4 +-
clang/lib/AST/ExprConstant.cpp | 26 ++-
clang/test/CodeGenCXX/constexpr-math.cpp | 172 ++++++------------
clang/test/SemaCXX/constexpr-math.cpp | 110 ++++++++---
clang/utils/TableGen/ClangBuiltinsEmitter.cpp | 2 +-
7 files changed, 189 insertions(+), 157 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index f955d21169556a..15249983e85b4a 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "LangStandard.h"
#include <cstring>
// VC++ defines 'alloca' as an object-like macro, which interferes with our
@@ -74,6 +75,7 @@ struct Info {
const char *Features;
HeaderDesc Header;
LanguageID Langs;
+ LangStandard UnprefixedOnlyConstexprSince;
};
/// Holds information about both target-independent and
@@ -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.
@@ -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);
}
private:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index cdbc0ee71909a4..c1b53c7ac1ae36 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3419,7 +3419,7 @@ 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"> {
@@ -3427,7 +3427,7 @@ def Fabs : FPMathTemplate, LibBuiltin<"math.h"> {
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
- let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+ let BuiltinPrefixedAliasIsConstexpr = 1;
}
def Finite : FPMathTemplate, GNULibBuiltin<"math.h"> {
@@ -3452,10 +3452,11 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> {
def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["frexp"];
- let Attributes = [NoThrow, Constexpr];
+ let Attributes = [NoThrow, Const, ConstexprSince];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
- let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
+ let BuiltinPrefixedAliasIsConstexpr = 1;
+ let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> {
@@ -3477,7 +3478,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"> {
@@ -3623,18 +3624,20 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> {
def Fmax : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmax"];
- let Attributes = [NoThrow, Const, Constexpr];
+ 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, Constexpr];
+ 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"> {
diff --git a/clang/include/clang/Basic/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d732..8306a893abab4d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -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 kinds
// =============
@@ -97,7 +98,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">;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f5d903ff85d789..a9307ebf0747e8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2926,7 +2926,7 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
// If during the evaluation of an expression, the result is not
// mathematically defined [...], the behavior is undefined.
// FIXME: C++ rules require us to not conform to IEEE 754 here.
- if (!Info.getLangOpts().CPlusPlus23 && LHS.isNaN()) {
+ if (LHS.isNaN()) {
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
return Info.noteUndefinedBehavior();
}
@@ -14710,9 +14710,17 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
default:
return false;
+ case Builtin::BIfrexp:
+ case Builtin::BIfrexpf:
+ case Builtin::BIfrexpl:
case Builtin::BI__builtin_frexp:
case Builtin::BI__builtin_frexpf:
case Builtin::BI__builtin_frexpl: {
+ 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))
@@ -14800,12 +14808,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))
@@ -14818,12 +14834,20 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}
+ case Builtin::BIfmin:
+ case Builtin::BIfminf:
+ 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))
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index f5546c0fcfed91..c93e867acea065 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -1,127 +1,65 @@
// 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: -DWIN -emit-llvm -o - %s | FileCheck %s --check-prefixes=WIN
// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
-// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=LNX
+// RUN: -emit-llvm -o - %s | FileCheck %s
-#ifdef WIN
-#define INFINITY ((float)(1e+300 * 1e+300))
-#define NAN (-(float)(INFINITY * 0.0F))
-#else
#define NAN (__builtin_nanf(""))
#define INFINITY (__builtin_inff())
-#endif
-// WIN-LABEL: define dso_local noundef i32 @_Z4funcv(
-// WIN-SAME: ) #[[ATTR0:[0-9]+]] {
-// WIN-NEXT: entry:
-// WIN-NEXT: [[I:%.*]] = alloca i32, align 4
-// WIN-NEXT: [[MIN1:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MIN2:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MIN3:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MIN4:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MIN5:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MIN6:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MIN7:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MIN8:%.*]] = alloca x86_fp80, align 16
-// WIN-NEXT: [[MAX1:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MAX2:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MAX3:%.*]] = alloca double, align 8
-// WIN-NEXT: [[MAX4:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MAX5:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MAX6:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MAX7:%.*]] = alloca float, align 4
-// WIN-NEXT: [[MAX8:%.*]] = alloca x86_fp80, align 16
-// WIN-NEXT: [[FREXP1:%.*]] = alloca double, align 8
-// WIN-NEXT: [[FREXP2:%.*]] = alloca double, align 8
-// WIN-NEXT: [[FREXP3:%.*]] = alloca double, align 8
-// WIN-NEXT: [[FREXP4:%.*]] = alloca float, align 4
-// WIN-NEXT: [[FREXP5:%.*]] = alloca float, align 4
-// WIN-NEXT: [[FREXP6:%.*]] = alloca float, align 4
-// WIN-NEXT: [[FREXP7:%.*]] = alloca float, align 4
-// WIN-NEXT: [[FREXP8:%.*]] = alloca x86_fp80, align 16
-// WIN-NEXT: store i32 0, ptr [[I]], align 4
-// WIN-NEXT: store double 1.300000e+00, ptr [[MIN1]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[MIN2]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[MIN3]], align 8
-// WIN-NEXT: store float 0xFFF8000000000000, ptr [[MIN4]], align 4
-// WIN-NEXT: store float -1.000000e+00, ptr [[MIN5]], align 4
-// WIN-NEXT: store float 0xFFF0000000000000, ptr [[MIN6]], align 4
-// WIN-NEXT: store float 0.000000e+00, ptr [[MIN7]], align 4
-// WIN-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[MIN8]], align 16
-// WIN-NEXT: store double 1.524000e+01, ptr [[MAX1]], align 8
-// WIN-NEXT: store double 0.000000e+00, ptr [[MAX2]], align 8
-// WIN-NEXT: store double 0.000000e+00, ptr [[MAX3]], align 8
-// WIN-NEXT: store float -1.000000e+00, ptr [[MAX4]], align 4
-// WIN-NEXT: store float 0x7FF0000000000000, ptr [[MAX5]], align 4
-// WIN-NEXT: store float 0.000000e+00, ptr [[MAX6]], align 4
-// WIN-NEXT: store float 0xFFF8000000000000, ptr [[MAX7]], align 4
-// WIN-NEXT: store x86_fp80 0xK4008C540C49BA5E353F8, ptr [[MAX8]], align 16
-// WIN-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[FREXP1]], align 8
-// WIN-NEXT: store double 0.000000e+00, ptr [[FREXP2]], align 8
-// WIN-NEXT: store double -0.000000e+00, ptr [[FREXP3]], align 8
-// WIN-NEXT: store float 0xFFF8000000000000, ptr [[FREXP4]], align 4
-// WIN-NEXT: store float 0x7FF8000000000000, ptr [[FREXP5]], align 4
-// WIN-NEXT: store float 0x7FF0000000000000, ptr [[FREXP6]], align 4
-// WIN-NEXT: store float 0x7FF0000000000000, ptr [[FREXP7]], align 4
-// WIN-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
-// WIN-NEXT: ret i32 0
-//
-// LNX-LABEL: define dso_local noundef i32 @_Z4funcv(
-// LNX-SAME: ) #[[ATTR0:[0-9]+]] {
-// LNX-NEXT: entry:
-// LNX-NEXT: [[I:%.*]] = alloca i32, align 4
-// LNX-NEXT: [[MIN1:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MIN2:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MIN3:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MIN4:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MIN5:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MIN6:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MIN7:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MIN8:%.*]] = alloca x86_fp80, align 16
-// LNX-NEXT: [[MAX1:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MAX2:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MAX3:%.*]] = alloca double, align 8
-// LNX-NEXT: [[MAX4:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MAX5:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MAX6:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MAX7:%.*]] = alloca float, align 4
-// LNX-NEXT: [[MAX8:%.*]] = alloca x86_fp80, align 16
-// LNX-NEXT: [[FREXP1:%.*]] = alloca double, align 8
-// LNX-NEXT: [[FREXP2:%.*]] = alloca double, align 8
-// LNX-NEXT: [[FREXP3:%.*]] = alloca double, align 8
-// LNX-NEXT: [[FREXP4:%.*]] = alloca float, align 4
-// LNX-NEXT: [[FREXP5:%.*]] = alloca float, align 4
-// LNX-NEXT: [[FREXP6:%.*]] = alloca float, align 4
-// LNX-NEXT: [[FREXP7:%.*]] = alloca float, align 4
-// LNX-NEXT: [[FREXP8:%.*]] = alloca x86_fp80, align 16
-// LNX-NEXT: store i32 0, ptr [[I]], align 4
-// LNX-NEXT: store double 1.300000e+00, ptr [[MIN1]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[MIN2]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[MIN3]], align 8
-// LNX-NEXT: store float 0x7FF8000000000000, ptr [[MIN4]], align 4
-// LNX-NEXT: store float -1.000000e+00, ptr [[MIN5]], align 4
-// LNX-NEXT: store float 0xFFF0000000000000, ptr [[MIN6]], align 4
-// LNX-NEXT: store float 0.000000e+00, ptr [[MIN7]], align 4
-// LNX-NEXT: store x86_fp80 0xK4005F6E978D4FDF3B646, ptr [[MIN8]], align 16
-// LNX-NEXT: store double 1.524000e+01, ptr [[MAX1]], align 8
-// LNX-NEXT: store double 0.000000e+00, ptr [[MAX2]], align 8
-// LNX-NEXT: store double 0.000000e+00, ptr [[MAX3]], align 8
-// LNX-NEXT: store float -1.000000e+00, ptr [[MAX4]], align 4
-// LNX-NEXT: store float 0x7FF0000000000000, ptr [[MAX5]], align 4
-// LNX-NEXT: store float 0.000000e+00, ptr [[MAX6]], align 4
-// LNX-NEXT: store float 0x7FF8000000000000, ptr [[MAX7]], align 4
-// LNX-NEXT: store x86_fp80 0xK4008C540C49BA5E353F8, ptr [[MAX8]], align 16
-// LNX-NEXT: store double 0x3FEEDCCCCCCCCCCD, ptr [[FREXP1]], align 8
-// LNX-NEXT: store double 0.000000e+00, ptr [[FREXP2]], align 8
-// LNX-NEXT: store double -0.000000e+00, ptr [[FREXP3]], align 8
-// LNX-NEXT: store float 0x7FF8000000000000, ptr [[FREXP4]], align 4
-// LNX-NEXT: store float 0xFFF8000000000000, ptr [[FREXP5]], align 4
-// LNX-NEXT: store float 0x7FF0000000000000, ptr [[FREXP6]], align 4
-// LNX-NEXT: store float 0x7FF0000000000000, ptr [[FREXP7]], align 4
-// LNX-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
-// LNX-NEXT: ret i32 0
+// 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: 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 0x7FF0000000000000, ptr [[FREXP7]], align 4
+// CHECK-NEXT: store x86_fp80 0xK3FFE81A9FBE76C8B4396, ptr [[FREXP8]], align 16
+// CHECK-NEXT: ret i32 0
//
int func()
{
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index 7ad7618f3df144..17e7a03d720d05 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -DWIN -verify -std=c++23 -fsyntax-only %s
+// RUN: %clang_cc1 -DWIN -verify=nan-not-constant -std=c++23 -fsyntax-only %s
// RUN: %clang_cc1 -verify -std=c++23 -fsyntax-only %s
+// RUN: %clang_cc1 -verify=cplusplus20andless -std=c++20 -fsyntax-only %s
// expected-no-diagnostics
@@ -15,38 +16,93 @@
template <auto, auto> constexpr bool is_same_val = false;
template <auto X> constexpr bool is_same_val<X, X> = true;
+extern "C" {
+ double fmin(double, double);
+ float fminf(float, float);
+ long double fminl(long double, long double);
+
+ double fmax(double, double);
+ float fmaxf(float, float);
+ long double fmaxl(long double, long double);
+
+ double frexp(double, int*);
+ float frexpf(float, int*);
+ long double frexpl(long double, int*);
+}
+
+#if __cplusplus <= 202002L
+#define CALL_BUILTIN(BASE_NAME, ...) __builtin_##BASE_NAME(__VA_ARGS__)
+#else
+#define CALL_BUILTIN(BASE_NAME, ...) BASE_NAME(__VA_ARGS__)
+#endif
+
int main() {
int i;
// fmin
- static_assert(is_same_val<__builtin_fmin(15.24, 1.3), 1.3>);
- static_assert(is_same_val<__builtin_fmin(-0.0, +0.0), -0.0>);
- static_assert(is_same_val<__builtin_fmin(+0.0, -0.0), -0.0>);
- static_assert(is_same_val<__builtin_fminf(NAN, -1), -1.f>);
- static_assert(is_same_val<__builtin_fminf(+INFINITY, 0), 0.f>);
- static_assert(is_same_val<__builtin_fminf(-INFINITY, 0), -INFINITY>);
- static_assert(is_same_val<__builtin_fminf(NAN, NAN), NAN>);
- static_assert(is_same_val<__builtin_fminl(123.456L, 789.012L), 123.456L>);
-
- // fmax
- static_assert(is_same_val<__builtin_fmax(15.24, 1.3), 15.24>);
- static_assert(is_same_val<__builtin_fmax(-0.0, +0.0), +0.0>);
- static_assert(is_same_val<__builtin_fmax(+0.0, -0.0), +0.0>);
- static_assert(is_same_val<__builtin_fmaxf(NAN, -1), -1.f>);
- static_assert(is_same_val<__builtin_fmaxf(+INFINITY, 0), INFINITY>);
- static_assert(is_same_val<__builtin_fmaxf(-INFINITY, 0), 0.f>);
- static_assert(is_same_val<__builtin_fmaxf(NAN, NAN), NAN>);
- static_assert(is_same_val<__builtin_fmaxl(123.456L, 789.012L), 789.012L>);
+ static_assert(is_same_val<CALL_BUILTIN(fmin, 15.24, 1.3), 1.3>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmin, -0.0, +0.0), -0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmin, +0.0, -0.0), -0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fminf, NAN, -1), -1.f>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fminf, +INFINITY, 0), 0.f>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fminf, -INFINITY, 0), -INFINITY>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fminf, NAN, NAN), NAN>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fminl, 123.456L, 789.012L), 123.456L>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+
+ static_assert(is_same_val<CALL_BUILTIN(fmax, 15.24, 1.3), 15.24>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmax, -0.0, +0.0), +0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmax, +0.0, -0.0), +0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmaxf, NAN, -1), -1.f>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmaxf, +INFINITY, 0), INFINITY>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmaxf, -INFINITY, 0), 0.f>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmaxf, NAN, NAN), NAN>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(fmaxl, 123.456L, 789.012L), 789.012L>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
// frexp
- static_assert(is_same_val<__builtin_frexp(123.45, &i), 123.45/128>);
- static_assert(is_same_val<__builtin_frexp(0.0, &i), 0.0>);
- static_assert(is_same_val<__builtin_frexp(-0.0, &i), -0.0>);
- static_assert(is_same_val<__builtin_frexpf(NAN, &i), NAN>);
- static_assert(is_same_val<__builtin_frexpf(-NAN, &i), -NAN>);
- static_assert(is_same_val<__builtin_frexpf(INFINITY, &i), INFINITY>);
- static_assert(is_same_val<__builtin_frexpf(-INFINITY, &i), -INFINITY>);
- static_assert(is_same_val<__builtin_frexpl(123.45L, &i), 123.45L/128>);
+ static_assert(is_same_val<CALL_BUILTIN(frexp, 123.45, &i), 123.45/128>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexp, 0.0, &i), 0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexp, -0.0, &i), -0.0>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, NAN, &i), NAN>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, -NAN, &i), -NAN>);
+ // nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
+ // nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
+ // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, INFINITY, &i), INFINITY>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, -INFINITY, &i), -INFINITY>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpl, 123.45L, &i), 123.45L/128>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
return 0;
}
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 94f12a08164fdc..43e4a25baaed0c 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -222,7 +222,7 @@ void PrintAttributes(const Record *Builtin, BuiltinType BT,
OS << 'f';
} else {
OS << 'F';
- if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
+ if (Builtin->getValueAsBit("BuiltinPrefixedAliasIsConstexpr"))
OS << 'E';
}
}
>From 5f676450ce383025f473c0d44b16043460441570 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 11 Jun 2024 06:28:02 -0700
Subject: [PATCH 10/19] Put back CodeGen/aix-builtin-mapping.c how it was
originally written.
---
clang/test/CodeGen/aix-builtin-mapping.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/clang/test/CodeGen/aix-builtin-mapping.c b/clang/test/CodeGen/aix-builtin-mapping.c
index 1936f23b71d522..a79218c6f1d8b9 100644
--- a/clang/test/CodeGen/aix-builtin-mapping.c
+++ b/clang/test/CodeGen/aix-builtin-mapping.c
@@ -6,8 +6,6 @@
// RUN: %clang_cc1 -triple powerpc-ibm-aix -mlong-double-64 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
// RUN: %clang_cc1 -triple powerpc64-ibm-aix -mlong-double-64 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
-long double input = 0.0L;
-
int main()
{
int DummyInt;
@@ -15,12 +13,10 @@ int main()
long double returnValue;
returnValue = __builtin_modfl(1.0L, &DummyLongDouble);
- returnValue = __builtin_frexpl(input, &DummyInt);
+ returnValue = __builtin_frexpl(0.0L, &DummyInt);
returnValue = __builtin_ldexpl(1.0L, 1);
}
-// CHECK: @input = global double 0.000000e+00
// CHECK: %call = call double @modf(double noundef 1.000000e+00, ptr noundef %DummyLongDouble) #3
-// CHECK: [[TMP0:%.*]] = load double, ptr @input
-// CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double 0.000000e+00)
// CHECK: %{{.+}} = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 1)
>From 49186b973440e73cb49ff2c62a4e7ed9607a39ca Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <Zahira.Ammarguellat at intel.com>
Date: Fri, 26 Jul 2024 05:31:28 -0700
Subject: [PATCH 11/19] Fix build issue in flang.
---
flang/lib/Frontend/CompilerInvocation.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 8c892d9d032e1d..7c7f003cf731ca 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1072,7 +1072,7 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
opts.setFPContractMode(fpContractMode);
}
- if (args.getLastArg(clang::driver::options::OPT_menable_no_infinities)) {
+ if (args.getLastArg(clang::driver::options::OPT_menable_no_infs)) {
opts.NoHonorInfs = true;
}
>From d32737e5c0528ca37828c3dc85978b3c0d131bf3 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 26 Jul 2024 11:29:33 -0700
Subject: [PATCH 12/19] Rewrote isInFrexpResultRange according to review
comments and fixed format.
---
clang/lib/AST/ExprConstant.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3710e027912208..6dbfc9c3a08804 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14779,15 +14779,13 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
}
// Checks that the value x is in the range (-1;-0.5], [0.5; 1)
static bool isInFrexpResultRange(const llvm::APFloat &x) {
- llvm::APFloat minusOne(x.getSemantics(), "-1.0");
- llvm::APFloat minusHalf(x.getSemantics(), "-0.5");
+ llvm::APFloat AbsX = abs(x);
+
llvm::APFloat half(x.getSemantics(), "0.5");
llvm::APFloat one(x.getSemantics(), "1.0");
- return ((x.compare(minusOne) == llvm::APFloat::cmpGreaterThan &&
- x.compare(minusHalf) != llvm::APFloat::cmpGreaterThan) ||
- (x.compare(half) != llvm::APFloat::cmpLessThan &&
- x.compare(one) == llvm::APFloat::cmpLessThan));
+ return (AbsX.compare(half) != llvm::APFloat::cmpLessThan &&
+ AbsX.compare(one) == llvm::APFloat::cmpLessThan);
}
void FloatExprEvaluator::StoreExponent(LValue Pointer, int exp) {
@@ -14821,7 +14819,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Builtin::Context BTC = Info.Ctx.BuiltinInfo;
if (BTC.isBuiltinConstant(FDecl->getBuiltinID()) >
Info.Ctx.getLangOpts().LangStd)
- return false;
+ return false;
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
@@ -14948,7 +14946,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Builtin::Context BTC = Info.Ctx.BuiltinInfo;
if (BTC.isBuiltinConstant(FDecl->getBuiltinID()) >
Info.Ctx.getLangOpts().LangStd)
- return false;
+ return false;
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
>From bd536f5010d275d5431a07a7eb733e5f1897fa9e Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 26 Jul 2024 11:37:14 -0700
Subject: [PATCH 13/19] Fix format.
---
clang/include/clang/Basic/Builtins.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index 9e3fb2c7a89520..a00efed2f126cf 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -15,10 +15,10 @@
#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"
-#include "LangStandard.h"
#include <cstring>
// VC++ defines 'alloca' as an object-like macro, which interferes with our
>From 32b788ac6e5ffd164bb86081aa670a77fbb44a6c Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 29 Jul 2024 12:16:26 -0700
Subject: [PATCH 14/19] Addressed missed review comments.
---
clang/include/clang/Basic/Builtins.td | 4 +++-
clang/include/clang/Basic/BuiltinsBase.td | 2 ++
clang/lib/AST/ExprConstant.cpp | 4 +++-
clang/test/CodeGenCXX/constexpr-math.cpp | 12 +++++++++---
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 08687a2f8979c2..9de225d19bd880 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -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];
let Prototype = "T(T, int*)";
+ let BuiltinPrefixedAliasIsConstexpr = 1;
+ let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def HugeVal : Builtin, FPMathWithF128Template {
diff --git a/clang/include/clang/Basic/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td
index ef31fbecd35b18..363d61083b8ec8 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -85,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 {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6dbfc9c3a08804..2ecb38fdf6d713 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14814,7 +14814,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BIfrexpl:
case Builtin::BI__builtin_frexp:
case Builtin::BI__builtin_frexpf:
- case Builtin::BI__builtin_frexpl: {
+ 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()) >
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index c93e867acea065..0ad0cac76e11f6 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -34,6 +34,8 @@
// 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
@@ -57,8 +59,10 @@
// 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 0x7FF0000000000000, ptr [[FREXP7]], 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()
@@ -91,9 +95,11 @@ int func()
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 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);
return 0;
}
>From 501e39a62e0caa865cbf0c612aafed990ec17e1b Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 5 Aug 2024 06:59:24 -0700
Subject: [PATCH 15/19] Addressed review comments. Remove StoreExponent
function and fixed LIT tests.
---
clang/include/clang/Basic/Builtins.td | 4 +-
clang/lib/AST/ExprConstant.cpp | 20 ++--------
clang/test/CodeGenCXX/constexpr-math.cpp | 48 ++++++++++++++++--------
clang/test/SemaCXX/constexpr-math.cpp | 20 ++++++----
4 files changed, 50 insertions(+), 42 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 9de225d19bd880..3fa3084c604575 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -253,7 +253,7 @@ def FmodF16F128 : F16F128MathTemplate, Builtin {
def FrexpF16F128 : F16F128MathTemplate, Builtin {
let Spellings = ["__builtin_frexp"];
- let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, ConstexprSince];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstexprSince];
let Prototype = "T(T, int*)";
let BuiltinPrefixedAliasIsConstexpr = 1;
let UnprefixedOnlyConstexprSince = "lang_cxx23";
@@ -3496,7 +3496,7 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> {
def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["frexp"];
- let Attributes = [NoThrow, Const, ConstexprSince];
+ let Attributes = [NoThrow, ConstexprSince];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2ecb38fdf6d713..bfd7a3d05eddc2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14718,8 +14718,6 @@ class FloatExprEvaluator
return true;
}
- void StoreExponent(LValue Pointer, int exp);
-
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -14788,19 +14786,6 @@ static bool isInFrexpResultRange(const llvm::APFloat &x) {
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);
- } else {
- llvm_unreachable("expecting a VarDecl for an exponent");
- }
-}
-
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -14832,7 +14817,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
assert((Result.isZero() || Result.isNaN() || Result.isInfinity() ||
isInFrexpResultRange(Result)) &&
"The value is not in the expected range for frexp.");
- StoreExponent(Pointer, FrexpExp);
+ APValue ExpVal{Result};
+ if (!handleAssignment(Info, E, Pointer,
+ E->getArg(1)->getType()->getPointeeType(), ExpVal))
+ return false;
return true;
}
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index 0ad0cac76e11f6..fdd939bf47ba1b 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -3,9 +3,14 @@
// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -std=c++23 \
// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple powerpc64-unknown-unknown \
+// RUN: -DFLOAT128 -target-feature +float128 -std=c++23 %s -o - \
+// RUN: | FileCheck -check-prefix=FLOAT128 %s
+
#define NAN (__builtin_nanf(""))
#define INFINITY (__builtin_inff())
+#if !defined(FLOAT128)
// CHECK-LABEL: define dso_local noundef i32 @_Z4funcv(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
@@ -34,9 +39,7 @@
// 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: [[FREXP9:%.*]] = alloca half, align 2
// 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
@@ -61,8 +64,7 @@
// 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: store half 0xH3B00, ptr [[FREXP9]], align 2
// CHECK-NEXT: ret i32 0
//
int func()
@@ -80,7 +82,7 @@ int func()
constexpr long double min8 = __builtin_fminl(123.456L, 789.012L);
// fmax
- 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);
@@ -90,17 +92,31 @@ int func()
constexpr long double max8 = __builtin_fmaxl(123.456L, 789.012L);
// frexp
- constexpr double frexp1 = __builtin_frexp(123.45, &i);
- 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);
+ constexpr double frexp1 = __builtin_frexp(123.45, (int [1]){});
+ constexpr double frexp2 = __builtin_frexp(0.0, (int [1]){});
+ constexpr double frexp3 = __builtin_frexp(-0.0, (int [1]){});
+ constexpr float frexp4 = __builtin_frexpf(NAN, (int [1]){});
+ constexpr float frexp5 = __builtin_frexpf(-NAN, (int [1]){});
+ constexpr float frexp6 = __builtin_frexpf(+INFINITY, (int [1]){});
+ constexpr float frexp7 = __builtin_frexpf(-INFINITY, (int [1]){});
+ constexpr __fp16 frexp9 = __builtin_frexpf16(3.5, (int [1]){});
+ constexpr long double frexp8 = __builtin_frexpl(259.328L, (int [1]){});
return 0;
}
+#elif FLOAT128
+// FLOAT128-LABEL: define dso_local noundef signext i32 @_Z9func_f128v(
+// FLOAT128-SAME: ) #[[ATTR0:[0-9]+]] {
+// FLOAT128-NEXT: entry:
+// FLOAT128-NEXT: [[I:%.*]] = alloca i32, align 4
+// FLOAT128-NEXT: [[FREXP10:%.*]] = alloca fp128, align 16
+// FLOAT128-NEXT: store fp128 0xL90000000000000003FFED58F5C28F5C2, ptr [[FREXP10]], align 16
+// FLOAT128-NEXT: ret i32 0
+//
+int func_f128() {
+ int i;
+ constexpr __float128 frexp10 = __builtin_frexpf128(234.78, (int [1]){}); // expected-error {{__float128 is not supported on this target}}
+ return 0;
+}
+#endif
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index 17e7a03d720d05..b2a52891dcea77 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -83,25 +83,29 @@ int main() {
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
// frexp
- static_assert(is_same_val<CALL_BUILTIN(frexp, 123.45, &i), 123.45/128>);
+ static_assert(is_same_val<CALL_BUILTIN(frexp, 123.45, (int [1]){}), 123.45/128>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexp, 0.0, &i), 0.0>);
+ static_assert(is_same_val<CALL_BUILTIN(frexp, 0.0, (int [1]){}), 0.0>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexp, -0.0, &i), -0.0>);
+ static_assert(is_same_val<CALL_BUILTIN(frexp, -0.0, (int [1]){}), -0.0>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexpf, NAN, &i), NAN>);
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, NAN, (int [1]){}), NAN>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
// cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexpf, -NAN, &i), -NAN>);
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, -NAN, (int [1]){}), -NAN>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
// cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexpf, INFINITY, &i), INFINITY>);
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, INFINITY, (int [1]){}), INFINITY>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexpf, -INFINITY, &i), -INFINITY>);
+ static_assert(is_same_val<CALL_BUILTIN(frexpf, -INFINITY, (int [1]){}), -INFINITY>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
- static_assert(is_same_val<CALL_BUILTIN(frexpl, 123.45L, &i), 123.45L/128>);
+ static_assert(is_same_val<CALL_BUILTIN(frexpl, 123.45L, (int [1]){}), 123.45L/128>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexpl, 259.328L, (int [1]){}), 259.328L/512>);
+ // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
+ static_assert(is_same_val<CALL_BUILTIN(frexp, 3.5, (int [1]){}), 3.5/4>);
// cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
return 0;
>From 0cc61eb3e22f7c9dc39317dcaf201265ac3282f0 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 13 Aug 2024 13:02:32 -0700
Subject: [PATCH 16/19] Replaced ConstexpSince by Constexpr for FrexpF16F128.
---
clang/include/clang/Basic/Builtins.td | 3 +--
clang/test/CodeGenCXX/constexpr-math.cpp | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 3fa3084c604575..ad9c216b377851 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -253,10 +253,9 @@ def FmodF16F128 : F16F128MathTemplate, Builtin {
def FrexpF16F128 : F16F128MathTemplate, Builtin {
let Spellings = ["__builtin_frexp"];
- let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstexprSince];
+ let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Constexpr];
let Prototype = "T(T, int*)";
let BuiltinPrefixedAliasIsConstexpr = 1;
- let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def HugeVal : Builtin, FPMathWithF128Template {
diff --git a/clang/test/CodeGenCXX/constexpr-math.cpp b/clang/test/CodeGenCXX/constexpr-math.cpp
index fdd939bf47ba1b..a6bcfd43d2b9be 100644
--- a/clang/test/CodeGenCXX/constexpr-math.cpp
+++ b/clang/test/CodeGenCXX/constexpr-math.cpp
@@ -99,9 +99,8 @@ int func()
constexpr float frexp5 = __builtin_frexpf(-NAN, (int [1]){});
constexpr float frexp6 = __builtin_frexpf(+INFINITY, (int [1]){});
constexpr float frexp7 = __builtin_frexpf(-INFINITY, (int [1]){});
- constexpr __fp16 frexp9 = __builtin_frexpf16(3.5, (int [1]){});
constexpr long double frexp8 = __builtin_frexpl(259.328L, (int [1]){});
-
+ constexpr __fp16 frexp9 = __builtin_frexpf16(3.5, (int [1]){});
return 0;
}
#elif FLOAT128
>From c615b2267bc68a7102fa88339732e76d2d368cee Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 22 Aug 2024 08:02:19 -0700
Subject: [PATCH 17/19] Removed builtin attribute ConstExprSince and replaced
it with a member function.
---
clang/include/clang/AST/Decl.h | 18 ++++++++++++++++++
clang/include/clang/Basic/Builtins.td | 9 +++------
clang/include/clang/Basic/BuiltinsBase.td | 3 ---
clang/lib/AST/Decl.cpp | 12 ++++++++++++
clang/lib/AST/ExprConstant.cpp | 20 ++++++++++----------
clang/lib/Sema/SemaDecl.cpp | 1 +
6 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 561a9d872acfb0..e4823b1ece8315 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2036,6 +2036,10 @@ class FunctionDecl : public DeclaratorDecl,
/// the DeclaratorDecl base class.
DeclarationNameLoc DNLoc;
+ /// Represents the language version since this function has been declared
+ /// constexpr.
+ clang::LangStandard::Kind ConstexprSinceVersion;
+
/// Specify that this function declaration is actually a function
/// template specialization.
///
@@ -2151,6 +2155,20 @@ class FunctionDecl : public DeclaratorDecl,
void setDeclarationNameLoc(DeclarationNameLoc L) { DNLoc = L; }
+ /// Set the language standard version at which this builtin became constexpr.
+ void setConstexprBuiltinSinceVersion(IdentifierInfo *builtinIdentifier);
+
+ /// Get the language standard version at which this builtin became constexpr.
+ clang::LangStandard::Kind getConstexprBuiltinSinceVersion() const {
+ return ConstexprSinceVersion;
+ }
+
+ /// Set the version of the language standard at which this declaration became
+ /// constexpr.
+ void setConstexprSinceVersion(clang::LangStandard::Kind LangVersion) {
+ ConstexprSinceVersion = LangVersion;
+ }
+
/// Returns the location of the ellipsis of a variadic function.
SourceLocation getEllipsisLoc() const {
const auto *FPT = getType()->getAs<FunctionProtoType>();
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index ad9c216b377851..0133a01bbfe192 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3495,11 +3495,10 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> {
def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["frexp"];
- let Attributes = [NoThrow, ConstexprSince];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "T(T, int*)";
let AddBuiltinPrefixedAlias = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
- let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> {
@@ -3667,20 +3666,18 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> {
def Fmax : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmax"];
- let Attributes = [NoThrow, Const, ConstexprSince];
+ let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
- let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmin"];
- let Attributes = [NoThrow, Const, ConstexprSince];
+ let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let BuiltinPrefixedAliasIsConstexpr = 1;
- let UnprefixedOnlyConstexprSince = "lang_cxx23";
}
def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
diff --git a/clang/include/clang/Basic/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td
index 363d61083b8ec8..a5461c0a70057d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,7 +70,6 @@ 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">;
@@ -86,7 +85,6 @@ class Builtin {
// to #undef them.
bit RequiresUndef = 0;
bit BuiltinPrefixedAliasIsConstexpr = 0;
- string UnprefixedOnlyConstexprSince = "";
}
class CustomEntry {
@@ -103,7 +101,6 @@ class LibBuiltin<string header, string languages = "ALL_LANGUAGES"> : Builtin {
string Languages = languages;
bit AddBuiltinPrefixedAlias = 0;
bit BuiltinPrefixedAliasIsConstexpr = 0;
- string UnprefixedOnlyConstexprSince = "";
}
class MSLibBuiltin<string header> : LibBuiltin<header, "ALL_MS_LANGUAGES">;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 490c4a2fc525cd..3960879e277374 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -71,6 +71,7 @@
#include <string>
#include <tuple>
#include <type_traits>
+#include <unordered_set>
using namespace clang;
@@ -3066,6 +3067,17 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
setTrailingRequiresClause(TrailingRequiresClause);
}
+void FunctionDecl::setConstexprBuiltinSinceVersion(IdentifierInfo *I) {
+ static const std::unordered_set<std::string> constexprFunctions = {
+ "__builtin_frexp", "__builtin_frexpf", "__builtin_frexpl",
+ "__builtin_fmax", "__builtin_fmaxf", "__builtin_fmaxl",
+ "__builtin_fmin", "__builtin_fminf", "__builtin_fminl"};
+ bool isConstExpr =
+ constexprFunctions.find(I->getName().str()) != constexprFunctions.end();
+ isConstExpr ? setConstexprSinceVersion(clang::LangStandard::lang_cxx23)
+ : setConstexprSinceVersion(clang::LangStandard::lang_cxx20);
+}
+
void FunctionDecl::getNameForDiagnostic(
raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index bfd7a3d05eddc2..eddccab96ebeed 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14803,10 +14803,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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;
+ clang::LangStandard::Kind ConstExprSinceVersion =
+ FDecl->getConstexprBuiltinSinceVersion();
+ if (ConstExprSinceVersion > Info.Ctx.getLangOpts().LangStd)
+ return false;
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
@@ -14907,9 +14907,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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)
+ clang::LangStandard::Kind ConstExprSinceVersion =
+ FDecl->getConstexprBuiltinSinceVersion();
+ if (ConstExprSinceVersion > Info.Ctx.getLangOpts().LangStd)
return false;
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
@@ -14933,9 +14933,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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)
+ clang::LangStandard::Kind ConstExprSinceVersion =
+ FDecl->getConstexprBuiltinSinceVersion();
+ if (ConstExprSinceVersion > Info.Ctx.getLangOpts().LangStd)
return false;
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7bdecb2546f30a..44bcfed00dfff3 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2307,6 +2307,7 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type,
Type->isFunctionProtoType(), ConstexprKind);
New->setImplicit();
New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
+ New->setConstexprBuiltinSinceVersion(II);
// Create Decl objects for each parameter, adding them to the
// FunctionDecl.
>From 5eec2db28bf9c221a2cebf9df65ce18516c76649 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 22 Aug 2024 08:54:13 -0700
Subject: [PATCH 18/19] Fix format.
---
clang/lib/AST/ExprConstant.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index eddccab96ebeed..daf1e5853a2d1c 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14806,7 +14806,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
clang::LangStandard::Kind ConstExprSinceVersion =
FDecl->getConstexprBuiltinSinceVersion();
if (ConstExprSinceVersion > Info.Ctx.getLangOpts().LangStd)
- return false;
+ return false;
LValue Pointer;
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluatePointer(E->getArg(1), Pointer, Info))
>From 299df9a9dcd8928066fae2ee6dad935d7ccd6c24 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 23 Aug 2024 11:22:07 -0700
Subject: [PATCH 19/19] Fix LIT failures.
---
clang/lib/AST/Decl.cpp | 22 +++++++++++++++-------
clang/test/SemaCXX/constexpr-math.cpp | 16 ----------------
2 files changed, 15 insertions(+), 23 deletions(-)
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 3960879e277374..7d6d8811abbcdd 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3068,14 +3068,22 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
}
void FunctionDecl::setConstexprBuiltinSinceVersion(IdentifierInfo *I) {
- static const std::unordered_set<std::string> constexprFunctions = {
+ const std::unordered_set<std::string> ConstexprFunctions = {
+ "__builtin_fmax", "__builtin_fmaxf", "__builtin_fmaxl",
+ "__builtin_fmin", "__builtin_fminf", "__builtin_fminl"};
+ const std::unordered_set<std::string> ConstexprFunctionsFrexp = {
"__builtin_frexp", "__builtin_frexpf", "__builtin_frexpl",
- "__builtin_fmax", "__builtin_fmaxf", "__builtin_fmaxl",
- "__builtin_fmin", "__builtin_fminf", "__builtin_fminl"};
- bool isConstExpr =
- constexprFunctions.find(I->getName().str()) != constexprFunctions.end();
- isConstExpr ? setConstexprSinceVersion(clang::LangStandard::lang_cxx23)
- : setConstexprSinceVersion(clang::LangStandard::lang_cxx20);
+ "__builtin_frexpf16", "__builtin_frexpf128"};
+ std::string BuiltinName = I->getName().str();
+ if (ConstexprFunctions.count(BuiltinName)) {
+ setConstexprSinceVersion(getLangOpts().CPlusPlus23
+ ? LangStandard::lang_cxx23
+ : getLangOpts().LangStd);
+ } else if (ConstexprFunctionsFrexp.count(BuiltinName)) {
+ setConstexprSinceVersion(LangStandard::lang_cxx23);
+ } else {
+ setConstexprSinceVersion(getLangOpts().LangStd);
+ }
}
void FunctionDecl::getNameForDiagnostic(
diff --git a/clang/test/SemaCXX/constexpr-math.cpp b/clang/test/SemaCXX/constexpr-math.cpp
index b2a52891dcea77..95ceb53e05a9cb 100644
--- a/clang/test/SemaCXX/constexpr-math.cpp
+++ b/clang/test/SemaCXX/constexpr-math.cpp
@@ -41,46 +41,30 @@ int main() {
// fmin
static_assert(is_same_val<CALL_BUILTIN(fmin, 15.24, 1.3), 1.3>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmin, -0.0, +0.0), -0.0>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmin, +0.0, -0.0), -0.0>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fminf, NAN, -1), -1.f>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
- // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fminf, +INFINITY, 0), 0.f>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fminf, -INFINITY, 0), -INFINITY>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fminf, NAN, NAN), NAN>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
- // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fminl, 123.456L, 789.012L), 123.456L>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmax, 15.24, 1.3), 15.24>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmax, -0.0, +0.0), +0.0>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmax, +0.0, -0.0), +0.0>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmaxf, NAN, -1), -1.f>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
- // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmaxf, +INFINITY, 0), INFINITY>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmaxf, -INFINITY, 0), 0.f>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmaxf, NAN, NAN), NAN>);
// nan-not-constant-error at -1 {{non-type template argument is not a constant expression}}
// nan-not-constant-note at -2 {{floating point arithmetic produces a NaN}}
- // cplusplus20andless-error at -3 {{non-type template argument is not a constant expression}}
static_assert(is_same_val<CALL_BUILTIN(fmaxl, 123.456L, 789.012L), 789.012L>);
- // cplusplus20andless-error at -1 {{non-type template argument is not a constant expression}}
// frexp
static_assert(is_same_val<CALL_BUILTIN(frexp, 123.45, (int [1]){}), 123.45/128>);
More information about the flang-commits
mailing list