Skip to content

Commit 10aff52

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 2228f05 commit 10aff52

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

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

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

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

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

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