[clang] [flang] [llvm] [C++23] [CLANG] Adding C++23 constexpr math functions: fmin, fmax and frexp. (PR #88978)

Zahira Ammarguellat via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 26 08:07:27 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/11] 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 52c0dd52c28b1..a35c77286229f 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 5a36621dc5cce..506621ac7e9c1 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 0000000000000..446bf3f4f7a50
--- /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/11] 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 506621ac7e9c1..1a6abb386071c 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 446bf3f4f7a50..ad7b6779a4ae0 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 0000000000000..f51ea1bcaf7ba
--- /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/11] 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 a35c77286229f..419e623c7bc04 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 1a6abb386071c..4e664905969ee 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 ad7b6779a4ae0..a48c312d05af0 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 f51ea1bcaf7ba..24e5bf70e3535 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/11] 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 4e664905969ee..be68ef11efb38 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 a48c312d05af0..039d2f288ddfa 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 24e5bf70e3535..2c4c29c1c6542 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/11] 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 419e623c7bc04..75a26e3cf2b58 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 be68ef11efb38..3a4abab8fd336 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 039d2f288ddfa..f5546c0fcfed9 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 2c4c29c1c6542..7ad7618f3df14 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 deb74cb2fdeb1..c9097b4f4e607 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/11] 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 3a4abab8fd336..f82ae8ec1a890 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 c9097b4f4e607..deb74cb2fdeb1 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/11] 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 f82ae8ec1a890..b1005ed756f7e 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/11] 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 b1005ed756f7e..6fbd46606d627 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 a79218c6f1d8b..1936f23b71d52 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/11] 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 f955d21169556..15249983e85b4 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 cdbc0ee71909a..c1b53c7ac1ae3 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 724747ec76d73..8306a893abab4 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 f5d903ff85d78..a9307ebf0747e 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 f5546c0fcfed9..c93e867acea06 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 7ad7618f3df14..17e7a03d720d0 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 94f12a08164fd..43e4a25baaed0 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/11] 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 1936f23b71d52..a79218c6f1d8b 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/11] 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 8c892d9d032e1..7c7f003cf731c 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;
   }
 



More information about the llvm-commits mailing list