blob: 32e9f6e413c25ca3daea10bf31c9fbbe93977cb8 [file] [log] [blame]
//===- 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/Bitcode/NaCl/NaClBitcodeHeader.h"
#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
#include "llvm/GVMaterializer.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/OperandTraits.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/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;
LLVMContext &Context;
public:
NaClBitcodeReaderValueList(LLVMContext &C) : Context(C) {}
~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);
// Gets the corresponding constant defining the address of the
// corresponding global variable defined by Idx, if already defined.
// Otherwise, creates a forward reference for Idx, and returns the
// placeholder constant for the address of the corresponding global
// variable defined by Idx.
Constant *getOrCreateGlobalVarRef(unsigned Idx, Module* M);
// Assigns Idx to the given value (if new), or assigns V to Idx (if Idx
// was forward referenced).
void AssignValue(Value *V, unsigned Idx);
// Assigns Idx to the given global variable. If the Idx currently has
// a forward reference (built by createGlobalVarFwdRef(unsigned Idx)),
// replaces uses of the global variable forward reference with the
// value GV.
void AssignGlobalVar(GlobalVariable *GV, 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;
MemoryBuffer *Buffer;
bool BufferOwned;
OwningPtr<NaClBitstreamReader> StreamFile;
NaClBitstreamCursor Stream;
StreamableMemoryObject *LazyStreamer;
uint64_t NextUnreadBit;
bool SeenValueSymbolTable;
std::string ErrorString;
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;
public:
explicit NaClBitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
bool AcceptSupportedOnly = true)
: Context(C), TheModule(0), Buffer(buffer), BufferOwned(false),
LazyStreamer(0), NextUnreadBit(0), SeenValueSymbolTable(false),
ValueList(C),
SeenFirstFunctionBody(false),
AcceptSupportedBitcodeOnly(AcceptSupportedOnly),
IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) {
}
explicit NaClBitcodeReader(StreamableMemoryObject *streamer, LLVMContext &C,
bool AcceptSupportedOnly = true)
: Context(C), TheModule(0), Buffer(0), BufferOwned(false),
LazyStreamer(streamer), NextUnreadBit(0), SeenValueSymbolTable(false),
ValueList(C),
SeenFirstFunctionBody(false),
AcceptSupportedBitcodeOnly(AcceptSupportedOnly),
IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) {
}
~NaClBitcodeReader() {
FreeState();
}
void FreeState();
/// setBufferOwned - If this is true, the reader will destroy the MemoryBuffer
/// when the reader is destroyed.
void setBufferOwned(bool Owned) { BufferOwned = Owned; }
virtual bool isMaterializable(const GlobalValue *GV) const;
virtual bool isDematerializable(const GlobalValue *GV) const;
virtual error_code Materialize(GlobalValue *GV);
virtual error_code MaterializeModule(Module *M);
virtual void Dematerialize(GlobalValue *GV);
bool Error(const std::string &Str) {
ErrorString = Str;
return true;
}
const std::string &getErrorString() const { return ErrorString; }
/// @brief Main interface to parsing a bitcode buffer.
/// @returns true if an error occurred.
bool ParseBitcodeInto(Module *M);
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.
bool InstallInstruction(BasicBlock *BB, Instruction *I);
FunctionType *AddPointerTypesToIntrinsicType(StringRef Name,
FunctionType *FTy);
void AddPointerTypesToIntrinsicParams();
bool ParseModule(bool Resume);
bool ParseTypeTable();
bool ParseTypeTableBody();
bool ParseGlobalVars();
bool ParseValueSymbolTable();
bool ParseConstants();
bool RememberAndSkipFunctionBody();
bool ParseFunctionBody(Function *F);
bool GlobalCleanup();
bool InitStream();
bool InitStreamFromBuffer();
bool InitLazyStream();
bool FindFunctionInStream(Function *F,
DenseMap<Function*, uint64_t>::iterator DeferredFunctionInfoIterator);
};
} // End llvm namespace
#endif