@@ -202,6 +202,99 @@ mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
202202 return mlir::FusedLoc::get ({begin, end}, metadata, builder.getContext ());
203203}
204204
205+ mlir::Operation *
206+ CIRGenModule::getAddrOfGlobal (GlobalDecl gd, ForDefinition_t isForDefinition) {
207+ const Decl *d = gd.getDecl ();
208+
209+ if (isa<CXXConstructorDecl>(d) || isa<CXXDestructorDecl>(d)) {
210+ errorNYI (d->getSourceRange (),
211+ " getAddrOfGlobal: C++ constructor/destructor" );
212+ return nullptr ;
213+ }
214+
215+ if (isa<CXXMethodDecl>(d)) {
216+ errorNYI (d->getSourceRange (), " getAddrOfGlobal: C++ method decl" );
217+ return nullptr ;
218+ }
219+
220+ if (isa<FunctionDecl>(d)) {
221+ errorNYI (d->getSourceRange (), " getAddrOfGlobal: function decl" );
222+ return nullptr ;
223+ }
224+
225+ return getAddrOfGlobalVar (cast<VarDecl>(d), /* ty=*/ nullptr , isForDefinition)
226+ .getDefiningOp ();
227+ }
228+
229+ void CIRGenModule::emitGlobalDecl (const clang::GlobalDecl &d) {
230+ // We call getAddrOfGlobal with isForDefinition set to ForDefinition in
231+ // order to get a Value with exactly the type we need, not something that
232+ // might have been created for another decl with the same mangled name but
233+ // different type.
234+ mlir::Operation *op = getAddrOfGlobal (d, ForDefinition);
235+
236+ // In case of different address spaces, we may still get a cast, even with
237+ // IsForDefinition equal to ForDefinition. Query mangled names table to get
238+ // GlobalValue.
239+ if (!op)
240+ op = getGlobalValue (getMangledName (d));
241+
242+ assert (op && " expected a valid global op" );
243+
244+ // Check to see if we've already emitted this. This is necessary for a
245+ // couple of reasons: first, decls can end up in deferred-decls queue
246+ // multiple times, and second, decls can end up with definitions in unusual
247+ // ways (e.g. by an extern inline function acquiring a strong function
248+ // redefinition). Just ignore those cases.
249+ // TODO: Not sure what to map this to for MLIR
250+ mlir::Operation *globalValueOp = op;
251+ if (auto gv = dyn_cast<cir::GetGlobalOp>(op))
252+ globalValueOp =
253+ mlir::SymbolTable::lookupSymbolIn (getModule (), gv.getNameAttr ());
254+
255+ if (auto cirGlobalValue =
256+ dyn_cast<cir::CIRGlobalValueInterface>(globalValueOp))
257+ if (!cirGlobalValue.isDeclaration ())
258+ return ;
259+
260+ // If this is OpenMP, check if it is legal to emit this global normally.
261+ assert (!cir::MissingFeatures::openMP ());
262+
263+ // Otherwise, emit the definition and move on to the next one.
264+ emitGlobalDefinition (d, op);
265+ }
266+
267+ void CIRGenModule::emitDeferred () {
268+ // Emit code for any potentially referenced deferred decls. Since a previously
269+ // unused static decl may become used during the generation of code for a
270+ // static function, iterate until no changes are made.
271+
272+ assert (!cir::MissingFeatures::openMP ());
273+ assert (!cir::MissingFeatures::deferredVtables ());
274+ assert (!cir::MissingFeatures::cudaSupport ());
275+
276+ // Stop if we're out of both deferred vtables and deferred declarations.
277+ if (deferredDeclsToEmit.empty ())
278+ return ;
279+
280+ // Grab the list of decls to emit. If emitGlobalDefinition schedules more
281+ // work, it will not interfere with this.
282+ std::vector<GlobalDecl> curDeclsToEmit;
283+ curDeclsToEmit.swap (deferredDeclsToEmit);
284+
285+ for (const GlobalDecl &d : curDeclsToEmit) {
286+ emitGlobalDecl (d);
287+
288+ // If we found out that we need to emit more decls, do that recursively.
289+ // This has the advantage that the decls are emitted in a DFS and related
290+ // ones are close together, which is convenient for testing.
291+ if (!deferredDeclsToEmit.empty ()) {
292+ emitDeferred ();
293+ assert (deferredDeclsToEmit.empty ());
294+ }
295+ }
296+ }
297+
205298void CIRGenModule::emitGlobal (clang::GlobalDecl gd) {
206299 if (const auto *cd = dyn_cast<clang::OpenACCConstructDecl>(gd.getDecl ())) {
207300 emitGlobalOpenACCDecl (cd);
@@ -240,8 +333,33 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
240333 }
241334 }
242335
243- // TODO(CIR): Defer emitting some global definitions until later
244- emitGlobalDefinition (gd);
336+ // Defer code generation to first use when possible, e.g. if this is an inline
337+ // function. If the global must always be emitted, do it eagerly if possible
338+ // to benefit from cache locality. Deferring code generation is necessary to
339+ // avoid adding initializers to external declarations.
340+ if (mustBeEmitted (global) && mayBeEmittedEagerly (global)) {
341+ // Emit the definition if it can't be deferred.
342+ emitGlobalDefinition (gd);
343+ return ;
344+ }
345+
346+ // If we're deferring emission of a C++ variable with an initializer, remember
347+ // the order in which it appeared on the file.
348+ assert (!cir::MissingFeatures::deferredCXXGlobalInit ());
349+
350+ llvm::StringRef mangledName = getMangledName (gd);
351+ if (getGlobalValue (mangledName) != nullptr ) {
352+ // The value has already been used and should therefore be emitted.
353+ addDeferredDeclToEmit (gd);
354+ } else if (mustBeEmitted (global)) {
355+ // The value must be emitted, but cannot be emitted eagerly.
356+ assert (!mayBeEmittedEagerly (global));
357+ addDeferredDeclToEmit (gd);
358+ } else {
359+ // Otherwise, remember that we saw a deferred decl with this name. The first
360+ // use of the mangled name will cause it to move into deferredDeclsToEmit.
361+ deferredDecls[mangledName] = gd;
362+ }
245363}
246364
247365void CIRGenModule::emitGlobalFunctionDefinition (clang::GlobalDecl gd,
@@ -402,6 +520,17 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
402520 CIRGenModule::createGlobalOp (*this , loc, mangledName, ty,
403521 /* insertPoint=*/ entry.getOperation ());
404522
523+ // This is the first use or definition of a mangled name. If there is a
524+ // deferred decl with this name, remember that we need to emit it at the end
525+ // of the file.
526+ auto ddi = deferredDecls.find (mangledName);
527+ if (ddi != deferredDecls.end ()) {
528+ // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
529+ // list, and remove it from DeferredDecls (since we don't need it anymore).
530+ addDeferredDeclToEmit (ddi->second );
531+ deferredDecls.erase (ddi);
532+ }
533+
405534 // Handle things which are present even on external declarations.
406535 if (d) {
407536 if (langOpts.OpenMP && !langOpts.OpenMPSimd )
@@ -1121,12 +1250,88 @@ void CIRGenModule::emitTentativeDefinition(const VarDecl *d) {
11211250 if (gv && !mlir::cast<cir::GlobalOp>(gv).isDeclaration ())
11221251 return ;
11231252
1124- assert (!cir::MissingFeatures::deferredDecls ());
1253+ // If we have not seen a reference to this variable yet, place it into the
1254+ // deferred declarations table to be emitted if needed later.
1255+ if (!mustBeEmitted (d) && !gv) {
1256+ deferredDecls[mangledName] = d;
1257+ return ;
1258+ }
11251259
11261260 // The tentative definition is the only definition.
11271261 emitGlobalVarDefinition (d);
11281262}
11291263
1264+ bool CIRGenModule::mustBeEmitted (const ValueDecl *global) {
1265+ // Never defer when EmitAllDecls is specified.
1266+ if (langOpts.EmitAllDecls )
1267+ return true ;
1268+
1269+ const auto *vd = dyn_cast<VarDecl>(global);
1270+ if (vd &&
1271+ ((codeGenOpts.KeepPersistentStorageVariables &&
1272+ (vd->getStorageDuration () == SD_Static ||
1273+ vd->getStorageDuration () == SD_Thread)) ||
1274+ (codeGenOpts.KeepStaticConsts && vd->getStorageDuration () == SD_Static &&
1275+ vd->getType ().isConstQualified ())))
1276+ return true ;
1277+
1278+ // TODO(cir): We do want to defer function decls, but it's not implemented.
1279+ assert (!cir::MissingFeatures::deferredFuncDecls ());
1280+ if (isa<FunctionDecl>(global))
1281+ return true ;
1282+
1283+ return getASTContext ().DeclMustBeEmitted (global);
1284+ }
1285+
1286+ bool CIRGenModule::mayBeEmittedEagerly (const ValueDecl *global) {
1287+ // In OpenMP 5.0 variables and function may be marked as
1288+ // device_type(host/nohost) and we should not emit them eagerly unless we sure
1289+ // that they must be emitted on the host/device. To be sure we need to have
1290+ // seen a declare target with an explicit mentioning of the function, we know
1291+ // we have if the level of the declare target attribute is -1. Note that we
1292+ // check somewhere else if we should emit this at all.
1293+ if (langOpts.OpenMP >= 50 && !langOpts.OpenMPSimd ) {
1294+ std::optional<OMPDeclareTargetDeclAttr *> activeAttr =
1295+ OMPDeclareTargetDeclAttr::getActiveAttr (global);
1296+ if (!activeAttr || (*activeAttr)->getLevel () != (unsigned )-1 )
1297+ return false ;
1298+ }
1299+
1300+ const auto *fd = dyn_cast<FunctionDecl>(global);
1301+ if (fd) {
1302+ // Implicit template instantiations may change linkage if they are later
1303+ // explicitly instantiated, so they should not be emitted eagerly.
1304+ if (fd->getTemplateSpecializationKind () == TSK_ImplicitInstantiation)
1305+ return false ;
1306+ // Defer until all versions have been semantically checked.
1307+ if (fd->hasAttr <TargetVersionAttr>() && !fd->isMultiVersion ())
1308+ return false ;
1309+ if (langOpts.SYCLIsDevice ) {
1310+ errorNYI (fd->getSourceRange (), " mayBeEmittedEagerly: SYCL" );
1311+ return false ;
1312+ }
1313+ }
1314+ const auto *vd = dyn_cast<VarDecl>(global);
1315+ if (vd)
1316+ if (astContext.getInlineVariableDefinitionKind (vd) ==
1317+ ASTContext::InlineVariableDefinitionKind::WeakUnknown)
1318+ // A definition of an inline constexpr static data member may change
1319+ // linkage later if it's redeclared outside the class.
1320+ return false ;
1321+
1322+ // If OpenMP is enabled and threadprivates must be generated like TLS, delay
1323+ // codegen for global variables, because they may be marked as threadprivate.
1324+ if (langOpts.OpenMP && langOpts.OpenMPUseTLS &&
1325+ astContext.getTargetInfo ().isTLSSupported () && isa<VarDecl>(global) &&
1326+ !global->getType ().isConstantStorage (astContext, false , false ) &&
1327+ !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration (global))
1328+ return false ;
1329+
1330+ assert ((fd || vd) &&
1331+ " Only FunctionDecl and VarDecl should hit this path so far." );
1332+ return true ;
1333+ }
1334+
11301335static bool shouldAssumeDSOLocal (const CIRGenModule &cgm,
11311336 cir::CIRGlobalValueInterface gv) {
11321337 if (gv.hasLocalLinkage ())
@@ -1394,6 +1599,13 @@ CIRGenModule::getGlobalVisibilityAttrFromDecl(const Decl *decl) {
13941599 return cirVisibility;
13951600}
13961601
1602+ void CIRGenModule::release () {
1603+ emitDeferred ();
1604+
1605+ // There's a lot of code that is not implemented yet.
1606+ assert (!cir::MissingFeatures::cgmRelease ());
1607+ }
1608+
13971609mlir::Type CIRGenModule::convertType (QualType type) {
13981610 return genTypes.convertType (type);
13991611}
0 commit comments