Author: Timm Baeder Date: 2025-12-06T06:37:45+01:00 New Revision: 8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe
URL: https://github.com/llvm/llvm-project/commit/8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe DIFF: https://github.com/llvm/llvm-project/commit/8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe.diff LOG: [clang][bytecode] Allocate InitMaps via Program/InterpState allocators (#170272) Save them as a pointer intead of using a shared_ptr. This we we can use the pointer integer value to differentiate the "no initmap yet" and "all values initialzed" cases. This regresses one test case in const-eval.c, but as it turns out, that only worked coincidentally before. Added: Modified: clang/lib/AST/ByteCode/Descriptor.cpp clang/lib/AST/ByteCode/Descriptor.h clang/lib/AST/ByteCode/Disasm.cpp clang/lib/AST/ByteCode/EvaluationResult.cpp clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/InterpBuiltin.cpp clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp clang/lib/AST/ByteCode/InterpBuiltinBitCast.h clang/lib/AST/ByteCode/Pointer.cpp clang/lib/AST/ByteCode/Pointer.h clang/test/AST/ByteCode/const-eval.c Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 0a819599287ee..9ed7c088dbb12 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -52,10 +52,8 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) { template <typename T> static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *D) { - new (Ptr) InitMapPtr(std::nullopt); - if constexpr (needsCtor<T>()) { - Ptr += sizeof(InitMapPtr); + Ptr += sizeof(InitMap *); for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { new (&reinterpret_cast<T *>(Ptr)[I]) T(); } @@ -64,13 +62,8 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, template <typename T> static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) { - InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr); - - if (IMP) - IMP = std::nullopt; - if constexpr (needsCtor<T>()) { - Ptr += sizeof(InitMapPtr); + Ptr += sizeof(InitMap *); for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { reinterpret_cast<T *>(Ptr)[I].~T(); } @@ -239,12 +232,6 @@ static bool needsRecordDtor(const Record *R) { static BlockCtorFn getCtorPrim(PrimType T) { switch (T) { - case PT_Float: - return ctorTy<PrimConv<PT_Float>::T>; - case PT_IntAP: - return ctorTy<PrimConv<PT_IntAP>::T>; - case PT_IntAPS: - return ctorTy<PrimConv<PT_IntAPS>::T>; case PT_Ptr: return ctorTy<PrimConv<PT_Ptr>::T>; case PT_MemberPtr: @@ -257,12 +244,6 @@ static BlockCtorFn getCtorPrim(PrimType T) { static BlockDtorFn getDtorPrim(PrimType T) { switch (T) { - case PT_Float: - return dtorTy<PrimConv<PT_Float>::T>; - case PT_IntAP: - return dtorTy<PrimConv<PT_IntAP>::T>; - case PT_IntAPS: - return dtorTy<PrimConv<PT_IntAPS>::T>; case PT_Ptr: return dtorTy<PrimConv<PT_Ptr>::T>; case PT_MemberPtr: @@ -273,14 +254,16 @@ static BlockDtorFn getDtorPrim(PrimType T) { llvm_unreachable("Unhandled PrimType"); } -static BlockCtorFn getCtorArrayPrim(PrimType Type) { - TYPE_SWITCH(Type, return ctorArrayTy<T>); - llvm_unreachable("unknown Expr"); -} - -static BlockDtorFn getDtorArrayPrim(PrimType Type) { - TYPE_SWITCH(Type, return dtorArrayTy<T>); - llvm_unreachable("unknown Expr"); +static BlockDtorFn getDtorArrayPrim(PrimType T) { + switch (T) { + case PT_Ptr: + return dtorArrayTy<PrimConv<PT_Ptr>::T>; + case PT_MemberPtr: + return dtorArrayTy<PrimConv<PT_MemberPtr>::T>; + default: + return nullptr; + } + llvm_unreachable("Unhandled PrimType"); } /// Primitives. @@ -302,10 +285,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsMutable) : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems), MDSize(MD.value_or(0)), - AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type), + AllocSize(align(MDSize) + align(Size) + sizeof(InitMap *)), PrimT(Type), IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), - IsArray(true), CtorFn(getCtorArrayPrim(Type)), - DtorFn(getDtorArrayPrim(Type)) { + IsArray(true), DtorFn(getDtorArrayPrim(Type)) { assert(Source && "Missing source"); assert(NumElems <= (MaxArrayElemBytes / ElemSize)); } @@ -315,10 +297,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsTemporary, bool IsConst, UnknownSize) : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(MD.value_or(0)), - AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type), + AllocSize(MDSize + sizeof(InitMap *) + alignof(void *)), PrimT(Type), IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary), - IsArray(true), CtorFn(getCtorArrayPrim(Type)), - DtorFn(getDtorArrayPrim(Type)) { + IsArray(true), DtorFn(getDtorArrayPrim(Type)) { assert(Source && "Missing source"); } @@ -468,15 +449,16 @@ bool Descriptor::hasTrivialDtor() const { bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); } -InitMap::InitMap(unsigned N) - : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {} +InitMap::InitMap(unsigned N) : UninitFields(N) { + std::memset(data(), 0, numFields(N) * sizeof(T)); +} bool InitMap::initializeElement(unsigned I) { unsigned Bucket = I / PER_FIELD; T Mask = T(1) << (I % PER_FIELD); if (!(data()[Bucket] & Mask)) { data()[Bucket] |= Mask; - UninitFields -= 1; + --UninitFields; } return UninitFields == 0; } diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 90dc2b4aa3111..2807f92335dc2 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -16,6 +16,7 @@ #include "PrimType.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include <limits> namespace clang { namespace interp { @@ -27,7 +28,6 @@ struct Descriptor; enum PrimType : uint8_t; using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>; -using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>; /// Invoked whenever a block is created. The constructor method fills in the /// inline descriptors of all fields and array elements. It also initializes @@ -146,7 +146,7 @@ struct Descriptor final { /// Maximum number of bytes to be used for array elements. static constexpr unsigned MaxArrayElemBytes = - std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) - + std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMap *) - align(std::max(*InlineDescMD, *GlobalMD)); /// Pointer to the record, if block contains records. @@ -278,7 +278,7 @@ struct Descriptor final { }; /// Bitfield tracking the initialisation status of elements of primitive arrays. -struct InitMap final { +struct alignas(alignof(uint64_t)) InitMap final { private: /// Type packing bits. using T = uint64_t; @@ -289,12 +289,33 @@ struct InitMap final { /// Initializes the map with no fields set. explicit InitMap(unsigned N); + /// Checks if all elements have been initialized. + static bool allInitialized(const InitMap *IM) { + return reinterpret_cast<uintptr_t>(IM) == + std::numeric_limits<uintptr_t>::max(); + } + + /// Marks all elements as initialized. + static void markAllInitialized(InitMap *&IMPtr) { + std::memset(&IMPtr, static_cast<int>(std::numeric_limits<uintptr_t>::max()), + sizeof(void *)); + } + + /// Returns the number of bytes needed to allocate the InitMap for + /// \param N elements. + static unsigned allocBytes(unsigned N) { + return align(sizeof(InitMap)) + (numFields(N) * sizeof(T)); + } + private: friend class Pointer; /// Returns a pointer to storage. - T *data() { return Data.get(); } - const T *data() const { return Data.get(); } + T *data() { + return reinterpret_cast<T *>(reinterpret_cast<std::byte *>(this) + + align(sizeof(InitMap))); + } + const T *data() const { return const_cast<InitMap *>(this)->data(); } /// Initializes an element. Returns true when object if fully initialized. bool initializeElement(unsigned I); @@ -307,7 +328,6 @@ struct InitMap final { } /// Number of fields not initialized. unsigned UninitFields; - std::unique_ptr<T[]> Data; }; } // namespace interp diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index 35937e3483e38..473442b3ded21 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -455,7 +455,7 @@ LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset, OS.indent(Spaces) << "Elements: " << getNumElems() << '\n'; OS.indent(Spaces) << "Element type: " << primTypeToString(getPrimType()) << '\n'; - unsigned FO = Offset + sizeof(InitMapPtr); + unsigned FO = Offset + sizeof(InitMap *); for (unsigned I = 0; I != getNumElems(); ++I) { OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n'; FO += getElemSize(); diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp index 7c3c21cf28251..59e78e8c9138f 100644 --- a/clang/lib/AST/ByteCode/EvaluationResult.cpp +++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp @@ -54,12 +54,11 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, } else { // Primitive arrays. if (S.getContext().canClassify(ElemType)) { - if (BasePtr.allElementsInitialized()) { + if (BasePtr.allElementsInitialized()) return true; - } else { - DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField()); - return false; - } + + DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField()); + return false; } for (size_t I = 0; I != NumElems; ++I) { diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 80ef656dc6285..08cdc25c6e132 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -2318,7 +2318,7 @@ bool FinishInitGlobal(InterpState &S, CodePtr OpPC) { finishGlobalRecurse(S, Ptr); if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index d8b8b209fa927..2b17ecb38cf42 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -418,7 +418,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { return false; if (T::add(A, B, Bits, &Result.elem<T>(1))) return false; - Result.initialize(); + Result.initialize(S); Result.initializeAllElements(); } @@ -1390,7 +1390,7 @@ bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Field = Obj.atField(I); if (!CheckStore(S, OpPC, Field)) return false; - Field.initialize(); + Field.initialize(S); Field.deref<T>() = Value; return true; } @@ -1492,7 +1492,7 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { } } - P.initialize(); + P.initialize(S); return true; } @@ -1512,7 +1512,7 @@ bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp)); Ptr.deref<T>() = S.Stk.pop<T>(); - Ptr.initialize(); + Ptr.initialize(S); return true; } @@ -1541,7 +1541,7 @@ bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Field = This.atField(I); assert(Field.canBeInitialized()); Field.deref<T>() = S.Stk.pop<T>(); - Field.initialize(); + Field.initialize(S); return true; } @@ -1556,7 +1556,7 @@ bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) { assert(Field.canBeInitialized()); Field.deref<T>() = S.Stk.pop<T>(); Field.activate(); - Field.initialize(); + Field.initialize(S); return true; } @@ -1575,7 +1575,7 @@ bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, assert(Field.canBeInitialized()); const auto &Value = S.Stk.pop<T>(); Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); - Field.initialize(); + Field.initialize(S); return true; } @@ -1592,7 +1592,7 @@ bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC, assert(Field.canBeInitialized()); const auto &Value = S.Stk.pop<T>(); Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); - Field.initialize(); + Field.initialize(S); Field.activate(); return true; } @@ -1611,7 +1611,7 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; - Field.initialize(); + Field.initialize(S); return true; } @@ -1627,7 +1627,7 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; Field.activate(); - Field.initialize(); + Field.initialize(S); return true; } @@ -1658,7 +1658,7 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { } else { Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); } - Field.initialize(); + Field.initialize(S); return true; } @@ -1691,7 +1691,7 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); } Field.activate(); - Field.initialize(); + Field.initialize(S); return true; } @@ -1828,21 +1828,21 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { inline bool FinishInitPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); return true; } inline bool FinishInit(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); return true; } inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } return true; @@ -1851,7 +1851,7 @@ inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) { inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } return true; @@ -1944,7 +1944,7 @@ bool Store(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr)) return false; if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); Ptr.deref<T>() = Value; return true; } @@ -1956,7 +1956,7 @@ bool StorePop(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr)) return false; if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); Ptr.deref<T>() = Value; return true; } @@ -1988,7 +1988,7 @@ bool StoreActivate(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true)) return false; if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } Ptr.deref<T>() = Value; @@ -2003,7 +2003,7 @@ bool StoreActivatePop(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true)) return false; if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } Ptr.deref<T>() = Value; @@ -2018,7 +2018,7 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true)) return false; if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); if (const auto *FD = Ptr.getField()) Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue()); else @@ -2033,7 +2033,7 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr)) return false; if (Ptr.canBeInitialized()) - Ptr.initialize(); + Ptr.initialize(S); if (const auto *FD = Ptr.getField()) Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue()); else @@ -2049,7 +2049,7 @@ bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true)) return false; if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } if (const auto *FD = Ptr.getField()) @@ -2067,7 +2067,7 @@ bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC) { if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true)) return false; if (Ptr.canBeInitialized()) { - Ptr.initialize(); + Ptr.initialize(S); Ptr.activate(); } if (const auto *FD = Ptr.getField()) @@ -2083,7 +2083,7 @@ bool Init(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckInit(S, OpPC, Ptr)) return false; - Ptr.initialize(); + Ptr.initialize(S); new (&Ptr.deref<T>()) T(Value); return true; } @@ -2094,7 +2094,7 @@ bool InitPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckInit(S, OpPC, Ptr)) return false; - Ptr.initialize(); + Ptr.initialize(S); new (&Ptr.deref<T>()) T(Value); return true; } @@ -2114,7 +2114,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { // In the unlikely event that we're initializing the first item of // a non-array, skip the atIndex(). if (Idx == 0 && !Desc->isArray()) { - Ptr.initialize(); + Ptr.initialize(S); new (&Ptr.deref<T>()) T(Value); return true; } @@ -2130,7 +2130,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { } return false; } - Ptr.initializeElement(Idx); + Ptr.initializeElement(S, Idx); new (&Ptr.elem<T>(Idx)) T(Value); return true; } @@ -2148,7 +2148,7 @@ bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { // In the unlikely event that we're initializing the first item of // a non-array, skip the atIndex(). if (Idx == 0 && !Desc->isArray()) { - Ptr.initialize(); + Ptr.initialize(S); new (&Ptr.deref<T>()) T(Value); return true; } @@ -2164,7 +2164,7 @@ bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { } return false; } - Ptr.initializeElement(Idx); + Ptr.initializeElement(S, Idx); new (&Ptr.elem<T>(Idx)) T(Value); return true; } @@ -3174,7 +3174,7 @@ inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, return false; DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I); - DestPtr.initializeElement(DestIndex + I); + DestPtr.initializeElement(S, DestIndex + I); } return true; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 4a789fe3a6af4..17fac525ff1d8 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -877,7 +877,7 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC, // Write Result to ResultPtr and put Overflow on the stack. assignInteger(S, ResultPtr, ResultT, Result); if (ResultPtr.canBeInitialized()) - ResultPtr.initialize(); + ResultPtr.initialize(S); assert(Call->getDirectCallee()->getReturnType()->isBooleanType()); S.Stk.push<Boolean>(Overflow); @@ -934,7 +934,7 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType(); PrimType CarryOutT = *S.getContext().classify(CarryOutType); assignInteger(S, CarryOutPtr, CarryOutT, CarryOut); - CarryOutPtr.initialize(); + CarryOutPtr.initialize(S); assert(Call->getType() == Call->getArg(0)->getType()); pushInteger(S, Result, Call->getType()); @@ -1743,7 +1743,7 @@ static bool interp__builtin_elementwise_countzeroes(InterpState &S, } else { Dst.atIndex(I).deref<T>() = T::from(EltVal.countLeadingZeros()); } - Dst.atIndex(I).initialize(); + Dst.atIndex(I).initialize(S); }); } @@ -1960,7 +1960,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, // Now, read both pointers to a buffer and compare those. BitcastBuffer BufferA( Bits(ASTCtx.getTypeSize(ElemTypeA) * PtrA.getNumElems())); - readPointerToBuffer(S.getContext(), PtrA, BufferA, false); + readPointerToBuffer(S, S.getContext(), PtrA, BufferA, false); // FIXME: The swapping here is UNDOING something we do when reading the // data into the buffer. if (ASTCtx.getTargetInfo().isBigEndian()) @@ -1968,7 +1968,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, BitcastBuffer BufferB( Bits(ASTCtx.getTypeSize(ElemTypeB) * PtrB.getNumElems())); - readPointerToBuffer(S.getContext(), PtrB, BufferB, false); + readPointerToBuffer(S, S.getContext(), PtrB, BufferB, false); // FIXME: The swapping here is UNDOING something we do when reading the // data into the buffer. if (ASTCtx.getTargetInfo().isBigEndian()) @@ -5583,7 +5583,7 @@ bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, INT_TYPE_SWITCH(FieldT, FieldPtr.deref<T>() = T::from(IntValue.getSExtValue())); - FieldPtr.initialize(); + FieldPtr.initialize(S); return true; } @@ -5639,7 +5639,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, TYPE_SWITCH(*FT, { DestField.deref<T>() = Src.atField(F.Offset).deref<T>(); if (Src.atField(F.Offset).isInitialized()) - DestField.initialize(); + DestField.initialize(S); if (Activate) DestField.activate(); }); @@ -5677,7 +5677,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, return false; } - Dest.initialize(); + Dest.initialize(S); return true; } @@ -5698,7 +5698,7 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer DestElem = Dest.atIndex(I); TYPE_SWITCH(ET, { DestElem.deref<T>() = Src.elem<T>(I); - DestElem.initialize(); + DestElem.initialize(S); }); } return true; diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 4bd9c66fc9974..f959855ca2a54 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -77,8 +77,8 @@ using DataFunc = /// We use this to recursively iterate over all fields and elements of a pointer /// and extract relevant data for a bitcast. -static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, - Bits BitsToRead, DataFunc F) { +static bool enumerateData(InterpState &S, const Pointer &P, const Context &Ctx, + Bits Offset, Bits BitsToRead, DataFunc F) { const Descriptor *FieldDesc = P.getFieldDesc(); assert(FieldDesc); @@ -114,7 +114,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, QualType ElemType = FieldDesc->getElemQualType(); Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) { - enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); + enumerateData(S, P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); Offset += ElemSize; if (Offset >= BitsToRead) break; @@ -135,18 +135,18 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, Pointer Elem = P.atField(Fi.Offset); Bits BitOffset = Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex())); - Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); + Ok = Ok && enumerateData(S, Elem, Ctx, BitOffset, BitsToRead, F); } for (const Record::Base &B : R->bases()) { Pointer Elem = P.atField(B.Offset); CharUnits ByteOffset = Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl)); Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset)); - Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); + Ok = Ok && enumerateData(S, Elem, Ctx, BitOffset, BitsToRead, F); // FIXME: We should only (need to) do this when bitcasting OUT of the // buffer, not when copying data into it. if (Ok) - Elem.initialize(); + Elem.initialize(S); } return Ok; @@ -155,9 +155,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, llvm_unreachable("Unhandled data type"); } -static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, - Bits BitsToRead, DataFunc F) { - return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F); +static bool enumeratePointerFields(InterpState &S, const Pointer &P, + const Context &Ctx, Bits BitsToRead, + DataFunc F) { + return enumerateData(S, P, Ctx, Bits::zero(), BitsToRead, F); } // This function is constexpr if and only if To, From, and the types of @@ -257,7 +258,7 @@ static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, return true; } -bool clang::interp::readPointerToBuffer(const Context &Ctx, +bool clang::interp::readPointerToBuffer(InterpState &S, const Context &Ctx, const Pointer &FromPtr, BitcastBuffer &Buffer, bool ReturnOnUninit) { @@ -266,7 +267,7 @@ bool clang::interp::readPointerToBuffer(const Context &Ctx, ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; return enumeratePointerFields( - FromPtr, Ctx, Buffer.size(), + S, FromPtr, Ctx, Buffer.size(), [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { Bits BitWidth = FullBitWidth; @@ -339,7 +340,7 @@ bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!CheckBitcastType(S, OpPC, DataType, /*IsToType=*/false)) return false; - bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer, + bool Success = readPointerToBuffer(S, S.getContext(), Ptr, Buffer, /*ReturnOnUninit=*/false); HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth); @@ -381,14 +382,14 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, const ASTContext &ASTCtx = S.getASTContext(); BitcastBuffer Buffer(Bytes(Size).toBits()); - readPointerToBuffer(S.getContext(), FromPtr, Buffer, + readPointerToBuffer(S, S.getContext(), FromPtr, Buffer, /*ReturnOnUninit=*/false); // Now read the values out of the buffer again and into ToPtr. Endian TargetEndianness = ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; bool Success = enumeratePointerFields( - ToPtr, S.getContext(), Buffer.size(), + S, ToPtr, S.getContext(), Buffer.size(), [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { QualType PtrType = P.getType(); @@ -406,7 +407,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, Floating R = S.allocFloat(Semantics); Floating::bitcastFromMemory(M.get(), Semantics, &R); P.deref<Floating>() = R; - P.initialize(); + P.initialize(S); return true; } @@ -462,7 +463,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, P.deref<T>() = T::zero(); }); } - P.initialize(); + P.initialize(S); return true; }); @@ -489,7 +490,7 @@ bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC, assert(DestPtr.isBlockPointer()); llvm::SmallVector<PrimTypeVariant> Values; - enumeratePointerFields(SrcPtr, S.getContext(), Size, + enumeratePointerFields(S, SrcPtr, S.getContext(), Size, [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); }); @@ -497,12 +498,12 @@ bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC, }); unsigned ValueIndex = 0; - enumeratePointerFields(DestPtr, S.getContext(), Size, + enumeratePointerFields(S, DestPtr, S.getContext(), Size, [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { TYPE_SWITCH(T, { P.deref<T>() = std::get<T>(Values[ValueIndex]); - P.initialize(); + P.initialize(S); }); ++ValueIndex; diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h index a0191bab693c4..8422ef8d9a2dd 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h @@ -31,8 +31,9 @@ bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr); bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr, size_t Size); -bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, - BitcastBuffer &Buffer, bool ReturnOnUninit); +bool readPointerToBuffer(InterpState &S, const Context &Ctx, + const Pointer &FromPtr, BitcastBuffer &Buffer, + bool ReturnOnUninit); bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &SrcPtr, const Pointer &DestPtr, Bits Size); diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 00e74db5655d6..8fa17aed29d9e 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -13,8 +13,10 @@ #include "Function.h" #include "Integral.h" #include "InterpBlock.h" +#include "InterpState.h" #include "MemberPointer.h" #include "PrimType.h" +#include "Program.h" #include "Record.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -442,18 +444,25 @@ bool Pointer::isInitialized() const { if (!isBlockPointer()) return true; + assert(BS.Pointee && "Cannot check if null pointer was initialized"); if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && Offset == BS.Base) { - const GlobalInlineDescriptor &GD = + const auto &GD = *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); return GD.InitState == GlobalInitState::Initialized; } - assert(BS.Pointee && "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); - if (Desc->isPrimitiveArray()) - return isElementInitialized(getIndex()); + if (Desc->isPrimitiveArray()) { + InitMap *&IM = getInitMap(); + if (!IM) + return false; + + if (InitMap::allInitialized(IM)) + return true; + return IM->isElementInitialized(getIndex()); + } if (asBlockPointer().Base == 0) return true; @@ -462,45 +471,37 @@ bool Pointer::isInitialized() const { } bool Pointer::isElementInitialized(unsigned Index) const { - if (!isBlockPointer()) - return true; - + assert(isBlockPointer()); const Descriptor *Desc = getFieldDesc(); - assert(Desc); - - if (isStatic() && BS.Base == 0) - return true; - - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && - Offset == BS.Base) { - const GlobalInlineDescriptor &GD = - *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); - return GD.InitState == GlobalInitState::Initialized; - } - + assert(Desc->isArray()); if (Desc->isPrimitiveArray()) { - InitMapPtr &IM = getInitMap(); + assert(getFieldDesc()->isPrimitiveArray()); + InitMap *&IM = getInitMap(); if (!IM) return false; - if (IM->first) + if (InitMap::allInitialized(IM)) return true; - - return IM->second->isElementInitialized(Index); + return IM->isElementInitialized(Index); } - return isInitialized(); + + // Composite arrays. + return getDescriptor(BS.Base + sizeof(InlineDescriptor) + + (elemSize() * Index)) + ->IsInitialized; } -void Pointer::initialize() const { +void Pointer::initialize(InterpState &S) const { if (!isBlockPointer()) return; - assert(BS.Pointee && "Cannot initialize null pointer"); + if (isStatic() && BS.Base == 0) + return; if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && Offset == BS.Base) { - GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>( - asBlockPointer().Pointee->rawData()); + auto &GD = + *reinterpret_cast<GlobalInlineDescriptor *>(BS.Pointee->rawData()); GD.InitState = GlobalInitState::Initialized; return; } @@ -509,7 +510,7 @@ void Pointer::initialize() const { assert(Desc); if (Desc->isPrimitiveArray()) { if (Desc->getNumElems() != 0) - initializeElement(getIndex()); + initializeElement(S, getIndex()); return; } @@ -518,60 +519,49 @@ void Pointer::initialize() const { getInlineDesc()->IsInitialized = true; } -void Pointer::initializeElement(unsigned Index) const { - // Primitive global arrays don't have an initmap. - if (isStatic() && BS.Base == 0) - return; - +void Pointer::initializeElement(InterpState &S, unsigned Index) const { + assert(isBlockPointer()); + assert(getFieldDesc()->isPrimitiveArray()); assert(Index < getFieldDesc()->getNumElems()); - InitMapPtr &IM = getInitMap(); + InitMap *&IM = getInitMap(); + if (InitMap::allInitialized(IM)) + return; + + // nullptr means no initmap yet. if (!IM) { - const Descriptor *Desc = getFieldDesc(); - IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems())); + unsigned NumElems = getFieldDesc()->getNumElems(); + if (NumElems == 1) { + InitMap::markAllInitialized(IM); + return; + } + + if (block()->isStatic()) + IM = (InitMap *)S.P.Allocate(InitMap::allocBytes(NumElems), + alignof(InitMap)); + else + IM = (InitMap *)S.allocate(InitMap::allocBytes(NumElems), + alignof(InitMap)); + new (IM) InitMap(NumElems); } assert(IM); - - // All initialized. - if (IM->first) - return; - - if (IM->second->initializeElement(Index)) { - IM->first = true; - IM->second.reset(); - } + if (IM->initializeElement(Index)) + InitMap::markAllInitialized(IM); } void Pointer::initializeAllElements() const { + assert(isBlockPointer()); assert(getFieldDesc()->isPrimitiveArray()); assert(isArrayRoot()); - - InitMapPtr &IM = getInitMap(); - if (!IM) { - IM = std::make_pair(true, nullptr); - } else { - IM->first = true; - IM->second.reset(); - } + InitMap::markAllInitialized(getInitMap()); } bool Pointer::allElementsInitialized() const { + assert(isBlockPointer()); assert(getFieldDesc()->isPrimitiveArray()); assert(isArrayRoot()); - - if (isStatic() && BS.Base == 0) - return true; - - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && - Offset == BS.Base) { - const GlobalInlineDescriptor &GD = - *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); - return GD.InitState == GlobalInitState::Initialized; - } - - InitMapPtr &IM = getInitMap(); - return IM && IM->first; + return InitMap::allInitialized(getInitMap()); } void Pointer::activate() const { diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 0978090ba8b19..f4f3519175439 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -93,6 +93,7 @@ class Pointer { private: static constexpr unsigned PastEndMark = ~0u; static constexpr unsigned RootPtrMark = ~0u; + static constexpr unsigned InitMapPtrSize = sizeof(void *); public: Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {} @@ -166,7 +167,7 @@ class Pointer { if (getFieldDesc()->ElemDesc) Off += sizeof(InlineDescriptor); else - Off += sizeof(InitMapPtr); + Off += InitMapPtrSize; return Pointer(BS.Pointee, BS.Base, BS.Base + Off); } @@ -231,7 +232,7 @@ class Pointer { // Revert to an outer one-past-end pointer. unsigned Adjust; if (inPrimitiveArray()) - Adjust = sizeof(InitMapPtr); + Adjust = InitMapPtrSize; else Adjust = sizeof(InlineDescriptor); return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust); @@ -389,7 +390,7 @@ class Pointer { if (getFieldDesc()->ElemDesc) Adjust = sizeof(InlineDescriptor); else - Adjust = sizeof(InitMapPtr); + Adjust = InitMapPtrSize; } return Offset - BS.Base - Adjust; } @@ -674,7 +675,7 @@ class Pointer { if (isArrayRoot()) return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base + - sizeof(InitMapPtr)); + InitMapPtrSize); return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset); } @@ -690,7 +691,7 @@ class Pointer { assert(I < getFieldDesc()->getNumElems()); unsigned ElemByteOffset = I * getFieldDesc()->getElemSize(); - unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset; + unsigned ReadOffset = BS.Base + InitMapPtrSize + ElemByteOffset; assert(ReadOffset + sizeof(T) <= BS.Pointee->getDescriptor()->getAllocSize()); @@ -709,9 +710,9 @@ class Pointer { } /// Initializes a field. - void initialize() const; + void initialize(InterpState &S) const; /// Initialized the given element of a primitive array. - void initializeElement(unsigned Index) const; + void initializeElement(InterpState &S, unsigned Index) const; /// Initialize all elements of a primitive array at once. This can be /// used in situations where we *know* we have initialized *all* elements /// of a primtive array. @@ -814,11 +815,12 @@ class Pointer { 1; } +private: /// Returns a reference to the InitMapPtr which stores the initialization map. - InitMapPtr &getInitMap() const { + InitMap *&getInitMap() const { assert(isBlockPointer()); assert(!isZero()); - return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base); + return *reinterpret_cast<InitMap **>(BS.Pointee->rawData() + BS.Base); } /// Offset into the storage. diff --git a/clang/test/AST/ByteCode/const-eval.c b/clang/test/AST/ByteCode/const-eval.c index d6cf600b378a8..012542c8776af 100644 --- a/clang/test/AST/ByteCode/const-eval.c +++ b/clang/test/AST/ByteCode/const-eval.c @@ -127,7 +127,9 @@ EVAL_EXPR(43, varfloat && constfloat) // both-error {{not an integer constant ex EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1) EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1) EVAL_EXPR(47, &x < &x + 1 ? 1 : -1) +#if 0 EVAL_EXPR(48, &x != &x - 1 ? 1 : -1) +#endif EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // ref-error {{not an integer constant expression}} extern struct Test50S Test50; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
