Skip to content

Commit b2f7b5d

Browse files
committed
[CodeGen] Support bitcode input containing multiple modules
When using -fsplit-lto-unit (explicitly specified or due to using -fsanitize=cfi/-fwhole-program-vtables), the emitted LLVM IR contains a module flag metadata `"EnableSplitLTOUnit"`. If a module contains both type metadata and `"EnableSplitLTOUnit"`, `ThinLTOBitcodeWriter.cpp` will write two modules into the bitcode file. Compiling the bitcode (not ThinLTO backend compilation) will lead to an error due to `parseIR` requiring a single module. ``` % clang -flto=thin a.cc -c -o a.bc % clang -c a.bc % clang -fsplit-lto-unit -flto=thin a.cc -c -o a.bc % clang -c a.bc error: Expected a single module 1 error generated. ``` There are multiple ways to have just one module in a bitcode file output: `-Xclang -fno-lto-unit`, not using features like `-fsanitize=cfi`, using `-fsanitize=cfi` with `-fno-split-lto-unit`. I think whether a bitcode input file contains 2 modules (internal implementation strategy) should not be a criterion to require an additional driver option when the user seek for a non-LTO compile action. Let's place the extra module (if present) into CodeGenOptions::LinkBitcodeFiles (originally for -cc1 -mlink-bitcode-file). Linker::linkModules will link the two modules together. This patch makes the following commands work: ``` clang -S -emit-llvm a.bc clang -S a.bc clang -c a.bc ``` Reviewed By: ormris Differential Revision: https://reviews.llvm.org/D154923
1 parent 9d525bf commit b2f7b5d

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,21 +1112,21 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
11121112
CompilerInstance &CI = getCompilerInstance();
11131113
SourceManager &SM = CI.getSourceManager();
11141114

1115+
auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> {
1116+
unsigned DiagID =
1117+
CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
1118+
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
1119+
CI.getDiagnostics().Report(DiagID) << EIB.message();
1120+
});
1121+
return {};
1122+
};
1123+
11151124
// For ThinLTO backend invocations, ensure that the context
11161125
// merges types based on ODR identifiers. We also need to read
11171126
// the correct module out of a multi-module bitcode file.
11181127
if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) {
11191128
VMContext->enableDebugTypeODRUniquing();
11201129

1121-
auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> {
1122-
unsigned DiagID =
1123-
CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
1124-
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
1125-
CI.getDiagnostics().Report(DiagID) << EIB.message();
1126-
});
1127-
return {};
1128-
};
1129-
11301130
Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
11311131
if (!BMsOrErr)
11321132
return DiagErrors(BMsOrErr.takeError());
@@ -1151,10 +1151,35 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
11511151
if (loadLinkModules(CI))
11521152
return nullptr;
11531153

1154+
// Handle textual IR and bitcode file with one single module.
11541155
llvm::SMDiagnostic Err;
11551156
if (std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext))
11561157
return M;
11571158

1159+
// If MBRef is a bitcode with multiple modules (e.g., -fsplit-lto-unit
1160+
// output), place the extra modules (actually only one, a regular LTO module)
1161+
// into LinkModules as if we are using -mlink-bitcode-file.
1162+
Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
1163+
if (BMsOrErr && BMsOrErr->size()) {
1164+
std::unique_ptr<llvm::Module> FirstM;
1165+
for (auto &BM : *BMsOrErr) {
1166+
Expected<std::unique_ptr<llvm::Module>> MOrErr =
1167+
BM.parseModule(*VMContext);
1168+
if (!MOrErr)
1169+
return DiagErrors(MOrErr.takeError());
1170+
if (FirstM)
1171+
LinkModules.push_back({std::move(*MOrErr), /*PropagateAttrs=*/false,
1172+
/*Internalize=*/false, /*LinkFlags=*/{}});
1173+
else
1174+
FirstM = std::move(*MOrErr);
1175+
}
1176+
if (FirstM)
1177+
return FirstM;
1178+
}
1179+
// If BMsOrErr fails, consume the error and use the error message from
1180+
// parseIR.
1181+
consumeError(BMsOrErr.takeError());
1182+
11581183
// Translate from the diagnostic info to the SourceManager location if
11591184
// available.
11601185
// TODO: Unify this with ConvertBackendLocation()
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// REQUIRES: x86-registered-target
2+
/// When the input is a -fsplit-lto-unit bitcode file, link the regular LTO file like -mlink-bitcode-file.
3+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm-bc -flto=thin -flto-unit -fsplit-lto-unit %s -o %t.bc
4+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-obj %t.bc -o %t.o
5+
// RUN: llvm-nm %t.o | FileCheck %s
6+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %t.bc -o - | FileCheck %s --check-prefix=CHECK-IR
7+
8+
// CHECK: V _ZTI1A
9+
// CHECK-NEXT: V _ZTI1B
10+
// CHECK-NEXT: V _ZTS1A
11+
// CHECK-NEXT: V _ZTS1B
12+
// CHECK-NEXT: V _ZTV1A
13+
// CHECK-NEXT: V _ZTV1B
14+
15+
// CHECK-IR-DAG: _ZTS1B = linkonce_odr constant
16+
// CHECK-IR-DAG: _ZTS1A = linkonce_odr constant
17+
// CHECK-IR-DAG: _ZTV1B = linkonce_odr unnamed_addr constant
18+
// CHECK-IR-DAG: _ZTI1A = linkonce_odr constant
19+
// CHECK-IR-DAG: _ZTI1B = linkonce_odr constant
20+
// CHECK-IR-DAG: _ZTV1A = linkonce_odr unnamed_addr constant
21+
22+
struct A {
23+
virtual int c(int i) = 0;
24+
};
25+
26+
struct B : A {
27+
virtual int c(int i) { return i; }
28+
};
29+
30+
int use() {
31+
return (new B)->c(0);
32+
}

0 commit comments

Comments
 (0)