Commit 8d7abae9 by Karl Schimpf

Update Subzero to start parsing PNaCl bitcode files.

This patch only handles global addresses in PNaCl bitcode files. Function blocks are still not parsed. Also, factors out a common API for translation, so that generated ICE can always be translated using the same code. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3892 R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/361733002
parent de4ca71e
...@@ -30,7 +30,7 @@ LLVM_LDFLAGS := `$(LLVM_BIN_PATH)/llvm-config --ldflags --libs` ...@@ -30,7 +30,7 @@ LLVM_LDFLAGS := `$(LLVM_BIN_PATH)/llvm-config --ldflags --libs`
OPTLEVEL := -O0 OPTLEVEL := -O0
CXX := g++ CXX := g++
CXXFLAGS := -Wall -Wextra -Werror -fno-rtti -fno-exceptions \ CXXFLAGS := -Wall -Wextra -Werror -fno-rtti -fno-exceptions \
$(OPTLEVEL) -g $(LLVM_CXXFLAGS) -m32 $(OPTLEVEL) -g $(LLVM_CXXFLAGS) -m32 -Wno-error=unused-parameter
LDFLAGS := -m32 LDFLAGS := -m32
SRCS= \ SRCS= \
...@@ -46,8 +46,10 @@ SRCS= \ ...@@ -46,8 +46,10 @@ SRCS= \
IceRegAlloc.cpp \ IceRegAlloc.cpp \
IceTargetLowering.cpp \ IceTargetLowering.cpp \
IceTargetLoweringX8632.cpp \ IceTargetLoweringX8632.cpp \
IceTranslator.cpp \
IceTypes.cpp \ IceTypes.cpp \
llvm2ice.cpp llvm2ice.cpp \
PNaClTranslator.cpp
OBJS=$(patsubst %.cpp, build/%.o, $(SRCS)) OBJS=$(patsubst %.cpp, build/%.o, $(SRCS))
......
//===- subzero/src/IceClFlags.h - Cl Flags for translation ------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares command line flags controlling translation.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICECLFLAGS_H
#define SUBZERO_SRC_ICECLFLAGS_H
namespace Ice {
class ClFlags {
public:
ClFlags()
: DisableInternal(false), SubzeroTimingEnabled(false),
DisableTranslation(false) {}
bool DisableInternal;
bool SubzeroTimingEnabled;
bool DisableTranslation;
};
}
#endif // SUBZERO_SRC_ICECLFLAGS_H
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
#include "IceCfg.h" #include "IceCfg.h"
#include "IceCfgNode.h" #include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceGlobalContext.h" #include "IceGlobalContext.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTargetLowering.h"
#include "IceTypes.h" #include "IceTypes.h"
#include "llvm/IR/Constant.h" #include "llvm/IR/Constant.h"
...@@ -616,64 +616,24 @@ private: ...@@ -616,64 +616,24 @@ private:
std::map<const BasicBlock *, Ice::CfgNode *> NodeMap; std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
}; };
} } // end of anonymous namespace.
int Ice::Converter::convertToIce(llvm::Module *Mod) { int Ice::Converter::convertToIce(llvm::Module *Mod) {
int ExitStatus = 0;
// Ideally, Func would be declared inside the loop and its object
// would be automatically deleted at the end of the loop iteration.
// However, emitting the constant pool requires a valid Cfg object,
// so we need to defer deleting the last non-empty Cfg object until
// outside the loop and after emitting the constant pool. TODO:
// Since all constants are globally pooled in the Ice::GlobalContext
// object, change all Ice::Constant related functions to use
// GlobalContext instead of Cfg, and then clean up this loop.
OwningPtr<Ice::Cfg> Func;
for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
if (I->empty()) if (I->empty())
continue; continue;
LLVM2ICEConverter FunctionConverter(Ctx); LLVM2ICEConverter FunctionConverter(Ctx);
Ice::Timer TConvert; Ice::Timer TConvert;
Func.reset(FunctionConverter.convertFunction(I)); Ice::Cfg *Fcn = FunctionConverter.convertFunction(I);
if (DisableInternal) if (Flags.SubzeroTimingEnabled) {
Func->setInternal(false);
if (SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Convert function " std::cerr << "[Subzero timing] Convert function "
<< Func->getFunctionName() << ": " << TConvert.getElapsedSec() << Fcn->getFunctionName() << ": " << TConvert.getElapsedSec()
<< " sec\n"; << " sec\n";
} }
translateFcn(Fcn);
if (DisableTranslation) {
Func->dump();
} else {
Ice::Timer TTranslate;
Func->translate();
if (SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Translate function "
<< Func->getFunctionName() << ": "
<< TTranslate.getElapsedSec() << " sec\n";
}
if (Func->hasError()) {
errs() << "ICE translation error: " << Func->getError() << "\n";
ExitStatus = 1;
}
Ice::Timer TEmit;
Func->emit();
if (SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Emit function "
<< Func->getFunctionName() << ": " << TEmit.getElapsedSec()
<< " sec\n";
}
}
} }
if (!DisableTranslation && Func) emitConstants();
Func->getTarget()->emitConstants();
return ExitStatus; return ExitStatus;
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#ifndef SUBZERO_SRC_ICECONVERTER_H #ifndef SUBZERO_SRC_ICECONVERTER_H
#define SUBZERO_SRC_ICECONVERTER_H #define SUBZERO_SRC_ICECONVERTER_H
#include "IceGlobalContext.h" #include "IceTranslator.h"
namespace llvm { namespace llvm {
class Module; class Module;
...@@ -22,27 +22,17 @@ class Module; ...@@ -22,27 +22,17 @@ class Module;
namespace Ice { namespace Ice {
class Converter { class Converter : public Translator {
public: public:
Converter(Ice::GlobalContext *Ctx, Converter(GlobalContext *Ctx, Ice::ClFlags &Flags) : Translator(Ctx, Flags) {}
bool DisableInternal,
bool SubzeroTimingEnabled,
bool DisableTranslation)
: Ctx(Ctx),
DisableInternal(DisableInternal),
SubzeroTimingEnabled(SubzeroTimingEnabled),
DisableTranslation(DisableTranslation)
{}
/// Converts the LLVM Module to ICE. Returns exit status 0 if successful, /// Converts the LLVM Module to ICE. Returns exit status 0 if successful,
/// Nonzero otherwise. /// Nonzero otherwise.
int convertToIce(llvm::Module *Mod); int convertToIce(llvm::Module *Mod);
private: private:
Ice::GlobalContext *Ctx; Converter(const Converter &) LLVM_DELETED_FUNCTION;
bool DisableInternal; Converter &operator=(const Converter &) LLVM_DELETED_FUNCTION;
bool SubzeroTimingEnabled;
bool DisableTranslation;
}; };
} }
#endif // SUBZERO_SRC_ICECONVERTER_H #endif // SUBZERO_SRC_ICECONVERTER_H
//===- subzero/src/IceTranslator.cpp - ICE to machine code ------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the general driver class for translating ICE to
// machine code.
//
//===----------------------------------------------------------------------===//
#include "IceTranslator.h"
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceTargetLowering.h"
#include <iostream>
using namespace Ice;
Translator::~Translator() {}
void Translator::translateFcn(Ice::Cfg *Fcn) {
Func.reset(Fcn);
if (Flags.DisableInternal)
Func->setInternal(false);
if (Flags.DisableTranslation) {
Func->dump();
} else {
Ice::Timer TTranslate;
Func->translate();
if (Flags.SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Translate function "
<< Func->getFunctionName() << ": " << TTranslate.getElapsedSec()
<< " sec\n";
}
if (Func->hasError()) {
std::cerr << "ICE translation error: " << Func->getError() << "\n";
ExitStatus = 1;
}
Ice::Timer TEmit;
Func->emit();
if (Flags.SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Emit function " << Func->getFunctionName()
<< ": " << TEmit.getElapsedSec() << " sec\n";
}
}
}
void Translator::emitConstants() {
if (!Flags.DisableTranslation && Func)
Func->getTarget()->emitConstants();
}
//===- subzero/src/IceTranslator.h - ICE to machine code --------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the general driver class for translating ICE to
// machine code.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETRANSLATOR_H
#define SUBZERO_SRC_ICETRANSLATOR_H
#include "llvm/ADT/OwningPtr.h"
namespace Ice {
class ClFlags;
class Cfg;
class GlobalContext;
// Base class for translating ICE to machine code.
// Derived classes convert other intermediate representations down to ICE,
// and then call the appropriate (inherited) methods to convert ICE into
// machine instructions.
class Translator {
public:
Translator(GlobalContext *Ctx, ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), ExitStatus(0) {}
~Translator();
int getExitStatus() const { return ExitStatus; }
protected:
GlobalContext *Ctx;
ClFlags &Flags;
// The exit status of the translation. 0 is successful. Nonzero
// otherwise.
bool ExitStatus;
// Ideally, Func would be inside the methods that converts IR to
// functions. However, emitting the constant pool requires a valid
// Cfg object, so we need to defer deleting the last non-empty Cfg
// object to emit the constant pool (via emitConstants). TODO:
// Since all constants are globally pooled in the GlobalContext
// object, change all Constant related functions to use
// GlobalContext instead of Cfg, and then make emitConstantPool use
// that.
llvm::OwningPtr<Cfg> Func;
/// Translates the constructed ICE function Fcn to machine code.
/// Note: As a side effect, Field Func is set to Fcn.
void translateFcn(Cfg *Fcn);
/// Emits the constant pool.
void emitConstants();
private:
Translator(const Translator &) LLVM_DELETED_FUNCTION;
Translator &operator=(const Translator &) LLVM_DELETED_FUNCTION;
};
}
#endif // SUBZERO_SRC_ICETRANSLATOR_H
//===- 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, int &ExitStatusFlag)
: NaClBitcodeParser(Cursor),
Mod(new Module(InputName, getGlobalContext())), Header(Header),
ExitStatusFlag(ExitStatusFlag), NumErrors(0), NumFunctionIds(0),
GlobalVarPlaceHolderType(Type::getInt8Ty(getLLVMContext())) {
Mod->setDataLayout(PNaClDataLayout);
}
virtual ~TopLevelParser() {}
LLVM_OVERRIDE;
virtual bool Error(const std::string &Message) LLVM_OVERRIDE {
ExitStatusFlag = 1;
++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 flag that should be set to 1 if an error occurs.
int &ExitStatusFlag;
// 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";
ExitStatus = 1;
return;
}
if (MemBuf->getBufferSize() % 4 != 0) {
errs() << IRFilename
<< ": Bitcode stream should be a multiple of 4 bytes in length.\n";
ExitStatus = 1;
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";
ExitStatus = 1;
return;
}
// Create a bitstream reader to read the bitcode file.
NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr);
NaClBitstreamCursor InputStream(InputStreamFile);
TopLevelParser Parser(MemBuf->getBufferIdentifier(), Header, InputStream,
ExitStatus);
int TopLevelBlocks = 0;
while (!InputStream.AtEndOfStream()) {
if (Parser.Parse()) {
ExitStatus = 1;
return;
}
++TopLevelBlocks;
}
if (TopLevelBlocks != 1) {
errs() << IRFilename
<< ": Contains more than one module. Found: " << TopLevelBlocks
<< "\n";
ExitStatus = 1;
}
return;
}
} // end of anonymous namespace.
//===- subzero/src/PNaClTranslator.h - ICE from bitcode ---------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the PNaCl bitcode file to ICE, to machine code
// translator.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_PNACLTRANSLATOR_H
#define SUBZERO_SRC_PNACLTRANSLATOR_H
#include "IceTranslator.h"
#include <string>
namespace Ice {
class PNaClTranslator : public Translator {
public:
PNaClTranslator(GlobalContext *Ctx, ClFlags &Flags)
: Translator(Ctx, Flags) {}
// Reads the PNaCl bitcode file and translates to ICE, which is then
// converted to machine code. Sets ExitStatus to non-zero if any
// errors occurred.
void translate(const std::string &IRFilename);
private:
PNaClTranslator(const PNaClTranslator &) LLVM_DELETED_FUNCTION;
PNaClTranslator &operator=(const PNaClTranslator &) LLVM_DELETED_FUNCTION;
};
}
#endif // SUBZERO_SRC_PNACLTRANSLATOR_H
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "IceCfg.h" #include "IceCfg.h"
#include "IceClFlags.h"
#include "IceConverter.h" #include "IceConverter.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceTargetLowering.h" #include "IceTargetLowering.h"
#include "IceTypes.h" #include "IceTypes.h"
#include "PNaClTranslator.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
...@@ -128,9 +129,15 @@ int main(int argc, char **argv) { ...@@ -128,9 +129,15 @@ int main(int argc, char **argv) {
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix); Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
Ice::ClFlags Flags;
Flags.DisableInternal = DisableInternal;
Flags.SubzeroTimingEnabled = SubzeroTimingEnabled;
Flags.DisableTranslation = DisableTranslation;
if (BuildOnRead) { if (BuildOnRead) {
std::cerr << "Direct build from bitcode not implemented yet!\n"; Ice::PNaClTranslator Translator(&Ctx, Flags);
return 1; Translator.translate(IRFilename);
return Translator.getExitStatus();
} else { } else {
// Parse the input LLVM IR file into a module. // Parse the input LLVM IR file into a module.
SMDiagnostic Err; SMDiagnostic Err;
...@@ -189,8 +196,7 @@ int main(int argc, char **argv) { ...@@ -189,8 +196,7 @@ int main(int argc, char **argv) {
} }
GlobalLowering.reset(); GlobalLowering.reset();
Ice::Converter Converter(&Ctx, DisableInternal, SubzeroTimingEnabled, Ice::Converter Converter(&Ctx, Flags);
DisableTranslation);
return Converter.convertToIce(Mod); return Converter.convertToIce(Mod);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment