https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/164215
This drastically reduces the preprocessed size of Context.cpp and InterpBuiltin.cpp. >From a3cec7a0ae150f72907f3ecac184367513eb2717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Mon, 20 Oct 2025 10:13:47 +0200 Subject: [PATCH] [clang][bytecode] Move shard interp functions to InterpHelpers.h This drastically reduces the preprocessed size of Context.cpp and InterpBuiltin.cpp. --- clang/lib/AST/ByteCode/Context.cpp | 5 +- clang/lib/AST/ByteCode/Interp.cpp | 1 + clang/lib/AST/ByteCode/Interp.h | 116 +------------------ clang/lib/AST/ByteCode/InterpBuiltin.cpp | 3 +- clang/lib/AST/ByteCode/InterpHelpers.h | 141 +++++++++++++++++++++++ 5 files changed, 149 insertions(+), 117 deletions(-) create mode 100644 clang/lib/AST/ByteCode/InterpHelpers.h diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 683e916391337..06f3a618813cb 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -7,12 +7,15 @@ //===----------------------------------------------------------------------===// #include "Context.h" +#include "Boolean.h" #include "ByteCodeEmitter.h" #include "Compiler.h" #include "EvalEmitter.h" -#include "Interp.h" +#include "Integral.h" #include "InterpFrame.h" +#include "InterpHelpers.h" #include "InterpStack.h" +#include "Pointer.h" #include "PrimType.h" #include "Program.h" #include "clang/AST/ASTLambda.h" diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index a72282caf5e73..a98347c49c03f 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -10,6 +10,7 @@ #include "Compiler.h" #include "Function.h" #include "InterpFrame.h" +#include "InterpHelpers.h" #include "InterpShared.h" #include "InterpStack.h" #include "Opcode.h" diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 2f7e2d98f3576..d8529daf591ee 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -22,6 +22,7 @@ #include "Function.h" #include "InterpBuiltinBitCast.h" #include "InterpFrame.h" +#include "InterpHelpers.h" #include "InterpStack.h" #include "InterpState.h" #include "MemberPointer.h" @@ -43,28 +44,10 @@ using FixedPointSemantics = llvm::FixedPointSemantics; /// Checks if the variable has externally defined storage. bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -/// Checks if the array is offsetable. -bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); - -/// Checks if a pointer is live and accessible. -bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); - -/// Checks if a pointer is a dummy pointer. -bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); - /// Checks if a pointer is null. bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); -/// Checks if a pointer is in range. -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); - -/// Checks if a field from which a pointer is going to be derived is valid. -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - CheckSubobjectKind CSK); - /// Checks if Ptr is a one-past-the-end pointer. bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); @@ -80,12 +63,6 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if the Descriptor is of a constexpr or const global variable. bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); -/// Checks if a pointer points to a mutable field. -bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); - -/// Checks if a value can be loaded from a block. -bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK = AK_Read); bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, @@ -110,12 +87,6 @@ bool CheckThis(InterpState &S, CodePtr OpPC); /// language mode. bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC); -/// Diagnose mismatched new[]/delete or new/delete[] pairs. -bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, - DynamicAllocator::Form AllocForm, - DynamicAllocator::Form DeleteForm, const Descriptor *D, - const Expr *NewExpr); - /// Check the source of the pointer passed to delete/delete[] has actually /// been heap allocated by us. bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, @@ -129,9 +100,6 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue); -/// Copy the contents of Src into Dest. -bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); - bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize); bool Call(InterpState &S, CodePtr OpPC, const Function *Func, @@ -149,19 +117,11 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool CheckBCPResult(InterpState &S, const Pointer &Ptr); bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -template <typename T> -static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { - const Expr *E = S.Current->getExpr(OpPC); - S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); - return S.noteUndefinedBehavior(); -} bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP); bool isConstexprUnknown(const Pointer &P); -inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems); - enum class ShiftDir { Left, Right }; /// Checks if the shift operation is legal. @@ -241,43 +201,6 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { return true; } -template <typename SizeT> -bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, - unsigned ElemSize, bool IsNoThrow) { - // FIXME: Both the SizeT::from() as well as the - // NumElements.toAPSInt() in this function are rather expensive. - - // Can't be too many elements if the bitwidth of NumElements is lower than - // that of Descriptor::MaxArrayElemBytes. - if ((NumElements->bitWidth() - NumElements->isSigned()) < - (sizeof(Descriptor::MaxArrayElemBytes) * 8)) - return true; - - // FIXME: GH63562 - // APValue stores array extents as unsigned, - // so anything that is greater that unsigned would overflow when - // constructing the array, we catch this here. - SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); - assert(MaxElements.isPositive()); - if (NumElements->toAPSInt().getActiveBits() > - ConstantArrayType::getMaxSizeBits(S.getASTContext()) || - *NumElements > MaxElements) { - if (!IsNoThrow) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - - if (NumElements->isSigned() && NumElements->isNegative()) { - S.FFDiag(Loc, diag::note_constexpr_new_negative) - << NumElements->toDiagnosticString(S.getASTContext()); - } else { - S.FFDiag(Loc, diag::note_constexpr_new_too_large) - << NumElements->toDiagnosticString(S.getASTContext()); - } - } - return false; - } - return true; -} - /// Checks if the result of a floating-point operation is valid /// in the current context. bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, @@ -286,19 +209,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, /// Checks why the given DeclRefExpr is invalid. bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR); -/// Interpreter entry point. -bool Interpret(InterpState &S); - -/// Interpret a builtin function. -bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, - uint32_t BuiltinID); - -/// Interpret an offsetof operation. -bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, - ArrayRef<int64_t> ArrayIndices, int64_t &Result); - -inline bool Invalid(InterpState &S, CodePtr OpPC); - enum class ArithOp { Add, Sub }; //===----------------------------------------------------------------------===// @@ -403,13 +313,6 @@ bool Add(InterpState &S, CodePtr OpPC) { return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); } -static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { - auto RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - return llvm::RoundingMode::NearestTiesToEven; - return RM; -} - inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &RHS = S.Stk.pop<Floating>(); const Floating &LHS = S.Stk.pop<Floating>(); @@ -3264,12 +3167,6 @@ inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) { /// Just emit a diagnostic. The expression that caused emission of this /// op is not valid in a constant context. -inline bool Invalid(InterpState &S, CodePtr OpPC) { - const SourceLocation &Loc = S.Current->getLocation(OpPC); - S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) - << S.Current->getRange(OpPC); - return false; -} inline bool Unsupported(InterpState &S, CodePtr OpPC) { const SourceLocation &Loc = S.Current->getLocation(OpPC); @@ -3701,17 +3598,6 @@ inline bool CheckDestruction(InterpState &S, CodePtr OpPC) { return CheckDestructor(S, OpPC, Ptr); } -inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) { - uint64_t Limit = S.getLangOpts().ConstexprStepLimit; - if (Limit != 0 && NumElems > Limit) { - S.FFDiag(S.Current->getSource(OpPC), - diag::note_constexpr_new_exceeds_limits) - << NumElems << Limit; - return false; - } - return true; -} - //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 0cb491063057c..c3a6ceae26067 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -8,9 +8,10 @@ #include "../ExprConstShared.h" #include "Boolean.h" #include "EvalEmitter.h" -#include "Interp.h" #include "InterpBuiltinBitCast.h" +#include "InterpHelpers.h" #include "PrimType.h" +#include "Program.h" #include "clang/AST/OSLog.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h new file mode 100644 index 0000000000000..73b71175b5fd3 --- /dev/null +++ b/clang/lib/AST/ByteCode/InterpHelpers.h @@ -0,0 +1,141 @@ +//===--- InterpHelpers.h - Interpreter Helper Functions --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_INTERP_INTERPHELPERS_H +#define LLVM_CLANG_AST_INTERP_INTERPHELPERS_H + +#include "DynamicAllocator.h" +#include "InterpState.h" +#include "Pointer.h" + +namespace clang { +class CallExpr; +class OffsetOfExpr; + +namespace interp { +class Block; +struct Descriptor; + +/// Interpreter entry point. +bool Interpret(InterpState &S); + +/// Checks if the array is offsetable. +bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + +/// Checks if a pointer is live and accessible. +bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); + +/// Checks if a pointer is a dummy pointer. +bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); + +/// Checks if a pointer is in range. +bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); + +/// Checks if a field from which a pointer is going to be derived is valid. +bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + CheckSubobjectKind CSK); + +/// Checks if a pointer points to a mutable field. +bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + +/// Checks if a value can be loaded from a block. +bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK = AK_Read); + +/// Diagnose mismatched new[]/delete or new/delete[] pairs. +bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, + DynamicAllocator::Form AllocForm, + DynamicAllocator::Form DeleteForm, const Descriptor *D, + const Expr *NewExpr); + +/// Copy the contents of Src into Dest. +bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); + +template <typename T> +static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { + const Expr *E = S.Current->getExpr(OpPC); + S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); + return S.noteUndefinedBehavior(); +} + +inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) { + uint64_t Limit = S.getLangOpts().ConstexprStepLimit; + if (Limit != 0 && NumElems > Limit) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_new_exceeds_limits) + << NumElems << Limit; + return false; + } + return true; +} + +static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { + auto RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + return llvm::RoundingMode::NearestTiesToEven; + return RM; +} + +inline bool Invalid(InterpState &S, CodePtr OpPC) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); + S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) + << S.Current->getRange(OpPC); + return false; +} + +template <typename SizeT> +bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, + unsigned ElemSize, bool IsNoThrow) { + // FIXME: Both the SizeT::from() as well as the + // NumElements.toAPSInt() in this function are rather expensive. + + // Can't be too many elements if the bitwidth of NumElements is lower than + // that of Descriptor::MaxArrayElemBytes. + if ((NumElements->bitWidth() - NumElements->isSigned()) < + (sizeof(Descriptor::MaxArrayElemBytes) * 8)) + return true; + + // FIXME: GH63562 + // APValue stores array extents as unsigned, + // so anything that is greater that unsigned would overflow when + // constructing the array, we catch this here. + SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); + assert(MaxElements.isPositive()); + if (NumElements->toAPSInt().getActiveBits() > + ConstantArrayType::getMaxSizeBits(S.getASTContext()) || + *NumElements > MaxElements) { + if (!IsNoThrow) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + + if (NumElements->isSigned() && NumElements->isNegative()) { + S.FFDiag(Loc, diag::note_constexpr_new_negative) + << NumElements->toDiagnosticString(S.getASTContext()); + } else { + S.FFDiag(Loc, diag::note_constexpr_new_too_large) + << NumElements->toDiagnosticString(S.getASTContext()); + } + } + return false; + } + return true; +} + +/// Interpret a builtin function. +bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, + uint32_t BuiltinID); + +/// Interpret an offsetof operation. +bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, + ArrayRef<int64_t> ArrayIndices, int64_t &Result); + +} // namespace interp +} // namespace clang + +#endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
