2222
2323#include " clang/AST/ExprCXX.h"
2424#include " clang/AST/GlobalDecl.h"
25+ #include " clang/AST/VTableBuilder.h"
2526#include " clang/CIR/MissingFeatures.h"
2627#include " llvm/Support/ErrorHandling.h"
2728
@@ -31,6 +32,10 @@ using namespace clang::CIRGen;
3132namespace {
3233
3334class CIRGenItaniumCXXABI : public CIRGenCXXABI {
35+ protected:
36+ // / All the vtables which have been defined.
37+ llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;
38+
3439public:
3540 CIRGenItaniumCXXABI (CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
3641 assert (!cir::MissingFeatures::cxxabiUseARMMethodPtrABI ());
@@ -58,6 +63,24 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
5863 // emitted with external linkage or as linkonce if they are inline and used.
5964 return false ;
6065 }
66+
67+ bool isVirtualOffsetNeededForVTableField (CIRGenFunction &cgf,
68+ CIRGenFunction::VPtr vptr) override ;
69+
70+ cir::GlobalOp getAddrOfVTable (const CXXRecordDecl *rd,
71+ CharUnits vptrOffset) override ;
72+
73+ mlir::Value getVTableAddressPoint (BaseSubobject base,
74+ const CXXRecordDecl *vtableClass) override ;
75+
76+ mlir::Value getVTableAddressPointInStructor (
77+ CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
78+ clang::BaseSubobject base,
79+ const clang::CXXRecordDecl *nearestVBase) override ;
80+
81+ bool doStructorsInitializeVPtrs (const CXXRecordDecl *vtableClass) override {
82+ return true ;
83+ }
6184};
6285
6386} // namespace
@@ -278,3 +301,91 @@ CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
278301 llvm_unreachable (" bad or NYI ABI kind" );
279302 }
280303}
304+
305+ cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable (const CXXRecordDecl *rd,
306+ CharUnits vptrOffset) {
307+ assert (vptrOffset.isZero () && " Itanium ABI only supports zero vptr offsets" );
308+ cir::GlobalOp &vtable = vtables[rd];
309+ if (vtable)
310+ return vtable;
311+
312+ // Queue up this vtable for possible deferred emission.
313+ assert (!cir::MissingFeatures::deferredVtables ());
314+
315+ SmallString<256 > name;
316+ llvm::raw_svector_ostream out (name);
317+ getMangleContext ().mangleCXXVTable (rd, out);
318+
319+ const VTableLayout &vtLayout =
320+ cgm.getItaniumVTableContext ().getVTableLayout (rd);
321+ mlir::Type vtableType = cgm.getVTables ().getVTableType (vtLayout);
322+
323+ // Use pointer alignment for the vtable. Otherwise we would align them based
324+ // on the size of the initializer which doesn't make sense as only single
325+ // values are read.
326+ unsigned ptrAlign = cgm.getItaniumVTableContext ().isRelativeLayout ()
327+ ? 32
328+ : cgm.getTarget ().getPointerAlign (LangAS::Default);
329+
330+ vtable = cgm.createOrReplaceCXXRuntimeVariable (
331+ cgm.getLoc (rd->getSourceRange ()), name, vtableType,
332+ cir::GlobalLinkageKind::ExternalLinkage,
333+ cgm.getASTContext ().toCharUnitsFromBits (ptrAlign));
334+ // LLVM codegen handles unnamedAddr
335+ assert (!cir::MissingFeatures::opGlobalUnnamedAddr ());
336+
337+ // In MS C++ if you have a class with virtual functions in which you are using
338+ // selective member import/export, then all virtual functions must be exported
339+ // unless they are inline, otherwise a link error will result. To match this
340+ // behavior, for such classes, we dllimport the vtable if it is defined
341+ // externally and all the non-inline virtual methods are marked dllimport, and
342+ // we dllexport the vtable if it is defined in this TU and all the non-inline
343+ // virtual methods are marked dllexport.
344+ if (cgm.getTarget ().hasPS4DLLImportExport ())
345+ cgm.errorNYI (rd->getSourceRange (),
346+ " getAddrOfVTable: PS4 DLL import/export" );
347+
348+ cgm.setGVProperties (vtable, rd);
349+ return vtable;
350+ }
351+
352+ mlir::Value
353+ CIRGenItaniumCXXABI::getVTableAddressPoint (BaseSubobject base,
354+ const CXXRecordDecl *vtableClass) {
355+ cir::GlobalOp vtable = getAddrOfVTable (vtableClass, CharUnits ());
356+
357+ // Find the appropriate vtable within the vtable group, and the address point
358+ // within that vtable.
359+ VTableLayout::AddressPointLocation addressPoint =
360+ cgm.getItaniumVTableContext ()
361+ .getVTableLayout (vtableClass)
362+ .getAddressPoint (base);
363+
364+ mlir::OpBuilder &builder = cgm.getBuilder ();
365+ auto vtablePtrTy = cir::VPtrType::get (builder.getContext ());
366+
367+ return builder.create <cir::VTableAddrPointOp>(
368+ cgm.getLoc (vtableClass->getSourceRange ()), vtablePtrTy,
369+ mlir::FlatSymbolRefAttr::get (vtable.getSymNameAttr ()),
370+ cir::AddressPointAttr::get (cgm.getBuilder ().getContext (),
371+ addressPoint.VTableIndex ,
372+ addressPoint.AddressPointIndex ));
373+ }
374+
375+ mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor (
376+ CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
377+ clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {
378+
379+ if (base.getBase ()->getNumVBases ()) {
380+ cgm.errorNYI (cgf.curFuncDecl ->getLocation (),
381+ " getVTableAddressPointInStructor: virtual base" );
382+ }
383+ return getVTableAddressPoint (base, vtableClass);
384+ }
385+
386+ bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField (
387+ CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {
388+ if (vptr.nearestVBase == nullptr )
389+ return false ;
390+ return needsVTTParameter (cgf.curGD );
391+ }
0 commit comments