aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenModule.cpp
diff options
context:
space:
mode:
authorAndy Kaylor <akaylor@nvidia.com>2025-06-05 13:08:29 -0700
committerGitHub <noreply@github.com>2025-06-05 13:08:29 -0700
commitaf54790ca0a3d55d58c2cd7c07d3c4e16c689c72 (patch)
treeef2afd6aa82a31f905616f4f4dd100389295007f /clang/lib/CIR/CodeGen/CIRGenModule.cpp
parent36dd1993a8d06c4ddd5732f926bcffacbb513649 (diff)
downloadllvm-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.cpp68
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;
}