implement scafolding for lazy deserialization of function bodies
authorChris Lattner <sabre@nondot.org>
Tue, 1 May 2007 04:59:48 +0000 (04:59 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 1 May 2007 04:59:48 +0000 (04:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@36614 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Reader/BitcodeReader.h

index 07089a85afec6313bcd491115d4543181ff10ee9..81ba5d7f4e7cc96103b2de886cc28f4bbb5df090 100644 (file)
@@ -13,7 +13,6 @@
 
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "BitcodeReader.h"
 
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "BitcodeReader.h"
-#include "llvm/Bitcode/BitstreamReader.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Module.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Module.h"
@@ -660,6 +659,30 @@ bool BitcodeReader::ParseConstants(BitstreamReader &Stream) {
   }
 }
 
   }
 }
 
+/// ParseFunction - When we see the block for a function body, remember where it
+/// is and then skip it.  This lets us lazily deserialize the functions.
+bool BitcodeReader::ParseFunction(BitstreamReader &Stream) {
+  // Get the function we are talking about.
+  if (FunctionsWithBodies.empty())
+    return Error("Insufficient function protos");
+  
+  Function *Fn = FunctionsWithBodies.back();
+  FunctionsWithBodies.pop_back();
+  
+  // Save the current stream state.
+  uint64_t CurBit = Stream.GetCurrentBitNo();
+  DeferredFunctionInfo[Fn] = std::make_pair(CurBit, Fn->getLinkage());
+  
+  // Set the functions linkage to GhostLinkage so we know it is lazily
+  // deserialized.
+  Fn->setLinkage(GlobalValue::GhostLinkage);
+  
+  // Skip over the function block for now.
+  if (Stream.SkipBlock())
+    return Error("Malformed block record");
+  return false;
+}
+
 bool BitcodeReader::ParseModule(BitstreamReader &Stream,
                                 const std::string &ModuleID) {
   // Reject multiple MODULE_BLOCK's in a single bitstream.
 bool BitcodeReader::ParseModule(BitstreamReader &Stream,
                                 const std::string &ModuleID) {
   // Reject multiple MODULE_BLOCK's in a single bitstream.
@@ -682,6 +705,8 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream,
       ResolveGlobalAndAliasInits();
       if (!GlobalInits.empty() || !AliasInits.empty())
         return Error("Malformed global initializer set");
       ResolveGlobalAndAliasInits();
       if (!GlobalInits.empty() || !AliasInits.empty())
         return Error("Malformed global initializer set");
+      if (!FunctionsWithBodies.empty())
+        return Error("Too few function bodies found");
       if (Stream.ReadBlockEnd())
         return Error("Error at end of module block");
       return false;
       if (Stream.ReadBlockEnd())
         return Error("Error at end of module block");
       return false;
@@ -709,6 +734,17 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream,
         if (ParseConstants(Stream) || ResolveGlobalAndAliasInits())
           return true;
         break;
         if (ParseConstants(Stream) || ResolveGlobalAndAliasInits())
           return true;
         break;
+      case bitc::FUNCTION_BLOCK_ID:
+        // If this is the first function body we've seen, reverse the
+        // FunctionsWithBodies list.
+        if (!HasReversedFunctionsWithBodies) {
+          std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end());
+          HasReversedFunctionsWithBodies = true;
+        }
+        
+        if (ParseFunction(Stream))
+          return true;
+        break;
       }
       continue;
     }
       }
       continue;
     }
@@ -819,6 +855,7 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream,
                                     "", TheModule);
 
       Func->setCallingConv(Record[1]);
                                     "", TheModule);
 
       Func->setCallingConv(Record[1]);
+      bool isProto = Record[2];
       Func->setLinkage(GetDecodedLinkage(Record[3]));
       Func->setAlignment((1 << Record[4]) >> 1);
       if (Record[5]) {
       Func->setLinkage(GetDecodedLinkage(Record[3]));
       Func->setAlignment((1 << Record[4]) >> 1);
       if (Record[5]) {
@@ -829,6 +866,11 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream,
       Func->setVisibility(GetDecodedVisibility(Record[6]));
       
       ValueList.push_back(Func);
       Func->setVisibility(GetDecodedVisibility(Record[6]));
       
       ValueList.push_back(Func);
+      
+      // If this is a function with a body, remember the prototype we are
+      // creating now, so that we can match up the body with them later.
+      if (!isProto)
+        FunctionsWithBodies.push_back(Func);
       break;
     }
     // ALIAS: [alias type, aliasee val#, linkage]
       break;
     }
     // ALIAS: [alias type, aliasee val#, linkage]
@@ -867,7 +909,7 @@ bool BitcodeReader::ParseBitcode() {
     return Error("Bitcode stream should be a multiple of 4 bytes in length");
   
   unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
     return Error("Bitcode stream should be a multiple of 4 bytes in length");
   
   unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
-  BitstreamReader Stream(BufPtr, BufPtr+Buffer->getBufferSize());
+  Stream.init(BufPtr, BufPtr+Buffer->getBufferSize());
   
   // Sniff for the signature.
   if (Stream.Read(8) != 'B' ||
   
   // Sniff for the signature.
   if (Stream.Read(8) != 'B' ||
@@ -900,6 +942,25 @@ bool BitcodeReader::ParseBitcode() {
   return false;
 }
 
   return false;
 }
 
+
+bool BitcodeReader::materializeFunction(Function *F, std::string *ErrInfo) {
+  // If it already is material, ignore the request.
+  if (!F->hasNotBeenReadFromBytecode()) return false;
+
+  DenseMap<Function*, std::pair<uint64_t, unsigned> >::iterator DFII = 
+    DeferredFunctionInfo.find(F);
+  assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!");
+  
+  // Move the bit stream to the saved position of the deferred function body and
+  // restore the real linkage type for the function.
+  Stream.JumpToBit(DFII->second.first);
+  F->setLinkage((GlobalValue::LinkageTypes)DFII->second.second);
+  DeferredFunctionInfo.erase(DFII);
+  
+  return false;
+}
+
+
 //===----------------------------------------------------------------------===//
 // External interface
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // External interface
 //===----------------------------------------------------------------------===//
index 0935c06f93ccde4d0d636d619b18f063978c109e..470758f0e5585dda6f5d80a47e0cbb2ccb910ced 100644 (file)
@@ -17,7 +17,9 @@
 #include "llvm/ModuleProvider.h"
 #include "llvm/Type.h"
 #include "llvm/User.h"
 #include "llvm/ModuleProvider.h"
 #include "llvm/Type.h"
 #include "llvm/User.h"
+#include "llvm/Bitcode/BitstreamReader.h"
 #include "llvm/Bitcode/LLVMBitCodes.h"
 #include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/ADT/DenseMap.h"
 #include <vector>
 
 namespace llvm {
 #include <vector>
 
 namespace llvm {
@@ -59,14 +61,31 @@ public:
 
 class BitcodeReader : public ModuleProvider {
   MemoryBuffer *Buffer;
 
 class BitcodeReader : public ModuleProvider {
   MemoryBuffer *Buffer;
+  BitstreamReader Stream;
+  
   const char *ErrorString;
   
   std::vector<PATypeHolder> TypeList;
   BitcodeReaderValueList ValueList;
   std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
   std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
   const char *ErrorString;
   
   std::vector<PATypeHolder> TypeList;
   BitcodeReaderValueList ValueList;
   std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
   std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
+  
+  // When reading the module header, this list is populated with functions that
+  // have bodies later in the file.
+  std::vector<Function*> FunctionsWithBodies;
+  
+  // After the module header has been read, the FunctionsWithBodies list is 
+  // reversed.  This keeps track of whether we've done this yet.
+  bool HasReversedFunctionsWithBodies;
+  
+  /// DeferredFunctionInfo - When function bodies are initially scanned, this
+  /// map contains info about where to find deferred function body (in the
+  /// stream) and what linkage the original function had.
+  DenseMap<Function*, std::pair<uint64_t, unsigned> > DeferredFunctionInfo;
 public:
 public:
-  BitcodeReader(MemoryBuffer *buffer) : Buffer(buffer), ErrorString(0) {}
+  BitcodeReader(MemoryBuffer *buffer) : Buffer(buffer), ErrorString(0) {
+    HasReversedFunctionsWithBodies = false;
+  }
   ~BitcodeReader();
   
   
   ~BitcodeReader();
   
   
@@ -77,10 +96,7 @@ public:
     Buffer = 0;
   }
   
     Buffer = 0;
   }
   
-  virtual bool materializeFunction(Function *F, std::string *ErrInfo = 0) {
-    // FIXME: TODO
-    return false;
-  }
+  virtual bool materializeFunction(Function *F, std::string *ErrInfo = 0);
   
   virtual Module *materializeModule(std::string *ErrInfo = 0) {
     // FIXME: TODO
   
   virtual Module *materializeModule(std::string *ErrInfo = 0) {
     // FIXME: TODO
@@ -106,6 +122,7 @@ private:
   bool ParseTypeSymbolTable(BitstreamReader &Stream);
   bool ParseValueSymbolTable(BitstreamReader &Stream);
   bool ParseConstants(BitstreamReader &Stream);
   bool ParseTypeSymbolTable(BitstreamReader &Stream);
   bool ParseValueSymbolTable(BitstreamReader &Stream);
   bool ParseConstants(BitstreamReader &Stream);
+  bool ParseFunction(BitstreamReader &Stream);
   bool ResolveGlobalAndAliasInits();
 };
   
   bool ResolveGlobalAndAliasInits();
 };