llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> Instead of using a local variable for the PC, save it in `InterpState`. Only comparatively few opcodes care about it, but with exceptions, all calls ops can change the PC. Saving it in the `InterpState` makes it easier to have opcode implementation jump around in bytecode. --- Patch is 22.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207393.diff 11 Files Affected: - (modified) clang/lib/AST/ByteCode/Interp.cpp (+47-69) - (modified) clang/lib/AST/ByteCode/Interp.h (+9-10) - (modified) clang/lib/AST/ByteCode/InterpFrame.cpp (+7-7) - (modified) clang/lib/AST/ByteCode/InterpFrame.h (+8-3) - (modified) clang/lib/AST/ByteCode/InterpStack.cpp (+6) - (modified) clang/lib/AST/ByteCode/InterpStack.h (+1) - (modified) clang/lib/AST/ByteCode/InterpState.cpp (+1-1) - (modified) clang/lib/AST/ByteCode/InterpState.h (+1) - (modified) clang/lib/AST/ByteCode/Opcodes.td (-6) - (modified) clang/lib/AST/ByteCode/Source.h (+2) - (modified) clang/utils/TableGen/ClangOpcodesEmitter.cpp (+20-21) ``````````diff diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 4815828adb613..dc93cc4fd698c 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -49,7 +49,7 @@ using namespace clang::interp; #define USE_TAILCALLS 1 #endif -PRESERVE_NONE static bool RetValue(InterpState &S, CodePtr &Ptr) { +PRESERVE_NONE static bool RetValue(InterpState &S) { llvm::report_fatal_error("Interpreter cannot return values"); } @@ -57,23 +57,23 @@ PRESERVE_NONE static bool RetValue(InterpState &S, CodePtr &Ptr) { // Jmp, Jt, Jf //===----------------------------------------------------------------------===// -static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) { - PC += Offset; - return S.noteStep(PC); +static bool Jmp(InterpState &S, CodePtr OpPC, int32_t Offset) { + S.PC += Offset; + return S.noteStep(OpPC); } -static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) { +static bool Jt(InterpState &S, CodePtr OpPC, int32_t Offset) { if (S.Stk.pop<bool>()) { - PC += Offset; - return S.noteStep(PC); + S.PC += Offset; + return S.noteStep(OpPC); } return true; } -static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { +static bool Jf(InterpState &S, CodePtr OpPC, int32_t Offset) { if (!S.Stk.pop<bool>()) { - PC += Offset; - return S.noteStep(PC); + S.PC += Offset; + return S.noteStep(OpPC); } return true; } @@ -234,43 +234,20 @@ 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, +PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, 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>()); -} - -void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, - const Function *Func) { +void cleanupAfterFunctionCall(InterpState &S, const Function *Func) { assert(S.Current); assert(Func); + // Pop variadic parameter values from the stack. if (S.Current->Caller && Func->isVariadic()) { - // CallExpr we're look for is at the return PC of the current function, i.e. - // in the caller. - // This code path should be executed very rarely. - unsigned NumVarArgs; - const Expr *const *Args = nullptr; - unsigned NumArgs = 0; - const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC()); - if (const auto *CE = dyn_cast<CallExpr>(CallSite)) { - Args = CE->getArgs(); - NumArgs = CE->getNumArgs(); - } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) { - Args = CE->getArgs(); - NumArgs = CE->getNumArgs(); - } else - assert(false && "Can't get arguments from that expression type"); - - assert(NumArgs >= Func->getNumWrittenParams()); - NumVarArgs = NumArgs - (Func->getNumWrittenParams() + - (isa<CXXOperatorCallExpr>(CallSite) && - Func->hasImplicitThisParam())); - for (unsigned I = 0; I != NumVarArgs; ++I) { - const Expr *A = Args[NumArgs - 1 - I]; - popArg(S, A); + unsigned VariadicArgSize = + S.Current->getArgSize() - S.Current->getFunction()->getArgSize(); + unsigned TargetStackSize = S.Stk.size() - VariadicArgSize; + while (S.Stk.size() != TargetStackSize) { + S.Stk.discardSlow(); } } @@ -1847,7 +1824,7 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, return false; auto Memory = new char[InterpFrame::allocSize(Func)]; - auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize); + auto NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize); InterpFrame *FrameBefore = S.Current; S.Current = NewFrame; @@ -1872,7 +1849,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, assert(Func); auto cleanup = [&]() -> bool { - cleanupAfterFunctionCall(S, OpPC, Func); + cleanupAfterFunctionCall(S, Func); return false; }; @@ -1940,7 +1917,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, return cleanup(); auto Memory = new char[InterpFrame::allocSize(Func)]; - auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize); + auto NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize); InterpFrame *FrameBefore = S.Current; S.Current = NewFrame; @@ -3124,7 +3101,7 @@ constexpr bool OpReturns(Opcode Op) { } #if USE_TAILCALLS -PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC); +PRESERVE_NONE static bool InterpNext(InterpState &S); #endif // The dispatcher functions read the opcode arguments from the @@ -3133,7 +3110,7 @@ PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC); #include "Opcodes.inc" #undef GET_INTERPFN_DISPATCHERS -using InterpFn = bool (*)(InterpState &, CodePtr &PC) PRESERVE_NONE; +using InterpFn = bool (*)(InterpState &) PRESERVE_NONE; // Array of the dispatcher functions defined above. const InterpFn InterpFunctions[] = { #define GET_INTERPFN_LIST @@ -3143,10 +3120,10 @@ const InterpFn InterpFunctions[] = { #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>(); +PRESERVE_NONE static bool InterpNext(InterpState &S) { + auto Op = S.PC.read<Opcode>(); auto Fn = InterpFunctions[Op]; - MUSTTAIL return Fn(S, PC); + MUSTTAIL return Fn(S); } #endif @@ -3156,16 +3133,17 @@ bool Interpret(InterpState &S) { // to return from this function and thus terminate // interpretation. assert(!S.Current->isRoot()); - CodePtr PC = S.Current->getPC(); + + S.PC = S.Current->getFunction()->getCodeBegin(); #if USE_TAILCALLS - return InterpNext(S, PC); + return InterpNext(S); #else while (true) { - auto Op = PC.read<Opcode>(); + auto Op = S.PC.read<Opcode>(); auto Fn = InterpFunctions[Op]; - if (!Fn(S, PC)) + if (!Fn(S)) return false; if (OpReturns(Op)) break; @@ -3184,9 +3162,10 @@ bool Interpret(InterpState &S) { /// 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, +PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset, PrimType PT) { - [[maybe_unused]] CodePtr PCBefore = RealPC; + // PC after reading the BCP opcode and both Offset/PT arguments. + [[maybe_unused]] CodePtr PCBefore = S.PC; size_t StackSizeBefore = S.Stk.size(); // Speculation depth must be at least 1 here, since we must have @@ -3196,22 +3175,21 @@ PRESERVE_NONE static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, assert(DepthBefore >= 1); #endif - CodePtr PC = RealPC; - auto SpeculativeInterp = [&S, &PC]() -> bool { + auto SpeculativeInterp = [&S, OpPC]() -> bool { // Ignore diagnostics during speculative execution. - PushIgnoreDiags(S, PC); - auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, PC); }); + PushIgnoreDiags(S, OpPC); + auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, OpPC); }); #if USE_TAILCALLS - auto Op = PC.read<Opcode>(); + auto Op = S.PC.read<Opcode>(); auto Fn = InterpFunctions[Op]; - return Fn(S, PC); + return Fn(S); #else while (true) { - auto Op = PC.read<Opcode>(); + auto Op = S.PC.read<Opcode>(); auto Fn = InterpFunctions[Op]; - if (!Fn(S, PC)) + if (!Fn(S)) return false; if (OpReturns(Op)) break; @@ -3235,20 +3213,21 @@ PRESERVE_NONE static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1)); } } else { + // Jump to the end of the speculation, just after the actual EndSpeculation + // op. + S.PC = PCBefore + Offset - align(sizeof(Opcode)); + // End the speculation manually since we didn't call EndSpeculation // naturally. - EndSpeculation(S, RealPC); + EndSpeculation(S); if (!S.inConstantContext()) - return Invalid(S, RealPC); + return Invalid(S, OpPC); 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); @@ -3258,7 +3237,6 @@ PRESERVE_NONE static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, // bool and PrimType arguments again. int32_t ParamSize = align(sizeof(PrimType)); assert(Offset >= ParamSize); - RealPC += Offset - ParamSize; return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 84564d0a33cff..61c2b0a5e5960 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -254,11 +254,10 @@ enum class ArithOp { Add, Sub }; // Returning values //===----------------------------------------------------------------------===// -void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, - const Function *Func); +void cleanupAfterFunctionCall(InterpState &S, const Function *Func); template <PrimType Name, class T = typename PrimConv<Name>::T> -PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC) { +PRESERVE_NONE bool Ret(InterpState &S) { const T &Ret = S.Stk.pop<T>(); assert(S.Current); @@ -266,11 +265,12 @@ PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC) { #ifndef NDEBUG assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); #endif + if (!S.checkingPotentialConstantExpression() || S.Current->Caller) - cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); + cleanupAfterFunctionCall(S, S.Current->getFunction()); if (InterpFrame *Caller = S.Current->Caller) { - PC = S.Current->getRetPC(); + S.PC = S.Current->getRetPC(); InterpFrame::free(S.Current); S.Current = Caller; S.Stk.push<T>(Ret); @@ -284,17 +284,16 @@ PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC) { return true; } -PRESERVE_NONE inline bool RetVoid(InterpState &S, CodePtr &PC) { - +PRESERVE_NONE inline bool RetVoid(InterpState &S) { #ifndef NDEBUG assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); #endif if (!S.checkingPotentialConstantExpression() || S.Current->Caller) - cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); + cleanupAfterFunctionCall(S, S.Current->getFunction()); if (InterpFrame *Caller = S.Current->Caller) { - PC = S.Current->getRetPC(); + S.PC = S.Current->getRetPC(); InterpFrame::free(S.Current); S.Current = Caller; } else { @@ -3699,7 +3698,7 @@ inline bool EndInit(InterpState &S, CodePtr OpPC) { // 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) { +PRESERVE_NONE inline bool EndSpeculation(InterpState &S) { #ifndef NDEBUG assert(S.SpeculationDepth != 0); --S.SpeculationDepth; diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index 7366aca114ca0..64bad66b9b6c8 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -160,7 +160,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const { return; const ASTContext &ASTCtx = S.getASTContext(); - const Expr *CallExpr = Caller->getExpr(getRetPC()); + const Expr *CallExpr = Caller->getExpr(getRetOpPC()); const FunctionDecl *F = getCallee(); auto PrintingPolicy = ASTCtx.getPrintingPolicy(); PrintingPolicy.SuppressLambdaBody = true; @@ -227,7 +227,7 @@ SourceRange InterpFrame::getCallRange() const { if (!C->RetPC) continue; SourceRange CallRange = - S.getRange(C->Caller->Func, C->RetPC - sizeof(uintptr_t)); + S.getRange(C->Caller->Func, C->getRetOpPC() - sizeof(uintptr_t)); if (CallRange.isValid()) return CallRange; } @@ -280,34 +280,34 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const { // Implicitly created functions don't have any code we could point at, // so return the call site. if (Func && !funcHasUsableBody(Func) && Caller) - return Caller->getSource(RetPC); + return Caller->getSource(getRetOpPC()); // Similarly, if the resulting source location is invalid anyway, // point to the caller instead. SourceInfo Result = S.getSource(Func, PC); if (Result.getLoc().isInvalid() && Caller) - return Caller->getSource(RetPC); + return Caller->getSource(getRetOpPC()); return Result; } const Expr *InterpFrame::getExpr(CodePtr PC) const { if (Func && !funcHasUsableBody(Func) && Caller) - return Caller->getExpr(RetPC); + return Caller->getExpr(getRetOpPC()); return S.getExpr(Func, PC); } SourceLocation InterpFrame::getLocation(CodePtr PC) const { if (Func && !funcHasUsableBody(Func) && Caller) - return Caller->getLocation(RetPC); + return Caller->getLocation(getRetOpPC()); return S.getLocation(Func, PC); } SourceRange InterpFrame::getRange(CodePtr PC) const { if (Func && !funcHasUsableBody(Func) && Caller) - return Caller->getRange(RetPC); + return Caller->getRange(getRetOpPC()); return S.getRange(Func, PC); } diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h index 731ffddc5a68d..9498a911f2892 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.h +++ b/clang/lib/AST/ByteCode/InterpFrame.h @@ -149,11 +149,15 @@ class InterpFrame final : public Frame { /// Checks if the frame is a root frame - return should quit the interpreter. bool isRoot() const { return !Func; } - /// Returns the PC of the frame's code start. - CodePtr getPC() const { return Func->getCodeBegin(); } - /// Returns the return address of the frame. CodePtr getRetPC() const { return RetPC; } + /// Returns the return address of the opcode in the caller frame. + CodePtr getRetOpPC() const { + // All the Call ops we have take a Function* and an unsigned. + if (RetPC) + return RetPC - align(sizeof(void *)) - align(sizeof(unsigned)); + return RetPC; + } /// Map a location to a source. SourceInfo getSource(CodePtr PC) const; @@ -162,6 +166,7 @@ class InterpFrame final : public Frame { SourceRange getRange(CodePtr PC) const; unsigned getDepth() const { return Depth; } + unsigned getArgSize() const { return ArgSize; } bool isStdFunction() const; diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index 461bc35979247..839540a7912f8 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -118,3 +118,9 @@ void InterpStack::dump() const { ++Index; } } + +void InterpStack::discardSlow() { + assert(!empty()); + + TYPE_SWITCH(ItemTypes.back(), { discard<T>(); }); +} diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 6d58f5a24bd77..2c02979ee6eec 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -57,6 +57,7 @@ class InterpStack final { } shrink(aligned_size<T>()); } + void discardSlow(); /// Returns a reference to the value on the top of the stack. template <typename T> T &peek() const { diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index 2d6ed98e6b52c..f6338cda56e34 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -149,7 +149,7 @@ StdAllocatorCaller InterpState::getStdAllocatorCaller(StringRef Name) const { if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") && TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) { QualType ElemType = TAL[0].getAsType(); - const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC())); + const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetOpPC())); return {NewCall, ElemType}; } } diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 4e4a053d6bbed..050fa4c77cd2f 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -177,6 +177,7 @@ class InterpState final : public State, public SourceMapper { mutable std::optional<llvm::BumpPtrAllocator> Allocator; public: + CodePtr PC; /// Reference to the module containing all bytecode. Program &P; /// Temporary stack. diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 7cda124b40e24..8123ca7497335 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -141,7 +141,6 @@ class Opcode { list<ArgType> Args = []; string Name = ""; bit CanReturn = 0; - bit ChangesPC = 0; bit HasCustomLink = 0; bit HasCustomEval = 0; bit HasGroup = 0; @@ -172,7 +171,6 @@ class IntegerOpcode : Opcode { class JumpOpcode : Opcode { let Args = [ArgSint32]; - let ChangesPC = 1; let HasCustomEval = 1; } @@ -192,7 +190,6 @@ def EndInit : SuccessOpcode; def StartSpeculation : SuccessOpcode; def EndSpeculation : SuccessOpcode; def BCP : Opcode { - let ChangesPC = 1; let HasCustomEval = 1; let Args = [ArgSint32, ArgPrimType]; } @@ -204,7 +201,6 @@ def BCP : Opcode { // [Value] -> [] def Ret : Opcode { let Types = [AllTypeClass]; - let ChangesPC = 1; let CanReturn = 1; let HasGroup = 1; let HasCustomEval = 1; @@ -213,14 +209,12 @@ def Ret : Opcode { // [] -> [] def RetVoid : Opcode { let CanReturn = 1; - let ChangesPC = 1; let HasCustomEval = 1; let CanFail = 0; } // [Value] -> [] def RetValue : Opcode { let CanReturn = 1; - let ChangesPC = 1; let HasCustomEval = 1; } // [] -> EXIT diff --git a/clang/lib/AST/ByteCode/Source.h b/clang/lib/AST/ByteCode/Source.h index 56ca197e66473..464c1c8bc9811 100644 --- a/clang/lib/AST/ByteCode/Source.h +++ b/clang/lib/AST/ByteCode/Source.h @@ -36,6 +36,8 @@ class CodePtr final { return *this; } + CodePtr operator+(int32_t Offset) { return CodePtr(Ptr + Offset); } + int32_t operator-(const CodePtr &RHS) const { assert(Ptr != nullptr && RHS.Ptr != nullptr && "Invalid code pointer"); return Ptr - RHS.Ptr; diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp index 7fef309e127ef..13a99900bc9ec 100644 --- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp +++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp @@ -115,25 +115,23 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N, 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"; + OS << "PRESERVE_NONE\nstatic bool Interp_" << ID << "(InterpState &S) {\n"; if (ID.str() == "EndSpeculation") { - OS << " MUSTTAIL return EndSpeculation(S, PC);\n"; + OS << " MUSTTAIL return EndSpeculation(S);\n"; OS << "}\n"; return; } bool CanReturn = R->getValueAsBit("CanReturn"); const auto &Args = R->getValueAsListOfDefs("Args"); - bool ChangesPC = R->getValueAsBit("ChangesPC"); bool CanFail = R->getValueAsBit("CanFail"); if (Args.empty()) { if (CanReturn) { OS << " MUSTTAIL return " << N; PrintTypes(OS, TS); - OS << "(S, PC);\n"; + OS << "(S);\n"; OS << "}\n"; return; } @@ -144,7 +142,7 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N, OS << N; PrintTypes(OS, TS); - OS << "(S, PC)"; + OS << "(S, S.PC)"; if (CanFail) OS << ") retu... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/207393 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
