diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 07089a85afe..81ba5d7f4e7 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -13,7 +13,6 @@ #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" @@ -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. @@ -682,6 +705,8 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream, 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; @@ -709,6 +734,17 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream, 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; } @@ -819,6 +855,7 @@ bool BitcodeReader::ParseModule(BitstreamReader &Stream, "", TheModule); Func->setCallingConv(Record[1]); + bool isProto = Record[2]; 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); + + // 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] @@ -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(); - BitstreamReader Stream(BufPtr, BufPtr+Buffer->getBufferSize()); + Stream.init(BufPtr, BufPtr+Buffer->getBufferSize()); // Sniff for the signature. if (Stream.Read(8) != 'B' || @@ -900,6 +942,25 @@ bool BitcodeReader::ParseBitcode() { return false; } + +bool BitcodeReader::materializeFunction(Function *F, std::string *ErrInfo) { + // If it already is material, ignore the request. + if (!F->hasNotBeenReadFromBytecode()) return false; + + DenseMap >::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 //===----------------------------------------------------------------------===// diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 0935c06f93c..470758f0e55 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -17,7 +17,9 @@ #include "llvm/ModuleProvider.h" #include "llvm/Type.h" #include "llvm/User.h" +#include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/ADT/DenseMap.h" #include namespace llvm { @@ -59,14 +61,31 @@ public: class BitcodeReader : public ModuleProvider { MemoryBuffer *Buffer; + BitstreamReader Stream; + const char *ErrorString; std::vector TypeList; BitcodeReaderValueList ValueList; std::vector > GlobalInits; std::vector > AliasInits; + + // When reading the module header, this list is populated with functions that + // have bodies later in the file. + std::vector 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 > DeferredFunctionInfo; public: - BitcodeReader(MemoryBuffer *buffer) : Buffer(buffer), ErrorString(0) {} + BitcodeReader(MemoryBuffer *buffer) : Buffer(buffer), ErrorString(0) { + HasReversedFunctionsWithBodies = false; + } ~BitcodeReader(); @@ -77,10 +96,7 @@ public: 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 @@ -106,6 +122,7 @@ private: bool ParseTypeSymbolTable(BitstreamReader &Stream); bool ParseValueSymbolTable(BitstreamReader &Stream); bool ParseConstants(BitstreamReader &Stream); + bool ParseFunction(BitstreamReader &Stream); bool ResolveGlobalAndAliasInits(); };