diff options
author | Andy Kaylor <akaylor@nvidia.com> | 2025-06-05 13:08:29 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-05 13:08:29 -0700 |
commit | af54790ca0a3d55d58c2cd7c07d3c4e16c689c72 (patch) | |
tree | ef2afd6aa82a31f905616f4f4dd100389295007f /clang/lib/CIR/CodeGen/CIRGenModule.cpp | |
parent | 36dd1993a8d06c4ddd5732f926bcffacbb513649 (diff) | |
download | llvm-af54790ca0a3d55d58c2cd7c07d3c4e16c689c72.zip llvm-af54790ca0a3d55d58c2cd7c07d3c4e16c689c72.tar.gz llvm-af54790ca0a3d55d58c2cd7c07d3c4e16c689c72.tar.bz2 |
[CIR] Defer emitting function definitions (#142862)
This change implements deferring function definition emission until
first use.
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenModule.cpp')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenModule.cpp | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index eb291de..87e3641 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -213,13 +213,18 @@ CIRGenModule::getAddrOfGlobal(GlobalDecl gd, ForDefinition_t isForDefinition) { } if (isa<CXXMethodDecl>(d)) { - errorNYI(d->getSourceRange(), "getAddrOfGlobal: C++ method decl"); - return nullptr; + const CIRGenFunctionInfo &fi = + getTypes().arrangeCXXMethodDeclaration(cast<CXXMethodDecl>(d)); + cir::FuncType ty = getTypes().getFunctionType(fi); + return getAddrOfFunction(gd, ty, /*ForVTable=*/false, /*DontDefer=*/false, + isForDefinition); } if (isa<FunctionDecl>(d)) { - errorNYI(d->getSourceRange(), "getAddrOfGlobal: function decl"); - return nullptr; + const CIRGenFunctionInfo &fi = getTypes().arrangeGlobalDeclaration(gd); + cir::FuncType ty = getTypes().getFunctionType(fi); + return getAddrOfFunction(gd, ty, /*ForVTable=*/false, /*DontDefer=*/false, + isForDefinition); } return getAddrOfGlobalVar(cast<VarDecl>(d), /*ty=*/nullptr, isForDefinition) @@ -1275,11 +1280,6 @@ bool CIRGenModule::mustBeEmitted(const ValueDecl *global) { vd->getType().isConstQualified()))) return true; - // TODO(cir): We do want to defer function decls, but it's not implemented. - assert(!cir::MissingFeatures::deferredFuncDecls()); - if (isa<FunctionDecl>(global)) - return true; - return getASTContext().DeclMustBeEmitted(global); } @@ -1523,6 +1523,56 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction( cir::FuncOp funcOp = createCIRFunction( invalidLoc ? theModule->getLoc() : getLoc(funcDecl->getSourceRange()), mangledName, mlir::cast<cir::FuncType>(funcType), funcDecl); + + // 'dontDefer' actually means don't move this to the deferredDeclsToEmit list. + if (dontDefer) { + // TODO(cir): This assertion will need an additional condition when we + // support incomplete functions. + assert(funcOp.getFunctionType() == funcType); + return funcOp; + } + + // All MSVC dtors other than the base dtor are linkonce_odr and delegate to + // each other bottoming out wiht the base dtor. Therefore we emit non-base + // dtors on usage, even if there is no dtor definition in the TU. + if (isa_and_nonnull<CXXDestructorDecl>(d)) + errorNYI(d->getSourceRange(), "getOrCreateCIRFunction: dtor"); + + // This is the first use or definition of a mangled name. If there is a + // deferred decl with this name, remember that we need to emit it at the end + // of the file. + auto ddi = deferredDecls.find(mangledName); + if (ddi != deferredDecls.end()) { + // Move the potentially referenced deferred decl to the + // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we + // don't need it anymore). + addDeferredDeclToEmit(ddi->second); + deferredDecls.erase(ddi); + + // Otherwise, there are cases we have to worry about where we're using a + // declaration for which we must emit a definition but where we might not + // find a top-level definition. + // - member functions defined inline in their classes + // - friend functions defined inline in some class + // - special member functions with implicit definitions + // If we ever change our AST traversal to walk into class methods, this + // will be unnecessary. + // + // We also don't emit a definition for a function if it's going to be an + // entry in a vtable, unless it's already marked as used. + } else if (getLangOpts().CPlusPlus && d) { + // Look for a declaration that's lexically in a record. + for (const auto *fd = cast<FunctionDecl>(d)->getMostRecentDecl(); fd; + fd = fd->getPreviousDecl()) { + if (isa<CXXRecordDecl>(fd->getLexicalDeclContext())) { + if (fd->doesThisDeclarationHaveABody()) { + addDeferredDeclToEmit(gd.getWithDecl(fd)); + break; + } + } + } + } + return funcOp; } |