@@ -226,6 +226,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
226
226
return hasUniqueVTablePointer (DestRecordTy);
227
227
}
228
228
229
+ std::optional<ExactDynamicCastInfo>
230
+ getExactDynamicCastInfo (QualType SrcRecordTy, QualType DestTy,
231
+ QualType DestRecordTy) override ;
232
+
229
233
llvm::Value *emitDynamicCastCall (CodeGenFunction &CGF, Address Value,
230
234
QualType SrcRecordTy, QualType DestTy,
231
235
QualType DestRecordTy,
@@ -234,6 +238,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
234
238
llvm::Value *emitExactDynamicCast (CodeGenFunction &CGF, Address ThisAddr,
235
239
QualType SrcRecordTy, QualType DestTy,
236
240
QualType DestRecordTy,
241
+ const ExactDynamicCastInfo &CastInfo,
237
242
llvm::BasicBlock *CastSuccess,
238
243
llvm::BasicBlock *CastFail) override ;
239
244
@@ -1681,10 +1686,11 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
1681
1686
return Value;
1682
1687
}
1683
1688
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
+
1688
1694
ASTContext &Context = getContext ();
1689
1695
1690
1696
// Find all the inheritance paths.
@@ -1722,41 +1728,56 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
1722
1728
if (!Offset)
1723
1729
Offset = PathOffset;
1724
1730
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 ()};
1734
1734
}
1735
1735
}
1736
+ if (!Offset)
1737
+ return std::nullopt;
1738
+ return ExactDynamicCastInfo{/* RequiresCastToPrimaryBase=*/ false , *Offset};
1739
+ }
1736
1740
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);
1742
1763
1743
1764
// 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
+
1758
1779
CGF.Builder .CreateCondBr (Success, CastSuccess, CastFail);
1759
- return Result ;
1780
+ return AdjustedThisPtr ;
1760
1781
}
1761
1782
1762
1783
llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid (CodeGenFunction &CGF,
0 commit comments