@@ -226,6 +226,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
226226 return hasUniqueVTablePointer (DestRecordTy);
227227 }
228228
229+ std::optional<ExactDynamicCastInfo>
230+ getExactDynamicCastInfo (QualType SrcRecordTy, QualType DestTy,
231+ QualType DestRecordTy) override ;
232+
229233 llvm::Value *emitDynamicCastCall (CodeGenFunction &CGF, Address Value,
230234 QualType SrcRecordTy, QualType DestTy,
231235 QualType DestRecordTy,
@@ -234,6 +238,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
234238 llvm::Value *emitExactDynamicCast (CodeGenFunction &CGF, Address ThisAddr,
235239 QualType SrcRecordTy, QualType DestTy,
236240 QualType DestRecordTy,
241+ const ExactDynamicCastInfo &CastInfo,
237242 llvm::BasicBlock *CastSuccess,
238243 llvm::BasicBlock *CastFail) override ;
239244
@@ -1681,10 +1686,11 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
16811686 return Value;
16821687}
16831688
1684- llvm::Value *ItaniumCXXABI::emitExactDynamicCast (
1685- CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1686- QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
1687- llvm::BasicBlock *CastFail) {
1689+ std::optional<CGCXXABI::ExactDynamicCastInfo>
1690+ ItaniumCXXABI::getExactDynamicCastInfo (QualType SrcRecordTy, QualType DestTy,
1691+ QualType DestRecordTy) {
1692+ assert (shouldEmitExactDynamicCast (DestRecordTy));
1693+
16881694 ASTContext &Context = getContext ();
16891695
16901696 // Find all the inheritance paths.
@@ -1722,41 +1728,56 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
17221728 if (!Offset)
17231729 Offset = PathOffset;
17241730 else if (Offset != PathOffset) {
1725- // Base appears in at least two different places. Find the most-derived
1726- // object and see if it's a DestDecl. Note that the most-derived object
1727- // must be at least as aligned as this base class subobject, and must
1728- // have a vptr at offset 0.
1729- ThisAddr = Address (emitDynamicCastToVoid (CGF, ThisAddr, SrcRecordTy),
1730- CGF.VoidPtrTy , ThisAddr.getAlignment ());
1731- SrcDecl = DestDecl;
1732- Offset = CharUnits::Zero ();
1733- break ;
1731+ // Base appears in at least two different places.
1732+ return ExactDynamicCastInfo{/* RequiresCastToPrimaryBase=*/ true ,
1733+ CharUnits::Zero ()};
17341734 }
17351735 }
1736+ if (!Offset)
1737+ return std::nullopt ;
1738+ return ExactDynamicCastInfo{/* RequiresCastToPrimaryBase=*/ false , *Offset};
1739+ }
17361740
1737- if (!Offset) {
1738- // If there are no public inheritance paths, the cast always fails.
1739- CGF.EmitBranch (CastFail);
1740- return llvm::PoisonValue::get (CGF.VoidPtrTy );
1741- }
1741+ llvm::Value *ItaniumCXXABI::emitExactDynamicCast (
1742+ CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1743+ QualType DestTy, QualType DestRecordTy,
1744+ const ExactDynamicCastInfo &ExactCastInfo, llvm::BasicBlock *CastSuccess,
1745+ llvm::BasicBlock *CastFail) {
1746+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl ();
1747+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl ();
1748+
1749+ llvm::Value *VTable = nullptr ;
1750+ if (ExactCastInfo.RequiresCastToPrimaryBase ) {
1751+ // Base appears in at least two different places. Find the most-derived
1752+ // object and see if it's a DestDecl. Note that the most-derived object
1753+ // must be at least as aligned as this base class subobject, and must
1754+ // have a vptr at offset 0.
1755+ llvm::Value *PrimaryBase =
1756+ emitDynamicCastToVoid (CGF, ThisAddr, SrcRecordTy);
1757+ ThisAddr = Address (PrimaryBase, CGF.VoidPtrTy , ThisAddr.getAlignment ());
1758+ SrcDecl = DestDecl;
1759+ Address VTablePtrPtr = ThisAddr.withElementType (CGF.VoidPtrPtrTy );
1760+ VTable = CGF.Builder .CreateLoad (VTablePtrPtr, " vtable" );
1761+ } else
1762+ VTable = CGF.GetVTablePtr (ThisAddr, CGF.UnqualPtrTy , SrcDecl);
17421763
17431764 // Compare the vptr against the expected vptr for the destination type at
1744- // this offset. Note that we do not know what type ThisAddr points to in
1745- // the case where the derived class multiply inherits from the base class
1746- // so we can't use GetVTablePtr, so we load the vptr directly instead.
1747- llvm::Instruction *VPtr = CGF.Builder .CreateLoad (
1748- ThisAddr.withElementType (CGF. VoidPtrPtrTy ), " vtable " );
1749- CGM. DecorateInstructionWithTBAA (
1750- VPtr, CGM. getTBAAVTablePtrAccessInfo (CGF. VoidPtrPtrTy ));
1751- llvm::Value *Success = CGF. Builder . CreateICmpEQ (
1752- VPtr, getVTableAddressPoint ( BaseSubobject (SrcDecl, *Offset), DestDecl));
1753- llvm::Value *Result = ThisAddr. emitRawPointer (CGF);
1754- if (!Offset-> isZero ())
1755- Result = CGF. Builder . CreateInBoundsGEP (
1756- CGF. CharTy , Result,
1757- { llvm::ConstantInt::get (CGF. PtrDiffTy , -Offset-> getQuantity ())});
1765+ // this offset.
1766+ llvm::Constant *ExpectedVTable = getVTableAddressPoint (
1767+ BaseSubobject (SrcDecl, ExactCastInfo. Offset ), DestDecl);
1768+ llvm::Value *Success = CGF.Builder .CreateICmpEQ (VTable, ExpectedVTable);
1769+ llvm::Value *AdjustedThisPtr = ThisAddr.emitRawPointer (CGF);
1770+
1771+ if (!ExactCastInfo. Offset . isZero ()) {
1772+ CharUnits::QuantityType Offset = ExactCastInfo. Offset . getQuantity ();
1773+ llvm::Constant *OffsetConstant =
1774+ llvm::ConstantInt::get (CGF. PtrDiffTy , -Offset );
1775+ AdjustedThisPtr = CGF. Builder . CreateInBoundsGEP (CGF. CharTy , AdjustedThisPtr,
1776+ OffsetConstant);
1777+ }
1778+
17581779 CGF.Builder .CreateCondBr (Success, CastSuccess, CastFail);
1759- return Result ;
1780+ return AdjustedThisPtr ;
17601781}
17611782
17621783llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid (CodeGenFunction &CGF,
0 commit comments