[llvm] r288195 - Bitcode: Introduce BitcodeWriter interface.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 29 12:43:48 PST 2016


Author: pcc
Date: Tue Nov 29 14:43:47 2016
New Revision: 288195

URL: http://llvm.org/viewvc/llvm-project?rev=288195&view=rev
Log:
Bitcode: Introduce BitcodeWriter interface.

This interface allows clients to write multiple modules to a single
bitcode file. Also introduce the llvm-cat utility which can be used
to create a bitcode file containing multiple modules.

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

Added:
    llvm/trunk/test/Bitcode/Inputs/multi-module.ll
    llvm/trunk/test/Bitcode/multi-module.ll
    llvm/trunk/tools/llvm-cat/
    llvm/trunk/tools/llvm-cat/CMakeLists.txt
    llvm/trunk/tools/llvm-cat/LLVMBuild.txt
    llvm/trunk/tools/llvm-cat/llvm-cat.cpp
Modified:
    llvm/trunk/include/llvm/Bitcode/BitcodeReader.h
    llvm/trunk/include/llvm/Bitcode/BitcodeWriter.h
    llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/test/CMakeLists.txt
    llvm/trunk/tools/LLVMBuild.txt

Modified: llvm/trunk/include/llvm/Bitcode/BitcodeReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/BitcodeReader.h?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/BitcodeReader.h (original)
+++ llvm/trunk/include/llvm/Bitcode/BitcodeReader.h Tue Nov 29 14:43:47 2016
@@ -66,6 +66,8 @@ namespace llvm {
                   bool ShouldLazyLoadMetadata);
 
   public:
+    ArrayRef<uint8_t> getBuffer() const { return Buffer; }
+
     /// Read the bitcode module and prepare for lazy deserialization of function
     /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.
     Expected<std::unique_ptr<Module>>

Modified: llvm/trunk/include/llvm/Bitcode/BitcodeWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/BitcodeWriter.h?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/BitcodeWriter.h (original)
+++ llvm/trunk/include/llvm/Bitcode/BitcodeWriter.h Tue Nov 29 14:43:47 2016
@@ -18,9 +18,36 @@
 #include <string>
 
 namespace llvm {
+  class BitstreamWriter;
   class Module;
   class raw_ostream;
 
+  class BitcodeWriter {
+    SmallVectorImpl<char> &Buffer;
+    std::unique_ptr<BitstreamWriter> Stream;
+
+   public:
+    /// Create a BitcodeWriter that writes to Buffer.
+    BitcodeWriter(SmallVectorImpl<char> &Buffer);
+
+    ~BitcodeWriter();
+
+    /// Write the specified module to the buffer specified at construction time.
+    ///
+    /// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a
+    /// Value in \c M.  These will be reconstructed exactly when \a M is
+    /// deserialized.
+    ///
+    /// If \c Index is supplied, the bitcode will contain the summary index
+    /// (currently for use in ThinLTO optimization).
+    ///
+    /// \p GenerateHash enables hashing the Module and including the hash in the
+    /// bitcode (currently for use in ThinLTO incremental build).
+    void writeModule(const Module *M, bool ShouldPreserveUseListOrder = false,
+                     const ModuleSummaryIndex *Index = nullptr,
+                     bool GenerateHash = false);
+  };
+
   /// \brief Write the specified module to the specified raw output stream.
   ///
   /// For streams where it matters, the given stream should be in "binary"

Modified: llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h (original)
+++ llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h Tue Nov 29 14:43:47 2016
@@ -509,6 +509,7 @@ public:
   void EnterBlockInfoBlock() {
     EnterSubblock(bitc::BLOCKINFO_BLOCK_ID, 2);
     BlockInfoCurBID = ~0U;
+    BlockInfoRecords.clear();
   }
 private:
   /// SwitchToBlockID - If we aren't already talking about the specified block

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Nov 29 14:43:47 2016
@@ -65,36 +65,20 @@ enum {
 };
 
 /// Abstract class to manage the bitcode writing, subclassed for each bitcode
-/// file type. Owns the BitstreamWriter, and includes the main entry point for
-/// writing.
-class BitcodeWriter {
+/// file type.
+class BitcodeWriterBase {
 protected:
-  /// Pointer to the buffer allocated by caller for bitcode writing.
-  const SmallVectorImpl<char> &Buffer;
-
-  /// The stream created and owned by the BitodeWriter.
-  BitstreamWriter Stream;
+  /// The stream created and owned by the client.
+  BitstreamWriter &Stream;
 
   /// Saves the offset of the VSTOffset record that must eventually be
   /// backpatched with the offset of the actual VST.
   uint64_t VSTOffsetPlaceholder = 0;
 
 public:
-  /// Constructs a BitcodeWriter object, and initializes a BitstreamRecord,
-  /// writing to the provided \p Buffer.
-  BitcodeWriter(SmallVectorImpl<char> &Buffer)
-      : Buffer(Buffer), Stream(Buffer) {}
-
-  virtual ~BitcodeWriter() = default;
-
-  /// Main entry point to write the bitcode file, which writes the bitcode
-  /// header and will then invoke the virtual writeBlocks() method.
-  void write();
-
-private:
-  /// Derived classes must implement this to write the corresponding blocks for
-  /// that bitcode file type.
-  virtual void writeBlocks() = 0;
+  /// Constructs a BitcodeWriterBase object that writes to the provided
+  /// \p Stream.
+  BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {}
 
 protected:
   bool hasVSTOffsetPlaceholder() { return VSTOffsetPlaceholder != 0; }
@@ -103,7 +87,10 @@ protected:
 };
 
 /// Class to manage the bitcode writing for a module.
-class ModuleBitcodeWriter : public BitcodeWriter {
+class ModuleBitcodeWriter : public BitcodeWriterBase {
+  /// Pointer to the buffer allocated by caller for bitcode writing.
+  const SmallVectorImpl<char> &Buffer;
+
   /// The Module to write to bitcode.
   const Module &M;
 
@@ -116,8 +103,8 @@ class ModuleBitcodeWriter : public Bitco
   /// True if a module hash record should be written.
   bool GenerateHash;
 
-  /// The start bit of the module block, for use in generating a module hash
-  uint64_t BitcodeStartBit = 0;
+  /// The start bit of the identification block.
+  uint64_t BitcodeStartBit;
 
   /// Map that holds the correspondence between GUIDs in the summary index,
   /// that came from indirect call profiles, and a value id generated by this
@@ -131,16 +118,11 @@ public:
   /// Constructs a ModuleBitcodeWriter object for the given Module,
   /// writing to the provided \p Buffer.
   ModuleBitcodeWriter(const Module *M, SmallVectorImpl<char> &Buffer,
-                      bool ShouldPreserveUseListOrder,
+                      BitstreamWriter &Stream, bool ShouldPreserveUseListOrder,
                       const ModuleSummaryIndex *Index, bool GenerateHash)
-      : BitcodeWriter(Buffer), M(*M), VE(*M, ShouldPreserveUseListOrder),
-        Index(Index), GenerateHash(GenerateHash) {
-    // Save the start bit of the actual bitcode, in case there is space
-    // saved at the start for the darwin header above. The reader stream
-    // will start at the bitcode, and we need the offset of the VST
-    // to line up.
-    BitcodeStartBit = Stream.GetCurrentBitNo();
-
+      : BitcodeWriterBase(Stream), Buffer(Buffer), M(*M),
+        VE(*M, ShouldPreserveUseListOrder), Index(Index),
+        GenerateHash(GenerateHash), BitcodeStartBit(Stream.GetCurrentBitNo()) {
     // Assign ValueIds to any callee values in the index that came from
     // indirect call profiles and were recorded as a GUID not a Value*
     // (which would have been assigned an ID by the ValueEnumerator).
@@ -162,21 +144,12 @@ public:
               assignValueId(CallEdge.first.getGUID());
   }
 
-private:
-  /// Main entry point for writing a module to bitcode, invoked by
-  /// BitcodeWriter::write() after it writes the header.
-  void writeBlocks() override;
-
-  /// Create the "IDENTIFICATION_BLOCK_ID" containing a single string with the
-  /// current llvm version, and a record for the epoch number.
-  void writeIdentificationBlock();
-
   /// Emit the current module to the bitstream.
-  void writeModule();
+  void write();
 
+private:
   uint64_t bitcodeStartBit() { return BitcodeStartBit; }
 
-  void writeStringRecord(unsigned Code, StringRef Str, unsigned AbbrevToUse);
   void writeAttributeGroupTable();
   void writeAttributeTable();
   void writeTypeTable();
@@ -310,7 +283,7 @@ private:
 };
 
 /// Class to manage the bitcode writing for a combined index.
-class IndexBitcodeWriter : public BitcodeWriter {
+class IndexBitcodeWriter : public BitcodeWriterBase {
   /// The combined index to write to bitcode.
   const ModuleSummaryIndex &Index;
 
@@ -329,11 +302,10 @@ public:
   /// Constructs a IndexBitcodeWriter object for the given combined index,
   /// writing to the provided \p Buffer. When writing a subset of the index
   /// for a distributed backend, provide a \p ModuleToSummariesForIndex map.
-  IndexBitcodeWriter(SmallVectorImpl<char> &Buffer,
-                     const ModuleSummaryIndex &Index,
+  IndexBitcodeWriter(BitstreamWriter &Stream, const ModuleSummaryIndex &Index,
                      const std::map<std::string, GVSummaryMapTy>
                          *ModuleToSummariesForIndex = nullptr)
-      : BitcodeWriter(Buffer), Index(Index),
+      : BitcodeWriterBase(Stream), Index(Index),
         ModuleToSummariesForIndex(ModuleToSummariesForIndex) {
     // Assign unique value ids to all summaries to be written, for use
     // in writing out the call graph edges. Save the mapping from GUID
@@ -480,11 +452,10 @@ public:
   /// Obtain the end iterator over the summaries to be written.
   iterator end() { return iterator(*this, /*IsAtEnd=*/true); }
 
-private:
-  /// Main entry point for writing a combined index to bitcode, invoked by
-  /// BitcodeWriter::write() after it writes the header.
-  void writeBlocks() override;
+  /// Main entry point for writing a combined index to bitcode.
+  void write();
 
+private:
   void writeIndex();
   void writeModStrings();
   void writeCombinedValueSymbolTable();
@@ -597,8 +568,8 @@ static unsigned getEncodedSynchScope(Syn
   llvm_unreachable("Invalid synch scope");
 }
 
-void ModuleBitcodeWriter::writeStringRecord(unsigned Code, StringRef Str,
-                                            unsigned AbbrevToUse) {
+static void writeStringRecord(BitstreamWriter &Stream, unsigned Code,
+                              StringRef Str, unsigned AbbrevToUse) {
   SmallVector<unsigned, 64> Vals;
 
   // Code: [strchar x N]
@@ -922,7 +893,7 @@ void ModuleBitcodeWriter::writeTypeTable
 
         // Emit the name if it is present.
         if (!ST->getName().empty())
-          writeStringRecord(bitc::TYPE_CODE_STRUCT_NAME, ST->getName(),
+          writeStringRecord(Stream, bitc::TYPE_CODE_STRUCT_NAME, ST->getName(),
                             StructNameAbbrev);
       }
       break;
@@ -1073,7 +1044,7 @@ void ModuleBitcodeWriter::writeComdats()
 /// Write a record that will eventually hold the word offset of the
 /// module-level VST. For now the offset is 0, which will be backpatched
 /// after the real VST is written. Saves the bit offset to backpatch.
-void BitcodeWriter::writeValueSymbolTableForwardDecl() {
+void BitcodeWriterBase::writeValueSymbolTableForwardDecl() {
   // Write a placeholder value in for the offset of the real VST,
   // which is written after the function blocks so that it can include
   // the offset of each function. The placeholder offset will be
@@ -1120,13 +1091,13 @@ static StringEncoding getStringEncoding(
 void ModuleBitcodeWriter::writeModuleInfo() {
   // Emit various pieces of data attached to a module.
   if (!M.getTargetTriple().empty())
-    writeStringRecord(bitc::MODULE_CODE_TRIPLE, M.getTargetTriple(),
+    writeStringRecord(Stream, bitc::MODULE_CODE_TRIPLE, M.getTargetTriple(),
                       0 /*TODO*/);
   const std::string &DL = M.getDataLayoutStr();
   if (!DL.empty())
-    writeStringRecord(bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/);
+    writeStringRecord(Stream, bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/);
   if (!M.getModuleInlineAsm().empty())
-    writeStringRecord(bitc::MODULE_CODE_ASM, M.getModuleInlineAsm(),
+    writeStringRecord(Stream, bitc::MODULE_CODE_ASM, M.getModuleInlineAsm(),
                       0 /*TODO*/);
 
   // Emit information about sections and GC, computing how many there are. Also
@@ -1142,7 +1113,7 @@ void ModuleBitcodeWriter::writeModuleInf
       // Give section names unique ID's.
       unsigned &Entry = SectionMap[GV.getSection()];
       if (!Entry) {
-        writeStringRecord(bitc::MODULE_CODE_SECTIONNAME, GV.getSection(),
+        writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, GV.getSection(),
                           0 /*TODO*/);
         Entry = SectionMap.size();
       }
@@ -1154,7 +1125,7 @@ void ModuleBitcodeWriter::writeModuleInf
       // Give section names unique ID's.
       unsigned &Entry = SectionMap[F.getSection()];
       if (!Entry) {
-        writeStringRecord(bitc::MODULE_CODE_SECTIONNAME, F.getSection(),
+        writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, F.getSection(),
                           0 /*TODO*/);
         Entry = SectionMap.size();
       }
@@ -1163,7 +1134,8 @@ void ModuleBitcodeWriter::writeModuleInf
       // Same for GC names.
       unsigned &Entry = GCMap[F.getGC()];
       if (!Entry) {
-        writeStringRecord(bitc::MODULE_CODE_GCNAME, F.getGC(), 0 /*TODO*/);
+        writeStringRecord(Stream, bitc::MODULE_CODE_GCNAME, F.getGC(),
+                          0 /*TODO*/);
         Entry = GCMap.size();
       }
     }
@@ -2761,11 +2733,13 @@ void ModuleBitcodeWriter::writeValueSymb
     // Get the offset of the VST we are writing, and backpatch it into
     // the VST forward declaration record.
     uint64_t VSTOffset = Stream.GetCurrentBitNo();
-    // The BitcodeStartBit was the stream offset of the actual bitcode
-    // (e.g. excluding any initial darwin header).
+    // The BitcodeStartBit was the stream offset of the identification block.
     VSTOffset -= bitcodeStartBit();
     assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
-    Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32);
+    // Note that we add 1 here because the offset is relative to one word
+    // before the start of the identification block, which was historically
+    // always the start of the regular bitcode header.
+    Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32 + 1);
   }
 
   Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
@@ -2853,7 +2827,10 @@ void ModuleBitcodeWriter::writeValueSymb
       // actual bitcode written to the stream).
       uint64_t BitcodeIndex = (*FunctionToBitcodeIndex)[F] - bitcodeStartBit();
       assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
-      NameVals.push_back(BitcodeIndex / 32);
+      // Note that we add 1 here because the offset is relative to one word
+      // before the start of the identification block, which was historically
+      // always the start of the regular bitcode header.
+      NameVals.push_back(BitcodeIndex / 32 + 1);
 
       Code = bitc::VST_CODE_FNENTRY;
       AbbrevToUse = FnEntry8BitAbbrev;
@@ -3617,7 +3594,9 @@ void IndexBitcodeWriter::writeCombinedGl
   Stream.ExitBlock();
 }
 
-void ModuleBitcodeWriter::writeIdentificationBlock() {
+/// Create the "IDENTIFICATION_BLOCK_ID" containing a single string with the
+/// current llvm version, and a record for the epoch number.
+void writeIdentificationBlock(BitstreamWriter &Stream) {
   Stream.EnterSubblock(bitc::IDENTIFICATION_BLOCK_ID, 5);
 
   // Write the "user readable" string identifying the bitcode producer
@@ -3626,7 +3605,7 @@ void ModuleBitcodeWriter::writeIdentific
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6));
   auto StringAbbrev = Stream.EmitAbbrev(Abbv);
-  writeStringRecord(bitc::IDENTIFICATION_CODE_STRING,
+  writeStringRecord(Stream, bitc::IDENTIFICATION_CODE_STRING,
                     "LLVM" LLVM_VERSION_STRING, StringAbbrev);
 
   // Write the epoch version
@@ -3655,24 +3634,9 @@ void ModuleBitcodeWriter::writeModuleHas
   Stream.EmitRecord(bitc::MODULE_CODE_HASH, Vals);
 }
 
-void BitcodeWriter::write() {
-  // Emit the file header first.
-  writeBitcodeHeader();
+void ModuleBitcodeWriter::write() {
+  writeIdentificationBlock(Stream);
 
-  writeBlocks();
-}
-
-void ModuleBitcodeWriter::writeBlocks() {
-  writeIdentificationBlock();
-  writeModule();
-}
-
-void IndexBitcodeWriter::writeBlocks() {
-  // Index contains only a single outer (module) block.
-  writeIndex();
-}
-
-void ModuleBitcodeWriter::writeModule() {
   Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
   size_t BlockStartPos = Buffer.size();
 
@@ -3801,7 +3765,7 @@ static void emitDarwinBCHeaderAndTrailer
 }
 
 /// Helper to write the header common to all bitcode files.
-void BitcodeWriter::writeBitcodeHeader() {
+static void writeBitcodeHeader(BitstreamWriter &Stream) {
   // Emit the file header.
   Stream.Emit((unsigned)'B', 8);
   Stream.Emit((unsigned)'C', 8);
@@ -3811,6 +3775,22 @@ void BitcodeWriter::writeBitcodeHeader()
   Stream.Emit(0xD, 4);
 }
 
+BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer)
+    : Buffer(Buffer), Stream(new BitstreamWriter(Buffer)) {
+  writeBitcodeHeader(*Stream);
+}
+
+BitcodeWriter::~BitcodeWriter() = default;
+
+void BitcodeWriter::writeModule(const Module *M,
+                                bool ShouldPreserveUseListOrder,
+                                const ModuleSummaryIndex *Index,
+                                bool GenerateHash) {
+  ModuleBitcodeWriter ModuleWriter(
+      M, Buffer, *Stream, ShouldPreserveUseListOrder, Index, GenerateHash);
+  ModuleWriter.write();
+}
+
 /// WriteBitcodeToFile - Write the specified module to the specified output
 /// stream.
 void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
@@ -3826,10 +3806,8 @@ void llvm::WriteBitcodeToFile(const Modu
   if (TT.isOSDarwin() || TT.isOSBinFormatMachO())
     Buffer.insert(Buffer.begin(), BWH_HeaderSize, 0);
 
-  // Emit the module into the buffer.
-  ModuleBitcodeWriter ModuleWriter(M, Buffer, ShouldPreserveUseListOrder, Index,
-                                   GenerateHash);
-  ModuleWriter.write();
+  BitcodeWriter Writer(Buffer);
+  Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash);
 
   if (TT.isOSDarwin() || TT.isOSBinFormatMachO())
     emitDarwinBCHeaderAndTrailer(Buffer, TT);
@@ -3838,7 +3816,7 @@ void llvm::WriteBitcodeToFile(const Modu
   Out.write((char*)&Buffer.front(), Buffer.size());
 }
 
-void IndexBitcodeWriter::writeIndex() {
+void IndexBitcodeWriter::write() {
   Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
 
   SmallVector<unsigned, 1> Vals;
@@ -3872,7 +3850,10 @@ void llvm::WriteIndexToFile(
   SmallVector<char, 0> Buffer;
   Buffer.reserve(256 * 1024);
 
-  IndexBitcodeWriter IndexWriter(Buffer, Index, ModuleToSummariesForIndex);
+  BitstreamWriter Stream(Buffer);
+  writeBitcodeHeader(Stream);
+
+  IndexBitcodeWriter IndexWriter(Stream, Index, ModuleToSummariesForIndex);
   IndexWriter.write();
 
   Out.write((char *)&Buffer.front(), Buffer.size());

Added: llvm/trunk/test/Bitcode/Inputs/multi-module.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/Inputs/multi-module.ll?rev=288195&view=auto
==============================================================================
--- llvm/trunk/test/Bitcode/Inputs/multi-module.ll (added)
+++ llvm/trunk/test/Bitcode/Inputs/multi-module.ll Tue Nov 29 14:43:47 2016
@@ -0,0 +1,3 @@
+define void @f2() {
+  ret void
+}

Added: llvm/trunk/test/Bitcode/multi-module.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/multi-module.ll?rev=288195&view=auto
==============================================================================
--- llvm/trunk/test/Bitcode/multi-module.ll (added)
+++ llvm/trunk/test/Bitcode/multi-module.ll Tue Nov 29 14:43:47 2016
@@ -0,0 +1,39 @@
+; RUN: llvm-cat -o %t %s %S/Inputs/multi-module.ll
+; RUN: not llvm-dis -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; ERROR: Expected a single module
+
+; FIXME: Introduce a tool for extracting modules from bitcode and use it here.
+; For now we can at least check that the bitcode contains multiple modules.
+; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s
+
+; RUN: llvm-as -o %t1 %s
+; RUN: llvm-as -o %t2 %S/Inputs/multi-module.ll
+; RUN: llvm-cat -o %t %t1 %t2
+; RUN: not llvm-dis -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s
+
+; RUN: llvm-cat -b -o %t %t1 %t2
+; RUN: not llvm-dis -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s
+
+; RUN: llvm-cat -b -o %t3 %t %t
+; RUN: not llvm-dis -o - %t3 2>&1 | FileCheck --check-prefix=ERROR %s
+; RUN: llvm-bcanalyzer -dump %t3 | FileCheck --check-prefix=BCA4 %s
+
+; BCA: <IDENTIFICATION_BLOCK
+; BCA: <MODULE_BLOCK
+; BCA: <IDENTIFICATION_BLOCK
+; BCA: <MODULE_BLOCK
+
+; BCA4: <IDENTIFICATION_BLOCK
+; BCA4: <MODULE_BLOCK
+; BCA4: <IDENTIFICATION_BLOCK
+; BCA4: <MODULE_BLOCK
+; BCA4: <IDENTIFICATION_BLOCK
+; BCA4: <MODULE_BLOCK
+; BCA4: <IDENTIFICATION_BLOCK
+; BCA4: <MODULE_BLOCK
+
+define void @f1() {
+  ret void
+}

Modified: llvm/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CMakeLists.txt?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/test/CMakeLists.txt (original)
+++ llvm/trunk/test/CMakeLists.txt Tue Nov 29 14:43:47 2016
@@ -32,6 +32,7 @@ set(LLVM_TEST_DEPENDS
           llvm-as
           llvm-bcanalyzer
           llvm-c-test
+          llvm-cat
           llvm-cxxfilt
           llvm-config
           llvm-cov

Modified: llvm/trunk/tools/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=288195&r1=288194&r2=288195&view=diff
==============================================================================
--- llvm/trunk/tools/LLVMBuild.txt (original)
+++ llvm/trunk/tools/LLVMBuild.txt Tue Nov 29 14:43:47 2016
@@ -24,6 +24,7 @@ subdirectories =
  llvm-ar
  llvm-as
  llvm-bcanalyzer
+ llvm-cat
  llvm-cov
  llvm-diff
  llvm-dis

Added: llvm/trunk/tools/llvm-cat/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cat/CMakeLists.txt?rev=288195&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cat/CMakeLists.txt (added)
+++ llvm/trunk/tools/llvm-cat/CMakeLists.txt Tue Nov 29 14:43:47 2016
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS
+  IRReader
+  BitWriter
+  Core
+  Support
+  )
+
+add_llvm_tool(llvm-cat
+  llvm-cat.cpp
+  )

Added: llvm/trunk/tools/llvm-cat/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cat/LLVMBuild.txt?rev=288195&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cat/LLVMBuild.txt (added)
+++ llvm/trunk/tools/llvm-cat/LLVMBuild.txt Tue Nov 29 14:43:47 2016
@@ -0,0 +1,22 @@
+;===- ./tools/llvm-cat/LLVMBuild.txt ---------------------------*- Conf -*--===;
+;
+;                     The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-cat
+parent = Tools
+required_libraries = AsmParser BitWriter

Added: llvm/trunk/tools/llvm-cat/llvm-cat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cat/llvm-cat.cpp?rev=288195&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cat/llvm-cat.cpp (added)
+++ llvm/trunk/tools/llvm-cat/llvm-cat.cpp Tue Nov 29 14:43:47 2016
@@ -0,0 +1,73 @@
+//===-- llvm-cat.cpp - LLVM module concatenation utility ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is for testing features that rely on multi-module bitcode files.
+// It takes a list of input modules and uses them to create a multi-module
+// bitcode file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace llvm;
+
+static cl::opt<bool>
+    BinaryCat("b", cl::desc("Whether to perform binary concatenation"));
+
+static cl::opt<std::string> OutputFilename("o", cl::Required,
+                                           cl::desc("Output filename"),
+                                           cl::value_desc("filename"));
+
+static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
+                                            cl::desc("<input  files>"));
+
+int main(int argc, char **argv) {
+  cl::ParseCommandLineOptions(argc, argv, "Module concatenation");
+
+  ExitOnError ExitOnErr("llvm-cat: ");
+  LLVMContext Context;
+
+  SmallVector<char, 0> Buffer;
+  BitcodeWriter Writer(Buffer);
+  if (BinaryCat) {
+    for (std::string InputFilename : InputFilenames) {
+      std::unique_ptr<MemoryBuffer> MB = ExitOnErr(
+          errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename)));
+      std::vector<BitcodeModule> Mods = ExitOnErr(getBitcodeModuleList(*MB));
+      for (auto &BitcodeMod : Mods)
+        Buffer.insert(Buffer.end(), BitcodeMod.getBuffer().begin(),
+                      BitcodeMod.getBuffer().end());
+    }
+  } else {
+    for (std::string InputFilename : InputFilenames) {
+      SMDiagnostic Err;
+      std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
+      if (!M) {
+        Err.print(argv[0], errs());
+        return 1;
+      }
+      Writer.writeModule(M.get());
+    }
+  }
+
+  std::error_code EC;
+  raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::F_None);
+  if (EC) {
+    llvm::errs() << argv[0] << ": cannot open " << OutputFilename
+                 << " for writing: " << EC.message();
+    return 1;
+  }
+
+  OS.write(Buffer.data(), Buffer.size());
+  return 0;
+}




More information about the llvm-commits mailing list