diff options
author | Fangrui Song <i@maskray.me> | 2023-07-21 20:05:35 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2023-07-21 20:05:35 -0700 |
commit | b2f7b5dbaefe4f2e3f8f279735ea3509a796693f (patch) | |
tree | 67a6872e672b76631bcec11d084e446959c4aa68 /clang/lib/CodeGen/CodeGenAction.cpp | |
parent | 9d525bf94b255df89587db955b5fa2d3c03c2c3e (diff) | |
download | llvm-b2f7b5dbaefe4f2e3f8f279735ea3509a796693f.zip llvm-b2f7b5dbaefe4f2e3f8f279735ea3509a796693f.tar.gz llvm-b2f7b5dbaefe4f2e3f8f279735ea3509a796693f.tar.bz2 |
[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
Diffstat (limited to 'clang/lib/CodeGen/CodeGenAction.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 43 |
1 files changed, 34 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 4879bcd..a3b7238 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -1112,21 +1112,21 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) { CompilerInstance &CI = getCompilerInstance(); SourceManager &SM = CI.getSourceManager(); + auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> { + unsigned DiagID = + CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); + handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { + CI.getDiagnostics().Report(DiagID) << EIB.message(); + }); + return {}; + }; + // For ThinLTO backend invocations, ensure that the context // merges types based on ODR identifiers. We also need to read // the correct module out of a multi-module bitcode file. if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) { VMContext->enableDebugTypeODRUniquing(); - auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> { - unsigned DiagID = - CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); - handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { - CI.getDiagnostics().Report(DiagID) << EIB.message(); - }); - return {}; - }; - Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef); if (!BMsOrErr) return DiagErrors(BMsOrErr.takeError()); @@ -1151,10 +1151,35 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) { if (loadLinkModules(CI)) return nullptr; + // Handle textual IR and bitcode file with one single module. llvm::SMDiagnostic Err; if (std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext)) return M; + // If MBRef is a bitcode with multiple modules (e.g., -fsplit-lto-unit + // output), place the extra modules (actually only one, a regular LTO module) + // into LinkModules as if we are using -mlink-bitcode-file. + Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef); + if (BMsOrErr && BMsOrErr->size()) { + std::unique_ptr<llvm::Module> FirstM; + for (auto &BM : *BMsOrErr) { + Expected<std::unique_ptr<llvm::Module>> MOrErr = + BM.parseModule(*VMContext); + if (!MOrErr) + return DiagErrors(MOrErr.takeError()); + if (FirstM) + LinkModules.push_back({std::move(*MOrErr), /*PropagateAttrs=*/false, + /*Internalize=*/false, /*LinkFlags=*/{}}); + else + FirstM = std::move(*MOrErr); + } + if (FirstM) + return FirstM; + } + // If BMsOrErr fails, consume the error and use the error message from + // parseIR. + consumeError(BMsOrErr.takeError()); + // Translate from the diagnostic info to the SourceManager location if // available. // TODO: Unify this with ConvertBackendLocation() |