Skip to content

Commit 263459b

Browse files
bcardosolopeslanza
authored andcommitted
[CIR][NFC] Break default method emission to run after CIR passes
This prevents us from doing unecessary codegen until we need the body of default methods. Some analysis won't require going inside such methods. In the future we should only enable the codegen in the pipeline that goes out to LLVM codegen.
1 parent 9b0ef16 commit 263459b

File tree

5 files changed

+83
-37
lines changed

5 files changed

+83
-37
lines changed

clang/include/clang/CIR/CIRGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class CIRGenerator : public clang::ASTConsumer {
9292
bool verifyModule();
9393

9494
void buildDeferredDecls();
95+
void buildDefaultMethods();
9596
};
9697

9798
} // namespace cir

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,14 @@ mlir::cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc,
14711471
return f;
14721472
}
14731473

1474+
bool isDefaultedMethod(const clang::FunctionDecl *FD) {
1475+
if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
1476+
(cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() ||
1477+
cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator()))
1478+
return true;
1479+
return false;
1480+
}
1481+
14741482
/// If the specified mangled name is not in the module,
14751483
/// create and return a CIR Function with the specified type. If there is
14761484
/// something in the module with the specified name, return it potentially
@@ -1608,7 +1616,10 @@ mlir::cir::FuncOp CIRGenModule::GetOrCreateCIRFunction(
16081616
FD = FD->getPreviousDecl()) {
16091617
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
16101618
if (FD->doesThisDeclarationHaveABody()) {
1611-
addDeferredDeclToEmit(GD.getWithDecl(FD));
1619+
if (isDefaultedMethod(FD))
1620+
addDefaultMethodsToEmit(GD.getWithDecl(FD));
1621+
else
1622+
addDeferredDeclToEmit(GD.getWithDecl(FD));
16121623
break;
16131624
}
16141625
}
@@ -1646,6 +1657,44 @@ mlir::Location CIRGenModule::getLoc(mlir::Location lhs, mlir::Location rhs) {
16461657
return mlir::FusedLoc::get(locs, metadata, builder.getContext());
16471658
}
16481659

1660+
void CIRGenModule::buildGlobalDecl(clang::GlobalDecl &D) {
1661+
// We should call GetAddrOfGlobal with IsForDefinition set to true in order
1662+
// to get a Value with exactly the type we need, not something that might
1663+
// have been created for another decl with the same mangled name but
1664+
// different type.
1665+
auto *Op = GetAddrOfGlobal(D, ForDefinition);
1666+
1667+
// In case of different address spaces, we may still get a cast, even with
1668+
// IsForDefinition equal to true. Query mangled names table to get
1669+
// GlobalValue.
1670+
if (!Op) {
1671+
Op = getGlobalValue(getMangledName(D));
1672+
}
1673+
1674+
// Make sure getGlobalValue returned non-null.
1675+
assert(Op);
1676+
assert(isa<mlir::cir::FuncOp>(Op) &&
1677+
"not implemented, only supports FuncOp for now");
1678+
1679+
// Check to see if we've already emitted this. This is necessary for a
1680+
// couple of reasons: first, decls can end up in deferred-decls queue
1681+
// multiple times, and second, decls can end up with definitions in unusual
1682+
// ways (e.g. by an extern inline function acquiring a strong function
1683+
// redefinition). Just ignore those cases.
1684+
// TODO: Not sure what to map this to for MLIR
1685+
if (auto Fn = cast<mlir::cir::FuncOp>(Op))
1686+
if (!Fn.isDeclaration())
1687+
return;
1688+
1689+
// If this is OpenMP, check if it is legal to emit this global normally.
1690+
if (getLangOpts().OpenMP) {
1691+
llvm_unreachable("NYI");
1692+
}
1693+
1694+
// Otherwise, emit the definition and move on to the next one.
1695+
buildGlobalDefinition(D, Op);
1696+
}
1697+
16491698
void CIRGenModule::buildDeferred() {
16501699
// Emit deferred declare target declarations
16511700
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)
@@ -1676,41 +1725,7 @@ void CIRGenModule::buildDeferred() {
16761725
CurDeclsToEmit.swap(DeferredDeclsToEmit);
16771726

16781727
for (auto &D : CurDeclsToEmit) {
1679-
// We should call GetAddrOfGlobal with IsForDefinition set to true in order
1680-
// to get a Value with exactly the type we need, not something that might
1681-
// have been created for another decl with the same mangled name but
1682-
// different type.
1683-
auto *Op = GetAddrOfGlobal(D, ForDefinition);
1684-
1685-
// In case of different address spaces, we may still get a cast, even with
1686-
// IsForDefinition equal to true. Query mangled names table to get
1687-
// GlobalValue.
1688-
if (!Op) {
1689-
Op = getGlobalValue(getMangledName(D));
1690-
}
1691-
1692-
// Make sure getGlobalValue returned non-null.
1693-
assert(Op);
1694-
assert(isa<mlir::cir::FuncOp>(Op) &&
1695-
"not implemented, only supports FuncOp for now");
1696-
1697-
// Check to see if we've already emitted this. This is necessary for a
1698-
// couple of reasons: first, decls can end up in deferred-decls queue
1699-
// multiple times, and second, decls can end up with definitions in unusual
1700-
// ways (e.g. by an extern inline function acquiring a strong function
1701-
// redefinition). Just ignore those cases.
1702-
// TODO: Not sure what to map this to for MLIR
1703-
if (auto Fn = cast<mlir::cir::FuncOp>(Op))
1704-
if (!Fn.isDeclaration())
1705-
continue;
1706-
1707-
// If this is OpenMP, check if it is legal to emit this global normally.
1708-
if (getLangOpts().OpenMP) {
1709-
llvm_unreachable("NYI");
1710-
}
1711-
1712-
// Otherwise, emit the definition and move on to the next one.
1713-
buildGlobalDefinition(D, Op);
1728+
buildGlobalDecl(D);
17141729

17151730
// If we found out that we need to emit more decls, do that recursively.
17161731
// This has the advantage that the decls are emitted in a DFS and related
@@ -1722,6 +1737,13 @@ void CIRGenModule::buildDeferred() {
17221737
}
17231738
}
17241739

1740+
void CIRGenModule::buildDefaultMethods() {
1741+
// Differently from DeferredDeclsToEmit, there's no recurrent use of
1742+
// DefaultMethodsToEmit, so use it directly for emission.
1743+
for (auto &D : DefaultMethodsToEmit)
1744+
buildGlobalDecl(D);
1745+
}
1746+
17251747
mlir::IntegerAttr CIRGenModule::getSize(CharUnits size) {
17261748
return mlir::IntegerAttr::get(
17271749
mlir::IntegerType::get(builder.getContext(), 64), size.getQuantity());

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,14 @@ class CIRGenModule {
262262
DeferredDeclsToEmit.emplace_back(GD);
263263
}
264264

265+
// After HandleTranslation finishes, differently from DeferredDeclsToEmit,
266+
// DefaultMethodsToEmit is only called after a set of CIR passes run. See
267+
// addDefaultMethodsToEmit usage for examples.
268+
std::vector<clang::GlobalDecl> DefaultMethodsToEmit;
269+
void addDefaultMethodsToEmit(clang::GlobalDecl GD) {
270+
DefaultMethodsToEmit.emplace_back(GD);
271+
}
272+
265273
std::pair<mlir::FunctionType, mlir::cir::FuncOp> getAddrAndTypeOfCXXStructor(
266274
clang::GlobalDecl GD, const CIRGenFunctionInfo *FnInfo = nullptr,
267275
mlir::FunctionType FnType = nullptr, bool Dontdefer = false,
@@ -329,6 +337,12 @@ class CIRGenModule {
329337
/// Emit any needed decls for which code generation was deferred.
330338
void buildDeferred();
331339

340+
/// Helper for `buildDeferred` to apply actual codegen.
341+
void buildGlobalDecl(clang::GlobalDecl &D);
342+
343+
/// Build default methods not emitted before this point.
344+
void buildDefaultMethods();
345+
332346
const llvm::Triple &getTriple() const { return target.getTriple(); }
333347

334348
// Finalize CIR code generation.

clang/lib/CIR/CodeGen/CIRGenerator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ void CIRGenerator::HandleInlineFunctionDefinition(FunctionDecl *D) {
106106
CGM->AddDeferredUnusedCoverageMapping(D);
107107
}
108108

109+
void CIRGenerator::buildDefaultMethods() { CGM->buildDefaultMethods(); }
110+
109111
void CIRGenerator::buildDeferredDecls() {
110112
if (DeferredInlineMemberFuncDefs.empty())
111113
return;

clang/lib/CIR/FrontendAction/CIRGenAction.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,19 @@ class CIRGenConsumer : public clang::ASTConsumer {
143143
switch (action) {
144144
case CIRGenAction::OutputType::EmitCIR:
145145
if (outputStream && mlirMod) {
146+
147+
// Run CIR cleanup, in the future also the relevent raising and
148+
// some code analysis.
146149
if (!feOptions.DisableCIRPasses) {
147150
runCIRToCIRPasses(mlirMod, mlirCtx.get(),
148151
!feOptions.DisableCIRVerifier);
149152
}
150-
mlir::OpPrintingFlags flags;
153+
154+
// Emit remaining defaulted C++ methods
155+
gen->buildDefaultMethods();
156+
151157
// FIXME: we cannot roundtrip prettyForm=true right now.
158+
mlir::OpPrintingFlags flags;
152159
flags.enableDebugInfo(/*prettyForm=*/false);
153160
mlirMod->print(*outputStream, flags);
154161
}

0 commit comments

Comments
 (0)