diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 51 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 7 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 128 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 12 |
6 files changed, 192 insertions, 20 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 7c1287a..ad1ad08d 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -287,6 +287,7 @@ public: virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr, QualType SrcRecordTy) = 0; + virtual bool shouldEmitExactDynamicCast(QualType DestRecordTy) = 0; virtual llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy, @@ -298,6 +299,15 @@ public: Address Value, QualType SrcRecordTy) = 0; + /// Emit a dynamic_cast from SrcRecordTy to DestRecordTy. The cast fails if + /// the dynamic type of Value is not exactly DestRecordTy. + virtual llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value, + QualType SrcRecordTy, + QualType DestTy, + QualType DestRecordTy, + llvm::BasicBlock *CastSuccess, + llvm::BasicBlock *CastFail) = 0; + virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0; virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 96435d9..6df5e37 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -2226,8 +2226,8 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF)) return nullptr; - CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end")); - return llvm::UndefValue::get(DestLTy); + CGF.Builder.ClearInsertionPoint(); + return llvm::PoisonValue::get(DestLTy); } llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, @@ -2240,17 +2240,16 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, // C++ [expr.dynamic.cast]p7: // If T is "pointer to cv void," then the result is a pointer to the most // derived object pointed to by v. - const PointerType *DestPTy = DestTy->getAs<PointerType>(); - - bool isDynamicCastToVoid; + bool IsDynamicCastToVoid = DestTy->isVoidPointerType(); QualType SrcRecordTy; QualType DestRecordTy; - if (DestPTy) { - isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType(); + if (IsDynamicCastToVoid) { + SrcRecordTy = SrcTy->getPointeeType(); + // No DestRecordTy. + } else if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) { SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType(); DestRecordTy = DestPTy->getPointeeType(); } else { - isDynamicCastToVoid = false; SrcRecordTy = SrcTy; DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType(); } @@ -2263,18 +2262,29 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(), SrcRecordTy); - if (DCE->isAlwaysNull()) - if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) + if (DCE->isAlwaysNull()) { + if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) { + // Expression emission is expected to retain a valid insertion point. + if (!Builder.GetInsertBlock()) + EmitBlock(createBasicBlock("dynamic_cast.unreachable")); return T; + } + } assert(SrcRecordTy->isRecordType() && "source type must be a record type!"); + // If the destination is effectively final, the cast succeeds if and only + // if the dynamic type of the pointer is exactly the destination type. + bool IsExact = !IsDynamicCastToVoid && + DestRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() && + CGM.getCXXABI().shouldEmitExactDynamicCast(DestRecordTy); + // C++ [expr.dynamic.cast]p4: // If the value of v is a null pointer value in the pointer case, the result // is the null pointer value of type T. bool ShouldNullCheckSrcValue = - CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(), - SrcRecordTy); + IsExact || CGM.getCXXABI().shouldDynamicCastCallBeNullChecked( + SrcTy->isPointerType(), SrcRecordTy); llvm::BasicBlock *CastNull = nullptr; llvm::BasicBlock *CastNotNull = nullptr; @@ -2290,29 +2300,38 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, } llvm::Value *Value; - if (isDynamicCastToVoid) { + if (IsDynamicCastToVoid) { Value = CGM.getCXXABI().emitDynamicCastToVoid(*this, ThisAddr, SrcRecordTy); + } else if (IsExact) { + // If the destination type is effectively final, this pointer points to the + // right type if and only if its vptr has the right value. + Value = CGM.getCXXABI().emitExactDynamicCast( + *this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, CastEnd, CastNull); } else { assert(DestRecordTy->isRecordType() && "destination type must be a record type!"); Value = CGM.getCXXABI().emitDynamicCastCall(*this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, CastEnd); - CastNotNull = Builder.GetInsertBlock(); } + CastNotNull = Builder.GetInsertBlock(); + llvm::Value *NullValue = nullptr; if (ShouldNullCheckSrcValue) { EmitBranch(CastEnd); EmitBlock(CastNull); + NullValue = EmitDynamicCastToNull(*this, DestTy); + CastNull = Builder.GetInsertBlock(); + EmitBranch(CastEnd); } EmitBlock(CastEnd); - if (ShouldNullCheckSrcValue) { + if (CastNull) { llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); + PHI->addIncoming(NullValue, CastNull); Value = PHI; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index ef49349..bb5d180 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7152,9 +7152,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, // Return a bogus pointer if RTTI is disabled, unless it's for EH. // FIXME: should we even be calling this method if RTTI is disabled // and it's not for EH? - if ((!ForEH && !getLangOpts().RTTI) || getLangOpts().CUDAIsDevice || - (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice && - getTriple().isNVPTX())) + if (!shouldEmitRTTI(ForEH)) return llvm::Constant::getNullValue(GlobalsInt8PtrTy); if (ForEH && Ty->isObjCObjectPointerType() && diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 2d2cce8..4903f09 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -926,6 +926,13 @@ public: // Return the function body address of the given function. llvm::Constant *GetFunctionStart(const ValueDecl *Decl); + // Return whether RTTI information should be emitted for this target. + bool shouldEmitRTTI(bool ForEH = false) { + return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice && + !(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice && + getTriple().isNVPTX()); + } + /// Get the address of the RTTI descriptor for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8870383..79a926c 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -36,6 +36,8 @@ #include "llvm/IR/Value.h" #include "llvm/Support/ScopedPrinter.h" +#include <optional> + using namespace clang; using namespace CodeGen; @@ -185,11 +187,56 @@ public: bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr, QualType SrcRecordTy) override; + /// Determine whether we know that all instances of type RecordTy will have + /// the same vtable pointer values, that is distinct from all other vtable + /// pointers. While this is required by the Itanium ABI, it doesn't happen in + /// practice in some cases due to language extensions. + bool hasUniqueVTablePointer(QualType RecordTy) { + const CXXRecordDecl *RD = RecordTy->getAsCXXRecordDecl(); + + // Under -fapple-kext, multiple definitions of the same vtable may be + // emitted. + if (!CGM.getCodeGenOpts().AssumeUniqueVTables || + getContext().getLangOpts().AppleKext) + return false; + + // If the type_info* would be null, the vtable might be merged with that of + // another type. + if (!CGM.shouldEmitRTTI()) + return false; + + // If there's only one definition of the vtable in the program, it has a + // unique address. + if (!llvm::GlobalValue::isWeakForLinker(CGM.getVTableLinkage(RD))) + return true; + + // Even if there are multiple definitions of the vtable, they are required + // by the ABI to use the same symbol name, so should be merged at load + // time. However, if the class has hidden visibility, there can be + // different versions of the class in different modules, and the ABI + // library might treat them as being the same. + if (CGM.GetLLVMVisibility(RD->getVisibility()) != + llvm::GlobalValue::DefaultVisibility) + return false; + + return true; + } + + bool shouldEmitExactDynamicCast(QualType DestRecordTy) override { + return hasUniqueVTablePointer(DestRecordTy); + } + llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy, QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) override; + llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address ThisAddr, + QualType SrcRecordTy, QualType DestTy, + QualType DestRecordTy, + llvm::BasicBlock *CastSuccess, + llvm::BasicBlock *CastFail) override; + llvm::Value *emitDynamicCastToVoid(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy) override; @@ -1202,7 +1249,8 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, // Track back to entry -2 and pull out the offset there. llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64( CGF.IntPtrTy, VTable, -2, "complete-offset.ptr"); - llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(CGF.IntPtrTy, OffsetPtr, CGF.getPointerAlign()); + llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(CGF.IntPtrTy, OffsetPtr, + CGF.getPointerAlign()); // Apply the offset. llvm::Value *CompletePtr = @@ -1463,6 +1511,84 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall( return Value; } +llvm::Value *ItaniumCXXABI::emitExactDynamicCast( + CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy, + QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess, + llvm::BasicBlock *CastFail) { + ASTContext &Context = getContext(); + + // Find all the inheritance paths. + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl(); + const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl(); + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + (void)DestDecl->isDerivedFrom(SrcDecl, Paths); + + // Find an offset within `DestDecl` where a `SrcDecl` instance and its vptr + // might appear. + std::optional<CharUnits> Offset; + for (const CXXBasePath &Path : Paths) { + // dynamic_cast only finds public inheritance paths. + if (Path.Access != AS_public) + continue; + + CharUnits PathOffset; + for (const CXXBasePathElement &PathElement : Path) { + // Find the offset along this inheritance step. + const CXXRecordDecl *Base = + PathElement.Base->getType()->getAsCXXRecordDecl(); + if (PathElement.Base->isVirtual()) { + // For a virtual base class, we know that the derived class is exactly + // DestDecl, so we can use the vbase offset from its layout. + const ASTRecordLayout &L = Context.getASTRecordLayout(DestDecl); + PathOffset = L.getVBaseClassOffset(Base); + } else { + const ASTRecordLayout &L = + Context.getASTRecordLayout(PathElement.Class); + PathOffset += L.getBaseClassOffset(Base); + } + } + + if (!Offset) + Offset = PathOffset; + else if (Offset != PathOffset) { + // Base appears in at least two different places. Find the most-derived + // object and see if it's a DestDecl. Note that the most-derived object + // must be at least as aligned as this base class subobject, and must + // have a vptr at offset 0. + ThisAddr = Address(emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy), + CGF.VoidPtrTy, ThisAddr.getAlignment()); + SrcDecl = DestDecl; + Offset = CharUnits::Zero(); + break; + } + } + + if (!Offset) { + // If there are no public inheritance paths, the cast always fails. + CGF.EmitBranch(CastFail); + return llvm::PoisonValue::get(CGF.VoidPtrTy); + } + + // Compare the vptr against the expected vptr for the destination type at + // this offset. Note that we do not know what type ThisAddr points to in + // the case where the derived class multiply inherits from the base class + // so we can't use GetVTablePtr, so we load the vptr directly instead. + llvm::Instruction *VPtr = CGF.Builder.CreateLoad( + ThisAddr.withElementType(CGF.VoidPtrPtrTy), "vtable"); + CGM.DecorateInstructionWithTBAA( + VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy)); + llvm::Value *Success = CGF.Builder.CreateICmpEQ( + VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl)); + llvm::Value *Result = ThisAddr.getPointer(); + if (!Offset->isZero()) + Result = CGF.Builder.CreateInBoundsGEP( + CGF.CharTy, Result, + {llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset->getQuantity())}); + CGF.Builder.CreateCondBr(Success, CastSuccess, CastFail); + return Result; +} + llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy) { diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index ea63e76..a692aba 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -153,6 +153,18 @@ public: bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr, QualType SrcRecordTy) override; + bool shouldEmitExactDynamicCast(QualType DestRecordTy) override { + // TODO: Add support for exact dynamic_casts. + return false; + } + llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value, + QualType SrcRecordTy, QualType DestTy, + QualType DestRecordTy, + llvm::BasicBlock *CastSuccess, + llvm::BasicBlock *CastFail) override { + llvm_unreachable("unsupported"); + } + llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy, QualType DestTy, QualType DestRecordTy, |