Index: lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h |
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..940412981a5900167a7ce1d01cfc138de490df4c |
--- /dev/null |
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h |
@@ -0,0 +1,359 @@ |
+//===- NaClBitcodeReader.h ------------------------------------*- C++ -*-===// |
+// Internal NaClBitcodeReader implementation |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// This header defines the NaClBitcodeReader class. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#ifndef NACL_BITCODE_READER_H |
+#define NACL_BITCODE_READER_H |
+ |
+#include "llvm/ADT/DenseMap.h" |
+#include "llvm/Analysis/NaCl/PNaClAllowedIntrinsics.h" |
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" |
+#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h" |
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
+#include "llvm/IR/DerivedTypes.h" |
+#include "llvm/IR/GVMaterializer.h" |
+#include "llvm/IR/Instruction.h" |
+#include "llvm/IR/OperandTraits.h" |
+#include "llvm/IR/Type.h" |
+#include "llvm/IR/ValueHandle.h" |
+#include <vector> |
+ |
+namespace llvm { |
+ class MemoryBuffer; |
+ class LLVMContext; |
+ class CastInst; |
+ |
+// Models a Cast. Used to cache casts created in a basic block by the |
+// PNaCl bitcode reader. |
+struct NaClBitcodeReaderCast { |
+ // Fields of the conversion. |
+ Instruction::CastOps Op; |
+ Type *Ty; |
+ Value *Val; |
+ |
+ NaClBitcodeReaderCast(Instruction::CastOps Op, Type *Ty, Value *Val) |
+ : Op(Op), Ty(Ty), Val(Val) {} |
+}; |
+ |
+// Models the data structure used to hash/compare Casts in a DenseMap. |
+template<> |
+struct DenseMapInfo<NaClBitcodeReaderCast> { |
+public: |
+ static NaClBitcodeReaderCast getEmptyKey() { |
+ return NaClBitcodeReaderCast(Instruction::CastOpsEnd, |
+ DenseMapInfo<Type*>::getEmptyKey(), |
+ DenseMapInfo<Value*>::getEmptyKey()); |
+ } |
+ static NaClBitcodeReaderCast getTombstoneKey() { |
+ return NaClBitcodeReaderCast(Instruction::CastOpsEnd, |
+ DenseMapInfo<Type*>::getTombstoneKey(), |
+ DenseMapInfo<Value*>::getTombstoneKey()); |
+ } |
+ static unsigned getHashValue(const NaClBitcodeReaderCast &C) { |
+ std::pair<int, std::pair<Type*, Value*> > Tuple; |
+ Tuple.first = C.Op; |
+ Tuple.second.first = C.Ty; |
+ Tuple.second.second = C.Val; |
+ return DenseMapInfo<std::pair<int, std::pair<Type*, Value*> > >::getHashValue(Tuple); |
+ } |
+ static bool isEqual(const NaClBitcodeReaderCast &LHS, |
+ const NaClBitcodeReaderCast &RHS) { |
+ return LHS.Op == RHS.Op && LHS.Ty == RHS.Ty && LHS.Val == RHS.Val; |
+ } |
+}; |
+ |
+//===----------------------------------------------------------------------===// |
+// NaClBitcodeReaderValueList Class |
+//===----------------------------------------------------------------------===// |
+ |
+class NaClBitcodeReaderValueList { |
+ std::vector<WeakVH> ValuePtrs; |
+public: |
+ NaClBitcodeReaderValueList() {} |
+ ~NaClBitcodeReaderValueList() {} |
+ |
+ // vector compatibility methods |
+ unsigned size() const { return ValuePtrs.size(); } |
+ void resize(unsigned N) { ValuePtrs.resize(N); } |
+ void push_back(Value *V) { |
+ ValuePtrs.push_back(V); |
+ } |
+ |
+ void clear() { |
+ ValuePtrs.clear(); |
+ } |
+ |
+ Value *operator[](unsigned i) const { |
+ assert(i < ValuePtrs.size()); |
+ return ValuePtrs[i]; |
+ } |
+ |
+ Value *back() const { return ValuePtrs.back(); } |
+ void pop_back() { ValuePtrs.pop_back(); } |
+ bool empty() const { return ValuePtrs.empty(); } |
+ void shrinkTo(unsigned N) { |
+ assert(N <= size() && "Invalid shrinkTo request!"); |
+ ValuePtrs.resize(N); |
+ } |
+ |
+ // Declares the type of the forward-referenced value Idx. Returns |
+ // true if an error occurred. It is an error if Idx's type has |
+ // already been declared. |
+ bool createValueFwdRef(unsigned Idx, Type *Ty); |
+ |
+ // Gets the forward reference value for Idx. |
+ Value *getValueFwdRef(unsigned Idx); |
+ |
+ // Assigns V to value index Idx. |
+ void AssignValue(Value *V, unsigned Idx); |
+ |
+ // Assigns Idx to the given value, overwriting the existing entry |
+ // and possibly modifying the type of the entry. |
+ void OverwriteValue(Value *V, unsigned Idx); |
+}; |
+ |
+ |
+class NaClBitcodeReader : public GVMaterializer { |
+ NaClBitcodeHeader Header; // Header fields of the PNaCl bitcode file. |
+ LLVMContext &Context; |
+ Module *TheModule; |
+ // If non-null, stream to write verbose errors to. |
+ raw_ostream *Verbose; |
+ PNaClAllowedIntrinsics AllowedIntrinsics; |
+ std::unique_ptr<MemoryBuffer> Buffer; |
+ std::unique_ptr<NaClBitstreamReader> StreamFile; |
+ NaClBitstreamCursor Stream; |
+ StreamingMemoryObject *LazyStreamer; |
+ uint64_t NextUnreadBit; |
+ bool SeenValueSymbolTable; |
+ std::vector<Type*> TypeList; |
+ NaClBitcodeReaderValueList ValueList; |
+ |
+ // Holds information about each BasicBlock in the function being read. |
+ struct BasicBlockInfo { |
+ // A basic block within the function being modeled. |
+ BasicBlock *BB; |
+ // The set of generated conversions. |
+ DenseMap<NaClBitcodeReaderCast, CastInst*> CastMap; |
+ // The set of generated conversions that were added for phi nodes, |
+ // and may need thier parent basic block defined. |
+ std::vector<CastInst*> PhiCasts; |
+ }; |
+ |
+ /// FunctionBBs - While parsing a function body, this is a list of the basic |
+ /// blocks for the function. |
+ std::vector<BasicBlockInfo> FunctionBBs; |
+ |
+ // When reading the module header, this list is populated with functions that |
+ // have bodies later in the file. |
+ std::vector<Function*> FunctionsWithBodies; |
+ |
+ // When intrinsic functions are encountered which require upgrading they are |
+ // stored here with their replacement function. |
+ typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap; |
+ UpgradedIntrinsicMap UpgradedIntrinsics; |
+ |
+ // Several operations happen after the module header has been read, but |
+ // before function bodies are processed. This keeps track of whether |
+ // we've done this yet. |
+ bool SeenFirstFunctionBody; |
+ |
+ /// DeferredFunctionInfo - When function bodies are initially scanned, this |
+ /// map contains info about where to find deferred function body in the |
+ /// stream. |
+ DenseMap<Function*, uint64_t> DeferredFunctionInfo; |
+ |
+ /// \brief True if we should only accept supported bitcode format. |
+ bool AcceptSupportedBitcodeOnly; |
+ |
+ /// \brief Integer type use for PNaCl conversion of pointers. |
+ Type *IntPtrType; |
+ |
+ static const std::error_category &BitcodeErrorCategory(); |
+ |
+public: |
+ |
+ /// Types of errors reported. |
+ enum ErrorType { |
+ CouldNotFindFunctionInStream, // Unable to find function in bitcode stream. |
+ InsufficientFunctionProtos, |
+ InvalidBitstream, // Error in bitstream format. |
+ InvalidBlock, // Invalid block found in bitcode. |
+ InvalidConstantReference, // Bad constant reference. |
+ InvalidDataAfterModule, // Invalid data after module. |
+ InvalidInstructionWithNoBB, // No basic block for instruction. |
+ InvalidMultipleBlocks, // Multiple blocks for a kind of block that should |
+ // have only one. |
+ InvalidRecord, // Record doesn't have expected size or structure. |
+ InvalidSkippedBlock, // Unable to skip unknown block in bitcode file. |
+ InvalidType, // Invalid type in record. |
+ InvalidTypeForValue, // Type of value incorrect. |
+ InvalidValue, // Invalid value in record. |
+ MalformedBlock // Unable to advance over block. |
+ }; |
+ |
+ explicit NaClBitcodeReader(MemoryBuffer *buffer, LLVMContext &C, |
+ raw_ostream *Verbose, |
+ bool AcceptSupportedOnly) |
+ : Context(C), TheModule(nullptr), Verbose(Verbose), AllowedIntrinsics(&C), |
+ Buffer(buffer), |
+ LazyStreamer(nullptr), NextUnreadBit(0), SeenValueSymbolTable(false), |
+ ValueList(), |
+ SeenFirstFunctionBody(false), |
+ AcceptSupportedBitcodeOnly(AcceptSupportedOnly), |
+ IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) { |
+ } |
+ explicit NaClBitcodeReader(StreamingMemoryObject *streamer, |
+ LLVMContext &C, |
+ raw_ostream *Verbose, |
+ bool AcceptSupportedOnly) |
+ : Context(C), TheModule(nullptr), Verbose(Verbose), AllowedIntrinsics(&C), |
+ Buffer(nullptr), |
+ LazyStreamer(streamer), NextUnreadBit(0), SeenValueSymbolTable(false), |
+ ValueList(), |
+ SeenFirstFunctionBody(false), |
+ AcceptSupportedBitcodeOnly(AcceptSupportedOnly), |
+ IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) { |
+ } |
+ ~NaClBitcodeReader() override { |
+ FreeState(); |
+ } |
+ |
+ void FreeState(); |
+ |
+ bool isDematerializable(const GlobalValue *GV) const override; |
+ std::error_code materialize(GlobalValue *GV) override; |
+ std::error_code MaterializeModule(Module *M) override; |
+ void Dematerialize(GlobalValue *GV) override; |
+ void releaseBuffer(); |
+ |
+ std::error_code Error(ErrorType E) const { |
+ return std::error_code(E, BitcodeErrorCategory()); |
+ } |
+ |
+ /// Generates the corresponding verbose Message, then generates error. |
+ std::error_code Error(ErrorType E, const std::string &Message) const; |
+ |
+ /// @brief Main interface to parsing a bitcode buffer. |
+ /// @returns true if an error occurred. |
+ std::error_code ParseBitcodeInto(Module *M); |
+ |
+ /// Convert alignment exponent (i.e. power of two (or zero)) to the |
+ /// corresponding alignment to use. If alignment is too large, it generates |
+ /// an error message and returns corresponding error code. |
+ std::error_code getAlignmentValue(uint64_t Exponent, unsigned &Alignment); |
+ |
+private: |
+ // Returns false if Header is acceptable. |
+ bool AcceptHeader() const { |
+ return !(Header.IsSupported() || |
+ (!AcceptSupportedBitcodeOnly && Header.IsReadable())); |
+ } |
+ uint32_t GetPNaClVersion() const { |
+ return Header.GetPNaClVersion(); |
+ } |
+ Type *getTypeByID(unsigned ID); |
+ // Returns the value associated with ID. The value must already exist, |
+ // or a forward referenced value created by getOrCreateFnVaueByID. |
+ Value *getFnValueByID(unsigned ID) { |
+ return ValueList.getValueFwdRef(ID); |
+ } |
+ BasicBlock *getBasicBlock(unsigned ID) const { |
+ if (ID >= FunctionBBs.size()) return 0; // Invalid ID |
+ return FunctionBBs[ID].BB; |
+ } |
+ |
+ /// \brief Read a value out of the specified record from slot '*Slot'. |
+ /// Increment *Slot past the number of slots used by the value in the record. |
+ /// Return true if there is an error. |
+ bool popValue(const SmallVector<uint64_t, 64> &Record, unsigned *Slot, |
+ unsigned InstNum, Value **ResVal) { |
+ if (*Slot == Record.size()) return true; |
+ // ValNo is encoded relative to the InstNum. |
+ unsigned ValNo = InstNum - (unsigned)Record[(*Slot)++]; |
+ *ResVal = getFnValueByID(ValNo); |
+ return *ResVal == 0; |
+ } |
+ |
+ /// getValue -- Version of getValue that returns ResVal directly, |
+ /// or 0 if there is an error. |
+ Value *getValue(const SmallVector<uint64_t, 64> &Record, unsigned Slot, |
+ unsigned InstNum) { |
+ if (Slot == Record.size()) return 0; |
+ // ValNo is encoded relative to the InstNum. |
+ unsigned ValNo = InstNum - (unsigned)Record[Slot]; |
+ return getFnValueByID(ValNo); |
+ } |
+ |
+ /// getValueSigned -- Like getValue, but decodes signed VBRs. |
+ Value *getValueSigned(const SmallVector<uint64_t, 64> &Record, unsigned Slot, |
+ unsigned InstNum) { |
+ if (Slot == Record.size()) return 0; |
+ // ValNo is encoded relative to the InstNum. |
+ unsigned ValNo = InstNum - |
+ (unsigned) NaClDecodeSignRotatedValue(Record[Slot]); |
+ return getFnValueByID(ValNo); |
+ } |
+ |
+ /// \brief Create an (elided) cast instruction for basic block |
+ /// BBIndex. Op is the type of cast. V is the value to cast. CT |
+ /// is the type to convert V to. DeferInsertion defines whether the |
+ /// generated conversion should also be installed into basic block |
+ /// BBIndex. Note: For PHI nodes, we don't insert when created |
+ /// (i.e. DeferInsertion=true), since they must be inserted at the end |
+ /// of the corresponding incoming basic block. |
+ CastInst *CreateCast(unsigned BBIndex, Instruction::CastOps Op, |
+ Type *CT, Value *V, bool DeferInsertion = false); |
+ |
+ /// \brief Add instructions to cast Op to the given type T into |
+ /// block BBIndex. Follows rules for pointer conversion as defined |
+ /// in llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp. |
+ /// |
+ /// Returns 0 if unable to generate conversion value (also generates |
+ /// an appropriate error message and calls Error). |
+ Value *ConvertOpToType(Value *Op, Type *T, unsigned BBIndex); |
+ |
+ /// \brief If Op is a scalar value, this is a nop. If Op is a |
+ /// pointer value, a PtrToInt instruction is inserted (in BBIndex) |
+ /// to convert Op to an integer. For defaults on DeferInsertion, |
+ /// see comments for method CreateCast. |
+ Value *ConvertOpToScalar(Value *Op, unsigned BBIndex, |
+ bool DeferInsertion = false); |
+ |
+ /// \brief Install instruction I into basic block BB. |
+ std::error_code InstallInstruction(BasicBlock *BB, Instruction *I); |
+ |
+ FunctionType *AddPointerTypesToIntrinsicType(StringRef Name, |
+ FunctionType *FTy); |
+ void AddPointerTypesToIntrinsicParams(); |
+ std::error_code ParseModule(bool Resume); |
+ std::error_code ParseTypeTable(); |
+ std::error_code ParseTypeTableBody(); |
+ std::error_code ParseGlobalVars(); |
+ std::error_code ParseValueSymbolTable(); |
+ std::error_code ParseConstants(); |
+ std::error_code RememberAndSkipFunctionBody(); |
+ std::error_code ParseFunctionBody(Function *F); |
+ std::error_code GlobalCleanup(); |
+ std::error_code InitStream(); |
+ std::error_code InitStreamFromBuffer(); |
+ std::error_code InitLazyStream(); |
+ std::error_code FindFunctionInStream( |
+ Function *F, |
+ DenseMap<Function*, uint64_t>::iterator DeferredFunctionInfoIterator); |
+}; |
+ |
+} // End llvm namespace |
+ |
+#endif |