@@ -118,6 +118,16 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
118
118
Address thisAddr, const CXXRecordDecl *classDecl,
119
119
const CXXRecordDecl *baseClassDecl) override ;
120
120
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
+
121
131
/* *************************** RTTI Uniqueness ******************************/
122
132
protected:
123
133
// / Returns true if the ABI requires RTTI type_info objects to be unique
@@ -1819,3 +1829,143 @@ mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
1819
1829
}
1820
1830
return vbaseOffset;
1821
1831
}
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