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