ormris created this revision.
ormris added reviewers: efriedma, rjmccall, MaskRay, aaron.ballman.
Herald added subscribers: steven_wu, hiraditya.
Herald added a project: All.
ormris requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Clang currently exits with an error message if asked to disassemble a
multi-module bitcode file. This might be confusing to some who are not
familiar with bitcode formats. In addition, multi-module bitcode files
are reasonably common, since they enable desired features. This patch
makes clang's behavior consistent for all common bitcode files.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153906

Files:
  clang/include/clang/CodeGen/CodeGenAction.h
  clang/lib/CodeGen/CodeGenAction.cpp
  clang/test/Frontend/split-lto-ir-support.cpp

Index: clang/test/Frontend/split-lto-ir-support.cpp
===================================================================
--- /dev/null
+++ clang/test/Frontend/split-lto-ir-support.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang -O0 -Xclang -mconstructor-aliases -c -flto=thin -Xclang -fsplit-lto-unit -ffunction-sections %s -o %t0.bc
+// RUN: rm -rf %t1.d && mkdir -p %t1.d
+// RUN: %clang -S -emit-llvm %t0.bc -o %t1.d/split-lto-ir-support.ll
+// RUN: %clang -S %t1.d/split-lto-ir-support.0.ll %t1.d/split-lto-ir-support.1.ll
+// RUN: FileCheck <split-lto-ir-support.0.s --check-prefix M0 %s
+// RUN: FileCheck <split-lto-ir-support.1.s --check-prefix M1 %s
+// M0: _ZN1BC2Ev:
+// M0: _ZN1AC2Ev:
+// M0: _ZN1B1cEi:
+// M1: _ZTV1B:
+// M1: _ZTV1A:
+
+struct A {
+  virtual int c(int i) = 0;
+};
+
+struct B : A {
+  virtual int c(int i) {
+    return i + 3;
+  }
+};
+
+int
+main(void)
+{
+  A *a = new B();
+
+  return a->c(0);
+}
Index: clang/lib/CodeGen/CodeGenAction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenAction.cpp
+++ clang/lib/CodeGen/CodeGenAction.cpp
@@ -1107,26 +1107,59 @@
   return std::move(Result);
 }
 
-std::unique_ptr<llvm::Module>
+std::vector<std::unique_ptr<llvm::Module>>
 CodeGenAction::loadModule(MemoryBufferRef MBRef) {
   CompilerInstance &CI = getCompilerInstance();
   SourceManager &SM = CI.getSourceManager();
 
+  std::vector<std::unique_ptr<llvm::Module>> Result;
+
+  if (!llvm::isBitcode((const unsigned char *)MBRef.getBufferStart(),
+                       (const unsigned char *)MBRef.getBufferEnd())) {
+    llvm::SMDiagnostic Err;
+    std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext);
+    if (!M) {
+      // Translate from the diagnostic info to the SourceManager location if
+      // available.
+      // TODO: Unify this with ConvertBackendLocation()
+      SourceLocation Loc;
+      if (Err.getLineNo() > 0) {
+        assert(Err.getColumnNo() >= 0);
+        Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()),
+                                      Err.getLineNo(), Err.getColumnNo() + 1);
+      }
+
+      // Strip off a leading diagnostic code if there is one.
+      StringRef Msg = Err.getMessage();
+      if (Msg.startswith("error: "))
+        Msg = Msg.substr(7);
+
+      unsigned DiagID =
+          CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+
+      CI.getDiagnostics().Report(Loc, DiagID) << Msg;
+      return {};
+    }
+
+    Result.push_back(std::move(M));
+    return Result;
+  }
+
+  auto DiagErrors = [&](Error E) -> std::vector<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());
@@ -1138,43 +1171,33 @@
     if (!Bm) {
       auto M = std::make_unique<llvm::Module>("empty", *VMContext);
       M->setTargetTriple(CI.getTargetOpts().Triple);
-      return M;
+      Result.push_back(std::move(M));
+      return Result;
     }
     Expected<std::unique_ptr<llvm::Module>> MOrErr =
         Bm->parseModule(*VMContext);
     if (!MOrErr)
       return DiagErrors(MOrErr.takeError());
-    return std::move(*MOrErr);
+    Result.push_back(std::move(MOrErr.get()));
+    return Result;
   }
 
   // Load bitcode modules to link with, if we need to.
   if (loadLinkModules(CI))
-    return nullptr;
-
-  llvm::SMDiagnostic Err;
-  if (std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext))
-    return M;
-
-  // Translate from the diagnostic info to the SourceManager location if
-  // available.
-  // TODO: Unify this with ConvertBackendLocation()
-  SourceLocation Loc;
-  if (Err.getLineNo() > 0) {
-    assert(Err.getColumnNo() >= 0);
-    Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()),
-                                  Err.getLineNo(), Err.getColumnNo() + 1);
-  }
+    return {};
 
-  // Strip off a leading diagnostic code if there is one.
-  StringRef Msg = Err.getMessage();
-  if (Msg.startswith("error: "))
-    Msg = Msg.substr(7);
+  Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
+  if (!BMsOrErr)
+    return DiagErrors(BMsOrErr.takeError());
 
-  unsigned DiagID =
-      CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+  for (auto BM : BMsOrErr.get()) {
+    auto M = BM.parseModule(*VMContext);
+    if (!M)
+      return DiagErrors(M.takeError());
+    Result.push_back(std::move(M.get()));
+  }
 
-  CI.getDiagnostics().Report(Loc, DiagID) << Msg;
-  return {};
+  return Result;
 }
 
 void CodeGenAction::ExecuteAction() {
@@ -1188,10 +1211,7 @@
   CompilerInstance &CI = getCompilerInstance();
   auto &CodeGenOpts = CI.getCodeGenOpts();
   auto &Diagnostics = CI.getDiagnostics();
-  std::unique_ptr<raw_pwrite_stream> OS =
-      GetOutputStream(CI, getCurrentFileOrBufferName(), BA);
-  if (BA != Backend_EmitNothing && !OS)
-    return;
+  const TargetOptions &TargetOpts = CI.getTargetOpts();
 
   SourceManager &SM = CI.getSourceManager();
   FileID FID = SM.getMainFileID();
@@ -1199,67 +1219,87 @@
   if (!MainFile)
     return;
 
-  TheModule = loadModule(*MainFile);
-  if (!TheModule)
-    return;
+  std::vector<std::unique_ptr<llvm::Module>> Modules = loadModule(*MainFile);
+
+  for (size_t I = 0; I < Modules.size(); ++I) {
+    llvm::Module *TheModule = Modules[I].get();
+    llvm::StringRef OutputPath = getCurrentFileOrBufferName();
+    std::unique_ptr<raw_pwrite_stream> OS = nullptr;
+    if (Modules.size() > 1) {
+      std::string FrontendPath = CI.getFrontendOpts().OutputFile;
+      if (!FrontendPath.empty())
+        OutputPath = FrontendPath;
+      llvm::SmallString<16> Ext = llvm::sys::path::extension(OutputPath);
+      llvm::SmallString<128> TmpName = OutputPath.drop_back(Ext.size());
+      TmpName += ".";
+      TmpName += std::to_string(I);
+      TmpName += ".ll";
+      OS = CI.createOutputFile(TmpName, false, false,
+                               CI.getFrontendOpts().UseTemporary);
+    } else {
+      OS = GetOutputStream(CI, OutputPath, BA);
+    }
 
-  const TargetOptions &TargetOpts = CI.getTargetOpts();
-  if (TheModule->getTargetTriple() != TargetOpts.Triple) {
-    Diagnostics.Report(SourceLocation(), diag::warn_fe_override_module)
-        << TargetOpts.Triple;
-    TheModule->setTargetTriple(TargetOpts.Triple);
-  }
+    if (BA == Backend_EmitNothing || !OS)
+      return;
 
-  EmbedObject(TheModule.get(), CodeGenOpts, Diagnostics);
-  EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile);
-
-  LLVMContext &Ctx = TheModule->getContext();
-
-  // Restore any diagnostic handler previously set before returning from this
-  // function.
-  struct RAII {
-    LLVMContext &Ctx;
-    std::unique_ptr<DiagnosticHandler> PrevHandler = Ctx.getDiagnosticHandler();
-    ~RAII() { Ctx.setDiagnosticHandler(std::move(PrevHandler)); }
-  } _{Ctx};
-
-  // Set clang diagnostic handler. To do this we need to create a fake
-  // BackendConsumer.
-  BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
-                         CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
-                         CI.getCodeGenOpts(), CI.getTargetOpts(),
-                         CI.getLangOpts(), TheModule.get(),
-                         std::move(LinkModules), *VMContext, nullptr);
-
-  // Link in each pending link module.
-  if (Result.LinkInModules(&*TheModule))
-    return;
+    if (TheModule->getTargetTriple() != TargetOpts.Triple) {
+        Diagnostics.Report(SourceLocation(), diag::warn_fe_override_module)
+                << TargetOpts.Triple;
+        TheModule->setTargetTriple(TargetOpts.Triple);
+    }
 
-  // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
-  // true here because the valued names are needed for reading textual IR.
-  Ctx.setDiscardValueNames(false);
-  Ctx.setDiagnosticHandler(
-      std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &Result));
+    EmbedObject(TheModule, CodeGenOpts, Diagnostics);
+    EmbedBitcode(TheModule, CodeGenOpts, *MainFile);
 
-  Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
-      setupLLVMOptimizationRemarks(
-          Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
-          CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
-          CodeGenOpts.DiagnosticsHotnessThreshold);
+    LLVMContext &Ctx = TheModule->getContext();
 
-  if (Error E = OptRecordFileOrErr.takeError()) {
-    reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts);
-    return;
+    // Restore any diagnostic handler previously set before returning from this
+    // function.
+    struct RAII {
+      LLVMContext &Ctx;
+      std::unique_ptr<DiagnosticHandler> PrevHandler =
+          Ctx.getDiagnosticHandler();
+      ~RAII() { Ctx.setDiagnosticHandler(std::move(PrevHandler)); }
+    } _{Ctx};
+
+    // Set clang diagnostic handler. To do this we need to create a fake
+    // BackendConsumer.
+    BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
+                           CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
+                           CI.getCodeGenOpts(), TargetOpts,
+                           CI.getLangOpts(), TheModule, std::move(LinkModules),
+                           *VMContext, nullptr);
+    // Link in each pending link module.
+    if (Result.LinkInModules(&*TheModule))
+      return;
+
+    // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
+    // true here because the valued names are needed for reading textual IR.
+    Ctx.setDiscardValueNames(false);
+    Ctx.setDiagnosticHandler(
+        std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &Result));
+
+    Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
+        setupLLVMOptimizationRemarks(
+            Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
+            CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
+            CodeGenOpts.DiagnosticsHotnessThreshold);
+
+    if (Error E = OptRecordFileOrErr.takeError()) {
+      reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts);
+      return;
+    }
+    std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
+        std::move(*OptRecordFileOrErr);
+
+    EmitBackendOutput(
+        Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, TargetOpts,
+        CI.getLangOpts(), CI.getTarget().getDataLayoutString(), TheModule, BA,
+        CI.getFileManager().getVirtualFileSystemPtr(), std::move(OS));
+    if (OptRecordFile)
+      OptRecordFile->keep();
   }
-  std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
-      std::move(*OptRecordFileOrErr);
-
-  EmitBackendOutput(
-      Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, TargetOpts,
-      CI.getLangOpts(), CI.getTarget().getDataLayoutString(), TheModule.get(),
-      BA, CI.getFileManager().getVirtualFileSystemPtr(), std::move(OS));
-  if (OptRecordFile)
-    OptRecordFile->keep();
 }
 
 //
Index: clang/include/clang/CodeGen/CodeGenAction.h
===================================================================
--- clang/include/clang/CodeGen/CodeGenAction.h
+++ clang/include/clang/CodeGen/CodeGenAction.h
@@ -51,7 +51,8 @@
   llvm::LLVMContext *VMContext;
   bool OwnsVMContext;
 
-  std::unique_ptr<llvm::Module> loadModule(llvm::MemoryBufferRef MBRef);
+  std::vector<std::unique_ptr<llvm::Module>>
+  loadModule(llvm::MemoryBufferRef MBRef);
 
   /// Load bitcode modules to link into our module from the options.
   bool loadLinkModules(CompilerInstance &CI);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to