Skip to content

Commit a14ddf3

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 a5c0f81 commit a14ddf3

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
@@ -1475,6 +1475,14 @@ mlir::cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc,
14751475
return f;
14761476
}
14771477

1478+
bool isDefaultedMethod(const clang::FunctionDecl *FD) {
1479+
if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
1480+
(cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() ||
1481+
cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator()))
1482+
return true;
1483+
return false;
1484+
}
1485+
14781486
/// If the specified mangled name is not in the module,
14791487
/// create and return a CIR Function with the specified type. If there is
14801488
/// something in the module with the specified name, return it potentially
@@ -1612,7 +1620,10 @@ mlir::cir::FuncOp CIRGenModule::GetOrCreateCIRFunction(
16121620
FD = FD->getPreviousDecl()) {
16131621
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
16141622
if (FD->doesThisDeclarationHaveABody()) {
1615-
addDeferredDeclToEmit(GD.getWithDecl(FD));
1623+
if (isDefaultedMethod(FD))
1624+
addDefaultMethodsToEmit(GD.getWithDecl(FD));
1625+
else
1626+
addDeferredDeclToEmit(GD.getWithDecl(FD));
16161627
break;
16171628
}
16181629
}
@@ -1650,6 +1661,44 @@ mlir::Location CIRGenModule::getLoc(mlir::Location lhs, mlir::Location rhs) {
16501661
return mlir::FusedLoc::get(locs, metadata, builder.getContext());
16511662
}
16521663

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

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

17191734
// If we found out that we need to emit more decls, do that recursively.
17201735
// This has the advantage that the decls are emitted in a DFS and related
@@ -1726,6 +1741,13 @@ void CIRGenModule::buildDeferred() {
17261741
}
17271742
}
17281743

1744+
void CIRGenModule::buildDefaultMethods() {
1745+
// Differently from DeferredDeclsToEmit, there's no recurrent use of
1746+
// DefaultMethodsToEmit, so use it directly for emission.
1747+
for (auto &D : DefaultMethodsToEmit)
1748+
buildGlobalDecl(D);
1749+
}
1750+
17291751
mlir::IntegerAttr CIRGenModule::getSize(CharUnits size) {
17301752
return mlir::IntegerAttr::get(
17311753
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)