https://github.com/zhangweize9-cyber updated https://github.com/llvm/llvm-project/pull/216611
>From 3b6ef25ffb618a937b14a555d7585c45cb96779d Mon Sep 17 00:00:00 2001 From: "A. Jiang" <[email protected]> Date: Mon, 17 Aug 2026 07:08:38 +0800 Subject: [PATCH] [libc++][test] Mark `UNSUPPORTED` for a test relying on `[[clang::trivial_abi]]` for compilers not supporting it (#211736) This patch marks `UNSUPPORTED` for compilers not supporting `[[clang::trivial_abi]]` (MSVC and GCC earlier than GCC 17) for a test relying on this attribute. --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 744 +++++++++--------- .../invalid-pointer-pairs-vector-extract.cpp | 2 - .../ExecutionEngine/Orc/SymbolLookupSet.h | 31 +- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 4 +- .../AMDGPU/elementwise-fma-operand1.ll | 100 +-- .../ExecutionEngine/Orc/CMakeLists.txt | 1 - .../Orc/SymbolLookupSetTest.cpp | 133 ---- .../unittests/ExecutionEngine/Orc/BUILD.gn | 1 - orc-rt/include/CMakeLists.txt | 1 - orc-rt/include/orc-rt/StringPool.h | 249 ------ orc-rt/test/unit/CMakeLists.txt | 1 - orc-rt/test/unit/StringPoolTest.cpp | 166 ---- 12 files changed, 380 insertions(+), 1053 deletions(-) delete mode 100644 llvm/unittests/ExecutionEngine/Orc/SymbolLookupSetTest.cpp delete mode 100644 orc-rt/include/orc-rt/StringPool.h delete mode 100644 orc-rt/test/unit/StringPoolTest.cpp diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index c17813140b10f..9b3f0b84dea39 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -63,12 +63,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { } public: - ItaniumCXXABI(CodeGen::CodeGenModule &CGM, - bool UseARMMethodPtrABI = false, - bool UseARMGuardVarABI = false) : - CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), - UseARMGuardVarABI(UseARMGuardVarABI), - Use32BitVTableOffsetABI(false) { } + ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool UseARMMethodPtrABI = false, + bool UseARMGuardVarABI = false) + : CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), + UseARMGuardVarABI(UseARMGuardVarABI), Use32BitVTableOffsetABI(false) {} bool classifyReturnType(CGFunctionInfo &FI) const override; @@ -130,12 +128,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override; CGCallee - EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, - const Expr *E, - Address This, - llvm::Value *&ThisPtrForCall, - llvm::Value *MemFnPtr, - const MemberPointerType *MPT) override; + EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, const Expr *E, + Address This, llvm::Value *&ThisPtrForCall, + llvm::Value *MemFnPtr, + const MemberPointerType *MPT) override; llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr, @@ -157,14 +153,14 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { llvm::Constant *BuildMemberPointer(const CXXMethodDecl *MD, CharUnits ThisAdjustment); - llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, llvm::Value *R, + llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, + llvm::Value *R, const MemberPointerType *MPT, bool Inequality) override; - llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *Addr, - const MemberPointerType *MPT) override; + llvm::Value * + EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *Addr, + const MemberPointerType *MPT) override; void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, @@ -261,9 +257,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { bool EmitBadCastCall(CodeGenFunction &CGF) override; llvm::Value * - GetVirtualBaseClassOffset(CodeGenFunction &CGF, Address This, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) override; + GetVirtualBaseClassOffset(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) override; void EmitCXXConstructors(const CXXConstructorDecl *D) override; @@ -369,17 +365,16 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { } StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; } - StringRef GetDeletedVirtualCallName() override - { return "__cxa_deleted_virtual"; } + StringRef GetDeletedVirtualCallName() override { + return "__cxa_deleted_virtual"; + } CharUnits getArrayCookieSizeImpl(QualType elementType) override; - Address InitializeArrayCookie(CodeGenFunction &CGF, - Address NewPtr, + Address InitializeArrayCookie(CodeGenFunction &CGF, Address NewPtr, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType) override; - llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, - Address allocPtr, + llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, Address allocPtr, CharUnits cookieSize) override; void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, @@ -392,14 +387,12 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD, llvm::Value *Val); void EmitThreadLocalInitFuncs( - CodeGenModule &CGM, - ArrayRef<const VarDecl *> CXXThreadLocals, + CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals, ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override; bool usesThreadWrapperFunction(const VarDecl *VD) const override { - return !isEmittedWithConstantInitializer(VD) || - mayNeedDestruction(VD); + return !isEmittedWithConstantInitializer(VD) || mayNeedDestruction(VD); } LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) override; @@ -446,43 +439,43 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { LoadVTablePtr(CodeGenFunction &CGF, Address This, const CXXRecordDecl *RD) override; - private: - llvm::Constant * - getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD); - - bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const { - const auto &VtableLayout = - CGM.getItaniumVTableContext().getVTableLayout(RD); - - for (const auto &VtableComponent : VtableLayout.vtable_components()) { - // Skip empty slot. - if (!VtableComponent.isUsedFunctionPointerKind()) - continue; - - const CXXMethodDecl *Method = VtableComponent.getFunctionDecl(); - const FunctionDecl *FD = Method->getDefinition(); - const bool IsInlined = - Method->getCanonicalDecl()->isInlined() || (FD && FD->isInlined()); - if (!IsInlined) - continue; - - StringRef Name = CGM.getMangledName( - VtableComponent.getGlobalDecl(/*HasVectorDeletingDtors=*/false)); - auto *Entry = CGM.GetGlobalValue(Name); - // This checks if virtual inline function has already been emitted. - // Note that it is possible that this inline function would be emitted - // after trying to emit vtable speculatively. Because of this we do - // an extra pass after emitting all deferred vtables to find and emit - // these vtables opportunistically. - if (!Entry || Entry->isDeclaration()) - return true; - } - return false; +private: + llvm::Constant * + getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD); + + bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const { + const auto &VtableLayout = + CGM.getItaniumVTableContext().getVTableLayout(RD); + + for (const auto &VtableComponent : VtableLayout.vtable_components()) { + // Skip empty slot. + if (!VtableComponent.isUsedFunctionPointerKind()) + continue; + + const CXXMethodDecl *Method = VtableComponent.getFunctionDecl(); + const FunctionDecl *FD = Method->getDefinition(); + const bool IsInlined = + Method->getCanonicalDecl()->isInlined() || (FD && FD->isInlined()); + if (!IsInlined) + continue; + + StringRef Name = CGM.getMangledName( + VtableComponent.getGlobalDecl(/*HasVectorDeletingDtors=*/false)); + auto *Entry = CGM.GetGlobalValue(Name); + // This checks if virtual inline function has already been emitted. + // Note that it is possible that this inline function would be emitted + // after trying to emit vtable speculatively. Because of this we do + // an extra pass after emitting all deferred vtables to find and emit + // these vtables opportunistically. + if (!Entry || Entry->isDeclaration()) + return true; + } + return false; } bool isVTableHidden(const CXXRecordDecl *RD) const { const auto &VtableLayout = - CGM.getItaniumVTableContext().getVTableLayout(RD); + CGM.getItaniumVTableContext().getVTableLayout(RD); for (const auto &VtableComponent : VtableLayout.vtable_components()) { if (VtableComponent.isRTTIKind()) { @@ -502,9 +495,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { class ARMCXXABI : public ItaniumCXXABI { public: - ARMCXXABI(CodeGen::CodeGenModule &CGM) : - ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true, - /*UseARMGuardVarABI=*/true) {} + ARMCXXABI(CodeGen::CodeGenModule &CGM) + : ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true, + /*UseARMGuardVarABI=*/true) {} bool constructorsAndDestructorsReturnThis() const override { return true; } @@ -512,8 +505,7 @@ class ARMCXXABI : public ItaniumCXXABI { QualType ResTy) override; CharUnits getArrayCookieSizeImpl(QualType elementType) override; - Address InitializeArrayCookie(CodeGenFunction &CGF, - Address NewPtr, + Address InitializeArrayCookie(CodeGenFunction &CGF, Address NewPtr, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType) override; @@ -533,8 +525,7 @@ class AppleARM64CXXABI : public ARMCXXABI { class FuchsiaCXXABI final : public ItaniumCXXABI { public: - explicit FuchsiaCXXABI(CodeGen::CodeGenModule &CGM) - : ItaniumCXXABI(CGM) {} + explicit FuchsiaCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM) {} private: bool constructorsAndDestructorsReturnThis() const override { return true; } @@ -557,8 +548,7 @@ class WebAssemblyCXXABI final : public ItaniumCXXABI { class XLCXXABI final : public ItaniumCXXABI { public: - explicit XLCXXABI(CodeGen::CodeGenModule &CGM) - : ItaniumCXXABI(CGM) {} + explicit XLCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM) {} void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, llvm::FunctionCallee dtor, @@ -570,7 +560,7 @@ class XLCXXABI final : public ItaniumCXXABI { void emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub, llvm::Constant *addr); }; -} +} // namespace CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { switch (CGM.getContext().getCXXABIKind()) { @@ -641,8 +631,8 @@ ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { /// the function to call. CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( CodeGenFunction &CGF, const Expr *E, Address ThisAddr, - llvm::Value *&ThisPtrForCall, - llvm::Value *MemFnPtr, const MemberPointerType *MPT) { + llvm::Value *&ThisPtrForCall, llvm::Value *MemFnPtr, + const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; const FunctionProtoType *FPT = @@ -689,9 +679,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( // Cast the adjusted this to a pointer to vtable pointer and load. llvm::Type *VTableTy = CGF.CGM.GlobalsInt8PtrTy; - CharUnits VTablePtrAlign = - CGF.CGM.getDynamicOffsetAlignment(ThisAddr.getAlignment(), RD, - CGF.getPointerAlign()); + CharUnits VTablePtrAlign = CGF.CGM.getDynamicOffsetAlignment( + ThisAddr.getAlignment(), RD, CGF.getPointerAlign()); llvm::Value *VTable = CGF.GetVTablePtr( Address(This, ThisAddr.getElementType(), VTablePtrAlign), VTableTy, RD); @@ -953,10 +942,9 @@ static llvm::Constant *pointerAuthResignConstant( /// MP when the derived MP does not point to a member of the base. /// This is why -1 is a reasonable choice for null data member /// pointers. -llvm::Value * -ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *src) { +llvm::Value *ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *src) { // Use constant emission if we can. if (isa<llvm::Constant>(src)) return EmitMemberPointerConversion(E, cast<llvm::Constant>(src)); @@ -1009,15 +997,16 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, } // Under Itanium, reinterprets don't require any additional processing. - if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + if (E->getCastKind() == CK_ReinterpretMemberPointer) + return src; llvm::Constant *adj = getMemberPointerAdjustment(E); - if (!adj) return src; + if (!adj) + return src; bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); - const MemberPointerType *destTy = - E->getType()->castAs<MemberPointerType>(); + const MemberPointerType *destTy = E->getType()->castAs<MemberPointerType>(); // For member data pointers, this is just a matter of adding the // offset if the source is non-null. @@ -1093,22 +1082,24 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E, src, DstType, E->getSubExpr()->getType(), CGM); // Under Itanium, reinterprets don't require any additional processing. - if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + if (E->getCastKind() == CK_ReinterpretMemberPointer) + return src; // If the adjustment is trivial, we don't need to do anything. llvm::Constant *adj = getMemberPointerAdjustment(E); - if (!adj) return src; + if (!adj) + return src; bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); - const MemberPointerType *destTy = - E->getType()->castAs<MemberPointerType>(); + const MemberPointerType *destTy = E->getType()->castAs<MemberPointerType>(); // For member data pointers, this is just a matter of adding the // offset if the source is non-null. if (destTy->isMemberDataPointer()) { // null maps to null. - if (src->isAllOnesValue()) return src; + if (src->isAllOnesValue()) + return src; if (isDerivedToBase) return llvm::ConstantExpr::getNSWSub(src, adj); @@ -1143,7 +1134,7 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true); llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0); - llvm::Constant *Values[2] = { Zero, Zero }; + llvm::Constant *Values[2] = {Zero, Zero}; return llvm::ConstantStruct::getAnon(Values); } @@ -1221,8 +1212,8 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, // virtual table offset (in bytes) of the function, // represented as a ptrdiff_t. MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset + 1); - MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, - ThisAdjustment.getQuantity()); + MemPtr[1] = + llvm::ConstantInt::get(CGM.PtrDiffTy, ThisAdjustment.getQuantity()); } } else { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); @@ -1239,9 +1230,9 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, llvm::Constant *addr = CGM.getMemberFunctionPointer(MD, Ty); MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy); - MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, - (UseARMMethodPtrABI ? 2 : 1) * - ThisAdjustment.getQuantity()); + MemPtr[1] = + llvm::ConstantInt::get(CGM.PtrDiffTy, (UseARMMethodPtrABI ? 2 : 1) * + ThisAdjustment.getQuantity()); } return llvm::ConstantStruct::getAnon(MemPtr); @@ -1265,7 +1256,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP, getContext().recordMemberDataPointerEvaluation(MPD); CharUnits FieldOffset = - getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD)); + getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD)); return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset); } @@ -1273,12 +1264,9 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP, /// the same if they're either bitwise identical *or* both null. /// /// ARM is different here only because null-ness is more complicated. -llvm::Value * -ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality) { +llvm::Value *ItaniumCXXABI::EmitMemberPointerComparison( + CodeGenFunction &CGF, llvm::Value *L, llvm::Value *R, + const MemberPointerType *MPT, bool Inequality) { CGBuilderTy &Builder = CGF.Builder; llvm::ICmpInst::Predicate Eq; @@ -1335,8 +1323,8 @@ ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, // Compute (l.adj | r.adj) & 1 and test it against zero. llvm::Value *OrAdj = Builder.CreateOr(LAdj, RAdj, "or.adj"); llvm::Value *OrAdjAnd1 = Builder.CreateAnd(OrAdj, One); - llvm::Value *OrAdjAnd1EqZero = Builder.CreateICmp(Eq, OrAdjAnd1, Zero, - "cmp.or.adj"); + llvm::Value *OrAdjAnd1EqZero = + Builder.CreateICmp(Eq, OrAdjAnd1, Zero, "cmp.or.adj"); EqZero = Builder.CreateBinOp(And, EqZero, OrAdjAnd1EqZero); } @@ -1347,17 +1335,15 @@ ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, return Result; } -llvm::Value * -ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *MemPtr, - const MemberPointerType *MPT) { +llvm::Value *ItaniumCXXABI::EmitMemberPointerIsNotNull( + CodeGenFunction &CGF, llvm::Value *MemPtr, const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; /// For member data pointers, this is just a check against -1. if (MPT->isMemberDataPointer()) { assert(MemPtr->getType() == CGM.PtrDiffTy); llvm::Value *NegativeOne = - llvm::Constant::getAllOnesValue(MemPtr->getType()); + llvm::Constant::getAllOnesValue(MemPtr->getType()); return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); } @@ -1373,8 +1359,8 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1); llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj"); llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); - llvm::Value *IsVirtual = Builder.CreateICmpNE(VirtualBit, Zero, - "memptr.isvirtual"); + llvm::Value *IsVirtual = + Builder.CreateICmpNE(VirtualBit, Zero, "memptr.isvirtual"); Result = Builder.CreateOr(Result, IsVirtual); } @@ -1409,8 +1395,7 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { /// at entry -2 in the vtable. void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, - Address Ptr, - QualType ElementType, + Address Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) { bool UseGlobalDelete = DE->isGlobalDelete(); if (UseGlobalDelete) { @@ -1452,7 +1437,7 @@ void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { // void __cxa_rethrow(); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::FunctionCallee Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); @@ -1466,7 +1451,7 @@ static llvm::FunctionCallee getAllocateExceptionFn(CodeGenModule &CGM) { // void *__cxa_allocate_exception(size_t thrown_size); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } @@ -1475,9 +1460,9 @@ static llvm::FunctionCallee getThrowFn(CodeGenModule &CGM) { // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, // void (*dest) (void *)); - llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.GlobalsInt8PtrTy, CGM.Int8PtrTy }; + llvm::Type *Args[3] = {CGM.Int8PtrTy, CGM.GlobalsInt8PtrTy, CGM.Int8PtrTy}; llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, Args, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, Args, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } @@ -1493,8 +1478,8 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); CharUnits ExnAlign = CGF.getContext().getExnObjectAlignment(); - CGF.EmitAnyExprToExn( - E->getSubExpr(), Address(ExceptionPtr, CGM.Int8Ty, ExnAlign)); + CGF.EmitAnyExprToExn(E->getSubExpr(), + Address(ExceptionPtr, CGM.Int8Ty, ExnAlign)); // Now throw the exception. llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, @@ -1516,9 +1501,10 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { Dtor = CGM.getAddrOfCXXStructor(GlobalDecl(DtorD, Dtor_Complete)); Dtor = CGM.getFunctionPointer(Dtor, DtorTy); } - if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy); + if (!Dtor) + Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy); - llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor }; + llvm::Value *args[] = {ExceptionPtr, TypeInfo, Dtor}; CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args); } @@ -1531,9 +1517,9 @@ static llvm::FunctionCallee getItaniumDynamicCastFn(CodeGenFunction &CGF) { llvm::Type *Int8PtrTy = CGF.Int8PtrTy; llvm::Type *GlobInt8PtrTy = CGF.GlobalsInt8PtrTy; llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); + CGF.ConvertType(CGF.getContext().getPointerDiffType()); - llvm::Type *Args[4] = { Int8PtrTy, GlobInt8PtrTy, GlobInt8PtrTy, PtrDiffTy }; + llvm::Type *Args[4] = {Int8PtrTy, GlobInt8PtrTy, GlobInt8PtrTy, PtrDiffTy}; llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); @@ -1572,7 +1558,7 @@ static CharUnits computeOffsetHint(ASTContext &Context, // Now walk all possible inheritance paths. for (const CXXBasePath &Path : Paths) { - if (Path.Access != AS_public) // Ignore non-public inheritance. + if (Path.Access != AS_public) // Ignore non-public inheritance. continue; ++NumPublicPaths; @@ -1625,12 +1611,11 @@ void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) { } llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF, - QualType SrcRecordTy, - Address ThisPtr, + QualType SrcRecordTy, Address ThisPtr, llvm::Type *StdTypeInfoPtrTy) { auto *ClassDecl = SrcRecordTy->castAsCXXRecordDecl(); - llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, CGM.GlobalsInt8PtrTy, - ClassDecl); + llvm::Value *Value = + CGF.GetVTablePtr(ThisPtr, CGM.GlobalsInt8PtrTy, ClassDecl); if (CGM.getLangOpts().RelativeCXXABIVTables) { // Load the type info. @@ -1879,24 +1864,22 @@ bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) { } llvm::Value * -ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, - Address This, +ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, Address This, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { llvm::Value *VTablePtr = CGF.GetVTablePtr(This, CGM.Int8PtrTy, ClassDecl); CharUnits VBaseOffsetOffset = CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); - llvm::Value *VBaseOffsetPtr = - CGF.Builder.CreateConstGEP1_64( - CGF.Int8Ty, VTablePtr, VBaseOffsetOffset.getQuantity(), - "vbase.offset.ptr"); + llvm::Value *VBaseOffsetPtr = CGF.Builder.CreateConstGEP1_64( + CGF.Int8Ty, VTablePtr, VBaseOffsetOffset.getQuantity(), + "vbase.offset.ptr"); llvm::Value *VBaseOffset; if (CGM.getLangOpts().RelativeCXXABIVTables) { - VBaseOffset = CGF.Builder.CreateAlignedLoad( - CGF.Int32Ty, VBaseOffsetPtr, CharUnits::fromQuantity(4), - "vbase.offset"); + VBaseOffset = CGF.Builder.CreateAlignedLoad(CGF.Int32Ty, VBaseOffsetPtr, + CharUnits::fromQuantity(4), + "vbase.offset"); } else { VBaseOffset = CGF.Builder.CreateAlignedLoad( CGM.PtrDiffTy, VBaseOffsetPtr, CGF.getPointerAlign(), "vbase.offset"); @@ -2041,8 +2024,8 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF, QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy); CGCallee Callee; - if (getContext().getLangOpts().AppleKext && - Type != Dtor_Base && DD->isVirtual()) + if (getContext().getLangOpts().AppleKext && Type != Dtor_Base && + DD->isVirtual()) Callee = CGF.BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent()); else Callee = CGCallee::forDirect(CGM.getAddrOfCXXStructor(GD), GD); @@ -2192,9 +2175,9 @@ ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base, VTableLayout::AddressPointLocation AddressPoint = Layout.getAddressPoint(Base); llvm::Value *Indices[] = { - llvm::ConstantInt::get(CGM.Int32Ty, 0), - llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.VTableIndex), - llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.AddressPointIndex), + llvm::ConstantInt::get(CGM.Int32Ty, 0), + llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.VTableIndex), + llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.AddressPointIndex), }; // Add inrange attribute to indicate that only the VTableIndex can be @@ -2228,13 +2211,15 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( VirtualPointerIndex); // And load the address point from the VTT. - llvm::Value *AP = - CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, - CGF.getPointerAlign()); - - if (auto PointerAuth = CGM.getVTablePointerAuthInfo(&CGF, VTableClass, VTT, - /*IsVTTEntry=*/true)) - AP = CGF.EmitPointerAuthAuth(*PointerAuth, AP); + llvm::Value *AP = CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, + CGF.getPointerAlign()); + + if (auto &Schema = + CGF.CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) { + CGPointerAuthInfo PointerAuth = + CGF.EmitPointerAuthInfo(Schema, VTT, GlobalDecl(), QualType()); + AP = CGF.EmitPointerAuthAuth(PointerAuth, AP); + } return AP; } @@ -2277,8 +2262,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, } CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, - GlobalDecl GD, - Address This, + GlobalDecl GD, Address This, llvm::Type *Ty, SourceLocation Loc) { llvm::Type *PtrTy = CGM.GlobalsInt8PtrTy; @@ -2350,8 +2334,10 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, CGPointerAuthInfo PointerAuth; if (Schema) { assert(VTableSlotPtr && "virtual function pointer not set"); - GD = CGM.getItaniumVTableContext().findOriginalMethod(GD.getCanonicalDecl()); - PointerAuth = CGF.EmitPointerAuthInfo(Schema, VTableSlotPtr, GD, QualType()); + GD = + CGM.getItaniumVTableContext().findOriginalMethod(GD.getCanonicalDecl()); + PointerAuth = + CGF.EmitPointerAuthInfo(Schema, VTableSlotPtr, GD, QualType()); } CGCallee Callee(GD, VFunc, PointerAuth); return Callee; @@ -2473,8 +2459,8 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, // In a base-to-derived cast, the non-virtual adjustment is applied first. if (NonVirtualAdjustment && !IsReturnAdjustment) { - V = CGF.Builder.CreateConstInBoundsByteGEP(V, - CharUnits::fromQuantity(NonVirtualAdjustment)); + V = CGF.Builder.CreateConstInBoundsByteGEP( + V, CharUnits::fromQuantity(NonVirtualAdjustment)); } // Perform the virtual adjustment if we have one. @@ -2488,9 +2474,8 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, CGF.Int8Ty, VTablePtr, VirtualAdjustment); if (CGF.CGM.getLangOpts().RelativeCXXABIVTables) { // Load the adjustment offset from the vtable as a 32-bit int. - Offset = - CGF.Builder.CreateAlignedLoad(CGF.Int32Ty, OffsetPtr, - CharUnits::fromQuantity(4)); + Offset = CGF.Builder.CreateAlignedLoad(CGF.Int32Ty, OffsetPtr, + CharUnits::fromQuantity(4)); } else { llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); @@ -2534,8 +2519,8 @@ ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret, /*IsReturnAdjustment=*/true); } -void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, - RValue RV, QualType ResultType) { +void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, + QualType ResultType) { if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl())) return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType); @@ -2606,8 +2591,8 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, Address numElementsPtr = allocPtr; CharUnits numElementsOffset = cookieSize - CGF.getSizeSize(); if (!numElementsOffset.isZero()) - numElementsPtr = - CGF.Builder.CreateConstInBoundsByteGEP(numElementsPtr, numElementsOffset); + numElementsPtr = CGF.Builder.CreateConstInBoundsByteGEP(numElementsPtr, + numElementsOffset); unsigned AS = allocPtr.getAddressSpace(); numElementsPtr = numElementsPtr.withElementType(CGF.SizeTy); @@ -2638,8 +2623,7 @@ CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { CGM.getContext().getTypeAlignInChars(elementType)); } -Address ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, - Address newPtr, +Address ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, Address newPtr, llvm::Value *numElements, const CXXNewExpr *expr, QualType elementType) { @@ -2650,8 +2634,8 @@ Address ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, // The first element is the element size. cookie = cookie.withElementType(CGF.SizeTy); - llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy, - getContext().getTypeSizeInChars(elementType).getQuantity()); + llvm::Value *elementSize = llvm::ConstantInt::get( + CGF.SizeTy, getContext().getTypeSizeInChars(elementType).getQuantity()); CGF.Builder.CreateStore(elementSize, cookie); // The second element is the element count. @@ -2669,8 +2653,8 @@ llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, CharUnits cookieSize) { // The number of elements is at offset sizeof(size_t) relative to // the allocated pointer. - Address numElementsPtr - = CGF.Builder.CreateConstInBoundsByteGEP(allocPtr, CGF.getSizeSize()); + Address numElementsPtr = + CGF.Builder.CreateConstInBoundsByteGEP(allocPtr, CGF.getSizeSize()); numElementsPtr = numElementsPtr.withElementType(CGF.SizeTy); return CGF.Builder.CreateLoad(numElementsPtr); @@ -2681,9 +2665,9 @@ llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, static llvm::FunctionCallee getGuardAcquireFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // int __cxa_guard_acquire(__guard *guard_object); - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy), - GuardPtrTy, /*isVarArg=*/false); + llvm::FunctionType *FTy = llvm::FunctionType::get( + CGM.getTypes().ConvertType(CGM.getContext().IntTy), GuardPtrTy, + /*isVarArg=*/false); return CGM.CreateRuntimeFunction( FTy, "__cxa_guard_acquire", llvm::AttributeList::get(CGM.getLLVMContext(), @@ -2695,7 +2679,7 @@ static llvm::FunctionCallee getGuardReleaseFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // void __cxa_guard_release(__guard *guard_object); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction( FTy, "__cxa_guard_release", llvm::AttributeList::get(CGM.getLLVMContext(), @@ -2707,7 +2691,7 @@ static llvm::FunctionCallee getGuardAbortFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // void __cxa_guard_abort(__guard *guard_object); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction( FTy, "__cxa_guard_abort", llvm::AttributeList::get(CGM.getLLVMContext(), @@ -2716,21 +2700,20 @@ static llvm::FunctionCallee getGuardAbortFn(CodeGenModule &CGM, } namespace { - struct CallGuardAbort final : EHScopeStack::Cleanup { - llvm::GlobalVariable *Guard; - CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {} +struct CallGuardAbort final : EHScopeStack::Cleanup { + llvm::GlobalVariable *Guard; + CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {} - void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()), - Guard); - } - }; -} + void Emit(CodeGenFunction &CGF, Flags flags) override { + CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()), + Guard); + } +}; +} // namespace /// The ARM code here follows the Itanium code closely enough that we /// just special-case it at particular places. -void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, - const VarDecl &D, +void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *var, bool shouldPerformInit) { CGBuilderTy &Builder = CGF.Builder; @@ -2787,10 +2770,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // Create the guard variable with a zero-initializer. // Just absorb linkage, visibility and dll storage class from the guarded // variable. - guard = new llvm::GlobalVariable(CGM.getModule(), guardTy, - false, var->getLinkage(), - llvm::ConstantInt::get(guardTy, 0), - guardName.str()); + guard = new llvm::GlobalVariable( + CGM.getModule(), guardTy, false, var->getLinkage(), + llvm::ConstantInt::get(guardTy, 0), guardName.str()); guard->setDSOLocal(var->isDSOLocal()); guard->setVisibility(var->getVisibility()); guard->setDLLStorageClass(var->getDLLStorageClass()); @@ -2870,8 +2852,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // // ARM64 C++ ABI 3.2.2: // This ABI instead only specifies the value bit 0 of the static guard - // variable; all other bits are platform defined. Bit 0 shall be 0 when the - // variable is not initialized and 1 when it is. + // variable; all other bits are platform defined. Bit 0 shall be 0 when + // the variable is not initialized and 1 when it is. llvm::Value *V = (UseARMGuardVarABI && !useInt8GuardVariable) ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1)) @@ -2905,13 +2887,13 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // Variables used when coping with thread-safe statics and exceptions. if (threadsafe) { // Call __cxa_guard_acquire. - llvm::Value *V - = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard); + llvm::Value *V = + CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard); llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); - Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), - InitBlock, EndBlock); + Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), InitBlock, + EndBlock); // Call __cxa_guard_abort along the exceptional edge. CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard); @@ -2957,7 +2939,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, const char *Name = "__cxa_atexit"; if (TLS) { const llvm::Triple &T = CGF.getTarget().getTriple(); - Name = T.isOSDarwin() ? "_tlv_atexit" : "__cxa_thread_atexit"; + Name = T.isOSDarwin() ? "_tlv_atexit" : "__cxa_thread_atexit"; } // We're assuming that the destructor function is something we can @@ -2978,7 +2960,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d); llvm::Type *paramTys[] = {dtorTy, AddrPtrTy, handle->getType()}; llvm::FunctionType *atexitTy = - llvm::FunctionType::get(CGF.IntTy, paramTys, false); + llvm::FunctionType::get(CGF.IntTy, paramTys, false); // Fetch the actual function. llvm::FunctionCallee atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name); @@ -3131,7 +3113,18 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, // destructors which we can handle directly in the runtime. Note that this is // not strictly 1-to-1 with using `atexit` because we no longer tear down // globals in reverse order of when they were constructed. - if (!CGM.getLangOpts().hasAtExit() && !D.isStaticLocal()) + + // If '-fno-use-cxa-atexit' and '-fno-register-global-dtors-with-atexit' are + // also sepcified, this means the user does not want any invocation to + // __cxa_atexit or atexit, but we still have to check if the declaration is + // static-local or thread-local, which should not be supported by this case. + // As we investigated, ELF has its .fini_array section to support the global + // destructors. So we can safely apply this to ELF. + if (!CGM.getLangOpts().hasAtExit() && + CGM.getTarget().getTriple().isOSBinFormatELF() && + !CGM.getCodeGenOpts().CXAAtExit && + !CGM.getCodeGenOpts().RegisterGlobalDtorsWithAtExit && + !D.isStaticLocal() && !D.getTLSKind()) return CGF.registerGlobalDtorWithLLVM(D, dtor, addr); // emitGlobalDtorWithCXAAtExit will emit a call to either __cxa_thread_atexit @@ -3180,9 +3173,8 @@ getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) { return llvm::GlobalValue::WeakODRLinkage; } -llvm::Function * -ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD, - llvm::Value *Val) { +llvm::Function *ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD, + llvm::Value *Val) { // Mangle the name for the thread_local wrapper function. SmallString<256> WrapperName; { @@ -3362,8 +3354,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( // This is needed whenever a thread wrapper function is not used, and // also when the symbol is weak. if (CGM.getTriple().isOSAIX() && VD->hasDefinition() && - isEmittedWithConstantInitializer(VD, true) && - !mayNeedDestruction(VD)) { + isEmittedWithConstantInitializer(VD, true) && !mayNeedDestruction(VD)) { // Init should be null. If it were non-null, then the logic above would // either be defining the function to be an alias or declaring the // function with the expectation that the definition of the variable @@ -3551,9 +3542,9 @@ ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) { namespace { class ItaniumRTTIBuilder { - CodeGenModule &CGM; // Per-module state. + CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; - const ItaniumCXXABI &CXXABI; // Per-module state. + const ItaniumCXXABI &CXXABI; // Per-module state. /// Fields - The fields of the RTTI descriptor currently being built. SmallVector<llvm::Constant *, 16> Fields; @@ -3613,7 +3604,7 @@ class ItaniumRTTIBuilder { PTI_ContainingClassIncomplete = 0x10, /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS). - //PTI_TransactionSafe = 0x20, + // PTI_TransactionSafe = 0x20, /// PTI_Noexcept - Pointee is noexcept function (C++1z). PTI_Noexcept = 0x40, @@ -3642,13 +3633,12 @@ class ItaniumRTTIBuilder { llvm::Constant *BuildTypeInfo(QualType Ty); /// BuildTypeInfo - Build the RTTI type info struct for the given type. - llvm::Constant *BuildTypeInfo( - QualType Ty, - llvm::GlobalVariable::LinkageTypes Linkage, - llvm::GlobalValue::VisibilityTypes Visibility, - llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass); + llvm::Constant * + BuildTypeInfo(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage, + llvm::GlobalValue::VisibilityTypes Visibility, + llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass); }; -} +} // namespace llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName( QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) { @@ -3731,53 +3721,50 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { // Types added here must also be added to EmitFundamentalRTTIDescriptors. switch (Ty->getKind()) { - case BuiltinType::Void: - case BuiltinType::NullPtr: - case BuiltinType::Bool: - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - case BuiltinType::Char_U: - case BuiltinType::Char_S: - case BuiltinType::UChar: - case BuiltinType::SChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Int: - case BuiltinType::UInt: - case BuiltinType::Long: - case BuiltinType::ULong: - case BuiltinType::LongLong: - case BuiltinType::ULongLong: - case BuiltinType::Half: - case BuiltinType::Float: - case BuiltinType::Double: - case BuiltinType::LongDouble: - case BuiltinType::Float16: - case BuiltinType::Float128: - case BuiltinType::Ibm128: - case BuiltinType::Char8: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::Int128: - case BuiltinType::UInt128: - return true; + case BuiltinType::Void: + case BuiltinType::NullPtr: + case BuiltinType::Bool: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char_U: + case BuiltinType::Char_S: + case BuiltinType::UChar: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::Float16: + case BuiltinType::Float128: + case BuiltinType::Ibm128: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Int128: + case BuiltinType::UInt128: + return true; -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - case BuiltinType::Id: +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ - case BuiltinType::Id: +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" - case BuiltinType::OCLSampler: - case BuiltinType::OCLEvent: - case BuiltinType::OCLClkEvent: - case BuiltinType::OCLQueue: - case BuiltinType::OCLReserveID: -#define SVE_TYPE(Name, Id, SingletonId) \ - case BuiltinType::Id: + case BuiltinType::OCLSampler: + case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLReserveID: +#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/AArch64ACLETypes.def" -#define PPC_VECTOR_TYPE(Name, Id, Size) \ - case BuiltinType::Id: +#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id: #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" @@ -3818,8 +3805,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::Dependent: #define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" llvm_unreachable("asking for RRTI for a placeholder type!"); @@ -3827,7 +3813,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: llvm_unreachable("FIXME: Objective-C types are unsupported!"); - } + } llvm_unreachable("Invalid BuiltinType Kind!"); } @@ -3867,13 +3853,13 @@ static bool IsStandardLibraryRTTIDescriptor(QualType Ty) { /// the given type exists somewhere else, and that we should not emit the type /// information in this translation unit. Assumes that it is not a /// standard-library type. -static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, - QualType Ty) { +static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { ASTContext &Context = CGM.getContext(); // If RTTI is disabled, assume it might be disabled in the // translation unit that defines any potential key function, too. - if (!Context.getLangOpts().RTTI) return false; + if (!Context.getLangOpts().RTTI) + return false; if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { const CXXRecordDecl *RD = @@ -3935,7 +3921,7 @@ static bool ContainsIncompleteClassType(QualType Ty) { return ContainsIncompleteClassType(PointerTy->getPointeeType()); if (const MemberPointerType *MemberPointerTy = - dyn_cast<MemberPointerType>(Ty)) { + dyn_cast<MemberPointerType>(Ty)) { // Check if the class type is incomplete. if (!MemberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition()) return true; @@ -3977,14 +3963,14 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty, llvm::Constant *StorageAddress) { // abi::__class_type_info. - static const char * const ClassTypeInfo = - "_ZTVN10__cxxabiv117__class_type_infoE"; + static const char *const ClassTypeInfo = + "_ZTVN10__cxxabiv117__class_type_infoE"; // abi::__si_class_type_info. - static const char * const SIClassTypeInfo = - "_ZTVN10__cxxabiv120__si_class_type_infoE"; + static const char *const SIClassTypeInfo = + "_ZTVN10__cxxabiv120__si_class_type_infoE"; // abi::__vmi_class_type_info. - static const char * const VMIClassTypeInfo = - "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + static const char *const VMIClassTypeInfo = + "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; const char *VTableName = nullptr; @@ -4238,10 +4224,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) { } llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( - QualType Ty, - llvm::GlobalVariable::LinkageTypes Linkage, - llvm::GlobalValue::VisibilityTypes Visibility, - llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) { + QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage, + llvm::GlobalValue::VisibilityTypes Visibility, + llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) { SmallString<256> Name; llvm::raw_svector_ostream Out(Name); CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); @@ -4443,13 +4428,15 @@ void ItaniumRTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) { // The builtin types are abi::__class_type_infos and don't require // extra fields. - if (isa<BuiltinType>(T)) return; + if (isa<BuiltinType>(T)) + return; ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl(); ObjCInterfaceDecl *Super = Class->getSuperClass(); // Root classes are also __class_type_info. - if (!Super) return; + if (!Super) + return; QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super); @@ -4466,18 +4453,18 @@ void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) { // It adds to abi::__class_type_info a single member pointing to the // type_info structure for the base type, llvm::Constant *BaseTypeInfo = - ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(RD->bases_begin()->getType()); + ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(RD->bases_begin()->getType()); Fields.push_back(BaseTypeInfo); } namespace { - /// SeenBases - Contains virtual and non-virtual bases seen when traversing - /// a class hierarchy. - struct SeenBases { - llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases; - llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases; - }; -} +/// SeenBases - Contains virtual and non-virtual bases seen when traversing +/// a class hierarchy. +struct SeenBases { + llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases; + llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases; +}; +} // namespace /// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in /// abi::__vmi_class_type_info. @@ -4533,7 +4520,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) { /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); // Itanium C++ ABI 2.9.5p6c: // __flags is a word with flags describing details about the class @@ -4578,8 +4565,7 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { if (TI.getTriple().isOSCygMing() && TI.getPointerWidth(LangAS::Default) > TI.getLongWidth()) OffsetFlagsTy = CGM.getContext().LongLongTy; - llvm::Type *OffsetFlagsLTy = - CGM.getTypes().ConvertType(OffsetFlagsTy); + llvm::Type *OffsetFlagsLTy = CGM.getTypes().ConvertType(OffsetFlagsTy); for (const auto &Base : RD->bases()) { // The __base_type member points to the RTTI for the base type. @@ -4594,8 +4580,8 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // the virtual base offset for the virtual base referenced (negative). CharUnits Offset; if (Base.isVirtual()) - Offset = - CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); + Offset = CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset( + RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); Offset = Layout.getBaseClassOffset(BaseDecl); @@ -4652,7 +4638,7 @@ void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { unsigned Flags = extractPBaseFlags(CGM.getContext(), PointeeTy); llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); // Itanium C++ ABI 2.9.5p7: @@ -4665,8 +4651,8 @@ void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info /// struct, used for member pointer types. -void -ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { +void ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo( + const MemberPointerType *Ty) { QualType PointeeTy = Ty->getPointeeType(); // Itanium C++ ABI 2.9.5p7: @@ -4679,7 +4665,7 @@ ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { Flags |= PTI_ContainingClassIncomplete; llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); // Itanium C++ ABI 2.9.5p7: @@ -4703,21 +4689,31 @@ llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty) { void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) { // Types added here must also be added to TypeInfoIsInStandardLibrary. - QualType FundamentalTypes[] = { - getContext().VoidTy, getContext().NullPtrTy, - getContext().BoolTy, getContext().WCharTy, - getContext().CharTy, getContext().UnsignedCharTy, - getContext().SignedCharTy, getContext().ShortTy, - getContext().UnsignedShortTy, getContext().IntTy, - getContext().UnsignedIntTy, getContext().LongTy, - getContext().UnsignedLongTy, getContext().LongLongTy, - getContext().UnsignedLongLongTy, getContext().Int128Ty, - getContext().UnsignedInt128Ty, getContext().HalfTy, - getContext().FloatTy, getContext().DoubleTy, - getContext().LongDoubleTy, getContext().Float128Ty, - getContext().Char8Ty, getContext().Char16Ty, - getContext().Char32Ty - }; + QualType FundamentalTypes[] = {getContext().VoidTy, + getContext().NullPtrTy, + getContext().BoolTy, + getContext().WCharTy, + getContext().CharTy, + getContext().UnsignedCharTy, + getContext().SignedCharTy, + getContext().ShortTy, + getContext().UnsignedShortTy, + getContext().IntTy, + getContext().UnsignedIntTy, + getContext().LongTy, + getContext().UnsignedLongTy, + getContext().LongLongTy, + getContext().UnsignedLongLongTy, + getContext().Int128Ty, + getContext().UnsignedInt128Ty, + getContext().HalfTy, + getContext().FloatTy, + getContext().DoubleTy, + getContext().LongDoubleTy, + getContext().Float128Ty, + getContext().Char8Ty, + getContext().Char16Ty, + getContext().Char32Ty}; llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass = RD->hasAttr<DLLExportAttr>() || CGM.shouldMapVisibilityToDLLExport(RD) ? llvm::GlobalValue::DLLExportStorageClass @@ -4726,12 +4722,12 @@ void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) { CodeGenModule::GetLLVMVisibility(RD->getVisibility()); for (const QualType &FundamentalType : FundamentalTypes) { QualType PointerType = getContext().getPointerType(FundamentalType); - QualType PointerTypeConst = getContext().getPointerType( - FundamentalType.withConst()); + QualType PointerTypeConst = + getContext().getPointerType(FundamentalType.withConst()); for (QualType Type : {FundamentalType, PointerType, PointerTypeConst}) ItaniumRTTIBuilder(*this).BuildTypeInfo( - Type, llvm::GlobalValue::ExternalLinkage, - Visibility, DLLStorageClass); + Type, llvm::GlobalValue::ExternalLinkage, Visibility, + DLLStorageClass); } } @@ -4903,8 +4899,8 @@ void ItaniumCXXABI::emitCXXStructor(GlobalDecl GD) { static llvm::FunctionCallee getBeginCatchFn(CodeGenModule &CGM) { // void *__cxa_begin_catch(void*); - llvm::FunctionType *FTy = llvm::FunctionType::get( - CGM.Int8PtrTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } @@ -4919,39 +4915,39 @@ static llvm::FunctionCallee getEndCatchFn(CodeGenModule &CGM) { static llvm::FunctionCallee getGetExceptionPtrFn(CodeGenModule &CGM) { // void *__cxa_get_exception_ptr(void*); - llvm::FunctionType *FTy = llvm::FunctionType::get( - CGM.Int8PtrTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr"); } namespace { - /// A cleanup to call __cxa_end_catch. In many cases, the caught - /// exception type lets us state definitively that the thrown exception - /// type does not have a destructor. In particular: - /// - Catch-alls tell us nothing, so we have to conservatively - /// assume that the thrown exception might have a destructor. - /// - Catches by reference behave according to their base types. - /// - Catches of non-record types will only trigger for exceptions - /// of non-record types, which never have destructors. - /// - Catches of record types can trigger for arbitrary subclasses - /// of the caught type, so we have to assume the actual thrown - /// exception type might have a throwing destructor, even if the - /// caught type's destructor is trivial or nothrow. - struct CallEndCatch final : EHScopeStack::Cleanup { - CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {} - bool MightThrow; - - void Emit(CodeGenFunction &CGF, Flags flags) override { - if (!MightThrow) { - CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM)); - return; - } - - CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM)); +/// A cleanup to call __cxa_end_catch. In many cases, the caught +/// exception type lets us state definitively that the thrown exception +/// type does not have a destructor. In particular: +/// - Catch-alls tell us nothing, so we have to conservatively +/// assume that the thrown exception might have a destructor. +/// - Catches by reference behave according to their base types. +/// - Catches of non-record types will only trigger for exceptions +/// of non-record types, which never have destructors. +/// - Catches of record types can trigger for arbitrary subclasses +/// of the caught type, so we have to assume the actual thrown +/// exception type might have a throwing destructor, even if the +/// caught type's destructor is trivial or nothrow. +struct CallEndCatch final : EHScopeStack::Cleanup { + CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {} + bool MightThrow; + + void Emit(CodeGenFunction &CGF, Flags flags) override { + if (!MightThrow) { + CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM)); + return; } - }; -} + + CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM)); + } +}; +} // namespace /// Emits a call to __cxa_begin_catch and enters a cleanup to call /// __cxa_end_catch. If -fassume-nothrow-exception-dtor is specified, we assume @@ -4959,11 +4955,10 @@ namespace { /// call can be marked as nounwind even if EndMightThrow is true. /// /// \param EndMightThrow - true if __cxa_end_catch might throw -static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, - llvm::Value *Exn, +static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, llvm::Value *Exn, bool EndMightThrow) { llvm::CallInst *call = - CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn); + CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn); CGF.EHStack.pushCleanup<CallEndCatch>( NormalAndEHCleanup, @@ -4974,15 +4969,13 @@ static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, /// A "special initializer" callback for initializing a catch /// parameter during catch initialization. -static void InitCatchParam(CodeGenFunction &CGF, - const VarDecl &CatchParam, - Address ParamAddr, - SourceLocation Loc) { +static void InitCatchParam(CodeGenFunction &CGF, const VarDecl &CatchParam, + Address ParamAddr, SourceLocation Loc) { // Load the exception from where the landing pad saved it. llvm::Value *Exn = CGF.getExceptionFromSlot(); CanQualType CatchType = - CGF.CGM.getContext().getCanonicalType(CatchParam.getType()); + CGF.CGM.getContext().getCanonicalType(CatchParam.getType()); llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType); // If we're catching by reference, we can just cast the object @@ -5007,31 +5000,31 @@ static void InitCatchParam(CodeGenFunction &CGF, // Exn points to the struct _Unwind_Exception header, which // we have to skip past in order to reach the exception data. unsigned HeaderSize = - CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException(); + CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException(); AdjustedExn = CGF.Builder.CreateConstGEP1_32(CGF.Int8Ty, Exn, HeaderSize); - // However, if we're catching a pointer-to-record type that won't - // work, because the personality function might have adjusted - // the pointer. There's actually no way for us to fully satisfy - // the language/ABI contract here: we can't use Exn because it - // might have the wrong adjustment, but we can't use the by-value - // pointer because it's off by a level of abstraction. - // - // The current solution is to dump the adjusted pointer into an - // alloca, which breaks language semantics (because changing the - // pointer doesn't change the exception) but at least works. - // The better solution would be to filter out non-exact matches - // and rethrow them, but this is tricky because the rethrow - // really needs to be catchable by other sites at this landing - // pad. The best solution is to fix the personality function. + // However, if we're catching a pointer-to-record type that won't + // work, because the personality function might have adjusted + // the pointer. There's actually no way for us to fully satisfy + // the language/ABI contract here: we can't use Exn because it + // might have the wrong adjustment, but we can't use the by-value + // pointer because it's off by a level of abstraction. + // + // The current solution is to dump the adjusted pointer into an + // alloca, which breaks language semantics (because changing the + // pointer doesn't change the exception) but at least works. + // The better solution would be to filter out non-exact matches + // and rethrow them, but this is tricky because the rethrow + // really needs to be catchable by other sites at this landing + // pad. The best solution is to fix the personality function. } else { // Pull the pointer for the reference type off. llvm::Type *PtrTy = CGF.ConvertTypeForMem(CaughtType); // Create the temporary and write the adjusted pointer into it. Address ExnPtrTmp = - CGF.CreateTempAlloca(PtrTy, CGF.getPointerAlign(), "exn.byref.tmp"); + CGF.CreateTempAlloca(PtrTy, CGF.getPointerAlign(), "exn.byref.tmp"); llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy); CGF.Builder.CreateStore(Casted, ExnPtrTmp); @@ -5041,7 +5034,7 @@ static void InitCatchParam(CodeGenFunction &CGF, } llvm::Value *ExnCast = - CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref"); + CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref"); CGF.Builder.CreateStore(ExnCast, ParamAddr); return; } @@ -5055,7 +5048,7 @@ static void InitCatchParam(CodeGenFunction &CGF, // the pointer by value. if (CatchType->hasPointerRepresentation()) { llvm::Value *CastExn = - CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted"); + CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted"); switch (CatchType.getQualifiers().getObjCLifetime()) { case Qualifiers::OCL_Strong: @@ -5117,7 +5110,7 @@ static void InitCatchParam(CodeGenFunction &CGF, // We have to call __cxa_get_exception_ptr to get the adjusted // pointer before copying. llvm::CallInst *rawAdjustedExn = - CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn); + CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn); // Cast that to the appropriate type. Address adjustedExn(CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy), @@ -5125,20 +5118,19 @@ static void InitCatchParam(CodeGenFunction &CGF, // The copy expression is defined in terms of an OpaqueValueExpr. // Find it and map it to the adjusted expression. - CodeGenFunction::OpaqueValueMapping - opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), - CGF.MakeAddrLValue(adjustedExn, CatchParam.getType())); + CodeGenFunction::OpaqueValueMapping opaque( + CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), + CGF.MakeAddrLValue(adjustedExn, CatchParam.getType())); // Call the copy ctor in a terminate scope. CGF.EHStack.pushTerminate(); // Perform the copy construction. - CGF.EmitAggExpr(copyExpr, - AggValueSlot::forAddr(ParamAddr, Qualifiers(), - AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap)); + CGF.EmitAggExpr( + copyExpr, AggValueSlot::forAddr( + ParamAddr, Qualifiers(), AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap)); // Leave the terminate scope. CGF.EHStack.popTerminate(); diff --git a/compiler-rt/test/asan/TestCases/invalid-pointer-pairs-vector-extract.cpp b/compiler-rt/test/asan/TestCases/invalid-pointer-pairs-vector-extract.cpp index 8c93ffa71ab30..2eea39ba91e17 100644 --- a/compiler-rt/test/asan/TestCases/invalid-pointer-pairs-vector-extract.cpp +++ b/compiler-rt/test/asan/TestCases/invalid-pointer-pairs-vector-extract.cpp @@ -4,8 +4,6 @@ // RUN: %env_asan_opts=detect_invalid_pointer_pairs=2:halt_on_error=0 %run %t 2>&1 | FileCheck %s // UNSUPPORTED: windows -// UNSUPPORTED: target={{.*solaris.*}} - // XFAIL: * #include <cstdint> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SymbolLookupSet.h b/llvm/include/llvm/ExecutionEngine/Orc/SymbolLookupSet.h index a3adf21986aea..bad4cd6052b8d 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/SymbolLookupSet.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/SymbolLookupSet.h @@ -225,33 +225,12 @@ class SymbolLookupSet { }); } - /// Merge entries that share a name, so that each name appears exactly once. - /// If a SymbolLookupSet is not duplicate-free by construction, this method - /// can be used to turn it into a proper set. - /// - /// Entries sharing a name need not agree on their flags. Where they differ - /// the strongest requirement wins: if any entry required the symbol then the - /// merged entry requires it too, so that a missing definition still fails the - /// lookup. - void mergeEntries() { - if (Symbols.size() < 2) - return; + /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free + /// by construction, this method can be used to turn it into a proper set. + void removeDuplicates() { sortByAddress(); - - auto Out = Symbols.begin(); - for (auto In = Out + 1; In != Symbols.end(); ++In) { - if (In->first == Out->first) { - // Same name: keep the stronger requirement. - if (In->second == SymbolLookupFlags::RequiredSymbol) - Out->second = SymbolLookupFlags::RequiredSymbol; - } else { - // New name: compact it down next to the previous survivor. - ++Out; - if (Out != In) - *Out = std::move(*In); - } - } - Symbols.erase(std::next(Out), Symbols.end()); + auto LastI = llvm::unique(Symbols); + Symbols.erase(LastI, Symbols.end()); } #ifndef NDEBUG diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index d078117061677..d7c37a021169e 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2173,8 +2173,8 @@ bool X86DAGToDAGISel::matchAdd(SDValue &N, X86ISelAddressMode &AM, }; X86ISelAddressMode Backup = AM; - if (!MatchOperand(N.getOperand(0)) && - !MatchOperand(Handle.getValue().getOperand(1))) + if (!matchAddressRecursively(N.getOperand(0), AM, Depth + 1) && + !matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) return false; AM = Backup; diff --git a/llvm/test/Transforms/SLPVectorizer/AMDGPU/elementwise-fma-operand1.ll b/llvm/test/Transforms/SLPVectorizer/AMDGPU/elementwise-fma-operand1.ll index c4c97622ac726..3bcc9f03d0220 100644 --- a/llvm/test/Transforms/SLPVectorizer/AMDGPU/elementwise-fma-operand1.ll +++ b/llvm/test/Transforms/SLPVectorizer/AMDGPU/elementwise-fma-operand1.ll @@ -2,17 +2,12 @@ ; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -slp-threshold=14 < %s | FileCheck %s ; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -slp-threshold=14 < %s | FileCheck %s ; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -slp-threshold=14 < %s | FileCheck %s -; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -slp-threshold=12 < %s | FileCheck %s --check-prefix=THR12 -; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -slp-threshold=12 < %s | FileCheck %s --check-prefix=THR12 -; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -slp-threshold=12 < %s | FileCheck %s --check-prefix=THR12 -; Elementwise d = c + a * b, where the fmul is operand 1 of the fadd. These -; targets halve the cost of a packed fmul, so SLP is tempted to vectorize and -; break the scalar fma chain. The 14 runs sit at the cost boundary. The 12 runs -; vectorize either way and guard against the fmuladd marking landing on the load -; at operand 0 after the fma detection picked the fmul at operand 1, which -; asserts. axpy4_mixed_reassoc carries reassoc on one lane only, so the whole -; bundle has to be reassociative before the search gives up on operand 1. +; Elementwise d = c + a * b, where the fmul is operand 1 of the fadd. The +; threshold puts the decision right at the cost boundary, so how the fmul and +; fadd are priced against a fused fma is what decides it. These targets halve +; the cost of a packed fmul, which is what tempts SLP into vectorizing and +; breaking the scalar fma chain. define void @axpy4_contract(ptr noalias %d, ptr noalias %a, ptr noalias %b, ptr noalias %c) { ; CHECK-LABEL: define void @axpy4_contract( @@ -26,17 +21,6 @@ define void @axpy4_contract(ptr noalias %d, ptr noalias %a, ptr noalias %b, ptr ; CHECK-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 ; CHECK-NEXT: ret void ; -; THR12-LABEL: define void @axpy4_contract( -; THR12-SAME: ptr noalias [[D:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0:[0-9]+]] { -; THR12-NEXT: [[ENTRY:.*:]] -; THR12-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[C]], align 4 -; THR12-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[A]], align 4 -; THR12-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[B]], align 4 -; THR12-NEXT: [[TMP3:%.*]] = fmul contract <4 x float> [[TMP1]], [[TMP2]] -; THR12-NEXT: [[TMP4:%.*]] = fadd contract <4 x float> [[TMP0]], [[TMP3]] -; THR12-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 -; THR12-NEXT: ret void -; entry: %c0 = load float, ptr %c, align 4 %a0 = load float, ptr %a, align 4 @@ -89,17 +73,6 @@ define void @axpy4_reassoc(ptr noalias %d, ptr noalias %a, ptr noalias %b, ptr n ; CHECK-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 ; CHECK-NEXT: ret void ; -; THR12-LABEL: define void @axpy4_reassoc( -; THR12-SAME: ptr noalias [[D:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] { -; THR12-NEXT: [[ENTRY:.*:]] -; THR12-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[C]], align 4 -; THR12-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[A]], align 4 -; THR12-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[B]], align 4 -; THR12-NEXT: [[TMP3:%.*]] = fmul reassoc contract <4 x float> [[TMP1]], [[TMP2]] -; THR12-NEXT: [[TMP4:%.*]] = fadd reassoc contract <4 x float> [[TMP0]], [[TMP3]] -; THR12-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 -; THR12-NEXT: ret void -; entry: %c0 = load float, ptr %c, align 4 %a0 = load float, ptr %a, align 4 @@ -139,66 +112,3 @@ entry: store float %r3, ptr %dp3, align 4 ret void } - -define void @axpy4_mixed_reassoc(ptr noalias %d, ptr noalias %a, ptr noalias %b, ptr noalias %c) { -; CHECK-LABEL: define void @axpy4_mixed_reassoc( -; CHECK-SAME: ptr noalias [[D:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[C]], align 4 -; CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[A]], align 4 -; CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[B]], align 4 -; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <4 x float> [[TMP1]], [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = fadd contract <4 x float> [[TMP0]], [[TMP3]] -; CHECK-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 -; CHECK-NEXT: ret void -; -; THR12-LABEL: define void @axpy4_mixed_reassoc( -; THR12-SAME: ptr noalias [[D:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] { -; THR12-NEXT: [[ENTRY:.*:]] -; THR12-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[C]], align 4 -; THR12-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[A]], align 4 -; THR12-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[B]], align 4 -; THR12-NEXT: [[TMP3:%.*]] = fmul contract <4 x float> [[TMP1]], [[TMP2]] -; THR12-NEXT: [[TMP4:%.*]] = fadd contract <4 x float> [[TMP0]], [[TMP3]] -; THR12-NEXT: store <4 x float> [[TMP4]], ptr [[D]], align 4 -; THR12-NEXT: ret void -; -entry: - %c0 = load float, ptr %c, align 4 - %a0 = load float, ptr %a, align 4 - %b0 = load float, ptr %b, align 4 - %m0 = fmul contract float %a0, %b0 - %r0 = fadd contract reassoc float %c0, %m0 - store float %r0, ptr %d, align 4 - %cp1 = getelementptr inbounds float, ptr %c, i64 1 - %c1 = load float, ptr %cp1, align 4 - %ap1 = getelementptr inbounds float, ptr %a, i64 1 - %a1 = load float, ptr %ap1, align 4 - %bp1 = getelementptr inbounds float, ptr %b, i64 1 - %b1 = load float, ptr %bp1, align 4 - %m1 = fmul contract float %a1, %b1 - %r1 = fadd contract float %c1, %m1 - %dp1 = getelementptr inbounds float, ptr %d, i64 1 - store float %r1, ptr %dp1, align 4 - %cp2 = getelementptr inbounds float, ptr %c, i64 2 - %c2 = load float, ptr %cp2, align 4 - %ap2 = getelementptr inbounds float, ptr %a, i64 2 - %a2 = load float, ptr %ap2, align 4 - %bp2 = getelementptr inbounds float, ptr %b, i64 2 - %b2 = load float, ptr %bp2, align 4 - %m2 = fmul contract float %a2, %b2 - %r2 = fadd contract float %c2, %m2 - %dp2 = getelementptr inbounds float, ptr %d, i64 2 - store float %r2, ptr %dp2, align 4 - %cp3 = getelementptr inbounds float, ptr %c, i64 3 - %c3 = load float, ptr %cp3, align 4 - %ap3 = getelementptr inbounds float, ptr %a, i64 3 - %a3 = load float, ptr %ap3, align 4 - %bp3 = getelementptr inbounds float, ptr %b, i64 3 - %b3 = load float, ptr %bp3, align 4 - %m3 = fmul contract float %a3, %b3 - %r3 = fadd contract float %c3, %m3 - %dp3 = getelementptr inbounds float, ptr %d, i64 3 - store float %r3, ptr %dp3, align 4 - ret void -} diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt index ac648b3f420bf..8af05a8b32e8f 100644 --- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -49,7 +49,6 @@ add_llvm_unittest(OrcJITTests SimpleExecutorMemoryManagerTest.cpp SimplePackedSerializationTest.cpp SPSProxySpecTest.cpp - SymbolLookupSetTest.cpp SymbolStringPoolTest.cpp TaskDispatchTest.cpp ThreadSafeModuleTest.cpp diff --git a/llvm/unittests/ExecutionEngine/Orc/SymbolLookupSetTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SymbolLookupSetTest.cpp deleted file mode 100644 index 95c3884e0b8e8..0000000000000 --- a/llvm/unittests/ExecutionEngine/Orc/SymbolLookupSetTest.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//===- SymbolLookupSetTest.cpp - Test SymbolLookupSet --------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/Orc/SymbolLookupSet.h" - -#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "gtest/gtest.h" - -using namespace llvm; -using namespace llvm::orc; - -namespace { - -class SymbolLookupSetTest : public testing::Test { -protected: - static constexpr SymbolLookupFlags Required = - SymbolLookupFlags::RequiredSymbol; - static constexpr SymbolLookupFlags Weak = - SymbolLookupFlags::WeaklyReferencedSymbol; - - std::shared_ptr<SymbolStringPool> SSP = std::make_shared<SymbolStringPool>(); - - SymbolStringPtr intern(StringRef S) { return SSP->intern(S); } - - /// Collect a lookup set into a name-sorted vector of (name, flags). - /// - /// A vector rather than a map so that a name surviving more than once is - /// visible, and name-sorted because mergeEntries sorts by pointer value, - /// leaving an order that depends on allocation and must not be asserted on. - using Entries = std::vector<std::pair<std::string, SymbolLookupFlags>>; - - static Entries contents(const SymbolLookupSet &LS) { - Entries Result; - for (const auto &[Name, Flags] : LS) - Result.emplace_back(std::string(*Name), Flags); - llvm::sort(Result); - return Result; - } -}; - -} // namespace - -// A set that is already duplicate-free is left alone, flags included. -TEST_F(SymbolLookupSetTest, MergeEntriesNoDuplicates) { - SymbolLookupSet LS; - LS.add(intern("foo"), Required); - LS.add(intern("bar"), Weak); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"bar", Weak}, {"foo", Required}})); -} - -// Duplicates that agree on flags collapse to a single entry. -TEST_F(SymbolLookupSetTest, MergeEntriesSameFlags) { - SymbolLookupSet LS; - LS.add(intern("foo"), Required); - LS.add(intern("foo"), Required); - LS.add(intern("bar"), Weak); - LS.add(intern("bar"), Weak); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"bar", Weak}, {"foo", Required}})); -} - -// A name requested both ways merges to RequiredSymbol: if any requester needs -// the symbol then a missing definition must fail the lookup. -// -// Both insertion orders are checked because mergeEntries sorts by pointer -// value, so which of the two entries is seen first is not under our control. -TEST_F(SymbolLookupSetTest, MergeEntriesRequiredWinsWeakFirst) { - SymbolLookupSet LS; - LS.add(intern("foo"), Weak); - LS.add(intern("foo"), Required); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"foo", Required}})); -} - -TEST_F(SymbolLookupSetTest, MergeEntriesRequiredWinsRequiredFirst) { - SymbolLookupSet LS; - LS.add(intern("foo"), Required); - LS.add(intern("foo"), Weak); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"foo", Required}})); -} - -// Merging must not invent a requirement: all-weak duplicates stay weak. -TEST_F(SymbolLookupSetTest, MergeEntriesAllWeakStaysWeak) { - SymbolLookupSet LS; - LS.add(intern("foo"), Weak); - LS.add(intern("foo"), Weak); - LS.add(intern("foo"), Weak); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"foo", Weak}})); -} - -// Several distinct names, each duplicated a different number of times and with -// mixed flags, all merge in one pass. -TEST_F(SymbolLookupSetTest, MergeEntriesMultipleRuns) { - SymbolLookupSet LS; - LS.add(intern("foo"), Weak); - LS.add(intern("bar"), Required); - LS.add(intern("foo"), Weak); - LS.add(intern("baz"), Weak); - LS.add(intern("bar"), Weak); - LS.add(intern("foo"), Required); - LS.add(intern("qux"), Required); - - LS.mergeEntries(); - - EXPECT_EQ(contents(LS), (Entries{{"bar", Required}, - {"baz", Weak}, - {"foo", Required}, - {"qux", Required}})); -} diff --git a/llvm/utils/gn/secondary/llvm/unittests/ExecutionEngine/Orc/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/ExecutionEngine/Orc/BUILD.gn index 5659ddfea45e0..dfbf74b3cd1a9 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/ExecutionEngine/Orc/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/ExecutionEngine/Orc/BUILD.gn @@ -48,7 +48,6 @@ unittest("OrcJITTests") { "SharedMemoryMapperTest.cpp", "SimpleExecutorMemoryManagerTest.cpp", "SimplePackedSerializationTest.cpp", - "SymbolLookupSetTest.cpp", "SymbolStringPoolTest.cpp", "TaskDispatchTest.cpp", "ThreadSafeModuleTest.cpp", diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt index 40c16d681e783..247d82ba709e6 100644 --- a/orc-rt/include/CMakeLists.txt +++ b/orc-rt/include/CMakeLists.txt @@ -32,7 +32,6 @@ set(ORC_RT_HEADERS orc-rt/SimplePackedSerialization.h orc-rt/SimpleSymbolTable.h orc-rt/StandaloneMachOUnwindInfoRegistrar.h - orc-rt/StringPool.h orc-rt/TaskGroup.h orc-rt/ThreadPoolRunner.h orc-rt/WrapperFunction.h diff --git a/orc-rt/include/orc-rt/StringPool.h b/orc-rt/include/orc-rt/StringPool.h deleted file mode 100644 index 85014da2b2e54..0000000000000 --- a/orc-rt/include/orc-rt/StringPool.h +++ /dev/null @@ -1,249 +0,0 @@ -//===------------- StringPool.h - Interning string pool ---------*- 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 -// -//===----------------------------------------------------------------------===// -// -// A thread-safe, ref-counted pool of uniqued strings. -// -//===----------------------------------------------------------------------===// - -#ifndef ORC_RT_STRINGPOOL_H -#define ORC_RT_STRINGPOOL_H - -#include <atomic> -#include <cassert> -#include <cstddef> -#include <mutex> -#include <string> -#include <string_view> -#include <unordered_map> -#include <utility> - -namespace orc_rt { - -class PooledStringPtr; -class NonOwningPooledStringPtr; - -/// Interns strings (e.g. symbol names, paths) behind ref-counted handles. An -/// entry is kept alive as long as at least one PooledStringPtr refers to it; -/// clearDeadEntries() reclaims entries with no owners left. -/// -/// intern() and clearDeadEntries() may be called concurrently from any -/// number of threads. Copying, moving, and destroying a PooledStringPtr -/// requires no lock -- only the atomic refcount in that ptr's own entry is -/// touched. -class StringPool { -private: - using RefCount = std::atomic<size_t>; - using PoolMap = std::unordered_map<std::string, RefCount>; - -public: - using PoolEntry = PoolMap::value_type; - - StringPool() = default; - StringPool(const StringPool &) = delete; - StringPool &operator=(const StringPool &) = delete; - ~StringPool(); - - /// Returns the PooledStringPtr for S, interning a copy on first reference. - PooledStringPtr intern(std::string_view S); - - /// Erase entries with no remaining PooledStringPtr owners. - void clearDeadEntries(); - - /// Returns true if this pool has no entries. - bool empty() const; - -private: - mutable std::mutex M; - PoolMap Pool; -}; - -/// Common base for PooledStringPtr and NonOwningPooledStringPtr: bool -/// conversion, dereference, and comparison. -/// -/// Comparisons and hashing are pointer-identity, scoped to whichever -/// StringPool produced the handle -- handles from different pools are never -/// equal, even for identical text. -class PooledStringPtrBase { - friend class StringPoolEntryUnsafe; - -public: - PooledStringPtrBase() = default; - PooledStringPtrBase(std::nullptr_t) noexcept {} - - explicit operator bool() const noexcept { return E != nullptr; } - - const std::string &operator*() const noexcept { return E->first; } - - friend bool operator==(PooledStringPtrBase LHS, - PooledStringPtrBase RHS) noexcept { - return LHS.E == RHS.E; - } - friend bool operator!=(PooledStringPtrBase LHS, - PooledStringPtrBase RHS) noexcept { - return !(LHS == RHS); - } - // Pointer-order only; not stable across runs (ASLR). Fine as a map/set key - // ordering, not for anything user-visible. - friend bool operator<(PooledStringPtrBase LHS, - PooledStringPtrBase RHS) noexcept { - return LHS.E < RHS.E; - } - -protected: - using PoolEntry = StringPool::PoolEntry; - - explicit PooledStringPtrBase(PoolEntry *E) noexcept : E(E) {} - PoolEntry *E = nullptr; -}; - -/// An owning, ref-counted handle to a string interned in some StringPool. -class PooledStringPtr : public PooledStringPtrBase { - friend class StringPool; - -public: - PooledStringPtr() = default; - PooledStringPtr(std::nullptr_t) noexcept {} - - /// Constructs an owning handle from a non-owning one, incrementing the - /// refcount. Other must be backed by an entry that some PooledStringPtr is - /// already keeping alive -- constructing from a NonOwningPooledStringPtr - /// whose entry has already been reclaimed by clearDeadEntries() is - /// undefined behavior. - explicit PooledStringPtr(NonOwningPooledStringPtr Other) noexcept; - - PooledStringPtr(const PooledStringPtr &Other) noexcept - : PooledStringPtrBase(Other.E) { - incRef(); - } - - PooledStringPtr &operator=(const PooledStringPtr &Other) noexcept { - if (this != &Other) { - decRef(); - E = Other.E; - incRef(); - } - return *this; - } - - PooledStringPtr(PooledStringPtr &&Other) noexcept { std::swap(E, Other.E); } - - PooledStringPtr &operator=(PooledStringPtr &&Other) noexcept { - decRef(); - E = nullptr; - std::swap(E, Other.E); - return *this; - } - - ~PooledStringPtr() { decRef(); } - -private: - explicit PooledStringPtr(PoolEntry *E) noexcept : PooledStringPtrBase(E) { - incRef(); - } - - void incRef() noexcept { - if (E) - ++E->second; - } - - void decRef() noexcept { - if (E) { - assert(E->second.load() != 0 && "double-release of PooledStringPtr"); - --E->second; - } - } -}; - -/// A non-owning handle to a string interned in some StringPool. -/// -/// Comparable and hashable interchangeably with PooledStringPtr (both wrap the -/// same underlying entry pointer), but copying a NonOwningPooledStringPtr never -/// touches the refcount, so it's cheaper to pass around than a PooledStringPtr. -/// It is silently invalidated if the entry's refcount drops to zero and is -/// reclaimed by clearDeadEntries(), so only use it where a corresponding -/// PooledStringPtr is known to be keeping the entry alive -- e.g. as a lookup -/// key into a table whose values (or a side table) hold the owning -/// PooledStringPtr for that same entry. -class NonOwningPooledStringPtr : public PooledStringPtrBase { -public: - NonOwningPooledStringPtr() = default; - NonOwningPooledStringPtr(std::nullptr_t) noexcept {} - explicit NonOwningPooledStringPtr(const PooledStringPtr &Other) noexcept - : PooledStringPtrBase(Other) {} -}; - -/// Provides unsafe (refcount-bypassing) access to the pool-entry pointer -/// underlying a PooledStringPtrBase. Used to implement std::hash and C API -/// operations. Not intended for general use. -class StringPoolEntryUnsafe { -public: - using PoolEntry = StringPool::PoolEntry; - - /// Extracts the pool-entry pointer from S without affecting its refcount. - static StringPoolEntryUnsafe from(const PooledStringPtrBase &S) { - return StringPoolEntryUnsafe(S.E); - } - - const void *rawPtr() const { return E; } - -private: - StringPoolEntryUnsafe(PoolEntry *E) : E(E) {} - PoolEntry *E = nullptr; -}; - -inline PooledStringPtr::PooledStringPtr(NonOwningPooledStringPtr Other) noexcept - : PooledStringPtrBase(Other) { - incRef(); -} - -inline StringPool::~StringPool() { -#ifndef NDEBUG - clearDeadEntries(); - assert(Pool.empty() && "Dangling PooledStringPtr at StringPool destruction"); -#endif -} - -inline PooledStringPtr StringPool::intern(std::string_view S) { - std::scoped_lock<std::mutex> Lock(M); - auto [I, Added] = Pool.try_emplace(std::string(S), 0); - return PooledStringPtr(&*I); -} - -inline void StringPool::clearDeadEntries() { - std::scoped_lock<std::mutex> Lock(M); - for (auto I = Pool.begin(), E = Pool.end(); I != E;) - if (I->second.load() == 0) - I = Pool.erase(I); - else - ++I; -} - -inline bool StringPool::empty() const { - std::scoped_lock<std::mutex> Lock(M); - return Pool.empty(); -} - -} // namespace orc_rt - -namespace std { -template <> struct hash<orc_rt::PooledStringPtr> { - size_t operator()(const orc_rt::PooledStringPtr &S) const noexcept { - return hash<const void *>()( - orc_rt::StringPoolEntryUnsafe::from(S).rawPtr()); - } -}; - -template <> struct hash<orc_rt::NonOwningPooledStringPtr> { - size_t operator()(const orc_rt::NonOwningPooledStringPtr &S) const noexcept { - return hash<const void *>()( - orc_rt::StringPoolEntryUnsafe::from(S).rawPtr()); - } -}; -} // namespace std - -#endif // ORC_RT_STRINGPOOL_H diff --git a/orc-rt/test/unit/CMakeLists.txt b/orc-rt/test/unit/CMakeLists.txt index 1916000506e31..7219c9897de1e 100644 --- a/orc-rt/test/unit/CMakeLists.txt +++ b/orc-rt/test/unit/CMakeLists.txt @@ -50,7 +50,6 @@ add_orc_rt_unittest(CoreTests SimpleSymbolTableTest.cpp StandaloneMachOUnwindInfoRegistrarTest.cpp StringExtrasTest.cpp - StringPoolTest.cpp TaskGroupTest.cpp ThreadPoolRunnerTest.cpp WrapperFunctionBufferTest.cpp diff --git a/orc-rt/test/unit/StringPoolTest.cpp b/orc-rt/test/unit/StringPoolTest.cpp deleted file mode 100644 index 85b866d12a275..0000000000000 --- a/orc-rt/test/unit/StringPoolTest.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===- StringPoolTest.cpp -------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Tests for orc-rt's StringPool.h APIs. -// -//===----------------------------------------------------------------------===// - -#include "orc-rt/StringPool.h" -#include "gtest/gtest.h" - -#include <unordered_set> - -using namespace orc_rt; - -TEST(StringPoolTest, EmptyByDefault) { - StringPool SP; - EXPECT_TRUE(SP.empty()); -} - -TEST(StringPoolTest, InternReturnsEqualContent) { - StringPool SP; - auto Foo = SP.intern("foo"); - EXPECT_TRUE(Foo); - EXPECT_EQ(*Foo, "foo"); - EXPECT_FALSE(SP.empty()); -} - -TEST(StringPoolTest, RepeatedInternIsIdentical) { - StringPool SP; - auto Foo1 = SP.intern("foo"); - auto Foo2 = SP.intern("foo"); - EXPECT_EQ(Foo1, Foo2); -} - -TEST(StringPoolTest, DifferentContentIsDistinct) { - StringPool SP; - auto Foo = SP.intern("foo"); - auto Bar = SP.intern("bar"); - EXPECT_NE(Foo, Bar); -} - -TEST(StringPoolTest, DifferentPoolsAreDistinct) { - StringPool SP1, SP2; - auto Foo1 = SP1.intern("foo"); - auto Foo2 = SP2.intern("foo"); - EXPECT_EQ(*Foo1, *Foo2); - EXPECT_NE(Foo1, Foo2); -} - -TEST(StringPoolTest, DefaultConstructedIsNull) { - PooledStringPtr Null; - EXPECT_FALSE(Null); - EXPECT_EQ(Null, PooledStringPtr(nullptr)); -} - -TEST(StringPoolTest, CopyKeepsEntryAlive) { - StringPool SP; - PooledStringPtr Copy; - { - auto Foo = SP.intern("foo"); - Copy = Foo; - } - // Foo has been destroyed. If copy-assignment above failed to incRef, the - // entry's refcount would already be zero and clearDeadEntries() would - // reclaim it. - SP.clearDeadEntries(); - ASSERT_FALSE(SP.empty()) << "Copy should have kept the entry alive"; - EXPECT_EQ(*Copy, "foo"); -} - -TEST(StringPoolTest, ClearDeadEntriesReclaimsUnreferenced) { - StringPool SP; - { - auto Foo = SP.intern("foo"); - } - EXPECT_FALSE(SP.empty()); - SP.clearDeadEntries(); - EXPECT_TRUE(SP.empty()); -} - -TEST(StringPoolTest, ClearDeadEntriesKeepsReferenced) { - StringPool SP; - auto Foo = SP.intern("foo"); - { - auto Bar = SP.intern("bar"); - } - SP.clearDeadEntries(); - ASSERT_FALSE(SP.empty()); - EXPECT_EQ(*Foo, "foo"); -} - -TEST(StringPoolTest, MoveLeavesSourceNull) { - StringPool SP; - auto Foo = SP.intern("foo"); - auto Moved = std::move(Foo); - EXPECT_FALSE(Foo); - EXPECT_TRUE(Moved); - EXPECT_EQ(*Moved, "foo"); -} - -TEST(StringPoolTest, NonOwningPtrComparesEqualToOwning) { - StringPool SP; - auto Foo = SP.intern("foo"); - NonOwningPooledStringPtr NonOwningFoo(Foo); - EXPECT_EQ(Foo, NonOwningFoo); - EXPECT_EQ(*NonOwningFoo, "foo"); -} - -TEST(StringPoolTest, NonOwningPtrDoesNotKeepEntryAlive) { - StringPool SP; - NonOwningPooledStringPtr NonOwningFoo; - { - auto Foo = SP.intern("foo"); - NonOwningFoo = NonOwningPooledStringPtr(Foo); - } - // Foo has been destroyed and was the only owner, so the entry should be - // reclaimed even though NonOwningFoo still points at it. - SP.clearDeadEntries(); - EXPECT_TRUE(SP.empty()); -} - -TEST(StringPoolTest, ConstructOwningFromNonOwningIncrementsRefcount) { - StringPool SP; - NonOwningPooledStringPtr NonOwningFoo; - { - auto Foo = SP.intern("foo"); - NonOwningFoo = NonOwningPooledStringPtr(Foo); - } - // The entry's refcount is now zero, but it has not yet been reclaimed by - // clearDeadEntries(), so re-deriving an owning ptr from NonOwningFoo here - // is well-defined and should keep the entry alive. - PooledStringPtr Reowned(NonOwningFoo); - SP.clearDeadEntries(); - ASSERT_FALSE(SP.empty()); - EXPECT_EQ(*Reowned, "foo"); -} - -TEST(StringPoolTest, UsableAsUnorderedSetKey) { - StringPool SP; - auto Foo1 = SP.intern("foo"); - auto Foo2 = SP.intern("foo"); - auto Bar = SP.intern("bar"); - - std::unordered_set<PooledStringPtr> S; - S.insert(Foo1); - S.insert(Foo2); - S.insert(Bar); - - EXPECT_EQ(S.size(), 2U); - EXPECT_TRUE(S.count(Foo1)); - EXPECT_TRUE(S.count(Bar)); -} - -TEST(StringPoolTest, OwningAndNonOwningHashInterchangeably) { - StringPool SP; - auto Foo = SP.intern("foo"); - NonOwningPooledStringPtr NonOwningFoo(Foo); - - EXPECT_EQ(std::hash<PooledStringPtr>()(Foo), - std::hash<NonOwningPooledStringPtr>()(NonOwningFoo)); -} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
