diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -145,10 +145,58 @@ /// Interpreter entry point. bool Interpret(InterpState &S, APValue &Result); -bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID); +/// Interpret a builtin function. +bool InterpretBuiltin(InterpState &S, CodePtr &PC, unsigned BuiltinID); enum class ArithOp { Add, Sub }; +//===----------------------------------------------------------------------===// +// Returning values +//===----------------------------------------------------------------------===// + +template ::T> +bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { + S.CallStackDepth--; + const T &Ret = S.Stk.pop(); + + assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); + if (Builtin || !S.checkingPotentialConstantExpression()) + S.Current->popArgs(); + + if (InterpFrame *Caller = S.Current->Caller) { + PC = S.Current->getRetPC(); + delete S.Current; + S.Current = Caller; + S.Stk.push(Ret); + } else { + delete S.Current; + S.Current = nullptr; + if (!ReturnValue(Ret, Result)) + return false; + } + return true; +} + +template +inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { + S.CallStackDepth--; + + assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); + if (Builtin || !S.checkingPotentialConstantExpression()) + S.Current->popArgs(); + + if (InterpFrame *Caller = S.Current->Caller) { + PC = S.Current->getRetPC(); + delete S.Current; + S.Current = Caller; + } else { + delete S.Current; + S.Current = nullptr; + } + return true; +} + //===----------------------------------------------------------------------===// // Add, Sub, Mul //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -26,51 +26,6 @@ using namespace clang; using namespace clang::interp; -//===----------------------------------------------------------------------===// -// Ret -//===----------------------------------------------------------------------===// - -template ::T> -static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { - S.CallStackDepth--; - const T &Ret = S.Stk.pop(); - - assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); - if (!S.checkingPotentialConstantExpression()) - S.Current->popArgs(); - - if (InterpFrame *Caller = S.Current->Caller) { - PC = S.Current->getRetPC(); - delete S.Current; - S.Current = Caller; - S.Stk.push(Ret); - } else { - delete S.Current; - S.Current = nullptr; - if (!ReturnValue(Ret, Result)) - return false; - } - return true; -} - -static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { - S.CallStackDepth--; - - assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); - if (!S.checkingPotentialConstantExpression()) - S.Current->popArgs(); - - if (InterpFrame *Caller = S.Current->Caller) { - PC = S.Current->getRetPC(); - delete S.Current; - S.Current = Caller; - } else { - delete S.Current; - S.Current = nullptr; - } - return true; -} - static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) { llvm::report_fatal_error("Interpreter cannot return values"); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -13,35 +13,17 @@ 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(); +bool InterpretBuiltin(InterpState &S, CodePtr &PC, unsigned BuiltinID) { + APValue Dummy; - 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 Ret(S, PC, Dummy); + case Builtin::BI__builtin_assume: + return RetVoid(S, PC, Dummy); + default: + return false; } return false; diff --git a/clang/test/AST/Interp/builtins.cpp b/clang/test/AST/Interp/builtins.cpp --- a/clang/test/AST/Interp/builtins.cpp +++ b/clang/test/AST/Interp/builtins.cpp @@ -22,3 +22,10 @@ bool is_this_constant() { return __builtin_is_constant_evaluated(); // CHECK: ret i1 false } + +constexpr bool assume() { + __builtin_assume(true); + __builtin_assume(false); + return true; +} +static_assert(assume(), "");