https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/188032
Reverts llvm/llvm-project#173756 Looks like that wasn't enough and we need to disable tail calls on Windows generally. >From 51cad800c9dd5cc13d1ba40a5a9fcb20f1640586 Mon Sep 17 00:00:00 2001 From: Timm Baeder <[email protected]> Date: Mon, 23 Mar 2026 13:54:34 +0100 Subject: [PATCH] Revert "[clang][bytecode] Use tailcalls via `[[clang::musttail]]` (#173756)" This reverts commit fdd00d2555a7d9a7c4d6c5c52e90bc5c157bd01f. --- clang/lib/AST/ByteCode/Compiler.cpp | 6 +- clang/lib/AST/ByteCode/EvalEmitter.cpp | 5 - clang/lib/AST/ByteCode/Interp.cpp | 243 +++++++------------ clang/lib/AST/ByteCode/Interp.h | 50 +--- clang/lib/AST/ByteCode/InterpState.h | 3 - clang/lib/AST/ByteCode/Opcodes.td | 3 - clang/test/SemaCXX/cxx2b-deducing-this.cpp | 1 - clang/test/SemaTemplate/stack-exhaustion.cpp | 4 - clang/utils/TableGen/ClangOpcodesEmitter.cpp | 135 ++++------- 9 files changed, 151 insertions(+), 299 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index c38eb0fa93877..642a59cf75642 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2819,7 +2819,7 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator( LabelTy LabelFalse = this->getLabel(); // Label for the false expr. if (IsBcpCall) { - if (!this->emitPushIgnoreDiags(E)) + if (!this->emitStartSpeculation(E)) return false; } @@ -2851,7 +2851,7 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator( this->emitLabel(LabelEnd); if (IsBcpCall) - return this->emitPopIgnoreDiags(E); + return this->emitEndSpeculation(E); return true; } @@ -5417,9 +5417,9 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, LabelTy EndLabel = this->getLabel(); if (!this->speculate(E, EndLabel)) return false; + this->fallthrough(EndLabel); if (!this->emitEndSpeculation(E)) return false; - this->fallthrough(EndLabel); if (DiscardResult) return this->emitPop(classifyPrim(E), E); return true; diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 8e8ffc131814b..3cfc1de1ff35e 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -11,7 +11,6 @@ #include "IntegralAP.h" #include "Interp.h" #include "clang/AST/DeclCXX.h" -#include "llvm/ADT/ScopeExit.h" using namespace clang; using namespace clang::interp; @@ -162,10 +161,6 @@ bool EvalEmitter::fallthrough(const LabelTy &Label) { bool EvalEmitter::speculate(const CallExpr *E, const LabelTy &EndLabel) { if (!isActive()) return true; - - PushIgnoreDiags(S, OpPC); - auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, OpPC); }); - size_t StackSizeBefore = S.Stk.size(); const Expr *Arg = E->getArg(0); if (!this->visit(Arg)) { diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 6e7a60d5e4332..1b6b785b58757 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -28,23 +28,7 @@ using namespace clang; using namespace clang::interp; -#if __has_cpp_attribute(clang::musttail) -#define MUSTTAIL [[clang::musttail]] -#elif __has_cpp_attribute(msvc::musttail) -#define MUSTTAIL [[msvc::musttail]] -#elif __has_attribute(musttail) -#define MUSTTAIL __attribute__((musttail)) -#endif - -// On MSVC, musttail does not guarantee tail calls in debug mode. -#if (defined(_MSC_VER) && defined(_DEBUG)) || !defined(MUSTTAIL) -#define MUSTTAIL -#define USE_TAILCALLS 0 -#else -#define USE_TAILCALLS 1 -#endif - -PRESERVE_NONE static bool RetValue(InterpState &S, CodePtr &Ptr) { +static bool RetValue(InterpState &S, CodePtr &Pt) { llvm::report_fatal_error("Interpreter cannot return values"); } @@ -71,6 +55,76 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { return S.noteStep(PC); } +// https://github.com/llvm/llvm-project/issues/102513 +#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) +#pragma optimize("", off) +#endif +// FIXME: We have the large switch over all opcodes here again, and in +// Interpret(). +static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) { + [[maybe_unused]] CodePtr PCBefore = RealPC; + size_t StackSizeBefore = S.Stk.size(); + + auto SpeculativeInterp = [&S, RealPC]() -> bool { + const InterpFrame *StartFrame = S.Current; + CodePtr PC = RealPC; + + for (;;) { + auto Op = PC.read<Opcode>(); + if (Op == OP_EndSpeculation) + return true; + CodePtr OpPC = PC; + + switch (Op) { +#define GET_INTERP +#include "Opcodes.inc" +#undef GET_INTERP + } + } + llvm_unreachable("We didn't see an EndSpeculation op?"); + }; + + if (SpeculativeInterp()) { + if (PT == PT_Ptr) { + const auto &Ptr = S.Stk.pop<Pointer>(); + assert(S.Stk.size() == StackSizeBefore); + S.Stk.push<Integral<32, true>>( + Integral<32, true>::from(CheckBCPResult(S, Ptr))); + } else { + // Pop the result from the stack and return success. + TYPE_SWITCH(PT, S.Stk.pop<T>();); + assert(S.Stk.size() == StackSizeBefore); + S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1)); + } + } else { + if (!S.inConstantContext()) + return Invalid(S, RealPC); + + S.Stk.clearTo(StackSizeBefore); + S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0)); + } + + // RealPC should not have been modified. + assert(*RealPC == *PCBefore); + + // Jump to end label. This is a little tricker than just RealPC += Offset + // because our usual jump instructions don't have any arguments, to the offset + // we get is a little too much and we need to subtract the size of the + // bool and PrimType arguments again. + int32_t ParamSize = align(sizeof(PrimType)); + assert(Offset >= ParamSize); + RealPC += Offset - ParamSize; + + [[maybe_unused]] CodePtr PCCopy = RealPC; + assert(PCCopy.read<Opcode>() == OP_EndSpeculation); + + return true; +} +// https://github.com/llvm/llvm-project/issues/102513 +#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) +#pragma optimize("", on) +#endif + static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD) { const SourceInfo &E = S.Current->getSource(OpPC); @@ -204,9 +258,6 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { namespace clang { namespace interp { -PRESERVE_NONE static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, - PrimType PT); - static void popArg(InterpState &S, const Expr *Arg) { PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr); TYPE_SWITCH(Ty, S.Stk.discard<T>()); @@ -2531,156 +2582,38 @@ bool CastMemberPtrDerivedPop(InterpState &S, CodePtr OpPC, int32_t Off, return castBackMemberPointer(S, Ptr, Off, BaseDecl); } -// FIXME: Would be nice to generate this instead of hardcoding it here. -constexpr bool OpReturns(Opcode Op) { - return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet || - Op == OP_RetSint8 || Op == OP_RetUint8 || Op == OP_RetSint16 || - Op == OP_RetUint16 || Op == OP_RetSint32 || Op == OP_RetUint32 || - Op == OP_RetSint64 || Op == OP_RetUint64 || Op == OP_RetIntAP || - Op == OP_RetIntAPS || Op == OP_RetBool || Op == OP_RetFixedPoint || - Op == OP_RetPtr || Op == OP_RetMemberPtr || Op == OP_RetFloat || - Op == OP_EndSpeculation; -} - -#if USE_TAILCALLS -PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC); +// https://github.com/llvm/llvm-project/issues/102513 +#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) +#pragma optimize("", off) #endif - -// The dispatcher functions read the opcode arguments from the -// bytecode and call the implementation function. -#define GET_INTERPFN_DISPATCHERS -#include "Opcodes.inc" -#undef GET_INTERPFN_DISPATCHERS - -using InterpFn = bool (*)(InterpState &, CodePtr &PC) PRESERVE_NONE; -// Array of the dispatcher functions defined above. -const InterpFn InterpFunctions[] = { -#define GET_INTERPFN_LIST -#include "Opcodes.inc" -#undef GET_INTERPFN_LIST -}; - -#if USE_TAILCALLS -// Read the next opcode and call the dispatcher function. -PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC) { - auto Op = PC.read<Opcode>(); - auto Fn = InterpFunctions[Op]; - MUSTTAIL return Fn(S, PC); -} -#endif - bool Interpret(InterpState &S) { // The current stack frame when we started Interpret(). // This is being used by the ops to determine wheter // to return from this function and thus terminate // interpretation. + const InterpFrame *StartFrame = S.Current; assert(!S.Current->isRoot()); CodePtr PC = S.Current->getPC(); -#if USE_TAILCALLS - return InterpNext(S, PC); -#else - while (true) { - auto Op = PC.read<Opcode>(); - auto Fn = InterpFunctions[Op]; - - if (!Fn(S, PC)) - return false; - if (OpReturns(Op)) - break; - } - return true; -#endif -} - -/// This is used to implement speculative execution via __builtin_constant_p -/// when we generate bytecode. -/// -/// The setup here is that we use the same tailcall mechanism for speculative -/// evaluation that we use for the regular one. -/// Since each speculative execution ends with an EndSpeculation opcode, -/// that one does NOT call InterpNext() but simply returns true. -/// This way, we return back to this function when we see an EndSpeculation, -/// OR (of course), when we encounter an error and one of the opcodes -/// returns false. -PRESERVE_NONE static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, - PrimType PT) { - [[maybe_unused]] CodePtr PCBefore = RealPC; - size_t StackSizeBefore = S.Stk.size(); - - // Speculation depth must be at least 1 here, since we must have - // passed a StartSpeculation op before. -#ifndef NDEBUG - [[maybe_unused]] unsigned DepthBefore = S.SpeculationDepth; - assert(DepthBefore >= 1); -#endif - - CodePtr PC = RealPC; - auto SpeculativeInterp = [&S, &PC]() -> bool { - // Ignore diagnostics during speculative execution. - PushIgnoreDiags(S, PC); - auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, PC); }); + // Empty program. + if (!PC) + return true; -#if USE_TAILCALLS + for (;;) { auto Op = PC.read<Opcode>(); - auto Fn = InterpFunctions[Op]; - return Fn(S, PC); -#else - while (true) { - auto Op = PC.read<Opcode>(); - auto Fn = InterpFunctions[Op]; + CodePtr OpPC = PC; - if (!Fn(S, PC)) - return false; - if (OpReturns(Op)) - break; - } - return true; -#endif - }; - - if (SpeculativeInterp()) { - // Speculation must've ended naturally via a EndSpeculation opcode. - assert(S.SpeculationDepth == DepthBefore - 1); - if (PT == PT_Ptr) { - const auto &Ptr = S.Stk.pop<Pointer>(); - assert(S.Stk.size() == StackSizeBefore); - S.Stk.push<Integral<32, true>>( - Integral<32, true>::from(CheckBCPResult(S, Ptr))); - } else { - // Pop the result from the stack and return success. - TYPE_SWITCH(PT, S.Stk.discard<T>();); - assert(S.Stk.size() == StackSizeBefore); - S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1)); + switch (Op) { +#define GET_INTERP +#include "Opcodes.inc" +#undef GET_INTERP } - } else { - // End the speculation manually since we didn't call EndSpeculation - // naturally. - EndSpeculation(S, RealPC); - - if (!S.inConstantContext()) - return Invalid(S, RealPC); - - S.Stk.clearTo(StackSizeBefore); - S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0)); } - - // RealPC should not have been modified. - assert(*RealPC == *PCBefore); - - // We have already evaluated this speculation's EndSpeculation opcode. - assert(S.SpeculationDepth == DepthBefore - 1); - - // Jump to end label. This is a little tricker than just RealPC += Offset - // because our usual jump instructions don't have any arguments, to the offset - // we get is a little too much and we need to subtract the size of the - // bool and PrimType arguments again. - int32_t ParamSize = align(sizeof(PrimType)); - assert(Offset >= ParamSize); - RealPC += Offset - ParamSize; - - return true; } +// https://github.com/llvm/llvm-project/issues/102513 +#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) +#pragma optimize("", on) +#endif } // namespace interp } // namespace clang diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 0646b87f9412c..eb41021bcf7cf 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -33,15 +33,8 @@ #include "clang/AST/Expr.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/ScopeExit.h" #include <type_traits> -#if __has_cpp_attribute(clang::preserve_none) -#define PRESERVE_NONE [[clang::preserve_none]] -#else -#define PRESERVE_NONE -#endif - namespace clang { namespace interp { @@ -240,7 +233,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func); template <PrimType Name, class T = typename PrimConv<Name>::T> -PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC) { +bool Ret(InterpState &S, CodePtr &PC) { const T &Ret = S.Stk.pop<T>(); assert(S.Current); @@ -259,11 +252,10 @@ PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC) { // The topmost frame should come from an EvalEmitter, // which has its own implementation of the Ret<> instruction. } - return true; } -PRESERVE_NONE inline bool RetVoid(InterpState &S, CodePtr &PC) { +inline bool RetVoid(InterpState &S, CodePtr &PC) { assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); if (!S.checkingPotentialConstantExpression() || S.Current->Caller) @@ -277,7 +269,6 @@ PRESERVE_NONE inline bool RetVoid(InterpState &S, CodePtr &PC) { InterpFrame::free(S.Current); S.Current = nullptr; } - return true; } @@ -3091,7 +3082,8 @@ static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) { //===----------------------------------------------------------------------===// // NoRet //===----------------------------------------------------------------------===// -PRESERVE_NONE inline bool NoRet(InterpState &S, CodePtr OpPC) { + +inline bool NoRet(InterpState &S, CodePtr OpPC) { SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); S.FFDiag(EndLoc, diag::note_constexpr_no_return); return false; @@ -3312,45 +3304,27 @@ inline bool Unsupported(InterpState &S, CodePtr OpPC) { return false; } -inline bool PushIgnoreDiags(InterpState &S, CodePtr OpPC) { - ++S.DiagIgnoreDepth; - if (S.DiagIgnoreDepth != 1) +inline bool StartSpeculation(InterpState &S, CodePtr OpPC) { + ++S.SpeculationDepth; + if (S.SpeculationDepth != 1) return true; + assert(S.PrevDiags == nullptr); S.PrevDiags = S.getEvalStatus().Diag; S.getEvalStatus().Diag = nullptr; - assert(!S.diagnosing()); return true; } -inline bool PopIgnoreDiags(InterpState &S, CodePtr OpPC) { - assert(S.DiagIgnoreDepth != 0); - --S.DiagIgnoreDepth; - if (S.DiagIgnoreDepth == 0) { +inline bool EndSpeculation(InterpState &S, CodePtr OpPC) { + assert(S.SpeculationDepth != 0); + --S.SpeculationDepth; + if (S.SpeculationDepth == 0) { S.getEvalStatus().Diag = S.PrevDiags; S.PrevDiags = nullptr; } return true; } -inline bool StartSpeculation(InterpState &S, CodePtr OpPC) { -#ifndef NDEBUG - ++S.SpeculationDepth; -#endif - return true; -} - -// This is special-cased in the tablegen opcode emitter. -// Its dispatch function will NOT call InterpNext -// and instead simply return true. -PRESERVE_NONE inline bool EndSpeculation(InterpState &S, CodePtr &OpPC) { -#ifndef NDEBUG - assert(S.SpeculationDepth != 0); - --S.SpeculationDepth; -#endif - return true; -} - inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) { S.ConstantContextOverride = Value; return true; diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 499a21a094e2c..8ed92432f1c7e 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -164,10 +164,7 @@ class InterpState final : public State, public SourceMapper { /// Things needed to do speculative execution. SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr; -#ifndef NDEBUG unsigned SpeculationDepth = 0; -#endif - unsigned DiagIgnoreDepth = 0; std::optional<bool> ConstantContextOverride; llvm::SmallVector< diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 5fbd35950c0eb..da3b850945499 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -178,9 +178,6 @@ def Jt : JumpOpcode; // [Bool] -> [], jumps if false. def Jf : JumpOpcode; -def PushIgnoreDiags : Opcode; -def PopIgnoreDiags : Opcode; - def StartSpeculation : Opcode; def EndSpeculation : Opcode; def BCP : Opcode { diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index b86731c7d7a11..efa5e06f8a32c 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++2b -Woverloaded-virtual %s -verify -// RUN: %clang_cc1 -fsyntax-only -std=c++2b -Woverloaded-virtual %s -verify -fexperimental-new-constant-interpreter // FIXME: can we improve these diagnostics? diff --git a/clang/test/SemaTemplate/stack-exhaustion.cpp b/clang/test/SemaTemplate/stack-exhaustion.cpp index 61014c7724ce2..c7bfea4132d5e 100644 --- a/clang/test/SemaTemplate/stack-exhaustion.cpp +++ b/clang/test/SemaTemplate/stack-exhaustion.cpp @@ -1,10 +1,6 @@ // RUN: %clang_cc1 -verify %s -DTEST=1 // RUN: %clang_cc1 -verify %s -DTEST=2 // RUN: %clang_cc1 -verify %s -DTEST=3 -// RUN: %clang_cc1 -verify %s -DTEST=1 -fexperimental-new-constant-interpreter -// RUN: %clang_cc1 -verify %s -DTEST=2 -fexperimental-new-constant-interpreter -// RUN: %clang_cc1 -verify %s -DTEST=3 -fexperimental-new-constant-interpreter - // REQUIRES: thread_support // FIXME: Detection of, or recovery from, stack exhaustion does not work on diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp index 3192891801ae9..d26122aca46bd 100644 --- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp +++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp @@ -34,8 +34,8 @@ class ClangOpcodesEmitter { /// The name is obtained by concatenating the name with the list of types. void EmitEnum(raw_ostream &OS, StringRef N, const Record *R); - void EmitInterpFnList(raw_ostream &OS, StringRef N, const Record *R); - void EmitInterpFnDispatchers(raw_ostream &OS, StringRef N, const Record *R); + /// Emits the switch case and the invocation in the interpreter. + void EmitInterp(raw_ostream &OS, StringRef N, const Record *R); /// Emits the disassembler. void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R); @@ -91,8 +91,7 @@ void ClangOpcodesEmitter::run(raw_ostream &OS) { N = Opcode->getName(); EmitEnum(OS, N, Opcode); - EmitInterpFnList(OS, N, Opcode); - EmitInterpFnDispatchers(OS, N, Opcode); + EmitInterp(OS, N, Opcode); EmitDisasm(OS, N, Opcode); EmitProto(OS, N, Opcode); EmitGroup(OS, N, Opcode); @@ -110,98 +109,60 @@ void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, OS << "#endif\n"; } -void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N, - const Record *R) { - OS << "#ifdef GET_INTERPFN_DISPATCHERS\n"; - // PRESERVE NONE static bool Interp_* (InterpState &S, CodePtr &PC) { - Enumerate(R, N, [&](ArrayRef<const Record *> TS, const Twine &ID) { - OS << "PRESERVE_NONE\nstatic bool Interp_" << ID - << "(InterpState &S, CodePtr &PC) {\n"; - - if (ID.str() == "EndSpeculation") { - OS << " MUSTTAIL return EndSpeculation(S, PC);\n"; - OS << "}\n"; - return; - } - - bool CanReturn = R->getValueAsBit("CanReturn"); - const auto &Args = R->getValueAsListOfDefs("Args"); - bool ChangesPC = R->getValueAsBit("ChangesPC"); - - if (Args.empty()) { - if (CanReturn) { - OS << " MUSTTAIL return " << N; - PrintTypes(OS, TS); - OS << "(S, PC);\n"; - OS << "}\n"; - return; - } - - OS << " if (!" << N; - PrintTypes(OS, TS); - OS << "(S, PC))\n"; - OS << " return false;\n"; - OS << "#if USE_TAILCALLS\n"; - OS << " MUSTTAIL return InterpNext(S, PC);\n"; - OS << "#else\n"; - OS << " return true;\n"; - OS << "#endif\n"; - OS << "}\n"; - return; - } +void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, + const Record *R) { + OS << "#ifdef GET_INTERP\n"; - OS << " {\n"; + Enumerate(R, N, + [this, R, &OS, &N](ArrayRef<const Record *> TS, const Twine &ID) { + bool CanReturn = R->getValueAsBit("CanReturn"); + bool ChangesPC = R->getValueAsBit("ChangesPC"); + const auto &Args = R->getValueAsListOfDefs("Args"); - if (!ChangesPC) - OS << " CodePtr OpPC = PC;\n"; + OS << "case OP_" << ID << ": {\n"; - // Emit calls to read arguments. - for (size_t I = 0, N = Args.size(); I < N; ++I) { - const auto *Arg = Args[I]; - bool AsRef = Arg->getValueAsBit("AsRef"); + if (CanReturn) + OS << " bool DoReturn = (S.Current == StartFrame);\n"; - if (AsRef) - OS << " const auto &V" << I; - else - OS << " const auto V" << I; - OS << " = "; - OS << "ReadArg<" << Arg->getValueAsString("Name") << ">(S, PC);\n"; - } + // Emit calls to read arguments. + for (size_t I = 0, N = Args.size(); I < N; ++I) { + const auto *Arg = Args[I]; + bool AsRef = Arg->getValueAsBit("AsRef"); - OS << " if (!" << N; - PrintTypes(OS, TS); - OS << "(S"; - if (ChangesPC) - OS << ", PC"; - else - OS << ", OpPC"; - for (size_t I = 0, N = Args.size(); I < N; ++I) - OS << ", V" << I; - OS << "))\n"; - OS << " return false;\n"; + if (AsRef) + OS << " const auto &V" << I; + else + OS << " const auto V" << I; + OS << " = "; + OS << "ReadArg<" << Arg->getValueAsString("Name") + << ">(S, PC);\n"; + } - OS << " }\n"; + // Emit a call to the template method and pass arguments. + OS << " if (!" << N; + PrintTypes(OS, TS); + OS << "(S"; + if (ChangesPC) + OS << ", PC"; + else + OS << ", OpPC"; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << ", V" << I; + OS << "))\n"; + OS << " return false;\n"; - if (!CanReturn) { - OS << "#if USE_TAILCALLS\n"; - OS << " MUSTTAIL return InterpNext(S, PC);\n"; - OS << "#else\n"; - OS << " return true;\n"; - OS << "#endif\n"; - } else - OS << " return true;\n"; + // Bail out if interpreter returned. + if (CanReturn) { + OS << " if (!S.Current || S.Current->isRoot())\n"; + OS << " return true;\n"; - OS << "}\n"; - }); - OS << "#endif\n"; -} + OS << " if (DoReturn)\n"; + OS << " return true;\n"; + } -void ClangOpcodesEmitter::EmitInterpFnList(raw_ostream &OS, StringRef N, - const Record *R) { - OS << "#ifdef GET_INTERPFN_LIST\n"; - Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) { - OS << "&Interp_" << ID << ",\n"; - }); + OS << " continue;\n"; + OS << "}\n"; + }); OS << "#endif\n"; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
