@@ -1771,12 +1771,129 @@ void CGOpenMPRuntime::emitDeclareTargetFunction(const FunctionDecl *FD,
17711771 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
17721772 }
17731773
1774+ // Register the indirect Vtable:
1775+ // This is similar to OMPTargetGlobalVarEntryIndirect, except that the
1776+ // size field refers to the size of memory pointed to, not the size of
1777+ // the pointer symbol itself (which is implicitly the size of a pointer).
17741778 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
17751779 Name, Addr, CGM.GetTargetTypeStoreSize(CGM.VoidPtrTy).getQuantity(),
17761780 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirect,
17771781 llvm::GlobalValue::WeakODRLinkage);
17781782}
17791783
1784+ void CGOpenMPRuntime::registerVTableOffloadEntry(llvm::GlobalVariable *VTable,
1785+ const VarDecl *VD) {
1786+ // TODO: add logic to avoid duplicate vtable registrations per
1787+ // translation unit; though for external linkage, this should no
1788+ // longer be an issue - or at least we can avoid the issue by
1789+ // checking for an existing offloading entry. But, perhaps the
1790+ // better approach is to defer emission of the vtables and offload
1791+ // entries until later (by tracking a list of items that need to be
1792+ // emitted).
1793+
1794+ llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1795+
1796+ // Generate a new externally visible global to point to the
1797+ // internally visible vtable. Doing this allows us to keep the
1798+ // visibility and linkage of the associated vtable unchanged while
1799+ // allowing the runtime to access its value. The externally
1800+ // visible global var needs to be emitted with a unique mangled
1801+ // name that won't conflict with similarly named (internal)
1802+ // vtables in other translation units.
1803+
1804+ // Register vtable with source location of dynamic object in map
1805+ // clause.
1806+ llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1807+ CGM, OMPBuilder, VD->getCanonicalDecl()->getBeginLoc(),
1808+ VTable->getName());
1809+
1810+ llvm::GlobalVariable *Addr = VTable;
1811+ size_t PointerSize = CGM.getDataLayout().getPointerSize();
1812+ SmallString<128> AddrName;
1813+ OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(AddrName, EntryInfo);
1814+ AddrName.append("addr");
1815+
1816+ if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1817+ Addr = new llvm::GlobalVariable(
1818+ CGM.getModule(), VTable->getType(),
1819+ /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, VTable,
1820+ AddrName,
1821+ /*InsertBefore*/ nullptr, llvm::GlobalValue::NotThreadLocal,
1822+ CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1823+ Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1824+ }
1825+ OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1826+ AddrName, VTable,
1827+ CGM.getDataLayout().getTypeAllocSize(VTable->getInitializer()->getType()),
1828+ llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirectVTable,
1829+ llvm::GlobalValue::WeakODRLinkage);
1830+ }
1831+
1832+ void CGOpenMPRuntime::emitAndRegisterVTable(CodeGenModule &CGM,
1833+ CXXRecordDecl *CXXRecord,
1834+ const VarDecl *VD) {
1835+ // Register C++ VTable to OpenMP Offload Entry if it's a new
1836+ // CXXRecordDecl.
1837+ if (CXXRecord && CXXRecord->isDynamicClass() &&
1838+ !CGM.getOpenMPRuntime().VTableDeclMap.contains(CXXRecord)) {
1839+ CGM.getOpenMPRuntime().VTableDeclMap.try_emplace(CXXRecord, VD);
1840+ CGM.EmitVTable(CXXRecord);
1841+ CodeGenVTables VTables = CGM.getVTables();
1842+ llvm::GlobalVariable *VTablesAddr = VTables.GetAddrOfVTable(CXXRecord);
1843+ if (VTablesAddr)
1844+ CGM.getOpenMPRuntime().registerVTableOffloadEntry(VTablesAddr, VD);
1845+ // Emit VTable for all the fields containing dynamic CXXRecord
1846+ for (const FieldDecl *Field : CXXRecord->fields()) {
1847+ if (CXXRecordDecl *RecordDecl = Field->getType()->getAsCXXRecordDecl())
1848+ emitAndRegisterVTable(CGM, RecordDecl, VD);
1849+ }
1850+ // Emit VTable for all dynamic parent class
1851+ for (CXXBaseSpecifier &Base : CXXRecord->bases()) {
1852+ if (CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl())
1853+ emitAndRegisterVTable(CGM, BaseDecl, VD);
1854+ }
1855+ }
1856+ };
1857+
1858+ void CGOpenMPRuntime::registerVTable(const OMPExecutableDirective &D) {
1859+ // Register VTable by scanning through the map clause of OpenMP target region.
1860+ // Get CXXRecordDecl and VarDecl from Expr.
1861+ auto GetVTableDecl = [](const Expr *E) {
1862+ QualType VDTy = E->getType();
1863+ CXXRecordDecl *CXXRecord = nullptr;
1864+ if (const auto *RefType = VDTy->getAs<LValueReferenceType>())
1865+ VDTy = RefType->getPointeeType();
1866+ if (VDTy->isPointerType())
1867+ CXXRecord = VDTy->getPointeeType()->getAsCXXRecordDecl();
1868+ else
1869+ CXXRecord = VDTy->getAsCXXRecordDecl();
1870+
1871+ const VarDecl *VD = nullptr;
1872+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
1873+ VD = cast<VarDecl>(DRE->getDecl());
1874+ else if (auto *MRE = dyn_cast<MemberExpr>(E)){
1875+ printf("here\n");
1876+ if (auto *BaseDRE = dyn_cast<DeclRefExpr>(MRE->getBase())){
1877+ printf("here 1\n");
1878+ if (auto *BaseVD = dyn_cast<VarDecl>(BaseDRE->getDecl())){
1879+ VD = BaseVD;
1880+ printf("here 2\n");
1881+ }
1882+ }
1883+ }
1884+ return std::pair<CXXRecordDecl *, const VarDecl *>(CXXRecord, VD);
1885+ };
1886+ // Collect VTable from OpenMP map clause.
1887+ for (const auto *C : D.getClausesOfKind<OMPMapClause>()) {
1888+ for (const auto *E : C->varlist()) {
1889+ auto DeclPair = GetVTableDecl(E);
1890+ // Ensure VD is not null
1891+ if (DeclPair.second)
1892+ emitAndRegisterVTable(CGM, DeclPair.first, DeclPair.second);
1893+ }
1894+ }
1895+ }
1896+
17801897Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
17811898 QualType VarType,
17821899 StringRef Name) {
@@ -6249,6 +6366,7 @@ void CGOpenMPRuntime::emitTargetOutlinedFunctionHelper(
62496366 CGM.handleAMDGPUWavesPerEUAttr(OutlinedFn, Attr);
62506367 }
62516368 }
6369+ registerVTable(D);
62526370}
62536371
62546372/// Checks if the expression is constant or does not have non-trivial function
@@ -9955,6 +10073,17 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
995510073 if (!S)
995610074 return;
995710075
10076+ // Register vtable from device for target data and target directives.
10077+ // Add this block here since scanForTargetRegionsFunctions ignores
10078+ // target data by checking if S is a executable directive (target).
10079+ if (auto *E = dyn_cast<OMPExecutableDirective>(S);
10080+ E && isOpenMPTargetDataManagementDirective(E->getDirectiveKind())) {
10081+ // Don't need to check if it's device compile
10082+ // since scanForTargetRegionsFunctions currently only called
10083+ // in device compilation.
10084+ registerVTable(*E);
10085+ }
10086+
995810087 // Codegen OMP target directives that offload compute to the device.
995910088 bool RequiresDeviceCodegen =
996010089 isa<OMPExecutableDirective>(S) &&
0 commit comments