Don't special-case stdout in llvm::WriteBitcodeToFile; just consider
[oota-llvm.git] / include / llvm / Bitcode / BitstreamWriter.h
index aed7c2f48a14c3552dbd3112dd07f57f9c6c8610..31d513cfb02113e3dcf2d415d2f98300ed6750f4 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef BITSTREAM_WRITER_H
 #define BITSTREAM_WRITER_H
 
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Bitcode/BitCodes.h"
 #include <vector>
 
@@ -79,6 +80,9 @@ public:
 
   std::vector<unsigned char> &getBuffer() { return Out; }
 
+  /// \brief Retrieve the current position in the stream, in bits.
+  uint64_t GetCurrentBitNo() const { return Out.size() * 8 + CurBit; }
+
   //===--------------------------------------------------------------------===//
   // Basic Primitives for emitting bits to the stream.
   //===--------------------------------------------------------------------===//
@@ -252,18 +256,23 @@ public:
   //===--------------------------------------------------------------------===//
 
 private:
+  /// EmitAbbreviatedLiteral - Emit a literal value according to its abbrev
+  /// record.  This is a no-op, since the abbrev specifies the literal to use. 
+  template<typename uintty>
+  void EmitAbbreviatedLiteral(const BitCodeAbbrevOp &Op, uintty V) {
+    assert(Op.isLiteral() && "Not a literal");
+    // If the abbrev specifies the literal value to use, don't emit
+    // anything.
+    assert(V == Op.getLiteralValue() &&
+           "Invalid abbrev for record!");
+  }
+  
   /// EmitAbbreviatedField - Emit a single scalar field value with the specified
   /// encoding.
   template<typename uintty>
   void EmitAbbreviatedField(const BitCodeAbbrevOp &Op, uintty V) {
-    if (Op.isLiteral()) {
-      // If the abbrev specifies the literal value to use, don't emit
-      // anything.
-      assert(V == Op.getLiteralValue() &&
-             "Invalid abbrev for record!");
-      return;
-    }
-
+    assert(!Op.isLiteral() && "Literals should use EmitAbbreviatedLiteral!");
+    
     // Encode the value as we are commanded.
     switch (Op.getEncoding()) {
     default: assert(0 && "Unknown encoding!");
@@ -278,46 +287,110 @@ private:
       break;
     }
   }
-public:
-
-  /// EmitRecord - Emit the specified record to the stream, using an abbrev if
-  /// we have one to compress the output.
+  
+  /// EmitRecordWithAbbrevImpl - This is the core implementation of the record
+  /// emission code.  If BlobData is non-null, then it specifies an array of
+  /// data that should be emitted as part of the Blob or Array operand that is
+  /// known to exist at the end of the record.
   template<typename uintty>
-  void EmitRecord(unsigned Code, SmallVectorImpl<uintty> &Vals,
-                  unsigned Abbrev = 0) {
-    if (Abbrev) {
-      unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV;
-      assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
-      BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo];
+  void EmitRecordWithAbbrevImpl(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
+                                StringRef Blob) {
+    const char *BlobData = Blob.data();
+    unsigned BlobLen = (unsigned) Blob.size();
+    unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV;
+    assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
+    BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo];
 
-      EmitCode(Abbrev);
+    EmitCode(Abbrev);
 
-      // Insert the code into Vals to treat it uniformly.
-      Vals.insert(Vals.begin(), Code);
-
-      unsigned RecordIdx = 0;
-      for (unsigned i = 0, e = static_cast<unsigned>(Abbv->getNumOperandInfos());
-           i != e; ++i) {
-        const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
-        if (Op.isLiteral() || Op.getEncoding() != BitCodeAbbrevOp::Array) {
-          assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
-          EmitAbbreviatedField(Op, Vals[RecordIdx]);
-          ++RecordIdx;
+    unsigned RecordIdx = 0;
+    for (unsigned i = 0, e = static_cast<unsigned>(Abbv->getNumOperandInfos());
+         i != e; ++i) {
+      const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
+      if (Op.isLiteral()) {
+        assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
+        EmitAbbreviatedLiteral(Op, Vals[RecordIdx]);
+        ++RecordIdx;
+      } else if (Op.getEncoding() == BitCodeAbbrevOp::Array) {
+        // Array case.
+        assert(i+2 == e && "array op not second to last?");
+        const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i);
+
+        // If this record has blob data, emit it, otherwise we must have record
+        // entries to encode this way.
+        if (BlobData) {
+          assert(RecordIdx == Vals.size() &&
+                 "Blob data and record entries specified for array!");
+          // Emit a vbr6 to indicate the number of elements present.
+          EmitVBR(static_cast<uint32_t>(BlobLen), 6);
+          
+          // Emit each field.
+          for (unsigned i = 0; i != BlobLen; ++i)
+            EmitAbbreviatedField(EltEnc, (unsigned char)BlobData[i]);
+          
+          // Know that blob data is consumed for assertion below.
+          BlobData = 0;
         } else {
-          // Array case.
-          assert(i+2 == e && "array op not second to last?");
-          const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i);
-
           // Emit a vbr6 to indicate the number of elements present.
           EmitVBR(static_cast<uint32_t>(Vals.size()-RecordIdx), 6);
 
           // Emit each field.
-          for (; RecordIdx != Vals.size(); ++RecordIdx)
+          for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx)
             EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
         }
+      } else if (Op.getEncoding() == BitCodeAbbrevOp::Blob) {
+        // If this record has blob data, emit it, otherwise we must have record
+        // entries to encode this way.
+        
+        // Emit a vbr6 to indicate the number of elements present.
+        if (BlobData) {
+          EmitVBR(static_cast<uint32_t>(BlobLen), 6);
+          assert(RecordIdx == Vals.size() &&
+                 "Blob data and record entries specified for blob operand!");
+        } else {
+          EmitVBR(static_cast<uint32_t>(Vals.size()-RecordIdx), 6);
+        }
+        
+        // Flush to a 32-bit alignment boundary.
+        FlushToWord();
+        assert((Out.size() & 3) == 0 && "Not 32-bit aligned");
+
+        // Emit each field as a literal byte.
+        if (BlobData) {
+          for (unsigned i = 0; i != BlobLen; ++i)
+            Out.push_back((unsigned char)BlobData[i]);
+          
+          // Know that blob data is consumed for assertion below.
+          BlobData = 0;
+        } else {
+          for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx) {
+            assert(Vals[RecordIdx] < 256 && "Value too large to emit as blob");
+            Out.push_back((unsigned char)Vals[RecordIdx]);
+          }
+        }
+        // Align end to 32-bits.
+        while (Out.size() & 3)
+          Out.push_back(0);
+        
+      } else {  // Single scalar field.
+        assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
+        EmitAbbreviatedField(Op, Vals[RecordIdx]);
+        ++RecordIdx;
       }
-      assert(RecordIdx == Vals.size() && "Not all record operands emitted!");
-    } else {
+    }
+    assert(RecordIdx == Vals.size() && "Not all record operands emitted!");
+    assert(BlobData == 0 &&
+           "Blob data specified for record that doesn't use it!");
+  }
+  
+public:
+
+  /// EmitRecord - Emit the specified record to the stream, using an abbrev if
+  /// we have one to compress the output.
+  template<typename uintty>
+  void EmitRecord(unsigned Code, SmallVectorImpl<uintty> &Vals,
+                  unsigned Abbrev = 0) {
+    if (!Abbrev) {
       // If we don't have an abbrev to use, emit this in its fully unabbreviated
       // form.
       EmitCode(bitc::UNABBREV_RECORD);
@@ -325,9 +398,53 @@ public:
       EmitVBR(static_cast<uint32_t>(Vals.size()), 6);
       for (unsigned i = 0, e = static_cast<unsigned>(Vals.size()); i != e; ++i)
         EmitVBR64(Vals[i], 6);
+      return;
     }
+
+    // Insert the code into Vals to treat it uniformly.
+    Vals.insert(Vals.begin(), Code);
+    
+    EmitRecordWithAbbrev(Abbrev, Vals);
+  }
+  
+  /// EmitRecordWithAbbrev - Emit a record with the specified abbreviation.
+  /// Unlike EmitRecord, the code for the record should be included in Vals as
+  /// the first entry.
+  template<typename uintty>
+  void EmitRecordWithAbbrev(unsigned Abbrev, SmallVectorImpl<uintty> &Vals) {
+    EmitRecordWithAbbrevImpl(Abbrev, Vals, StringRef());
+  }
+  
+  /// EmitRecordWithBlob - Emit the specified record to the stream, using an
+  /// abbrev that includes a blob at the end.  The blob data to emit is
+  /// specified by the pointer and length specified at the end.  In contrast to
+  /// EmitRecord, this routine expects that the first entry in Vals is the code
+  /// of the record.
+  template<typename uintty>
+  void EmitRecordWithBlob(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
+                          StringRef Blob) {
+    EmitRecordWithAbbrevImpl(Abbrev, Vals, Blob);
+  }
+  template<typename uintty>
+  void EmitRecordWithBlob(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
+                          const char *BlobData, unsigned BlobLen) {
+    return EmitRecordWithAbbrevImpl(Abbrev, Vals, StringRef(BlobData, BlobLen));
   }
 
+  /// EmitRecordWithArray - Just like EmitRecordWithBlob, works with records
+  /// that end with an array.
+  template<typename uintty>
+  void EmitRecordWithArray(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
+                          StringRef Array) {
+    EmitRecordWithAbbrevImpl(Abbrev, Vals, Array);
+  }
+  template<typename uintty>
+  void EmitRecordWithArray(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
+                          const char *ArrayData, unsigned ArrayLen) {
+    return EmitRecordWithAbbrevImpl(Abbrev, Vals, StringRef(ArrayData, 
+                                                            ArrayLen));
+  }
+  
   //===--------------------------------------------------------------------===//
   // Abbrev Emission
   //===--------------------------------------------------------------------===//