[clang] [clang][bytecode] Only pass OpPC if needed (PR #207479)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 3 21:16:53 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Quite a few opcode implementations don't ever report a diagnostic, so they don't need the `OpPC` at all. Add a tablegen bit to disable passing `OpPC` altogether.
---
Full diff: https://github.com/llvm/llvm-project/pull/207479.diff
5 Files Affected:
- (modified) clang/lib/AST/ByteCode/EvalEmitter.cpp (+2-2)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+4-4)
- (modified) clang/lib/AST/ByteCode/Interp.h (+27-28)
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+22-24)
- (modified) clang/utils/TableGen/ClangOpcodesEmitter.cpp (+14-4)
``````````diff
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index dbec700c80d44..34c85c7c66bdd 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -209,8 +209,8 @@ bool EvalEmitter::speculate(const CallExpr *E, const LabelTy &EndLabel) {
if (!isActive())
return true;
- PushIgnoreDiags(S, OpPC);
- auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, OpPC); });
+ PushIgnoreDiags(S);
+ auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S); });
size_t StackSizeBefore = S.Stk.size();
const Expr *Arg = E->getArg(0);
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index dc93cc4fd698c..6d9b8bc78668f 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -2891,7 +2891,7 @@ static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) {
}
}
-bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
+bool FinishInitGlobal(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
finishGlobalRecurse(S, Ptr);
@@ -3175,10 +3175,10 @@ PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset,
assert(DepthBefore >= 1);
#endif
- auto SpeculativeInterp = [&S, OpPC]() -> bool {
+ auto SpeculativeInterp = [&S]() -> bool {
// Ignore diagnostics during speculative execution.
- PushIgnoreDiags(S, OpPC);
- auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S, OpPC); });
+ PushIgnoreDiags(S);
+ auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S); });
#if USE_TAILCALLS
auto Op = S.PC.read<Opcode>();
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 61c2b0a5e5960..26cada1685186 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1537,20 +1537,19 @@ bool GE(InterpState &S, CodePtr OpPC) {
//===----------------------------------------------------------------------===//
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool Dup(InterpState &S, CodePtr OpPC) {
+bool Dup(InterpState &S) {
S.Stk.push<T>(S.Stk.peek<T>());
return true;
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool Pop(InterpState &S, CodePtr OpPC) {
+bool Pop(InterpState &S) {
S.Stk.discard<T>();
return true;
}
/// [Value1, Value2] -> [Value2, Value1]
-template <PrimType TopName, PrimType BottomName>
-bool Flip(InterpState &S, CodePtr OpPC) {
+template <PrimType TopName, PrimType BottomName> bool Flip(InterpState &S) {
using TopT = typename PrimConv<TopName>::T;
using BottomT = typename PrimConv<BottomName>::T;
@@ -1568,7 +1567,7 @@ bool Flip(InterpState &S, CodePtr OpPC) {
//===----------------------------------------------------------------------===//
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
+bool Const(InterpState &S, const T &Arg) {
if constexpr (needsAlloc<T>()) {
T Result = S.allocAP<T>(Arg.bitWidth());
Result.copy(Arg.toAPSInt());
@@ -1596,7 +1595,7 @@ bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
return true;
}
-inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
+inline bool ConstFloat(InterpState &S, const Floating &F) {
Floating Result = S.allocFloat(F.getSemantics());
Result.copy(F.getAPFloat());
S.Stk.push<Floating>(Result);
@@ -2120,21 +2119,21 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return true;
}
-inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
+inline bool FinishInitPop(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.canBeInitialized())
Ptr.initialize();
return true;
}
-inline bool FinishInit(InterpState &S, CodePtr OpPC) {
+inline bool FinishInit(InterpState &S) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (Ptr.canBeInitialized())
Ptr.initialize();
return true;
}
-inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) {
+inline bool FinishInitActivate(InterpState &S) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (Ptr.canBeInitialized()) {
Ptr.initialize();
@@ -2143,7 +2142,7 @@ inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) {
return true;
}
-inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) {
+inline bool FinishInitActivatePop(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.canBeInitialized()) {
Ptr.initialize();
@@ -2152,7 +2151,7 @@ inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) {
return true;
}
-bool FinishInitGlobal(InterpState &S, CodePtr OpPC);
+bool FinishInitGlobal(InterpState &S);
inline bool Dump(InterpState &S, CodePtr OpPC) {
S.Stk.dump();
@@ -2261,14 +2260,14 @@ bool StorePop(InterpState &S, CodePtr OpPC) {
return true;
}
-static inline bool Activate(InterpState &S, CodePtr OpPC) {
+static inline bool Activate(InterpState &S) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (Ptr.canBeInitialized())
Ptr.activate();
return true;
}
-static inline bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+static inline bool ActivateThisField(InterpState &S, uint32_t I) {
if (S.checkingPotentialConstantExpression())
return false;
if (!S.Current->hasThisPointer())
@@ -3139,12 +3138,12 @@ static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
//===----------------------------------------------------------------------===//
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool Zero(InterpState &S, CodePtr OpPC) {
+bool Zero(InterpState &S) {
S.Stk.push<T>(T::zero());
return true;
}
-static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
+static inline bool ZeroIntAP(InterpState &S, uint32_t BitWidth) {
auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
if (!Result.singleWord())
std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
@@ -3152,7 +3151,7 @@ static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
return true;
}
-static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
+static inline bool ZeroIntAPS(InterpState &S, uint32_t BitWidth) {
auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
if (!Result.singleWord())
std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
@@ -3161,7 +3160,7 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Type *Ty) {
+inline bool Null(InterpState &S, uint64_t Value, const Type *Ty) {
// FIXME(perf): This is a somewhat often-used function and the value of a
// null pointer is almost always 0.
S.Stk.push<T>(Value, Ty);
@@ -3433,13 +3432,13 @@ PRESERVE_NONE inline bool NoRet(InterpState &S, CodePtr OpPC) {
// NarrowPtr, ExpandPtr
//===----------------------------------------------------------------------===//
-inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
+inline bool NarrowPtr(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
S.Stk.push<Pointer>(Ptr.narrow());
return true;
}
-inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
+inline bool ExpandPtr(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isBlockPointer())
S.Stk.push<Pointer>(Ptr.expand());
@@ -3654,7 +3653,7 @@ inline bool Unsupported(InterpState &S, CodePtr OpPC) {
return false;
}
-inline bool PushIgnoreDiags(InterpState &S, CodePtr OpPC) {
+inline bool PushIgnoreDiags(InterpState &S) {
++S.DiagIgnoreDepth;
if (S.DiagIgnoreDepth != 1)
return true;
@@ -3666,7 +3665,7 @@ inline bool PushIgnoreDiags(InterpState &S, CodePtr OpPC) {
return true;
}
-inline bool PopIgnoreDiags(InterpState &S, CodePtr OpPC) {
+inline bool PopIgnoreDiags(InterpState &S) {
assert(S.DiagIgnoreDepth != 0);
--S.DiagIgnoreDepth;
if (S.DiagIgnoreDepth == 0) {
@@ -3677,20 +3676,20 @@ inline bool PopIgnoreDiags(InterpState &S, CodePtr OpPC) {
return true;
}
-inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {
+inline bool StartSpeculation(InterpState &S) {
#ifndef NDEBUG
++S.SpeculationDepth;
#endif
return true;
}
-inline bool StartInit(InterpState &S, CodePtr OpPC) {
+inline bool StartInit(InterpState &S) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
S.InitializingPtrs.push_back(Ptr.view());
return true;
}
-inline bool EndInit(InterpState &S, CodePtr OpPC) {
+inline bool EndInit(InterpState &S) {
S.InitializingPtrs.pop_back();
return true;
}
@@ -3706,22 +3705,22 @@ PRESERVE_NONE inline bool EndSpeculation(InterpState &S) {
return true;
}
-inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {
+inline bool PushCC(InterpState &S, bool Value) {
S.ConstantContextOverride = Value;
return true;
}
-inline bool PopCC(InterpState &S, CodePtr OpPC) {
+inline bool PopCC(InterpState &S) {
S.ConstantContextOverride = std::nullopt;
return true;
}
-inline bool PushMSVCCE(InterpState &S, CodePtr OpPC) {
+inline bool PushMSVCCE(InterpState &S) {
// This is a per-frame property.
++S.Current->MSVCConstexprAllowed;
return true;
}
-inline bool PopMSVCCE(InterpState &S, CodePtr OpPC) {
+inline bool PopMSVCCE(InterpState &S) {
assert(S.Current->MSVCConstexprAllowed >= 1);
// This is a per-frame property.
--S.Current->MSVCConstexprAllowed;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 8123ca7497335..cf99c1f056527 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -145,10 +145,12 @@ class Opcode {
bit HasCustomEval = 0;
bit HasGroup = 0;
bit CanFail = 1;
+ bit NeedsOpPC = 1;
}
class SuccessOpcode : Opcode {
let CanFail = 0;
+ let NeedsOpPC = 0;
}
class AluOpcode : Opcode {
@@ -272,11 +274,10 @@ def EnableLocal : Opcode {
// Constants
//===----------------------------------------------------------------------===//
-class ConstOpcode<Type Ty, ArgType ArgTy> : Opcode {
+class ConstOpcode<Type Ty, ArgType ArgTy> : SuccessOpcode {
let Types = [SingletonTypeClass<Ty>];
let Args = [ArgTy];
let Name = "Const";
- let CanFail = 0;
}
// [] -> [Integer]
@@ -293,35 +294,29 @@ def ConstIntAPS : ConstOpcode<IntAPS, ArgIntAPS>;
def ConstBool : ConstOpcode<Bool, ArgBool>;
def ConstFixedPoint : ConstOpcode<FixedPoint, ArgFixedPoint>;
-def ConstFloat : Opcode {
+def ConstFloat : SuccessOpcode {
let Args = [ArgFloat];
- let CanFail = 0;
}
// [] -> [Integer]
-def Zero : Opcode {
+def Zero : SuccessOpcode {
let Types = [FixedSizeIntegralTypeClass];
let HasGroup = 1;
- let CanFail = 0;
-
}
-def ZeroIntAP : Opcode {
+def ZeroIntAP : SuccessOpcode {
let Args = [ArgUint32];
- let CanFail = 0;
}
-def ZeroIntAPS : Opcode {
+def ZeroIntAPS : SuccessOpcode {
let Args = [ArgUint32];
- let CanFail = 0;
}
// [] -> [Pointer]
-def Null : Opcode {
+def Null : SuccessOpcode {
let Types = [PtrTypeClass];
let Args = [ArgUint64, ArgTypePtr];
let HasGroup = 1;
- let CanFail = 0;
}
//===----------------------------------------------------------------------===//
@@ -551,8 +546,13 @@ def StoreBitFieldPop : StoreBitFieldOpcode {}
def StoreBitFieldActivate : StoreBitFieldOpcode {}
def StoreBitFieldActivatePop : StoreBitFieldOpcode {}
-def Activate : SuccessOpcode;
-def ActivateThisField : Opcode { let Args = [ArgUint32]; }
+def Activate : SuccessOpcode {
+ let NeedsOpPC = 0;
+}
+def ActivateThisField : Opcode {
+ let Args = [ArgUint32];
+ let NeedsOpPC = 0;
+}
// [Pointer, Value] -> []
def Init : StoreOpcode {}
@@ -846,23 +846,20 @@ def GE : ComparisonOpcode;
//===----------------------------------------------------------------------===//
// [Value] -> []
-def Pop : Opcode {
+def Pop : SuccessOpcode {
let Types = [AllTypeClass];
let HasGroup = 1;
- let CanFail = 0;
}
// [Value] -> [Value, Value]
-def Dup : Opcode {
+def Dup : SuccessOpcode {
let Types = [AllTypeClass];
let HasGroup = 1;
- let CanFail = 0;
}
-def Flip : Opcode {
+def Flip : SuccessOpcode {
let Types = [AllTypeClass, AllTypeClass];
let HasGroup = 1;
- let CanFail = 0;
}
// [] -> []
@@ -878,7 +875,9 @@ def DynamicCast : Opcode {
}
def InvalidStore : Opcode { let Args = [ArgTypePtr]; }
-def CheckPseudoDtor : SuccessOpcode;
+def CheckPseudoDtor : SuccessOpcode {
+ let NeedsOpPC = 1;
+}
def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef, ArgBool];
@@ -970,9 +969,8 @@ def CheckDestruction : Opcode;
def CtorCheck : Opcode;
-def PushCC : Opcode {
+def PushCC : SuccessOpcode {
let Args = [ArgBool];
- let CanFail = 0;
}
def PopCC : SuccessOpcode;
def PushMSVCCE : SuccessOpcode;
diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
index 13a99900bc9ec..4a3c901d2de7f 100644
--- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -126,6 +126,7 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
bool CanReturn = R->getValueAsBit("CanReturn");
const auto &Args = R->getValueAsListOfDefs("Args");
bool CanFail = R->getValueAsBit("CanFail");
+ bool PassOpPC = R->getValueAsBit("NeedsOpPC");
if (Args.empty()) {
if (CanReturn) {
@@ -142,7 +143,11 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
OS << N;
PrintTypes(OS, TS);
- OS << "(S, S.PC)";
+ OS << "(S";
+ if (PassOpPC)
+ OS << ", S.PC)";
+ else
+ OS << ")";
if (CanFail)
OS << ") return false";
@@ -160,7 +165,8 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
OS << " {\n";
- OS << " CodePtr OpPC = S.PC;\n";
+ if (PassOpPC)
+ OS << " CodePtr OpPC = S.PC;\n";
// Emit calls to read arguments.
for (size_t I = 0, N = Args.size(); I < N; ++I) {
@@ -182,7 +188,8 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
OS << N;
PrintTypes(OS, TS);
OS << "(S";
- OS << ", OpPC";
+ if (PassOpPC)
+ OS << ", OpPC";
for (size_t I = 0, N = Args.size(); I < N; ++I)
OS << ", V" << I;
@@ -431,10 +438,13 @@ void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,
if (N == "EndSpeculation") {
OS << "return EndSpeculation(S);\n";
} else {
+ bool PassOpPC = R->getValueAsBit("NeedsOpPC");
OS << " return " << N;
PrintTypes(OS, TS);
- OS << "(S, OpPC";
+ OS << "(S";
+ if (PassOpPC)
+ OS << ", OpPC";
for (size_t I = 0, N = Args.size(); I < N; ++I)
OS << ", A" << I;
OS << ");\n";
``````````
</details>
https://github.com/llvm/llvm-project/pull/207479
More information about the cfe-commits
mailing list