blob: 8c42af1475d58178e9c60fb91fda331cf72ef791 [file] [log] [blame] [edit]
//===- 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;
std::vector<StructType *> getIdentifiedStructTypes() const 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);
// GVMaterializer interface. It's a no-op for PNaCl bitcode, which has no
// metadata.
std::error_code materializeMetadata() override { return std::error_code(); };
// GVMaterializer interface. Causes debug info to be stripped from the module
// on materialization. It's a no-op for PNaCl bitcode, which has no metadata.
void setStripDebugInfo() override {};
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