Index: clang/lib/AST/CMakeLists.txt =================================================================== --- clang/lib/AST/CMakeLists.txt +++ clang/lib/AST/CMakeLists.txt @@ -73,6 +73,7 @@ Interp/Frame.cpp Interp/Function.cpp Interp/Floating.cpp + Interp/InterpBuiltin.cpp Interp/Interp.cpp Interp/InterpBlock.cpp Interp/InterpFrame.cpp Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1370,10 +1370,8 @@ template bool ByteCodeExprGen::VisitCallExpr(const CallExpr *E) { - assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet"); - const Decl *Callee = E->getCalleeDecl(); - if (const auto *FuncDecl = dyn_cast_or_null(Callee)) { + if (const auto *FuncDecl = dyn_cast_if_present(Callee)) { const Function *Func = getFunction(FuncDecl); if (!Func) return false; Index: clang/lib/AST/Interp/Function.h =================================================================== --- clang/lib/AST/Interp/Function.h +++ clang/lib/AST/Interp/Function.h @@ -138,6 +138,8 @@ // Checks if the funtion already has a body attached. bool hasBody() const { return HasBody; } + unsigned getBuiltinID() const { return F->getBuiltinID(); } + unsigned getNumParams() const { return ParamTypes.size(); } private: Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -110,6 +110,8 @@ /// Interpreter entry point. bool Interpret(InterpState &S, APValue &Result); +bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID); + enum class ArithOp { Add, Sub }; //===----------------------------------------------------------------------===// @@ -1349,21 +1351,29 @@ InterpFrame *FrameBefore = S.Current; S.Current = NewFrame.get(); - APValue CallResult; - // Note that we cannot assert(CallResult.hasValue()) here since - // Ret() above only sets the APValue if the curent frame doesn't - // have a caller set. - if (Interpret(S, CallResult)) { - NewFrame.release(); // Frame was delete'd already. - assert(S.Current == FrameBefore); - - // For constructors, check that all fields have been initialized. - if (Func->isConstructor()) { - if (!CheckCtorCall(S, PC, ThisPtr)) - return false; + // Evaluate builtin functions directly. + if (unsigned BID = Func->getBuiltinID()) { + if (InterpretBuiltin(S, PC, BID)) { + NewFrame.release(); + return true; } + } else { + APValue CallResult; + // Note that we cannot assert(CallResult.hasValue()) here since + // Ret() above only sets the APValue if the curent frame doesn't + // have a caller set. + if (Interpret(S, CallResult)) { + NewFrame.release(); // Frame was delete'd already. + assert(S.Current == FrameBefore); + + // For constructors, check that all fields have been initialized. + if (Func->isConstructor()) { + if (!CheckCtorCall(S, PC, ThisPtr)) + return false; + } - return true; + return true; + } } // Interpreting the function failed somehow. Reset to Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -349,6 +349,11 @@ } } + // Builtin functions are always fine, provided we implement them, which + // we will check later. + if (F->getBuiltinID()) + return true; + if (!F->isConstexpr()) { const SourceLocation &Loc = S.Current->getLocation(OpPC); if (S.getLangOpts().CPlusPlus11) { Index: clang/lib/AST/Interp/InterpBuiltin.cpp =================================================================== --- /dev/null +++ clang/lib/AST/Interp/InterpBuiltin.cpp @@ -0,0 +1,51 @@ +//===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "Boolean.h" +#include "Interp.h" +#include "PrimType.h" +#include "clang/Basic/Builtins.h" + +namespace clang { +namespace interp { + +/// This is a slightly simplified version of the Ret() we have in Interp.cpp +/// If they end up diverging in the future, we should get rid of the code +/// duplication. +template ::T> +static bool Ret(InterpState &S, CodePtr &PC) { + S.CallStackDepth--; + const T &Ret = S.Stk.pop(); + + assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); + if (!S.checkingPotentialConstantExpression()) + S.Current->popArgs(); + + InterpFrame *Caller = S.Current->Caller; + assert(Caller); + + PC = S.Current->getRetPC(); + delete S.Current; + S.Current = Caller; + S.Stk.push(Ret); + + return true; +} + +bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID) { + switch (BuiltinID) { + case Builtin::BI__builtin_is_constant_evaluated: + S.Stk.push(Boolean::from(S.inConstantContext())); + Ret(S, PC); + return true; + } + + return false; +} + +} // namespace interp +} // namespace clang Index: clang/test/AST/Interp/builtins.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/builtins.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -S -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated +// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated +// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated -S -emit-llvm -o - | FileCheck %s + +// expected-no-diagnostics +// ref-no-diagnostics + +using size_t = decltype(sizeof(int)); + +namespace std { +inline constexpr bool is_constant_evaluated() noexcept { + return __builtin_is_constant_evaluated(); +} +} // namespace std + +constexpr bool b = std::is_constant_evaluated(); +static_assert(b, ""); +static_assert(std::is_constant_evaluated() , ""); + + +bool is_this_constant() { + return __builtin_is_constant_evaluated(); // CHECK: ret i1 false +}