[llvm] r289899 - IPO: Introduce ThinLTOBitcodeWriter pass.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 15 16:26:30 PST 2016


Author: pcc
Date: Thu Dec 15 18:26:30 2016
New Revision: 289899

URL: http://llvm.org/viewvc/llvm-project?rev=289899&view=rev
Log:
IPO: Introduce ThinLTOBitcodeWriter pass.

This pass prepares a module containing type metadata for ThinLTO by splitting
it into regular and thin LTO parts if possible, and writing both parts to
a multi-module bitcode file. Modules that do not contain type metadata are
written unmodified as a single module.

All globals with type metadata are added to the regular LTO module, and
the rest are added to the thin LTO module.

Differential Revision: https://reviews.llvm.org/D27324

Added:
    llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/no-type-md.ll
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll
    llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll
Modified:
    llvm/trunk/include/llvm/InitializePasses.h
    llvm/trunk/include/llvm/Transforms/IPO.h
    llvm/trunk/lib/Transforms/IPO/CMakeLists.txt
    llvm/trunk/tools/opt/opt.cpp

Modified: llvm/trunk/include/llvm/InitializePasses.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=289899&r1=289898&r2=289899&view=diff
==============================================================================
--- llvm/trunk/include/llvm/InitializePasses.h (original)
+++ llvm/trunk/include/llvm/InitializePasses.h Thu Dec 15 18:26:30 2016
@@ -354,6 +354,7 @@ void initializeVirtRegRewriterPass(PassR
 void initializeWholeProgramDevirtPass(PassRegistry &);
 void initializeWinEHPreparePass(PassRegistry&);
 void initializeWriteBitcodePassPass(PassRegistry &);
+void initializeWriteThinLTOBitcodePass(PassRegistry &);
 void initializeXRayInstrumentationPass(PassRegistry &);
 }
 

Modified: llvm/trunk/include/llvm/Transforms/IPO.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO.h?rev=289899&r1=289898&r2=289899&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO.h Thu Dec 15 18:26:30 2016
@@ -28,6 +28,7 @@ class Pass;
 class Function;
 class BasicBlock;
 class GlobalValue;
+class raw_ostream;
 
 //===----------------------------------------------------------------------===//
 //
@@ -235,6 +236,9 @@ ModulePass *createGlobalSplitPass();
 ModulePass *createSampleProfileLoaderPass();
 ModulePass *createSampleProfileLoaderPass(StringRef Name);
 
+/// Write ThinLTO-ready bitcode to Str.
+ModulePass *createWriteThinLTOBitcodePass(raw_ostream &Str);
+
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/lib/Transforms/IPO/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/CMakeLists.txt?rev=289899&r1=289898&r2=289899&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/CMakeLists.txt (original)
+++ llvm/trunk/lib/Transforms/IPO/CMakeLists.txt Thu Dec 15 18:26:30 2016
@@ -28,6 +28,7 @@ add_llvm_library(LLVMipo
   SampleProfile.cpp
   StripDeadPrototypes.cpp
   StripSymbols.cpp
+  ThinLTOBitcodeWriter.cpp
   WholeProgramDevirt.cpp
 
   ADDITIONAL_HEADER_DIRS

Added: llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp?rev=289899&view=auto
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp (added)
+++ llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp Thu Dec 15 18:26:30 2016
@@ -0,0 +1,344 @@
+//===- ThinLTOBitcodeWriter.cpp - Bitcode writing pass for ThinLTO --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass prepares a module containing type metadata for ThinLTO by splitting
+// it into regular and thin LTO parts if possible, and writing both parts to
+// a multi-module bitcode file. Modules that do not contain type metadata are
+// written unmodified as a single module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Analysis/ModuleSummaryAnalysis.h"
+#include "llvm/Analysis/TypeMetadataUtils.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+using namespace llvm;
+
+namespace {
+
+// Produce a unique identifier for this module by taking the MD5 sum of the
+// names of the module's strong external symbols. This identifier is
+// normally guaranteed to be unique, or the program would fail to link due to
+// multiply defined symbols.
+//
+// If the module has no strong external symbols (such a module may still have a
+// semantic effect if it performs global initialization), we cannot produce a
+// unique identifier for this module, so we return the empty string, which
+// causes the entire module to be written as a regular LTO module.
+std::string getModuleId(Module *M) {
+  MD5 Md5;
+  bool ExportsSymbols = false;
+  auto AddGlobal = [&](GlobalValue &GV) {
+    if (GV.isDeclaration() || GV.getName().startswith("llvm.") ||
+        !GV.hasExternalLinkage())
+      return;
+    ExportsSymbols = true;
+    Md5.update(GV.getName());
+    Md5.update(ArrayRef<uint8_t>{0});
+  };
+
+  for (auto &F : *M)
+    AddGlobal(F);
+  for (auto &GV : M->globals())
+    AddGlobal(GV);
+  for (auto &GA : M->aliases())
+    AddGlobal(GA);
+  for (auto &IF : M->ifuncs())
+    AddGlobal(IF);
+
+  if (!ExportsSymbols)
+    return "";
+
+  MD5::MD5Result R;
+  Md5.final(R);
+
+  SmallString<32> Str;
+  MD5::stringifyResult(R, Str);
+  return ("$" + Str).str();
+}
+
+// Promote each local-linkage entity defined by ExportM and used by ImportM by
+// changing visibility and appending the given ModuleId.
+void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) {
+  auto PromoteInternal = [&](GlobalValue &ExportGV) {
+    if (!ExportGV.hasLocalLinkage())
+      return;
+
+    GlobalValue *ImportGV = ImportM.getNamedValue(ExportGV.getName());
+    if (!ImportGV || ImportGV->use_empty())
+      return;
+
+    std::string NewName = (ExportGV.getName() + ModuleId).str();
+
+    ExportGV.setName(NewName);
+    ExportGV.setLinkage(GlobalValue::ExternalLinkage);
+    ExportGV.setVisibility(GlobalValue::HiddenVisibility);
+
+    ImportGV->setName(NewName);
+    ImportGV->setVisibility(GlobalValue::HiddenVisibility);
+  };
+
+  for (auto &F : ExportM)
+    PromoteInternal(F);
+  for (auto &GV : ExportM.globals())
+    PromoteInternal(GV);
+  for (auto &GA : ExportM.aliases())
+    PromoteInternal(GA);
+  for (auto &IF : ExportM.ifuncs())
+    PromoteInternal(IF);
+}
+
+// Promote all internal (i.e. distinct) type ids used by the module by replacing
+// them with external type ids formed using the module id.
+//
+// Note that this needs to be done before we clone the module because each clone
+// will receive its own set of distinct metadata nodes.
+void promoteTypeIds(Module &M, StringRef ModuleId) {
+  DenseMap<Metadata *, Metadata *> LocalToGlobal;
+  auto ExternalizeTypeId = [&](CallInst *CI, unsigned ArgNo) {
+    Metadata *MD =
+        cast<MetadataAsValue>(CI->getArgOperand(ArgNo))->getMetadata();
+
+    if (isa<MDNode>(MD) && cast<MDNode>(MD)->isDistinct()) {
+      Metadata *&GlobalMD = LocalToGlobal[MD];
+      if (!GlobalMD) {
+        std::string NewName =
+            (to_string(LocalToGlobal.size()) + ModuleId).str();
+        GlobalMD = MDString::get(M.getContext(), NewName);
+      }
+
+      CI->setArgOperand(ArgNo,
+                        MetadataAsValue::get(M.getContext(), GlobalMD));
+    }
+  };
+
+  if (Function *TypeTestFunc =
+          M.getFunction(Intrinsic::getName(Intrinsic::type_test))) {
+    for (const Use &U : TypeTestFunc->uses()) {
+      auto CI = cast<CallInst>(U.getUser());
+      ExternalizeTypeId(CI, 1);
+    }
+  }
+
+  if (Function *TypeCheckedLoadFunc =
+          M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load))) {
+    for (const Use &U : TypeCheckedLoadFunc->uses()) {
+      auto CI = cast<CallInst>(U.getUser());
+      ExternalizeTypeId(CI, 2);
+    }
+  }
+
+  for (GlobalObject &GO : M.global_objects()) {
+    SmallVector<MDNode *, 1> MDs;
+    GO.getMetadata(LLVMContext::MD_type, MDs);
+
+    GO.eraseMetadata(LLVMContext::MD_type);
+    for (auto MD : MDs) {
+      auto I = LocalToGlobal.find(MD->getOperand(1));
+      if (I == LocalToGlobal.end()) {
+        GO.addMetadata(LLVMContext::MD_type, *MD);
+        continue;
+      }
+      GO.addMetadata(
+          LLVMContext::MD_type,
+          *MDNode::get(M.getContext(),
+                       ArrayRef<Metadata *>{MD->getOperand(0), I->second}));
+    }
+  }
+}
+
+// Drop unused globals, and drop type information from function declarations.
+// FIXME: If we made functions typeless then there would be no need to do this.
+void simplifyExternals(Module &M) {
+  FunctionType *EmptyFT =
+      FunctionType::get(Type::getVoidTy(M.getContext()), false);
+
+  for (auto I = M.begin(), E = M.end(); I != E;) {
+    Function &F = *I++;
+    if (F.isDeclaration() && F.use_empty()) {
+      F.eraseFromParent();
+      continue;
+    }
+
+    if (!F.isDeclaration() || F.getFunctionType() == EmptyFT)
+      continue;
+
+    Function *NewF =
+        Function::Create(EmptyFT, GlobalValue::ExternalLinkage, "", &M);
+    NewF->setVisibility(F.getVisibility());
+    NewF->takeName(&F);
+    F.replaceAllUsesWith(ConstantExpr::getBitCast(NewF, F.getType()));
+    F.eraseFromParent();
+  }
+
+  for (auto I = M.global_begin(), E = M.global_end(); I != E;) {
+    GlobalVariable &GV = *I++;
+    if (GV.isDeclaration() && GV.use_empty()) {
+      GV.eraseFromParent();
+      continue;
+    }
+  }
+}
+
+void filterModule(
+    Module *M, std::function<bool(const GlobalValue *)> ShouldKeepDefinition) {
+  for (Function &F : *M) {
+    if (ShouldKeepDefinition(&F))
+      continue;
+
+    F.deleteBody();
+    F.clearMetadata();
+  }
+
+  for (GlobalVariable &GV : M->globals()) {
+    if (ShouldKeepDefinition(&GV))
+      continue;
+
+    GV.setInitializer(nullptr);
+    GV.setLinkage(GlobalValue::ExternalLinkage);
+    GV.clearMetadata();
+  }
+
+  for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end();
+       I != E;) {
+    GlobalAlias *GA = &*I++;
+    if (ShouldKeepDefinition(GA))
+      continue;
+
+    GlobalObject *GO;
+    if (I->getValueType()->isFunctionTy())
+      GO = Function::Create(cast<FunctionType>(GA->getValueType()),
+                            GlobalValue::ExternalLinkage, "", M);
+    else
+      GO = new GlobalVariable(
+          *M, GA->getValueType(), false, GlobalValue::ExternalLinkage,
+          (Constant *)nullptr, "", (GlobalVariable *)nullptr,
+          GA->getThreadLocalMode(), GA->getType()->getAddressSpace());
+    GO->takeName(GA);
+    GA->replaceAllUsesWith(GO);
+    GA->eraseFromParent();
+  }
+}
+
+// If it's possible to split M into regular and thin LTO parts, do so and write
+// a multi-module bitcode file with the two parts to OS. Otherwise, write only a
+// regular LTO bitcode file to OS.
+void splitAndWriteThinLTOBitcode(raw_ostream &OS, Module &M) {
+  std::string ModuleId = getModuleId(&M);
+  if (ModuleId.empty()) {
+    // We couldn't generate a module ID for this module, just write it out as a
+    // regular LTO module.
+    WriteBitcodeToFile(&M, OS);
+    return;
+  }
+
+  promoteTypeIds(M, ModuleId);
+
+  auto IsInMergedM = [&](const GlobalValue *GV) {
+    auto *GVar = dyn_cast<GlobalVariable>(GV->getBaseObject());
+    if (!GVar)
+      return false;
+
+    SmallVector<MDNode *, 1> MDs;
+    GVar->getMetadata(LLVMContext::MD_type, MDs);
+    return !MDs.empty();
+  };
+
+  ValueToValueMapTy VMap;
+  std::unique_ptr<Module> MergedM(CloneModule(&M, VMap, IsInMergedM));
+
+  filterModule(&M, [&](const GlobalValue *GV) { return !IsInMergedM(GV); });
+
+  promoteInternals(*MergedM, M, ModuleId);
+  promoteInternals(M, *MergedM, ModuleId);
+
+  simplifyExternals(*MergedM);
+
+  SmallVector<char, 0> Buffer;
+  BitcodeWriter W(Buffer);
+
+  // FIXME: Try to re-use BSI and PFI from the original module here.
+  ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, nullptr);
+  W.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index,
+                /*GenerateHash=*/true);
+
+  W.writeModule(MergedM.get());
+
+  OS << Buffer;
+}
+
+// Returns whether this module needs to be split because it uses type metadata.
+bool requiresSplit(Module &M) {
+  SmallVector<MDNode *, 1> MDs;
+  for (auto &GO : M.global_objects()) {
+    GO.getMetadata(LLVMContext::MD_type, MDs);
+    if (!MDs.empty())
+      return true;
+  }
+
+  return false;
+}
+
+void writeThinLTOBitcode(raw_ostream &OS, Module &M,
+                         const ModuleSummaryIndex *Index) {
+  // See if this module has any type metadata. If so, we need to split it.
+  if (requiresSplit(M))
+    return splitAndWriteThinLTOBitcode(OS, M);
+
+  // Otherwise we can just write it out as a regular module.
+  WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false, Index,
+                     /*GenerateHash=*/true);
+}
+
+class WriteThinLTOBitcode : public ModulePass {
+  raw_ostream &OS; // raw_ostream to print on
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+  WriteThinLTOBitcode() : ModulePass(ID), OS(dbgs()) {
+    initializeWriteThinLTOBitcodePass(*PassRegistry::getPassRegistry());
+  }
+
+  explicit WriteThinLTOBitcode(raw_ostream &o)
+      : ModulePass(ID), OS(o) {
+    initializeWriteThinLTOBitcodePass(*PassRegistry::getPassRegistry());
+  }
+
+  StringRef getPassName() const override { return "ThinLTO Bitcode Writer"; }
+
+  bool runOnModule(Module &M) override {
+    const ModuleSummaryIndex *Index =
+        &(getAnalysis<ModuleSummaryIndexWrapperPass>().getIndex());
+    writeThinLTOBitcode(OS, M, Index);
+    return true;
+  }
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+    AU.addRequired<ModuleSummaryIndexWrapperPass>();
+  }
+};
+} // anonymous namespace
+
+char WriteThinLTOBitcode::ID = 0;
+INITIALIZE_PASS_BEGIN(WriteThinLTOBitcode, "write-thinlto-bitcode",
+                      "Write ThinLTO Bitcode", false, true)
+INITIALIZE_PASS_DEPENDENCY(ModuleSummaryIndexWrapperPass)
+INITIALIZE_PASS_END(WriteThinLTOBitcode, "write-thinlto-bitcode",
+                    "Write ThinLTO Bitcode", false, true)
+
+ModulePass *llvm::createWriteThinLTOBitcodePass(raw_ostream &Str) {
+  return new WriteThinLTOBitcode(Str);
+}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/no-type-md.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/no-type-md.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/no-type-md.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/no-type-md.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,13 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-dis -o - %t | FileCheck %s
+; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s
+
+; BCA: <GLOBALVAL_SUMMARY_BLOCK
+
+; CHECK: @g = global i8 42
+ at g = global i8 42
+
+; CHECK: define void @f()
+define void @f() {
+  ret void
+}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,40 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-modextract -b -n 0 -o %t0 %t
+; RUN: llvm-modextract -b -n 1 -o %t1 %t
+; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=M0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=M1 %s
+; RUN: llvm-bcanalyzer -dump %t0 | FileCheck --check-prefix=BCA0 %s
+; RUN: llvm-bcanalyzer -dump %t1 | FileCheck --check-prefix=BCA1 %s
+
+; ERROR: llvm-modextract: error: module index out of range; bitcode file contains 2 module(s)
+
+; BCA0: <GLOBALVAL_SUMMARY_BLOCK
+; BCA1-NOT: <GLOBALVAL_SUMMARY_BLOCK
+
+; M0: @g = external global i8{{$}}
+; M1: @g = global i8 42, !type !0, !type !1, !type !2
+ at g = global i8 42, !type !1, !type !2, !type !4
+
+; M0: define void @f()
+; M1-NOT: @f()
+define void @f() {
+  ; M0: llvm.type.test{{.*}}metadata !"1$f50b51a12bb012bebbeff978335e34cf"
+  %p = call i1 @llvm.type.test(i8* null, metadata !0)
+  ; M0: llvm.type.checked.load{{.*}}metadata !"2$f50b51a12bb012bebbeff978335e34cf"
+  %q = call {i8*, i1} @llvm.type.checked.load(i8* null, i32 0, metadata !3)
+  ret void
+}
+
+declare i1 @llvm.type.test(i8*, metadata)
+declare {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata)
+
+!0 = distinct !{}
+; M1: !0 = !{i32 0, !"1$f50b51a12bb012bebbeff978335e34cf"}
+!1 = !{i32 0, !0}
+; M1: !1 = !{i32 1, !"1$f50b51a12bb012bebbeff978335e34cf"}
+!2 = !{i32 1, !0}
+
+!3 = distinct !{}
+; M1: !2 = !{i32 0, !"2$f50b51a12bb012bebbeff978335e34cf"}
+!4 = !{i32 0, !3}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,27 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-modextract -b -n 0 -o %t0 %t
+; RUN: llvm-modextract -b -n 1 -o %t1 %t
+; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=M0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=M1 %s
+; RUN: llvm-bcanalyzer -dump %t0 | FileCheck --check-prefix=BCA0 %s
+; RUN: llvm-bcanalyzer -dump %t1 | FileCheck --check-prefix=BCA1 %s
+
+; ERROR: llvm-modextract: error: module index out of range; bitcode file contains 2 module(s)
+
+; BCA0: <GLOBALVAL_SUMMARY_BLOCK
+; BCA1-NOT: <GLOBALVAL_SUMMARY_BLOCK
+
+; M0: @"g$581d7631532fa146ba4061179da39272" = external hidden global i8{{$}}
+; M1: @"g$581d7631532fa146ba4061179da39272" = hidden global i8 42, !type !0
+ at g = internal global i8 42, !type !0
+
+; M0: define i8* @f()
+; M1-NOT: @f()
+define i8* @f() {
+  ; M0: ret i8* @"g$581d7631532fa146ba4061179da39272"
+  ret i8* @g
+}
+
+; M1: !0 = !{i32 0, !"typeid"}
+!0 = !{i32 0, !"typeid"}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,32 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-modextract -b -n 0 -o %t0 %t
+; RUN: llvm-modextract -b -n 1 -o %t1 %t
+; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=M0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=M1 %s
+; RUN: llvm-bcanalyzer -dump %t0 | FileCheck --check-prefix=BCA0 %s
+; RUN: llvm-bcanalyzer -dump %t1 | FileCheck --check-prefix=BCA1 %s
+
+; ERROR: llvm-modextract: error: module index out of range; bitcode file contains 2 module(s)
+
+; BCA0: <GLOBALVAL_SUMMARY_BLOCK
+; BCA1-NOT: <GLOBALVAL_SUMMARY_BLOCK
+
+; M0: @g = external global void ()*{{$}}
+; M1: @g = global void ()* @"f$13757e0fb71915e385efa4dc9d1e08fd", !type !0
+ at g = global void ()* @f, !type !0
+
+; M0: define hidden void @"f$13757e0fb71915e385efa4dc9d1e08fd"()
+; M1: declare hidden void @"f$13757e0fb71915e385efa4dc9d1e08fd"()
+define internal void @f() {
+  call void @f2()
+  ret void
+}
+
+; M0: define internal void @f2()
+define internal void @f2() {
+  ret void
+}
+
+; M1: !0 = !{i32 0, !"typeid"}
+!0 = !{i32 0, !"typeid"}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,26 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-modextract -b -n 0 -o %t0 %t
+; RUN: llvm-modextract -b -n 1 -o %t1 %t
+; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=M0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=M1 %s
+; RUN: llvm-bcanalyzer -dump %t0 | FileCheck --check-prefix=BCA0 %s
+; RUN: llvm-bcanalyzer -dump %t1 | FileCheck --check-prefix=BCA1 %s
+
+; ERROR: llvm-modextract: error: module index out of range; bitcode file contains 2 module(s)
+
+; BCA0: <GLOBALVAL_SUMMARY_BLOCK
+; BCA1-NOT: <GLOBALVAL_SUMMARY_BLOCK
+
+; M0: @g = external global i8{{$}}
+; M1: @g = global i8 42, !type !0
+ at g = global i8 42, !type !0
+
+; M0: define i8* @f()
+; M1-NOT: @f()
+define i8* @f() {
+  ret i8* @g
+}
+
+; M1: !0 = !{i32 0, !"typeid"}
+!0 = !{i32 0, !"typeid"}

Added: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll?rev=289899&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll (added)
+++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll Thu Dec 15 18:26:30 2016
@@ -0,0 +1,21 @@
+; RUN: opt -thinlto-bc -o %t %s
+; RUN: llvm-dis -o - %t | FileCheck %s
+; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s
+
+; BCA-NOT: <GLOBALVAL_SUMMARY_BLOCK
+
+; CHECK: @llvm.global_ctors = appending global
+ at llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @f }]
+
+; CHECK: @g = internal global i8 42, !type !0
+ at g = internal global i8 42, !type !0
+
+declare void @sink(i8*)
+
+; CHECK: define internal void @f()
+define internal void @f() {
+  call void @sink(i8* @g)
+  ret void
+}
+
+!0 = !{i32 0, !"typeid"}

Modified: llvm/trunk/tools/opt/opt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/opt.cpp?rev=289899&r1=289898&r2=289899&view=diff
==============================================================================
--- llvm/trunk/tools/opt/opt.cpp (original)
+++ llvm/trunk/tools/opt/opt.cpp Thu Dec 15 18:26:30 2016
@@ -99,6 +99,10 @@ static cl::opt<bool>
 OutputAssembly("S", cl::desc("Write output as LLVM assembly"));
 
 static cl::opt<bool>
+    OutputThinLTOBC("thinlto-bc",
+                    cl::desc("Write output as ThinLTO-ready bitcode"));
+
+static cl::opt<bool>
 NoVerify("disable-verify", cl::desc("Do not run the verifier"), cl::Hidden);
 
 static cl::opt<bool>
@@ -704,7 +708,9 @@ int main(int argc, char **argv) {
       if (EmitModuleHash)
         report_fatal_error("Text output is incompatible with -module-hash");
       Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder));
-    } else
+    } else if (OutputThinLTOBC)
+      Passes.add(createWriteThinLTOBitcodePass(*OS));
+    else
       Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder,
                                          EmitSummaryIndex, EmitModuleHash));
   }




More information about the llvm-commits mailing list