Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}

Expand Down
38 changes: 38 additions & 0 deletions clang/test/CIR/CodeGen/deferred-fn-defs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR --implicit-check-not=externNotCalled \
// RUN: --implicit-check-not=internalNotCalled --implicit-check-not=inlineNotCalled

extern int externCalled();
extern int externNotCalled();

namespace {
int internalCalled() { return 1; }
int internalNotCalled() { return 2; }
}

struct S {
int inlineCalled() { return 3; }
int inlineNotCalled() { return 4; }
};

void use() {
S s;
externCalled();
internalCalled();
s.inlineCalled();
}

// CIR: cir.func{{.*}} @_Z12externCalledv
// This shouldn't have a body.
// CIR-NOT: cir.return

// CIR: cir.func{{.*}} @_ZN12_GLOBAL__N_114internalCalledEv
// CIR: %[[ONE:.*]] = cir.const #cir.int<1>
// CIR: cir.store %[[ONE]], %[[RET_ADDR:.*]]

// CIR: cir.func{{.*}} @_ZN1S12inlineCalledEv
// CIR: %[[THIS:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["this", init]
// CIR: %[[THREE:.*]] = cir.const #cir.int<3>
// CIR: cir.store %[[THREE]], %[[RET_ADDR:.*]]

// CIR: cir.func{{.*}} @_Z3usev()