[clang] Revert "[clang][bytecode] Use tailcalls via `[[clang::musttail]]`" (PR #188032)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 23 05:55:18 PDT 2026
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 <tbaeder at redhat.com>
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";
}
More information about the cfe-commits
mailing list