Skip to content

Commit 6f28fff

Browse files
authored
[CIR] Implement opportunistic VTable emission (#1749)
Implemented opportunistic vtable emission, which marks vtables as `available_externally` to enable inlining if optimizations are enabled. Added `GlobalOp` verifier support `available_externally` linkage type, all cases are covered now, so I removed the `default` case. Added the `vtable-available-externally` CIRGen test.
1 parent 32eacb5 commit 6f28fff

File tree

5 files changed

+58
-10
lines changed

5 files changed

+58
-10
lines changed

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,7 +3394,7 @@ void CIRGenModule::Release() {
33943394
assert(!MissingFeatures::emitModuleInitializers());
33953395
emitDeferred(getCodeGenOpts().ClangIRBuildDeferredThreshold);
33963396
assert(!MissingFeatures::emittedDeferredDecls());
3397-
assert(!MissingFeatures::emitVTablesOpportunistically());
3397+
emitVTablesOpportunistically();
33983398
assert(!MissingFeatures::applyGlobalValReplacements());
33993399
applyReplacements();
34003400
assert(!MissingFeatures::emitMultiVersionFunctions());
@@ -4034,8 +4034,6 @@ cir::GlobalOp CIRGenModule::createOrReplaceCXXRuntimeVariable(
40344034
}
40354035

40364036
bool CIRGenModule::shouldOpportunisticallyEmitVTables() {
4037-
if (codeGenOpts.OptimizationLevel != 0)
4038-
llvm_unreachable("NYI");
40394037
return codeGenOpts.OptimizationLevel > 0;
40404038
}
40414039

@@ -4266,6 +4264,25 @@ void CIRGenModule::addGlobalAnnotations(const ValueDecl *d,
42664264
func.setAnnotationsAttr(builder.getArrayAttr(annotations));
42674265
}
42684266

4267+
void CIRGenModule::emitVTablesOpportunistically() {
4268+
// Try to emit external vtables as available_externally if they have emitted
4269+
// all inlined virtual functions. It runs after EmitDeferred() and therefore
4270+
// is not allowed to create new references to things that need to be emitted
4271+
// lazily. Note that it also uses fact that we eagerly emitting RTTI.
4272+
4273+
assert(
4274+
(opportunisticVTables.empty() || shouldOpportunisticallyEmitVTables()) &&
4275+
"Only emit opportunistic vtables with optimizations");
4276+
4277+
for (const CXXRecordDecl *rd : opportunisticVTables) {
4278+
assert(getVTables().isVTableExternal(rd) &&
4279+
"This queue should only contain external vtables");
4280+
if (getCXXABI().canSpeculativelyEmitVTable(rd))
4281+
VTables.GenerateClassData(rd);
4282+
}
4283+
opportunisticVTables.clear();
4284+
}
4285+
42694286
void CIRGenModule::emitGlobalAnnotations() {
42704287
for (const auto &[mangledName, vd] : deferredAnnotations) {
42714288
mlir::Operation *gv = getGlobalValue(mangledName);

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ class CIRGenModule : public CIRGenTypeCache {
573573
/// A queue of (optional) vtables to consider emitting.
574574
std::vector<const clang::CXXRecordDecl *> DeferredVTables;
575575

576+
/// A queue of (optional) vtables that may be emitted opportunistically.
577+
std::vector<const clang::CXXRecordDecl *> opportunisticVTables;
578+
576579
mlir::Type getVTableComponentType();
577580
CIRGenVTables &getVTables() { return VTables; }
578581

@@ -783,6 +786,12 @@ class CIRGenModule : public CIRGenTypeCache {
783786
/// Emit any needed decls for which code generation was deferred.
784787
void emitDeferred(unsigned recursionLimit);
785788

789+
/// Try to emit external vtables as available_externally if they have emitted
790+
/// all inlined virtual functions. It runs after EmitDeferred() and therefore
791+
/// is not allowed to create new references to things that need to be emitted
792+
/// lazily.
793+
void emitVTablesOpportunistically();
794+
786795
/// Helper for `emitDeferred` to apply actual codegen.
787796
void emitGlobalDecl(clang::GlobalDecl &D);
788797

clang/lib/CIR/CodeGen/CIRGenVTables.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,10 @@ void CIRGenModule::emitDeferredVTables() {
137137
#endif
138138

139139
for (const CXXRecordDecl *RD : DeferredVTables)
140-
if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD)) {
140+
if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
141141
VTables.GenerateClassData(RD);
142-
} else if (shouldOpportunisticallyEmitVTables()) {
143-
llvm_unreachable("NYI");
144-
}
142+
else if (shouldOpportunisticallyEmitVTables())
143+
opportunisticVTables.push_back(RD);
145144

146145
assert(savedSize == DeferredVTables.size() &&
147146
"deferred extra vtables during vtable emission?");

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,6 +2257,7 @@ LogicalResult cir::GlobalOp::verify() {
22572257
case GlobalLinkageKind::CommonLinkage:
22582258
case GlobalLinkageKind::WeakAnyLinkage:
22592259
case GlobalLinkageKind::WeakODRLinkage:
2260+
case GlobalLinkageKind::AvailableExternallyLinkage:
22602261
// FIXME: mlir's concept of visibility gets tricky with LLVM ones,
22612262
// for instance, symbol declarations cannot be "public", so we
22622263
// have to mark them "private" to workaround the symbol verifier.
@@ -2265,9 +2266,6 @@ LogicalResult cir::GlobalOp::verify() {
22652266
<< stringifyGlobalLinkageKind(getLinkage())
22662267
<< "' linkage";
22672268
break;
2268-
default:
2269-
return emitError() << stringifyGlobalLinkageKind(getLinkage())
2270-
<< ": verifier not implemented\n";
22712269
}
22722270

22732271
// TODO: verify visibility for declarations?
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 %s -I%S -triple x86_64-unknown-linux-gnu -std=c++98 -O0 -disable-llvm-passes -emit-cir -o %t
2+
// RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK %s < %t
3+
// RUN: %clang_cc1 %s -I%S -triple x86_64-unknown-linux-gnu -std=c++98 -O2 -disable-llvm-passes -emit-cir -o %t.opt
4+
// RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-FORCE-EMIT %s < %t.opt
5+
6+
// CHECK: cir.global{{.*}} external @_ZTV1A
7+
// CHECK-FORCE-EMIT: cir.global{{.*}} available_externally @_ZTV1A
8+
struct A {
9+
A();
10+
virtual void f();
11+
virtual ~A() { }
12+
};
13+
14+
A::A() { }
15+
16+
void f(A* a) {
17+
a->f();
18+
};
19+
20+
// CHECK-LABEL: cir.func{{.*}} @_Z1gv
21+
// CHECK: cir.call @_Z1fP1A
22+
void g() {
23+
A a;
24+
f(&a);
25+
}

0 commit comments

Comments
 (0)