@@ -116,6 +116,16 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
116116 Address thisAddr, const CXXRecordDecl *classDecl,
117117 const CXXRecordDecl *baseClassDecl) override ;
118118
119+ // The traditional clang CodeGen emits calls to `__dynamic_cast` directly into
120+ // LLVM in the `emitDynamicCastCall` function. In CIR, `dynamic_cast`
121+ // expressions are lowered to `cir.dyn_cast` ops instead of calls to runtime
122+ // functions. So during CIRGen we don't need the `emitDynamicCastCall`
123+ // function that clang CodeGen has.
124+ mlir::Value emitDynamicCast (CIRGenFunction &cgf, mlir::Location loc,
125+ QualType srcRecordTy, QualType destRecordTy,
126+ cir::PointerType destCIRTy, bool isRefCast,
127+ Address src) override ;
128+
119129 /* *************************** RTTI Uniqueness ******************************/
120130protected:
121131 // / Returns true if the ABI requires RTTI type_info objects to be unique
@@ -1796,3 +1806,143 @@ mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
17961806 }
17971807 return vbaseOffset;
17981808}
1809+
1810+ static cir::FuncOp getBadCastFn (CIRGenFunction &cgf) {
1811+ // Prototype: void __cxa_bad_cast();
1812+
1813+ // TODO(cir): set the calling convention of the runtime function.
1814+ assert (!cir::MissingFeatures::opFuncCallingConv ());
1815+
1816+ cir::FuncType fnTy =
1817+ cgf.getBuilder ().getFuncType ({}, cgf.getBuilder ().getVoidTy ());
1818+ return cgf.cgm .createRuntimeFunction (fnTy, " __cxa_bad_cast" );
1819+ }
1820+
1821+ // TODO(cir): This could be shared with classic codegen.
1822+ static CharUnits computeOffsetHint (ASTContext &astContext,
1823+ const CXXRecordDecl *src,
1824+ const CXXRecordDecl *dst) {
1825+ CXXBasePaths paths (/* FindAmbiguities=*/ true , /* RecordPaths=*/ true ,
1826+ /* DetectVirtual=*/ false );
1827+
1828+ // If Dst is not derived from Src we can skip the whole computation below and
1829+ // return that Src is not a public base of Dst. Record all inheritance paths.
1830+ if (!dst->isDerivedFrom (src, paths))
1831+ return CharUnits::fromQuantity (-2ULL );
1832+
1833+ unsigned numPublicPaths = 0 ;
1834+ CharUnits offset;
1835+
1836+ // Now walk all possible inheritance paths.
1837+ for (const CXXBasePath &path : paths) {
1838+ if (path.Access != AS_public) // Ignore non-public inheritance.
1839+ continue ;
1840+
1841+ ++numPublicPaths;
1842+
1843+ for (const CXXBasePathElement &pathElement : path) {
1844+ // If the path contains a virtual base class we can't give any hint.
1845+ // -1: no hint.
1846+ if (pathElement.Base ->isVirtual ())
1847+ return CharUnits::fromQuantity (-1ULL );
1848+
1849+ if (numPublicPaths > 1 ) // Won't use offsets, skip computation.
1850+ continue ;
1851+
1852+ // Accumulate the base class offsets.
1853+ const ASTRecordLayout &L =
1854+ astContext.getASTRecordLayout (pathElement.Class );
1855+ offset += L.getBaseClassOffset (
1856+ pathElement.Base ->getType ()->getAsCXXRecordDecl ());
1857+ }
1858+ }
1859+
1860+ // -2: Src is not a public base of Dst.
1861+ if (numPublicPaths == 0 )
1862+ return CharUnits::fromQuantity (-2ULL );
1863+
1864+ // -3: Src is a multiple public base type but never a virtual base type.
1865+ if (numPublicPaths > 1 )
1866+ return CharUnits::fromQuantity (-3ULL );
1867+
1868+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
1869+ // Return the offset of Src from the origin of Dst.
1870+ return offset;
1871+ }
1872+
1873+ static cir::FuncOp getItaniumDynamicCastFn (CIRGenFunction &cgf) {
1874+ // Prototype:
1875+ // void *__dynamic_cast(const void *sub,
1876+ // global_as const abi::__class_type_info *src,
1877+ // global_as const abi::__class_type_info *dst,
1878+ // std::ptrdiff_t src2dst_offset);
1879+
1880+ mlir::Type voidPtrTy = cgf.getBuilder ().getVoidPtrTy ();
1881+ mlir::Type rttiPtrTy = cgf.getBuilder ().getUInt8PtrTy ();
1882+ mlir::Type ptrDiffTy = cgf.convertType (cgf.getContext ().getPointerDiffType ());
1883+
1884+ // TODO(cir): mark the function as nowind willreturn readonly.
1885+ assert (!cir::MissingFeatures::opFuncNoUnwind ());
1886+ assert (!cir::MissingFeatures::opFuncWillReturn ());
1887+ assert (!cir::MissingFeatures::opFuncReadOnly ());
1888+
1889+ // TODO(cir): set the calling convention of the runtime function.
1890+ assert (!cir::MissingFeatures::opFuncCallingConv ());
1891+
1892+ cir::FuncType FTy = cgf.getBuilder ().getFuncType (
1893+ {voidPtrTy, rttiPtrTy, rttiPtrTy, ptrDiffTy}, voidPtrTy);
1894+ return cgf.cgm .createRuntimeFunction (FTy, " __dynamic_cast" );
1895+ }
1896+
1897+ static cir::DynamicCastInfoAttr emitDynamicCastInfo (CIRGenFunction &cgf,
1898+ mlir::Location loc,
1899+ QualType srcRecordTy,
1900+ QualType destRecordTy) {
1901+ auto srcRtti = mlir::cast<cir::GlobalViewAttr>(
1902+ cgf.cgm .getAddrOfRTTIDescriptor (loc, srcRecordTy));
1903+ auto destRtti = mlir::cast<cir::GlobalViewAttr>(
1904+ cgf.cgm .getAddrOfRTTIDescriptor (loc, destRecordTy));
1905+
1906+ cir::FuncOp runtimeFuncOp = getItaniumDynamicCastFn (cgf);
1907+ cir::FuncOp badCastFuncOp = getBadCastFn (cgf);
1908+ auto runtimeFuncRef = mlir::FlatSymbolRefAttr::get (runtimeFuncOp);
1909+ auto badCastFuncRef = mlir::FlatSymbolRefAttr::get (badCastFuncOp);
1910+
1911+ const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl ();
1912+ const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl ();
1913+ CharUnits offsetHint = computeOffsetHint (cgf.getContext (), srcDecl, destDecl);
1914+
1915+ mlir::Type ptrdiffTy = cgf.convertType (cgf.getContext ().getPointerDiffType ());
1916+ auto offsetHintAttr = cir::IntAttr::get (ptrdiffTy, offsetHint.getQuantity ());
1917+
1918+ return cir::DynamicCastInfoAttr::get (srcRtti, destRtti, runtimeFuncRef,
1919+ badCastFuncRef, offsetHintAttr);
1920+ }
1921+
1922+ mlir::Value CIRGenItaniumCXXABI::emitDynamicCast (CIRGenFunction &cgf,
1923+ mlir::Location loc,
1924+ QualType srcRecordTy,
1925+ QualType destRecordTy,
1926+ cir::PointerType destCIRTy,
1927+ bool isRefCast, Address src) {
1928+ bool isCastToVoid = destRecordTy.isNull ();
1929+ assert ((!isCastToVoid || !isRefCast) && " cannot cast to void reference" );
1930+
1931+ if (isCastToVoid) {
1932+ cgm.errorNYI (loc, " emitDynamicCastToVoid" );
1933+ return {};
1934+ }
1935+
1936+ // If the destination is effectively final, the cast succeeds if and only
1937+ // if the dynamic type of the pointer is exactly the destination type.
1938+ if (destRecordTy->getAsCXXRecordDecl ()->isEffectivelyFinal () &&
1939+ cgf.cgm .getCodeGenOpts ().OptimizationLevel > 0 ) {
1940+ cgm.errorNYI (loc, " emitExactDynamicCast" );
1941+ return {};
1942+ }
1943+
1944+ cir::DynamicCastInfoAttr castInfo =
1945+ emitDynamicCastInfo (cgf, loc, srcRecordTy, destRecordTy);
1946+ return cgf.getBuilder ().createDynCast (loc, src.getPointer (), destCIRTy,
1947+ isRefCast, castInfo);
1948+ }
0 commit comments