[clang] ff80fc0 - [clang][Interp] Implement __builtin_isnan()
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 29 01:48:30 PDT 2023
Author: Timm Bäder
Date: 2023-07-29T10:48:10+02:00
New Revision: ff80fc0ea2f9ec043d679f343c875bdf43e1395e
URL: https://github.com/llvm/llvm-project/commit/ff80fc0ea2f9ec043d679f343c875bdf43e1395e
DIFF: https://github.com/llvm/llvm-project/commit/ff80fc0ea2f9ec043d679f343c875bdf43e1395e.diff
LOG: [clang][Interp] Implement __builtin_isnan()
The previous version was using llvm::reverse(CallExpr::arguments()),
which causes problems when clang is compiled with GCC.
Differential Revision: https://reviews.llvm.org/D155369
Added:
Modified:
clang/lib/AST/Interp/Function.cpp
clang/lib/AST/Interp/Function.h
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/InterpBuiltin.cpp
clang/test/Sema/constant-builtins-fmin.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Function.cpp b/clang/lib/AST/Interp/Function.cpp
index 75312999d23d66..e409002171c4b7 100644
--- a/clang/lib/AST/Interp/Function.cpp
+++ b/clang/lib/AST/Interp/Function.cpp
@@ -7,10 +7,11 @@
//===----------------------------------------------------------------------===//
#include "Function.h"
-#include "Program.h"
#include "Opcode.h"
+#include "Program.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/Builtins.h"
using namespace clang;
using namespace clang::interp;
@@ -47,3 +48,9 @@ bool Function::isVirtual() const {
return M->isVirtual();
return false;
}
+
+bool Function::needsRuntimeArgPop(const ASTContext &Ctx) const {
+ if (!isBuiltin())
+ return false;
+ return Ctx.BuiltinInfo.hasCustomTypechecking(getBuiltinID());
+}
diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index 644d4cd53b1e19..5444c9f59cda7e 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -171,6 +171,12 @@ class Function final {
unsigned getBuiltinID() const { return F->getBuiltinID(); }
+ bool isBuiltin() const { return F->getBuiltinID() != 0; }
+
+ /// Does this function need its arguments to be classified at runtime
+ /// rather than at bytecode-compile-time?
+ bool needsRuntimeArgPop(const ASTContext &Ctx) const;
+
unsigned getNumParams() const { return ParamTypes.size(); }
unsigned getParamOffset(unsigned ParamIndex) const {
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index b891306e6aa405..2b7f3bf35aa598 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -122,6 +122,19 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
namespace clang {
namespace interp {
+bool popBuiltinArgs(InterpState &S, CodePtr OpPC) {
+ assert(S.Current && S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()));
+ const Expr *E = S.Current->getExpr(OpPC);
+ assert(isa<CallExpr>(E));
+ const CallExpr *CE = cast<CallExpr>(E);
+ for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
+ const Expr *A = CE->getArg(I);
+ PrimType Ty = S.getContext().classify(A->getType()).value_or(PT_Ptr);
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+ }
+ return true;
+}
+
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 9eae79ba5d1e7a..4da5985e3b3d6f 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -181,6 +181,9 @@ enum class ArithOp { Add, Sub };
// Returning values
//===----------------------------------------------------------------------===//
+/// Pop arguments of builtins defined as func-name(...).
+bool popBuiltinArgs(InterpState &S, CodePtr OpPC);
+
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
const T &Ret = S.Stk.pop<T>();
@@ -197,8 +200,16 @@ bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
}
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
- if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
- S.Current->popArgs();
+ if (!S.checkingPotentialConstantExpression() || S.Current->Caller) {
+ // Certain builtin functions are declared as func-name(...), so the
+ // parameters are checked in Sema and only available through the CallExpr.
+ // The interp::Function we create for them has 0 parameters, so we need to
+ // remove them from the stack by checking the CallExpr.
+ if (S.Current && S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()))
+ popBuiltinArgs(S, PC);
+ else
+ S.Current->popArgs();
+ }
if (InterpFrame *Caller = S.Current->Caller) {
PC = S.Current->getRetPC();
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index b023d09df48784..01c41339bba8c8 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -162,6 +162,17 @@ static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC,
return true;
}
+/// Defined as __builtin_isnan(...), to accommodate the fact that it can
+/// take a float, double, long double, etc.
+/// But for us, that's all a Floating anyway.
+static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame, const Function *F) {
+ const Floating &Arg = S.Stk.peek<Floating>();
+
+ S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Arg.isNan()));
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
InterpFrame *Frame = S.Current;
APValue Dummy;
@@ -223,6 +234,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
return Ret<PT_Float>(S, OpPC, Dummy);
break;
+ case Builtin::BI__builtin_isnan:
+ if (interp__builtin_isnan(S, OpPC, Frame, F))
+ return Ret<PT_Sint32>(S, OpPC, Dummy);
+ break;
+
default:
return false;
}
diff --git a/clang/test/Sema/constant-builtins-fmin.cpp b/clang/test/Sema/constant-builtins-fmin.cpp
index bf3e81e21e6179..8c80f7550666ea 100644
--- a/clang/test/Sema/constant-builtins-fmin.cpp
+++ b/clang/test/Sema/constant-builtins-fmin.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics
constexpr double NaN = __builtin_nan("");
More information about the cfe-commits
mailing list