Support for expanding the result of EXTRACT_ELEMENT.
[oota-llvm.git] / lib / Bitcode / Reader / Deserialize.cpp
index ccd929a440dc4dda46b9dcc5424c8e273dca9197..2014557a1012da2755b6e2f0fda94a27dc3e4939 100644 (file)
@@ -2,8 +2,8 @@
 //
 //                     The LLVM Compiler Infrastructure
 //
-// This file was developed by Ted Kremenek and is distributed under the
-// University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Bitcode/Serialization.h"
+#include "llvm/Bitcode/Deserialize.h"
+
+#ifdef DEBUG_BACKPATCH
+#include "llvm/Support/Streams.h"
+#endif
 
 using namespace llvm;
 
 Deserializer::Deserializer(BitstreamReader& stream)
-  : Stream(stream), RecIdx(0) {
+  : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {
+
+    StreamStart = Stream.GetCurrentBitNo();
 }
 
 Deserializer::~Deserializer() {
   assert (RecIdx >= Record.size() && 
           "Still scanning bitcode record when deserialization completed.");
+#ifdef DEBUG_BACKPATCH
+  for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
+    assert (I->first.hasFinalPtr() &&
+            "Some pointers were not backpatched.");
+#endif
 }
 
-void Deserializer::ReadRecord() {
-  // FIXME: Check if we haven't run off the edge of the stream.
-  // FIXME: Handle abbreviations.
-  unsigned Code = Stream.ReadCode();
-  // FIXME: Check for the correct code.
-  assert (Record.size() == 0);
+
+bool Deserializer::inRecord() {
+  if (Record.size() > 0) {
+    if (RecIdx >= Record.size()) {
+      RecIdx = 0;
+      Record.clear();
+      AbbrevNo = 0;
+      return false;
+    }
+    else
+      return true;
+  }
+
+  return false;
+}
+
+bool Deserializer::AdvanceStream() {
+  assert (!inRecord() && 
+          "Cannot advance stream.  Still processing a record.");
   
-  Stream.ReadRecord(Code,Record);
+  if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
+      AbbrevNo >= bitc::UNABBREV_RECORD)
+    return true;
   
+  while (!Stream.AtEndOfStream()) {
+    
+    uint64_t Pos = Stream.GetCurrentBitNo();
+    AbbrevNo = Stream.ReadCode();    
+  
+    switch (AbbrevNo) {        
+      case bitc::ENTER_SUBBLOCK: {
+        unsigned id = Stream.ReadSubBlockID();
+        
+        // Determine the extent of the block.  This is useful for jumping around
+        // the stream.  This is hack: we read the header of the block, save
+        // the length, and then revert the bitstream to a location just before
+        // the block is entered.
+        uint64_t BPos = Stream.GetCurrentBitNo();
+        Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
+        Stream.SkipToWord();
+        unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
+        Stream.JumpToBit(BPos);
+                
+        BlockStack.push_back(Location(Pos,id,NumWords));
+        break;
+      } 
+        
+      case bitc::END_BLOCK: {
+        bool x = Stream.ReadBlockEnd();
+        assert(!x && "Error at block end."); x=x;
+        BlockStack.pop_back();
+        continue;
+      }
+        
+      case bitc::DEFINE_ABBREV:
+        Stream.ReadAbbrevRecord();
+        continue;
+
+      default:
+        break;
+    }
+    
+    return true;
+  }
+  
+  return false;
+}
+
+void Deserializer::ReadRecord() {
+
+  while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
+    assert (!BlockStack.empty());
+    Stream.EnterSubBlock(BlockStack.back().BlockID);
+    AbbrevNo = 0;
+  }
+
+  if (Stream.AtEndOfStream())
+    return;
+  
+  assert (Record.empty());
+  assert (AbbrevNo >= bitc::UNABBREV_RECORD);
+  RecordCode = Stream.ReadRecord(AbbrevNo,Record);
   assert (Record.size() > 0);
 }
 
-uint64_t Deserializer::ReadInt(unsigned Bits) {
+void Deserializer::SkipBlock() {
+  assert (!inRecord());
+
+  if (AtEnd())
+    return;
+
+  AdvanceStream();  
+
+  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+  BlockStack.pop_back();
+  Stream.SkipBlock();
+
+  AbbrevNo = 0;
+  AdvanceStream();
+}
+
+bool Deserializer::SkipToBlock(unsigned BlockID) {
+  assert (!inRecord());
+  
+  AdvanceStream();
+  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+  
+  unsigned BlockLevel = BlockStack.size();
+
+  while (!AtEnd() &&
+         BlockLevel == BlockStack.size() && 
+         getCurrentBlockID() != BlockID)
+    SkipBlock();
+
+  return !(AtEnd() || BlockLevel != BlockStack.size());
+}
+
+Deserializer::Location Deserializer::getCurrentBlockLocation() {
+  if (!inRecord())
+    AdvanceStream();
+  
+  return BlockStack.back();
+}
+
+bool Deserializer::JumpTo(const Location& Loc) {
+    
+  assert (!inRecord());
+
+  AdvanceStream();
+  
+  assert (!BlockStack.empty() || AtEnd());
+    
+  uint64_t LastBPos = StreamStart;
+  
+  while (!BlockStack.empty()) {
+    
+    LastBPos = BlockStack.back().BitNo;
+    
+    // Determine of the current block contains the location of the block
+    // we are looking for.
+    if (BlockStack.back().contains(Loc)) {
+      // We found the enclosing block.  We must first POP it off to
+      // destroy any accumulated context within the block scope.  We then
+      // jump to the position of the block and enter it.
+      Stream.JumpToBit(LastBPos);
+      
+      if (BlockStack.size() == Stream.BlockScope.size())
+        Stream.PopBlockScope();
+
+      BlockStack.pop_back();
+      
+      AbbrevNo = 0;
+      AdvanceStream();      
+      assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+      
+      Stream.EnterSubBlock(BlockStack.back().BlockID);
+      break;
+    }
+
+    // This block does not contain the block we are looking for.  Pop it.
+    if (BlockStack.size() == Stream.BlockScope.size())
+      Stream.PopBlockScope();
+    
+    BlockStack.pop_back();
+
+  }
+
+  // Check if we have popped our way to the outermost scope.  If so,
+  // we need to adjust our position.
+  if (BlockStack.empty()) {
+    assert (Stream.BlockScope.empty());
+    
+    Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart : LastBPos);
+    AbbrevNo = 0;
+    AdvanceStream();
+  }
+
+  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+  assert (!BlockStack.empty());
+  
+  while (!AtEnd() && BlockStack.back() != Loc) {
+    if (BlockStack.back().contains(Loc)) {
+      Stream.EnterSubBlock(BlockStack.back().BlockID);
+      AbbrevNo = 0;
+      AdvanceStream();
+      continue;
+    }
+    else
+      SkipBlock();
+  }
+  
+  if (AtEnd())
+    return false;
+  
+  assert (BlockStack.back() == Loc);
+
+  return true;
+}
+
+void Deserializer::Rewind() {
+  while (!Stream.BlockScope.empty())
+    Stream.PopBlockScope();
+  
+  while (!BlockStack.empty())
+    BlockStack.pop_back();
+  
+  Stream.JumpToBit(StreamStart);
+  AbbrevNo = 0;
+}
+  
+
+unsigned Deserializer::getCurrentBlockID() { 
+  if (!inRecord())
+    AdvanceStream();
+  
+  return BlockStack.back().BlockID;
+}
+
+unsigned Deserializer::getRecordCode() {
+  if (!inRecord()) {
+    AdvanceStream();
+    assert (AbbrevNo >= bitc::UNABBREV_RECORD);
+    ReadRecord();
+  }
+  
+  return RecordCode;
+}
+
+bool Deserializer::FinishedBlock(Location BlockLoc) {
+  if (!inRecord())
+    AdvanceStream();
+
+  for (llvm::SmallVector<Location,8>::reverse_iterator
+        I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
+      if (*I == BlockLoc)
+        return false;
+  
+  return true;
+}
+
+unsigned Deserializer::getAbbrevNo() {
+  if (!inRecord())
+    AdvanceStream();
+  
+  return AbbrevNo;
+}
+
+bool Deserializer::AtEnd() {
+  if (inRecord())
+    return false;
+  
+  if (!AdvanceStream())
+    return true;
+  
+  return false;
+}
+
+uint64_t Deserializer::ReadInt() {
   // FIXME: Any error recovery/handling with incomplete or bad files?
   if (!inRecord())
     ReadRecord();
 
-  // FIXME: check for loss of precision in read (compare to Bits)
   return Record[RecIdx++];
 }
 
-char* Deserializer::ReadCString(char* cstr, unsigned MaxLen, bool isNullTerm) {
+int64_t Deserializer::ReadSInt() {
+  uint64_t x = ReadInt();
+  int64_t magnitude = x >> 1;
+  return x & 0x1 ? -magnitude : magnitude;
+}
+
+char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
   if (cstr == NULL)
     MaxLen = 0; // Zero this just in case someone does something funny.
   
-  unsigned len = ReadInt(32);
+  unsigned len = ReadInt();
 
-  // FIXME: perform dynamic checking of lengths?
   assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);
 
   if (!cstr)
@@ -60,24 +321,134 @@ char* Deserializer::ReadCString(char* cstr, unsigned MaxLen, bool isNullTerm) {
   assert (cstr != NULL);
   
   for (unsigned i = 0; i < len; ++i)
-    cstr[i] = ReadInt(8);
+    cstr[i] = (char) ReadInt();
   
   if (isNullTerm)
-    cstr[len+1] = '\0';
+    cstr[len] = '\0';
   
   return cstr;
 }
 
-void Deserializer::ReadCString(std::vector<char>& buff, bool isNullTerm) {
-  buff.clear();
-
-  unsigned len = ReadInt(32);
+void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm,
+                            unsigned Idx) {
   
-  buff.reserve(len);
+  unsigned len = ReadInt();
+
+  // If Idx is beyond the current before size, reduce Idx to refer to the
+  // element after the last element.
+  if (Idx > buff.size())
+    Idx = buff.size();
+
+  buff.reserve(len+Idx);
+  buff.resize(Idx);      
   
   for (unsigned i = 0; i < len; ++i)
-    buff.push_back(ReadInt(8));
+    buff.push_back((char) ReadInt());
   
   if (isNullTerm)
     buff.push_back('\0');
 }
+
+void Deserializer::RegisterPtr(const SerializedPtrID& PtrId,
+                               const void* Ptr) {
+  
+  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+  
+  assert (!HasFinalPtr(E) && "Pointer already registered.");
+
+#ifdef DEBUG_BACKPATCH
+  llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
+#endif 
+  
+  SetPtr(E,Ptr);
+}
+
+void Deserializer::ReadUIntPtr(uintptr_t& PtrRef, 
+                               const SerializedPtrID& PtrId,
+                               bool AllowBackpatch) {  
+  if (PtrId == 0) {
+    PtrRef = 0;
+    return;
+  }
+  
+  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+  
+  if (HasFinalPtr(E)) {
+    PtrRef = GetFinalPtr(E);
+
+#ifdef DEBUG_BACKPATCH
+    llvm::cerr << "ReadUintPtr: " << PtrId
+               << " <-- " <<  (void*) GetFinalPtr(E) << '\n';
+#endif    
+  }
+  else {
+    assert (AllowBackpatch &&
+            "Client forbids backpatching for this pointer.");
+    
+#ifdef DEBUG_BACKPATCH
+    llvm::cerr << "ReadUintPtr: " << PtrId << " (NO PTR YET)\n";
+#endif
+    
+    // Register backpatch.  Check the freelist for a BPNode.
+    BPNode* N;
+
+    if (FreeList) {
+      N = FreeList;
+      FreeList = FreeList->Next;
+    }
+    else // No available BPNode.  Allocate one.
+      N = (BPNode*) Allocator.Allocate<BPNode>();
+    
+    new (N) BPNode(GetBPNode(E),PtrRef);
+    SetBPNode(E,N);
+  }
+}
+
+uintptr_t Deserializer::ReadInternalRefPtr() {
+  SerializedPtrID PtrId = ReadPtrID();
+  
+  assert (PtrId != 0 && "References cannot refer the NULL address.");
+
+  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+  
+  assert (HasFinalPtr(E) &&
+          "Cannot backpatch references.  Object must be already deserialized.");
+  
+  return GetFinalPtr(E);
+}
+
+void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
+  BPNode* Last = NULL;
+  
+  for (BPNode* N = Head; N != NULL; N=N->Next) {
+    Last = N;
+    N->PtrRef |= reinterpret_cast<uintptr_t>(P);
+  }
+  
+  if (Last) {
+    Last->Next = FreeList;
+    FreeList = Head;
+  }
+  
+  Ptr = const_cast<void*>(P);
+}
+
+
+#define INT_READ(TYPE)\
+void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
+  X = (TYPE) D.ReadInt(); }
+
+INT_READ(bool)
+INT_READ(unsigned char)
+INT_READ(unsigned short)
+INT_READ(unsigned int)
+INT_READ(unsigned long)
+
+#define SINT_READ(TYPE)\
+void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
+  X = (TYPE) D.ReadSInt(); }
+
+INT_READ(signed char)
+INT_READ(signed short)
+INT_READ(signed int)
+INT_READ(signed long)