[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