blob: 0eb6d7cbbafc2dc87940cafa26c565d507582c4a [file] [log] [blame]
//===- subzero/src/PNaClTranslator.cpp - ICE from bitcode -----------------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PNaCl bitcode file to Ice, to machine code
// translator.
//
//===----------------------------------------------------------------------===//
#include "PNaClTranslator.h"
#include "IceCfg.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ValueHandle.h"
#include <vector>
#include <cassert>
using namespace llvm;
namespace {
// Top-level class to read PNaCl bitcode files, and translate to ICE.
class TopLevelParser : public NaClBitcodeParser {
TopLevelParser(const TopLevelParser &) LLVM_DELETED_FUNCTION;
TopLevelParser &operator=(const TopLevelParser &) LLVM_DELETED_FUNCTION;
public:
TopLevelParser(const std::string &InputName, NaClBitcodeHeader &Header,
NaClBitstreamCursor &Cursor, bool &ErrorStatus)
: NaClBitcodeParser(Cursor),
Mod(new Module(InputName, getGlobalContext())), Header(Header),
ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
GlobalVarPlaceHolderType(Type::getInt8Ty(getLLVMContext())) {
Mod->setDataLayout(PNaClDataLayout);
}
virtual ~TopLevelParser() {}
LLVM_OVERRIDE;
virtual bool Error(const std::string &Message) LLVM_OVERRIDE {
ErrorStatus = true;
++NumErrors;
return NaClBitcodeParser::Error(Message);
}
/// Returns the number of errors found while parsing the bitcode
/// file.
unsigned getNumErrors() const { return NumErrors; }
/// Returns the LLVM module associated with the translation.
Module *getModule() const { return Mod.get(); }
/// Returns the number of bytes in the bitcode header.
size_t getHeaderSize() const { return Header.getHeaderSize(); }
/// Returns the llvm context to use.
LLVMContext &getLLVMContext() const { return Mod->getContext(); }
/// Changes the size of the type list to the given size.
void resizeTypeIDValues(unsigned NewSize) { TypeIDValues.resize(NewSize); }
/// Returns the type associated with the given index.
Type *getTypeByID(unsigned ID) {
// Note: method resizeTypeIDValues expands TypeIDValues
// to the specified size, and fills elements with NULL.
Type *Ty = ID < TypeIDValues.size() ? TypeIDValues[ID] : NULL;
if (Ty)
return Ty;
return reportTypeIDAsUndefined(ID);
}
/// Defines type for ID.
void setTypeID(unsigned ID, Type *Ty) {
if (ID < TypeIDValues.size() && TypeIDValues[ID] == NULL) {
TypeIDValues[ID] = Ty;
return;
}
reportBadSetTypeID(ID, Ty);
}
/// Sets the next function ID to the given LLVM function.
void setNextFunctionID(Function *Fcn) {
++NumFunctionIds;
ValueIDValues.push_back(Fcn);
}
/// Defines the next function ID as one that has an implementation
/// (i.e a corresponding function block in the bitcode).
void setNextValueIDAsImplementedFunction() {
DefiningFunctionsList.push_back(ValueIDValues.size());
}
/// Returns the LLVM IR value associatd with the global value ID.
Value *getGlobalValueByID(unsigned ID) const {
if (ID >= ValueIDValues.size())
return 0;
return ValueIDValues[ID];
}
/// Returns the number of function addresses (i.e. ID's) defined in
/// the bitcode file.
unsigned getNumFunctionIDs() const { return NumFunctionIds; }
/// Returns the number of global values defined in the bitcode
/// file.
unsigned getNumGlobalValueIDs() const { return ValueIDValues.size(); }
/// Resizes the list of value IDs to include Count global variable
/// IDs.
void resizeValueIDsForGlobalVarCount(unsigned Count) {
ValueIDValues.resize(ValueIDValues.size() + Count);
}
/// Returns the global variable address associated with the given
/// value ID. If the ID refers to a global variable address not yet
/// defined, a placeholder is created so that we can fix it up
/// later.
Constant *getOrCreateGlobalVarRef(unsigned ID) {
if (ID >= ValueIDValues.size())
return 0;
if (Value *C = ValueIDValues[ID])
return dyn_cast<Constant>(C);
Constant *C = new GlobalVariable(*Mod, GlobalVarPlaceHolderType, false,
GlobalValue::ExternalLinkage, 0);
ValueIDValues[ID] = C;
return C;
}
/// Assigns the given global variable (address) to the given value
/// ID. Returns true if ID is a valid global variable ID. Otherwise
/// returns false.
bool assignGlobalVariable(GlobalVariable *GV, unsigned ID) {
if (ID < NumFunctionIds || ID >= ValueIDValues.size())
return false;
WeakVH &OldV = ValueIDValues[ID];
if (OldV == 0) {
ValueIDValues[ID] = GV;
return true;
}
// If reached, there was a forward reference to this value. Replace it.
Value *PrevVal = OldV;
GlobalVariable *Placeholder = cast<GlobalVariable>(PrevVal);
Placeholder->replaceAllUsesWith(
ConstantExpr::getBitCast(GV, Placeholder->getType()));
Placeholder->eraseFromParent();
ValueIDValues[ID] = GV;
return true;
}
private:
// The parsed module.
OwningPtr<Module> Mod;
// The bitcode header.
NaClBitcodeHeader &Header;
// The exit status that should be set to true if an error occurs.
bool &ErrorStatus;
// The number of errors reported.
unsigned NumErrors;
// The types associated with each type ID.
std::vector<Type *> TypeIDValues;
// The (global) value IDs.
std::vector<WeakVH> ValueIDValues;
// The number of function IDs.
unsigned NumFunctionIds;
// The list of value IDs (in the order found) of defining function
// addresses.
std::vector<unsigned> DefiningFunctionsList;
// Cached global variable placeholder type. Used for all forward
// references to global variable addresses.
Type *GlobalVarPlaceHolderType;
virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
/// Reports that type ID is undefined, and then returns
/// the void type.
Type *reportTypeIDAsUndefined(unsigned ID);
/// Reports error about bad call to setTypeID.
void reportBadSetTypeID(unsigned ID, Type *Ty);
};
Type *TopLevelParser::reportTypeIDAsUndefined(unsigned ID) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't find type for type id: " << ID;
Error(StrBuf.str());
Type *Ty = Type::getVoidTy(getLLVMContext());
// To reduce error messages, update type list if possible.
if (ID < TypeIDValues.size())
TypeIDValues[ID] = Ty;
return Ty;
}
void TopLevelParser::reportBadSetTypeID(unsigned ID, Type *Ty) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
if (ID >= TypeIDValues.size()) {
StrBuf << "Type index " << ID << " out of range: can't install.";
} else {
// Must be case that index already defined.
StrBuf << "Type index " << ID << " defined as " << *TypeIDValues[ID]
<< " and " << *Ty << ".";
}
Error(StrBuf.str());
}
// Base class for parsing blocks within the bitcode file. Note:
// Because this is the base class of block parsers, we generate error
// messages if ParseBlock or ParseRecord is not overridden in derived
// classes.
class BlockParserBaseClass : public NaClBitcodeParser {
public:
// Constructor for the top-level module block parser.
BlockParserBaseClass(unsigned BlockID, TopLevelParser *Context)
: NaClBitcodeParser(BlockID, Context), Context(Context) {}
virtual ~BlockParserBaseClass() LLVM_OVERRIDE {}
protected:
// The context parser that contains the decoded state.
TopLevelParser *Context;
// Constructor for nested block parsers.
BlockParserBaseClass(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: NaClBitcodeParser(BlockID, EnclosingParser),
Context(EnclosingParser->Context) {}
// Generates an error Message with the bit address prefixed to it.
virtual bool Error(const std::string &Message) LLVM_OVERRIDE {
uint64_t Bit = Record.GetStartBit() + Context->getHeaderSize() * 8;
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "(" << format("%" PRIu64 ":%u", (Bit / 8),
static_cast<unsigned>(Bit % 8)) << ") " << Message;
return Context->Error(StrBuf.str());
}
// Default implementation. Reports that block is unknown and skips
// its contents.
virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
// Default implementation. Reports that the record is not
// understood.
virtual void ProcessRecord() LLVM_OVERRIDE;
/// Checks if the size of the record is Size. If not, an error is
/// produced using the given RecordName. Return true if error was
/// reported. Otherwise false.
bool checkRecordSize(unsigned Size, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() != Size) {
return RecordSizeError(Size, RecordName, 0);
}
return false;
}
/// Checks if the size of the record is at least as large as the
/// LowerLimit.
bool checkRecordSizeAtLeast(unsigned LowerLimit, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() < LowerLimit) {
return RecordSizeError(LowerLimit, RecordName, "at least");
}
return false;
}
/// Checks if the size of the record is no larger than the
/// UpperLimit.
bool checkRecordSizeNoMoreThan(unsigned UpperLimit, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() > UpperLimit) {
return RecordSizeError(UpperLimit, RecordName, "no more than");
}
return false;
}
/// Checks if the size of the record is at least as large as the
/// LowerLimit, and no larger than the UpperLimit.
bool checkRecordSizeInRange(unsigned LowerLimit, unsigned UpperLimit,
const char *RecordName) {
return checkRecordSizeAtLeast(LowerLimit, RecordName) ||
checkRecordSizeNoMoreThan(UpperLimit, RecordName);
}
private:
/// Generates a record size error. ExpectedSize is the number
/// of elements expected. RecordName is the name of the kind of
/// record that has incorrect size. ContextMessage (if not 0)
/// is appended to "record expects" to describe how ExpectedSize
/// should be interpreted.
bool RecordSizeError(unsigned ExpectedSize, const char *RecordName,
const char *ContextMessage) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << RecordName << " record expects";
if (ContextMessage)
StrBuf << " " << ContextMessage;
StrBuf << " " << ExpectedSize << " argument";
if (ExpectedSize > 1)
StrBuf << "s";
StrBuf << ". Found: " << Record.GetValues().size();
return Error(StrBuf.str());
}
};
bool BlockParserBaseClass::ParseBlock(unsigned BlockID) {
// If called, derived class doesn't know how to handle block.
// Report error and skip.
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Don't know how to parse block id: " << BlockID;
Error(StrBuf.str());
SkipBlock();
return false;
}
void BlockParserBaseClass::ProcessRecord() {
// If called, derived class doesn't know how to handle.
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Don't know how to process record: " << Record;
Error(StrBuf.str());
}
// Class to parse a types block.
class TypesParser : public BlockParserBaseClass {
public:
TypesParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser), NextTypeId(0) {}
~TypesParser() LLVM_OVERRIDE {}
private:
// The type ID that will be associated with the next type defining
// record in the types block.
unsigned NextTypeId;
virtual void ProcessRecord() LLVM_OVERRIDE;
};
void TypesParser::ProcessRecord() {
Type *Ty = NULL;
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
switch (Record.GetCode()) {
case naclbitc::TYPE_CODE_NUMENTRY:
// NUMENTRY: [numentries]
if (checkRecordSize(1, "Type count"))
return;
Context->resizeTypeIDValues(Values[0]);
return;
case naclbitc::TYPE_CODE_VOID:
// VOID
if (checkRecordSize(0, "Type void"))
break;
Ty = Type::getVoidTy(Context->getLLVMContext());
break;
case naclbitc::TYPE_CODE_FLOAT:
// FLOAT
if (checkRecordSize(0, "Type float"))
break;
Ty = Type::getFloatTy(Context->getLLVMContext());
break;
case naclbitc::TYPE_CODE_DOUBLE:
// DOUBLE
if (checkRecordSize(0, "Type double"))
break;
Ty = Type::getDoubleTy(Context->getLLVMContext());
break;
case naclbitc::TYPE_CODE_INTEGER:
// INTEGER: [width]
if (checkRecordSize(1, "Type integer"))
break;
Ty = IntegerType::get(Context->getLLVMContext(), Values[0]);
// TODO(kschimpf) Check if size is legal.
break;
case naclbitc::TYPE_CODE_VECTOR:
// VECTOR: [numelts, eltty]
if (checkRecordSize(2, "Type vector"))
break;
Ty = VectorType::get(Context->getTypeByID(Values[1]), Values[0]);
break;
case naclbitc::TYPE_CODE_FUNCTION: {
// FUNCTION: [vararg, retty, paramty x N]
if (checkRecordSizeAtLeast(2, "Type signature"))
break;
SmallVector<Type *, 8> ArgTys;
for (unsigned i = 2, e = Values.size(); i != e; ++i) {
ArgTys.push_back(Context->getTypeByID(Values[i]));
}
Ty = FunctionType::get(Context->getTypeByID(Values[1]), ArgTys, Values[0]);
break;
}
default:
BlockParserBaseClass::ProcessRecord();
break;
}
// If Ty not defined, assume error. Use void as filler.
if (Ty == NULL)
Ty = Type::getVoidTy(Context->getLLVMContext());
Context->setTypeID(NextTypeId++, Ty);
}
/// Parses the globals block (i.e. global variables).
class GlobalsParser : public BlockParserBaseClass {
public:
GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0),
Alignment(1), IsConstant(false) {
NextGlobalID = Context->getNumFunctionIDs();
}
virtual ~GlobalsParser() LLVM_OVERRIDE {}
private:
// Holds the sequence of initializers for the global.
SmallVector<Constant *, 10> Initializers;
// Keeps track of how many initializers are expected for
// the global variable being built.
unsigned InitializersNeeded;
// The alignment assumed for the global variable being built.
unsigned Alignment;
// True if the global variable being built is a constant.
bool IsConstant;
// The index of the next global variable.
unsigned NextGlobalID;
virtual void ExitBlock() LLVM_OVERRIDE {
verifyNoMissingInitializers();
unsigned NumIDs = Context->getNumGlobalValueIDs();
if (NextGlobalID < NumIDs) {
unsigned NumFcnIDs = Context->getNumFunctionIDs();
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Globals block expects " << (NumIDs - NumFcnIDs)
<< " global definitions. Found: " << (NextGlobalID - NumFcnIDs);
Error(StrBuf.str());
}
BlockParserBaseClass::ExitBlock();
}
virtual void ProcessRecord() LLVM_OVERRIDE;
// Checks if the number of initializers needed is the same as the
// number found in the bitcode file. If different, and error message
// is generated, and the internal state of the parser is fixed so
// this condition is no longer violated.
void verifyNoMissingInitializers() {
if (InitializersNeeded != Initializers.size()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Global variable @g"
<< (NextGlobalID - Context->getNumFunctionIDs()) << " expected "
<< InitializersNeeded << " initializer";
if (InitializersNeeded > 1)
StrBuf << "s";
StrBuf << ". Found: " << Initializers.size();
Error(StrBuf.str());
// Fix up state so that we can continue.
InitializersNeeded = Initializers.size();
installGlobalVar();
}
}
// Reserves a slot in the list of initializers being built. If there
// isn't room for the slot, an error message is generated.
void reserveInitializer(const char *RecordName) {
if (InitializersNeeded <= Initializers.size()) {
Error(std::string(RecordName) +
" record: Too many initializers, ignoring.");
}
}
// Takes the initializers (and other parser state values) and
// installs a global variable (with the initializers) into the list
// of ValueIDs.
void installGlobalVar() {
Constant *Init = NULL;
switch (Initializers.size()) {
case 0:
Error("No initializer for global variable in global vars block");
return;
case 1:
Init = Initializers[0];
break;
default:
Init = ConstantStruct::getAnon(Context->getLLVMContext(), Initializers,
true);
break;
}
GlobalVariable *GV =
new GlobalVariable(*Context->getModule(), Init->getType(), IsConstant,
GlobalValue::InternalLinkage, Init, "");
GV->setAlignment(Alignment);
if (!Context->assignGlobalVariable(GV, NextGlobalID)) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Defining global V[" << NextGlobalID
<< "] not allowed. Out of range.";
Error(StrBuf.str());
}
++NextGlobalID;
Initializers.clear();
InitializersNeeded = 0;
Alignment = 1;
IsConstant = false;
}
};
void GlobalsParser::ProcessRecord() {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
switch (Record.GetCode()) {
case naclbitc::GLOBALVAR_COUNT:
// COUNT: [n]
if (checkRecordSize(1, "Globals count"))
return;
if (NextGlobalID != Context->getNumFunctionIDs()) {
Error("Globals count record not first in block.");
return;
}
verifyNoMissingInitializers();
Context->resizeValueIDsForGlobalVarCount(Values[0]);
return;
case naclbitc::GLOBALVAR_VAR: {
// VAR: [align, isconst]
if (checkRecordSize(2, "Globals variable"))
return;
verifyNoMissingInitializers();
InitializersNeeded = 1;
Initializers.clear();
Alignment = (1 << Values[0]) >> 1;
IsConstant = Values[1] != 0;
return;
}
case naclbitc::GLOBALVAR_COMPOUND:
// COMPOUND: [size]
if (checkRecordSize(1, "globals compound"))
return;
if (Initializers.size() > 0 || InitializersNeeded != 1) {
Error("Globals compound record not first initializer");
return;
}
if (Values[0] < 2) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Globals compound record size invalid. Found: " << Values[0];
Error(StrBuf.str());
return;
}
InitializersNeeded = Values[0];
return;
case naclbitc::GLOBALVAR_ZEROFILL: {
// ZEROFILL: [size]
if (checkRecordSize(1, "Globals zerofill"))
return;
reserveInitializer("Globals zerofill");
Type *Ty =
ArrayType::get(Type::getInt8Ty(Context->getLLVMContext()), Values[0]);
Constant *Zero = ConstantAggregateZero::get(Ty);
Initializers.push_back(Zero);
break;
}
case naclbitc::GLOBALVAR_DATA: {
// DATA: [b0, b1, ...]
if (checkRecordSizeAtLeast(1, "Globals data"))
return;
reserveInitializer("Globals data");
unsigned Size = Values.size();
SmallVector<uint8_t, 32> Buf;
for (unsigned i = 0; i < Size; ++i)
Buf.push_back(static_cast<uint8_t>(Values[i]));
Constant *Init = ConstantDataArray::get(
Context->getLLVMContext(), ArrayRef<uint8_t>(Buf.data(), Buf.size()));
Initializers.push_back(Init);
break;
}
case naclbitc::GLOBALVAR_RELOC: {
// RELOC: [val, [addend]]
if (checkRecordSizeInRange(1, 2, "Globals reloc"))
return;
Constant *BaseVal = Context->getOrCreateGlobalVarRef(Values[0]);
if (BaseVal == 0) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't find global relocation value: " << Values[0];
Error(StrBuf.str());
return;
}
Type *IntPtrType = IntegerType::get(Context->getLLVMContext(), 32);
Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType);
if (Values.size() == 2) {
Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, Values[1]));
}
Initializers.push_back(Val);
break;
}
default:
BlockParserBaseClass::ProcessRecord();
return;
}
// If reached, just processed another initializer. See if time
// to install global.
if (InitializersNeeded == Initializers.size())
installGlobalVar();
}
// Parses a valuesymtab block in the bitcode file.
class ValuesymtabParser : public BlockParserBaseClass {
typedef SmallString<128> StringType;
public:
ValuesymtabParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser,
bool AllowBbEntries)
: BlockParserBaseClass(BlockID, EnclosingParser),
AllowBbEntries(AllowBbEntries) {}
virtual ~ValuesymtabParser() LLVM_OVERRIDE {}
private:
// True if entries to name basic blocks allowed.
bool AllowBbEntries;
virtual void ProcessRecord() LLVM_OVERRIDE;
void ConvertToString(StringType &ConvertedName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
for (size_t i = 1, e = Values.size(); i != e; ++i) {
ConvertedName += static_cast<char>(Values[i]);
}
}
};
void ValuesymtabParser::ProcessRecord() {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
StringType ConvertedName;
switch (Record.GetCode()) {
case naclbitc::VST_CODE_ENTRY: {
// VST_ENTRY: [ValueId, namechar x N]
if (checkRecordSizeAtLeast(2, "Valuesymtab value entry"))
return;
ConvertToString(ConvertedName);
Value *V = Context->getGlobalValueByID(Values[0]);
if (V == 0) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid global address ID in valuesymtab: " << Values[0];
Error(StrBuf.str());
return;
}
V->setName(StringRef(ConvertedName.data(), ConvertedName.size()));
return;
}
case naclbitc::VST_CODE_BBENTRY: {
// VST_BBENTRY: [BbId, namechar x N]
// For now, since we aren't processing function blocks, don't handle.
if (AllowBbEntries) {
Error("Valuesymtab bb entry not implemented");
return;
}
break;
}
default:
break;
}
// If reached, don't know how to handle record.
BlockParserBaseClass::ProcessRecord();
return;
}
/// Parses the module block in the bitcode file.
class ModuleParser : public BlockParserBaseClass {
public:
ModuleParser(unsigned BlockID, TopLevelParser *Context)
: BlockParserBaseClass(BlockID, Context) {}
virtual ~ModuleParser() LLVM_OVERRIDE {}
protected:
virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
virtual void ProcessRecord() LLVM_OVERRIDE;
};
bool ModuleParser::ParseBlock(unsigned BlockID) LLVM_OVERRIDE {
switch (BlockID) {
case naclbitc::BLOCKINFO_BLOCK_ID:
return NaClBitcodeParser::ParseBlock(BlockID);
case naclbitc::TYPE_BLOCK_ID_NEW: {
TypesParser Parser(BlockID, this);
return Parser.ParseThisBlock();
}
case naclbitc::GLOBALVAR_BLOCK_ID: {
GlobalsParser Parser(BlockID, this);
return Parser.ParseThisBlock();
}
case naclbitc::VALUE_SYMTAB_BLOCK_ID: {
ValuesymtabParser Parser(BlockID, this, false);
return Parser.ParseThisBlock();
}
case naclbitc::FUNCTION_BLOCK_ID: {
Error("Function block parser not yet implemented, skipping");
SkipBlock();
return false;
}
default:
return BlockParserBaseClass::ParseBlock(BlockID);
}
}
void ModuleParser::ProcessRecord() {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
switch (Record.GetCode()) {
case naclbitc::MODULE_CODE_VERSION: {
// VERSION: [version#]
if (checkRecordSize(1, "Module version"))
return;
unsigned Version = Values[0];
if (Version != 1) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Unknown bitstream version: " << Version;
Error(StrBuf.str());
}
return;
}
case naclbitc::MODULE_CODE_FUNCTION: {
// FUNCTION: [type, callingconv, isproto, linkage]
if (checkRecordSize(4, "Function heading"))
return;
Type *Ty = Context->getTypeByID(Values[0]);
FunctionType *FTy = dyn_cast<FunctionType>(Ty);
if (FTy == 0) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function heading expects function type. Found: " << Ty;
Error(StrBuf.str());
return;
}
CallingConv::ID CallingConv;
if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function heading has unknown calling convention: "
<< Values[1];
Error(StrBuf.str());
return;
}
GlobalValue::LinkageTypes Linkage;
if (!naclbitc::DecodeLinkage(Values[3], Linkage)) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function heading has unknown linkage. Found " << Values[3];
Error(StrBuf.str());
return;
}
Function *Func = Function::Create(FTy, Linkage, "", Context->getModule());
Func->setCallingConv(CallingConv);
if (Values[2] == 0)
Context->setNextValueIDAsImplementedFunction();
Context->setNextFunctionID(Func);
// TODO(kschimpf) verify if Func matches PNaCl ABI.
return;
}
default:
BlockParserBaseClass::ProcessRecord();
return;
}
}
bool TopLevelParser::ParseBlock(unsigned BlockID) {
if (BlockID == naclbitc::MODULE_BLOCK_ID) {
ModuleParser Parser(BlockID, this);
bool ReturnValue = Parser.ParseThisBlock();
// TODO(kschimpf): Remove once translating function blocks.
errs() << "Global addresses:\n";
for (size_t i = 0; i < ValueIDValues.size(); ++i) {
errs() << "[" << i << "]: " << *ValueIDValues[i] << "\n";
}
return ReturnValue;
}
// Generate error message by using default block implementation.
BlockParserBaseClass Parser(BlockID, this);
return Parser.ParseThisBlock();
}
} // end of anonymous namespace
namespace Ice {
void PNaClTranslator::translate(const std::string &IRFilename) {
OwningPtr<MemoryBuffer> MemBuf;
if (error_code ec =
MemoryBuffer::getFileOrSTDIN(IRFilename.c_str(), MemBuf)) {
errs() << "Error reading '" << IRFilename << "': " << ec.message() << "\n";
ErrorStatus = true;
return;
}
if (MemBuf->getBufferSize() % 4 != 0) {
errs() << IRFilename
<< ": Bitcode stream should be a multiple of 4 bytes in length.\n";
ErrorStatus = true;
return;
}
const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart();
const unsigned char *EndBufPtr = BufPtr + MemBuf->getBufferSize();
// Read header and verify it is good.
NaClBitcodeHeader Header;
if (Header.Read(BufPtr, EndBufPtr) || !Header.IsSupported()) {
errs() << "Invalid PNaCl bitcode header.\n";
ErrorStatus = true;
return;
}
// Create a bitstream reader to read the bitcode file.
NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr);
NaClBitstreamCursor InputStream(InputStreamFile);
TopLevelParser Parser(MemBuf->getBufferIdentifier(), Header, InputStream,
ErrorStatus);
int TopLevelBlocks = 0;
while (!InputStream.AtEndOfStream()) {
if (Parser.Parse()) {
ErrorStatus = true;
return;
}
++TopLevelBlocks;
}
if (TopLevelBlocks != 1) {
errs() << IRFilename
<< ": Contains more than one module. Found: " << TopLevelBlocks
<< "\n";
ErrorStatus = true;
}
return;
}
} // end of namespace Ice