[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
This commit is contained in:
parent
7dbc7b18a0
commit
ff80fc0ea2
@ -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());
|
||||
}
|
||||
|
||||
@ -171,6 +171,12 @@ public:
|
||||
|
||||
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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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("");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user