[clang] c2273e3 - [clang][Interp] Implement __builtin_nan family
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 28 01:29:11 PDT 2023
Author: Timm Bäder
Date: 2023-07-28T10:28:55+02:00
New Revision: c2273e33bd13a227271a53cde5868546e41dc3bf
URL: https://github.com/llvm/llvm-project/commit/c2273e33bd13a227271a53cde5868546e41dc3bf
DIFF: https://github.com/llvm/llvm-project/commit/c2273e33bd13a227271a53cde5868546e41dc3bf.diff
LOG: [clang][Interp] Implement __builtin_nan family
Differential Revision: https://reviews.llvm.org/D155356
Added:
Modified:
clang/lib/AST/Interp/InterpBuiltin.cpp
clang/test/AST/Interp/builtin-functions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index b29747221ab552..a8758d8cc0569a 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -9,6 +9,7 @@
#include "Interp.h"
#include "PrimType.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/TargetInfo.h"
namespace clang {
namespace interp {
@@ -59,6 +60,67 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame, const Function *F,
+ bool Signaling) {
+ const Pointer &Arg = getParam<Pointer>(Frame, 0);
+
+ if (!CheckLoad(S, OpPC, Arg))
+ return false;
+
+ assert(Arg.getFieldDesc()->isPrimitiveArray());
+
+ // Convert the given string to an integer using StringRef's API.
+ llvm::APInt Fill;
+ std::string Str;
+ assert(Arg.getNumElems() >= 1);
+ for (unsigned I = 0;; ++I) {
+ const Pointer &Elem = Arg.atIndex(I);
+
+ if (!CheckLoad(S, OpPC, Elem))
+ return false;
+
+ if (Elem.deref<int8_t>() == 0)
+ break;
+
+ Str += Elem.deref<char>();
+ }
+
+ // Treat empty strings as if they were zero.
+ if (Str.empty())
+ Fill = llvm::APInt(32, 0);
+ else if (StringRef(Str).getAsInteger(0, Fill))
+ return false;
+
+ const llvm::fltSemantics &TargetSemantics =
+ S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
+
+ Floating Result;
+ if (S.getCtx().getTargetInfo().isNan2008()) {
+ if (Signaling)
+ Result = Floating(
+ llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
+ else
+ Result = Floating(
+ llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
+ } else {
+ // Prior to IEEE 754-2008, architectures were allowed to choose whether
+ // the first bit of their significand was set for qNaN or sNaN. MIPS chose
+ // a
diff erent encoding to what became a standard in 2008, and for pre-
+ // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
+ // sNaN. This is now known as "legacy NaN" encoding.
+ if (Signaling)
+ Result = Floating(
+ llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
+ else
+ Result = Floating(
+ llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
+ }
+
+ S.Stk.push<Floating>(Result);
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
InterpFrame *Frame = S.Current;
APValue Dummy;
@@ -72,7 +134,24 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
case Builtin::BI__builtin_strcmp:
if (interp__builtin_strcmp(S, OpPC, Frame))
return Ret<PT_Sint32>(S, OpPC, Dummy);
- return false;
+ break;
+ case Builtin::BI__builtin_nan:
+ case Builtin::BI__builtin_nanf:
+ case Builtin::BI__builtin_nanl:
+ case Builtin::BI__builtin_nanf16:
+ case Builtin::BI__builtin_nanf128:
+ if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
+ return Ret<PT_Float>(S, OpPC, Dummy);
+ break;
+ case Builtin::BI__builtin_nans:
+ case Builtin::BI__builtin_nansf:
+ case Builtin::BI__builtin_nansl:
+ case Builtin::BI__builtin_nansf16:
+ case Builtin::BI__builtin_nansf128:
+ if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
+ return Ret<PT_Float>(S, OpPC, Dummy);
+ break;
+
default:
return false;
}
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index eff8f80b7649a1..ef28f003117dc3 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -std=c++20 -verify=ref %s -Wno-constant-evaluated
+
namespace strcmp {
constexpr char kFoobar[6] = {'f','o','o','b','a','r'};
@@ -34,3 +37,26 @@ namespace strcmp {
// ref-error {{not an integral constant}} \
// ref-note {{dereferenced one-past-the-end}}
}
+
+namespace nan {
+ constexpr double NaN1 = __builtin_nan("");
+
+ /// The current interpreter does not accept this, but it should.
+ constexpr float NaN2 = __builtin_nans([](){return "0xAE98";}()); // ref-error {{must be initialized by a constant expression}}
+
+ constexpr double NaN3 = __builtin_nan("foo"); // expected-error {{must be initialized by a constant expression}} \
+ // ref-error {{must be initialized by a constant expression}}
+ constexpr float NaN4 = __builtin_nanf("");
+ constexpr long double NaN5 = __builtin_nanf128("");
+
+ /// FIXME: This should be accepted by the current interpreter as well.
+ constexpr char f[] = {'0', 'x', 'A', 'E', '\0'};
+ constexpr double NaN6 = __builtin_nan(f); // ref-error {{must be initialized by a constant expression}}
+
+ /// FIXME: Current interpreter misses diagnostics.
+ constexpr char f2[] = {'0', 'x', 'A', 'E'}; /// No trailing 0 byte.
+ constexpr double NaN7 = __builtin_nan(f2); // ref-error {{must be initialized by a constant expression}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{read of dereferenced one-past-the-end pointer}} \
+ // expected-note {{in call to}}
+}
More information about the cfe-commits
mailing list