Start processing function blocks. Handle binops and returns. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3894 R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/395193005
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp index 0eb6d7c..5381315 100644 --- a/src/PNaClTranslator.cpp +++ b/src/PNaClTranslator.cpp
@@ -14,6 +14,12 @@ #include "PNaClTranslator.h" #include "IceCfg.h" +#include "IceCfgNode.h" +#include "IceClFlags.h" +#include "IceDefs.h" +#include "IceInst.h" +#include "IceOperand.h" +#include "IceTypeConverter.h" #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h" #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" @@ -33,28 +39,42 @@ namespace { +// TODO(kschimpf) Remove error recovery once implementation complete. +static cl::opt<bool> AllowErrorRecovery( + "allow-pnacl-reader-error-recovery", + cl::desc("Allow error recovery when reading PNaCl bitcode."), + cl::init(false)); + // 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), + TopLevelParser(Ice::Translator &Translator, const std::string &InputName, + NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor, + bool &ErrorStatus) + : NaClBitcodeParser(Cursor), Translator(Translator), Mod(new Module(InputName, getGlobalContext())), Header(Header), - ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0), - GlobalVarPlaceHolderType(Type::getInt8Ty(getLLVMContext())) { + TypeConverter(getLLVMContext()), ErrorStatus(ErrorStatus), NumErrors(0), + NumFunctionIds(0), NumFunctionBlocks(0), + GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) { Mod->setDataLayout(PNaClDataLayout); } virtual ~TopLevelParser() {} LLVM_OVERRIDE; + Ice::Translator &getTranslator() { return Translator; } + + // Generates error with given Message. Always returns true. virtual bool Error(const std::string &Message) LLVM_OVERRIDE { ErrorStatus = true; ++NumErrors; - return NaClBitcodeParser::Error(Message); + NaClBitcodeParser::Error(Message); + if (!AllowErrorRecovery) + report_fatal_error("Unable to continue"); + return true; } /// Returns the number of errors found while parsing the bitcode @@ -104,10 +124,20 @@ DefiningFunctionsList.push_back(ValueIDValues.size()); } + /// Returns the value id that should be associated with the the + /// current function block. Increments internal counters during call + /// so that it will be in correct position for next function block. + unsigned getNextFunctionBlockValueID() { + if (NumFunctionBlocks >= DefiningFunctionsList.size()) + report_fatal_error( + "More function blocks than defined function addresses"); + return DefiningFunctionsList[NumFunctionBlocks++]; + } + /// Returns the LLVM IR value associatd with the global value ID. Value *getGlobalValueByID(unsigned ID) const { if (ID >= ValueIDValues.size()) - return 0; + return NULL; return ValueIDValues[ID]; } @@ -131,7 +161,7 @@ /// later. Constant *getOrCreateGlobalVarRef(unsigned ID) { if (ID >= ValueIDValues.size()) - return 0; + return NULL; if (Value *C = ValueIDValues[ID]) return dyn_cast<Constant>(C); Constant *C = new GlobalVariable(*Mod, GlobalVarPlaceHolderType, false, @@ -147,7 +177,7 @@ if (ID < NumFunctionIds || ID >= ValueIDValues.size()) return false; WeakVH &OldV = ValueIDValues[ID]; - if (OldV == 0) { + if (OldV == NULL) { ValueIDValues[ID] = GV; return true; } @@ -162,11 +192,46 @@ return true; } + /// Returns the corresponding ICE type for LLVMTy. + Ice::Type convertToIceType(Type *LLVMTy) { + Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy); + if (IceTy >= Ice::IceType_NUM) { + return convertToIceTypeError(LLVMTy); + } + return IceTy; + } + + /// Returns the corresponding LLVM type for IceTy. + Type *convertToLLVMType(Ice::Type IceTy) const { + return TypeConverter.convertToLLVMType(IceTy); + } + + /// Returns the LLVM integer type with the given number of Bits. If + /// Bits is not a valid PNaCl type, returns NULL. + Type *getLLVMIntegerType(unsigned Bits) const { + return TypeConverter.getLLVMIntegerType(Bits); + } + + /// Returns the LLVM vector with the given Size and Ty. If not a + /// valid PNaCl vector type, returns NULL. + Type *getLLVMVectorType(unsigned Size, Ice::Type Ty) const { + return TypeConverter.getLLVMVectorType(Size, Ty); + } + + /// Returns the model for pointer types in ICE. + Ice::Type getIcePointerType() const { + return TypeConverter.getIcePointerType(); + } + private: + // The translator associated with the parser. + Ice::Translator &Translator; // The parsed module. OwningPtr<Module> Mod; // The bitcode header. NaClBitcodeHeader &Header; + // Converter between LLVM and ICE types. + Ice::TypeConverter TypeConverter; // The exit status that should be set to true if an error occurs. bool &ErrorStatus; // The number of errors reported. @@ -177,6 +242,8 @@ std::vector<WeakVH> ValueIDValues; // The number of function IDs. unsigned NumFunctionIds; + // The number of function blocks (processed so far). + unsigned NumFunctionBlocks; // The list of value IDs (in the order found) of defining function // addresses. std::vector<unsigned> DefiningFunctionsList; @@ -192,6 +259,10 @@ /// Reports error about bad call to setTypeID. void reportBadSetTypeID(unsigned ID, Type *Ty); + + // Reports that there is no corresponding ICE type for LLVMTy, and + // returns ICE::IceType_void. + Ice::Type convertToIceTypeError(Type *LLVMTy); }; Type *TopLevelParser::reportTypeIDAsUndefined(unsigned ID) { @@ -199,7 +270,8 @@ raw_string_ostream StrBuf(Buffer); StrBuf << "Can't find type for type id: " << ID; Error(StrBuf.str()); - Type *Ty = Type::getVoidTy(getLLVMContext()); + // TODO(kschimpf) Remove error recovery once implementation complete. + Type *Ty = TypeConverter.convertToLLVMType(Ice::IceType_void); // To reduce error messages, update type list if possible. if (ID < TypeIDValues.size()) TypeIDValues[ID] = Ty; @@ -219,6 +291,14 @@ Error(StrBuf.str()); } +Ice::Type TopLevelParser::convertToIceTypeError(Type *LLVMTy) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Invalid LLVM type: " << *LLVMTy; + Error(StrBuf.str()); + return Ice::IceType_void; +} + // 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 @@ -240,6 +320,9 @@ : NaClBitcodeParser(BlockID, EnclosingParser), Context(EnclosingParser->Context) {} + // Gets the translator associated with the bitcode parser. + Ice::Translator &getTranslator() { return Context->getTranslator(); } + // 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; @@ -258,66 +341,72 @@ // 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) { + // Checks if the size of the record is Size. Return true if valid. + // Otherwise generates an error and returns false. + bool isValidRecordSize(unsigned Size, const char *RecordName) { const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); - if (Values.size() != Size) { - return RecordSizeError(Size, RecordName, 0); - } + if (Values.size() == Size) + return true; + ReportRecordSizeError(Size, RecordName, NULL); return false; } - /// Checks if the size of the record is at least as large as the - /// LowerLimit. - bool checkRecordSizeAtLeast(unsigned LowerLimit, const char *RecordName) { + // Checks if the size of the record is at least as large as the + // LowerLimit. Returns true if valid. Otherwise generates an error + // and returns false. + bool isValidRecordSizeAtLeast(unsigned LowerLimit, const char *RecordName) { const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); - if (Values.size() < LowerLimit) { - return RecordSizeError(LowerLimit, RecordName, "at least"); - } + if (Values.size() >= LowerLimit) + return true; + ReportRecordSizeError(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) { + // Checks if the size of the record is no larger than the + // UpperLimit. Returns true if valid. Otherwise generates an error + // and returns false. + bool isValidRecordSizeAtMost(unsigned UpperLimit, const char *RecordName) { const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); - if (Values.size() > UpperLimit) { - return RecordSizeError(UpperLimit, RecordName, "no more than"); - } + if (Values.size() <= UpperLimit) + return true; + ReportRecordSizeError(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); + // Checks if the size of the record is at least as large as the + // LowerLimit, and no larger than the UpperLimit. Returns true if + // valid. Otherwise generates an error and returns false. + bool isValidRecordSizeInRange(unsigned LowerLimit, unsigned UpperLimit, + const char *RecordName) { + return isValidRecordSizeAtLeast(LowerLimit, RecordName) || + isValidRecordSizeAtMost(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) + /// record that has incorrect size. ContextMessage (if not NULL) /// 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()); - } + void ReportRecordSizeError(unsigned ExpectedSize, const char *RecordName, + const char *ContextMessage); }; +void BlockParserBaseClass::ReportRecordSizeError(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(); + Error(StrBuf.str()); +} + bool BlockParserBaseClass::ParseBlock(unsigned BlockID) { // If called, derived class doesn't know how to handle block. // Report error and skip. @@ -325,6 +414,7 @@ raw_string_ostream StrBuf(Buffer); StrBuf << "Don't know how to parse block id: " << BlockID; Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. SkipBlock(); return false; } @@ -359,45 +449,64 @@ switch (Record.GetCode()) { case naclbitc::TYPE_CODE_NUMENTRY: // NUMENTRY: [numentries] - if (checkRecordSize(1, "Type count")) + if (!isValidRecordSize(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()); + if (!isValidRecordSize(0, "Type void")) + return; + Ty = Context->convertToLLVMType(Ice::IceType_void); break; case naclbitc::TYPE_CODE_FLOAT: // FLOAT - if (checkRecordSize(0, "Type float")) - break; - Ty = Type::getFloatTy(Context->getLLVMContext()); + if (!isValidRecordSize(0, "Type float")) + return; + Ty = Context->convertToLLVMType(Ice::IceType_f32); break; case naclbitc::TYPE_CODE_DOUBLE: // DOUBLE - if (checkRecordSize(0, "Type double")) - break; - Ty = Type::getDoubleTy(Context->getLLVMContext()); + if (!isValidRecordSize(0, "Type double")) + return; + Ty = Context->convertToLLVMType(Ice::IceType_f64); 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. + if (!isValidRecordSize(1, "Type integer")) + return; + Ty = Context->getLLVMIntegerType(Values[0]); + if (Ty == NULL) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Type integer record with invalid bitsize: " << Values[0]; + Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. + // Fix type so that we can continue. + Ty = Context->convertToLLVMType(Ice::IceType_i32); + } break; - case naclbitc::TYPE_CODE_VECTOR: + case naclbitc::TYPE_CODE_VECTOR: { // VECTOR: [numelts, eltty] - if (checkRecordSize(2, "Type vector")) - break; - Ty = VectorType::get(Context->getTypeByID(Values[1]), Values[0]); + if (!isValidRecordSize(2, "Type vector")) + return; + Type *BaseTy = Context->getTypeByID(Values[1]); + Ty = Context->getLLVMVectorType(Values[0], + Context->convertToIceType(BaseTy)); + if (Ty == NULL) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Invalid type vector record: <" << Values[0] << " x " << *BaseTy + << ">"; + Error(StrBuf.str()); + Ty = Context->convertToLLVMType(Ice::IceType_void); + } break; + } case naclbitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] - if (checkRecordSizeAtLeast(2, "Type signature")) - break; + if (!isValidRecordSizeAtLeast(2, "Type signature")) + return; SmallVector<Type *, 8> ArgTys; for (unsigned i = 2, e = Values.size(); i != e; ++i) { ArgTys.push_back(Context->getTypeByID(Values[i])); @@ -407,11 +516,11 @@ } default: BlockParserBaseClass::ProcessRecord(); - break; + return; } // If Ty not defined, assume error. Use void as filler. if (Ty == NULL) - Ty = Type::getVoidTy(Context->getLLVMContext()); + Ty = Context->convertToLLVMType(Ice::IceType_void); Context->setTypeID(NextTypeId++, Ty); } @@ -474,6 +583,7 @@ StrBuf << "s"; StrBuf << ". Found: " << Initializers.size(); Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. // Fix up state so that we can continue. InitializersNeeded = Initializers.size(); installGlobalVar(); @@ -530,7 +640,7 @@ switch (Record.GetCode()) { case naclbitc::GLOBALVAR_COUNT: // COUNT: [n] - if (checkRecordSize(1, "Globals count")) + if (!isValidRecordSize(1, "Globals count")) return; if (NextGlobalID != Context->getNumFunctionIDs()) { Error("Globals count record not first in block."); @@ -541,7 +651,7 @@ return; case naclbitc::GLOBALVAR_VAR: { // VAR: [align, isconst] - if (checkRecordSize(2, "Globals variable")) + if (!isValidRecordSize(2, "Globals variable")) return; verifyNoMissingInitializers(); InitializersNeeded = 1; @@ -552,7 +662,7 @@ } case naclbitc::GLOBALVAR_COMPOUND: // COMPOUND: [size] - if (checkRecordSize(1, "globals compound")) + if (!isValidRecordSize(1, "globals compound")) return; if (Initializers.size() > 0 || InitializersNeeded != 1) { Error("Globals compound record not first initializer"); @@ -569,18 +679,18 @@ return; case naclbitc::GLOBALVAR_ZEROFILL: { // ZEROFILL: [size] - if (checkRecordSize(1, "Globals zerofill")) + if (!isValidRecordSize(1, "Globals zerofill")) return; reserveInitializer("Globals zerofill"); Type *Ty = - ArrayType::get(Type::getInt8Ty(Context->getLLVMContext()), Values[0]); + ArrayType::get(Context->convertToLLVMType(Ice::IceType_i8), Values[0]); Constant *Zero = ConstantAggregateZero::get(Ty); Initializers.push_back(Zero); break; } case naclbitc::GLOBALVAR_DATA: { // DATA: [b0, b1, ...] - if (checkRecordSizeAtLeast(1, "Globals data")) + if (!isValidRecordSizeAtLeast(1, "Globals data")) return; reserveInitializer("Globals data"); unsigned Size = Values.size(); @@ -594,17 +704,17 @@ } case naclbitc::GLOBALVAR_RELOC: { // RELOC: [val, [addend]] - if (checkRecordSizeInRange(1, 2, "Globals reloc")) + if (!isValidRecordSizeInRange(1, 2, "Globals reloc")) return; Constant *BaseVal = Context->getOrCreateGlobalVarRef(Values[0]); - if (BaseVal == 0) { + if (BaseVal == NULL) { 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); + Type *IntPtrType = Context->convertToLLVMType(Context->getIcePointerType()); Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType); if (Values.size() == 2) { Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, Values[1])); @@ -654,11 +764,11 @@ switch (Record.GetCode()) { case naclbitc::VST_CODE_ENTRY: { // VST_ENTRY: [ValueId, namechar x N] - if (checkRecordSizeAtLeast(2, "Valuesymtab value entry")) + if (!isValidRecordSizeAtLeast(2, "Valuesymtab value entry")) return; ConvertToString(ConvertedName); Value *V = Context->getGlobalValueByID(Values[0]); - if (V == 0) { + if (V == NULL) { std::string Buffer; raw_string_ostream StrBuf(Buffer); StrBuf << "Invalid global address ID in valuesymtab: " << Values[0]; @@ -685,6 +795,354 @@ return; } +/// Parses function blocks in the bitcode file. +class FunctionParser : public BlockParserBaseClass { + FunctionParser(const FunctionParser &) LLVM_DELETED_FUNCTION; + FunctionParser &operator=(const FunctionParser &) LLVM_DELETED_FUNCTION; + +public: + FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser) + : BlockParserBaseClass(BlockID, EnclosingParser), + Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0), + FcnId(Context->getNextFunctionBlockValueID()), + LLVMFunc(cast<Function>(Context->getGlobalValueByID(FcnId))), + CachedNumGlobalValueIDs(Context->getNumGlobalValueIDs()), + InstIsTerminating(false) { + Func->setFunctionName(LLVMFunc->getName()); + Func->setReturnType(Context->convertToIceType(LLVMFunc->getReturnType())); + Func->setInternal(LLVMFunc->hasInternalLinkage()); + CurrentNode = InstallNextBasicBlock(); + for (Function::const_arg_iterator ArgI = LLVMFunc->arg_begin(), + ArgE = LLVMFunc->arg_end(); + ArgI != ArgE; ++ArgI) { + Func->addArg(NextInstVar(Context->convertToIceType(ArgI->getType()))); + } + } + + ~FunctionParser() LLVM_OVERRIDE; + +private: + // Timer for reading function bitcode and converting to ICE. + Ice::Timer TConvert; + // The corresponding ICE function defined by the function block. + Ice::Cfg *Func; + // The index to the current basic block being built. + uint32_t CurrentBbIndex; + // The basic block being built. + Ice::CfgNode *CurrentNode; + // The ID for the function. + unsigned FcnId; + // The corresponding LLVM function. + Function *LLVMFunc; + // Holds operands local to the function block, based on indices + // defined in the bitcode file. + std::vector<Ice::Operand *> LocalOperands; + // Holds the dividing point between local and global absolute value indices. + uint32_t CachedNumGlobalValueIDs; + // True if the last processed instruction was a terminating + // instruction. + bool InstIsTerminating; + + virtual void ProcessRecord() LLVM_OVERRIDE; + + virtual void ExitBlock() LLVM_OVERRIDE; + + // Creates and appends a new basic block to the list of basic blocks. + Ice::CfgNode *InstallNextBasicBlock() { return Func->makeNode(); } + + // Returns the Index-th basic block in the list of basic blocks. + Ice::CfgNode *GetBasicBlock(uint32_t Index) { + const Ice::NodeList &Nodes = Func->getNodes(); + if (Index >= Nodes.size()) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Reference to basic block " << Index + << " not found. Must be less than " << Nodes.size(); + Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. + Index = 0; + } + return Nodes[Index]; + } + + // Generates the next available local variable using the given + // type. Note: if Ty is void, this function returns NULL. + Ice::Variable *NextInstVar(Ice::Type Ty) { + if (Ty == Ice::IceType_void) + return NULL; + Ice::Variable *Var = Func->makeVariable(Ty, CurrentNode); + LocalOperands.push_back(Var); + return Var; + } + + // Converts a relative index (to the next instruction to be read) to + // an absolute value index. + uint32_t convertRelativeToAbsIndex(int32_t Id) { + int32_t AbsNextId = CachedNumGlobalValueIDs + LocalOperands.size(); + if (Id > 0 && AbsNextId < static_cast<uint32_t>(Id)) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Invalid relative value id: " << Id + << " (must be <= " << AbsNextId << ")"; + Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. + return 0; + } + return AbsNextId - Id; + } + + // Returns the value referenced by the given value Index. + Ice::Operand *getOperand(uint32_t Index) { + if (Index < CachedNumGlobalValueIDs) { + // TODO(kschimpf): Define implementation. + report_fatal_error("getOperand of global addresses not implemented"); + } + uint32_t LocalIndex = Index - CachedNumGlobalValueIDs; + if (LocalIndex >= LocalOperands.size()) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Value index " << Index << " out of range. Must be less than " + << (LocalOperands.size() + CachedNumGlobalValueIDs); + Error(StrBuf.str()); + report_fatal_error("Unable to continue"); + } + return LocalOperands[LocalIndex]; + } + + // Generates type error message for binary operator Op + // operating on Type OpTy. + void ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy); + + // Validates if integer logical Op, for type OpTy, is valid. + // Returns true if valid. Otherwise generates error message and + // returns false. + bool isValidIntegerLogicalOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) { + if (Ice::isIntegerType(OpTy)) + return true; + ReportInvalidBinaryOp(Op, OpTy); + return false; + } + + // Validates if integer (or vector of integers) arithmetic Op, for type + // OpTy, is valid. Returns true if valid. Otherwise generates + // error message and returns false. + bool isValidIntegerArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) { + if (Ice::isIntegerArithmeticType(OpTy)) + return true; + ReportInvalidBinaryOp(Op, OpTy); + return false; + } + + // Checks if floating arithmetic Op, for type OpTy, is valid. + // Returns false if valid. Otherwise generates an error message and + // returns true. + bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) { + if (Ice::isFloatingType(OpTy)) + return true; + ReportInvalidBinaryOp(Op, OpTy); + return false; + } + + // Reports that the given binary Opcode, for the given type Ty, + // is not understood. + void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty); + + // Takes the PNaCl bitcode binary operator Opcode, and the opcode + // type Ty, and sets Op to the corresponding ICE binary + // opcode. Returns true if able to convert, false otherwise. + bool convertBinopOpcode(unsigned Opcode, Ice::Type Ty, + Ice::InstArithmetic::OpKind &Op) { + Instruction::BinaryOps LLVMOpcode; + if (!naclbitc::DecodeBinaryOpcode(Opcode, Context->convertToLLVMType(Ty), + LLVMOpcode)) { + ReportInvalidBinopOpcode(Opcode, Ty); + // TODO(kschimpf) Remove error recovery once implementation complete. + Op = Ice::InstArithmetic::Add; + return false; + } + switch (LLVMOpcode) { + default: { + ReportInvalidBinopOpcode(Opcode, Ty); + // TODO(kschimpf) Remove error recovery once implementation complete. + Op = Ice::InstArithmetic::Add; + return false; + } + case Instruction::Add: + Op = Ice::InstArithmetic::Add; + return isValidIntegerArithOp(Op, Ty); + case Instruction::FAdd: + Op = Ice::InstArithmetic::Fadd; + return isValidFloatingArithOp(Op, Ty); + case Instruction::Sub: + Op = Ice::InstArithmetic::Sub; + return isValidIntegerArithOp(Op, Ty); + case Instruction::FSub: + Op = Ice::InstArithmetic::Fsub; + return isValidFloatingArithOp(Op, Ty); + case Instruction::Mul: + Op = Ice::InstArithmetic::Mul; + return isValidIntegerArithOp(Op, Ty); + case Instruction::FMul: + Op = Ice::InstArithmetic::Fmul; + return isValidFloatingArithOp(Op, Ty); + case Instruction::UDiv: + Op = Ice::InstArithmetic::Udiv; + return isValidIntegerArithOp(Op, Ty); + case Instruction::SDiv: + Op = Ice::InstArithmetic::Sdiv; + return isValidIntegerArithOp(Op, Ty); + case Instruction::FDiv: + Op = Ice::InstArithmetic::Fdiv; + return isValidFloatingArithOp(Op, Ty); + case Instruction::URem: + Op = Ice::InstArithmetic::Urem; + return isValidIntegerArithOp(Op, Ty); + case Instruction::SRem: + Op = Ice::InstArithmetic::Srem; + return isValidIntegerArithOp(Op, Ty); + case Instruction::FRem: + Op = Ice::InstArithmetic::Frem; + return isValidFloatingArithOp(Op, Ty); + case Instruction::Shl: + Op = Ice::InstArithmetic::Shl; + return isValidIntegerArithOp(Op, Ty); + case Instruction::LShr: + Op = Ice::InstArithmetic::Lshr; + return isValidIntegerArithOp(Op, Ty); + case Instruction::AShr: + Op = Ice::InstArithmetic::Ashr; + return isValidIntegerArithOp(Op, Ty); + case Instruction::And: + Op = Ice::InstArithmetic::And; + return isValidIntegerLogicalOp(Op, Ty); + case Instruction::Or: + Op = Ice::InstArithmetic::Or; + return isValidIntegerLogicalOp(Op, Ty); + case Instruction::Xor: + Op = Ice::InstArithmetic::Xor; + return isValidIntegerLogicalOp(Op, Ty); + } + } +}; + +FunctionParser::~FunctionParser() { + if (getTranslator().getFlags().SubzeroTimingEnabled) { + errs() << "[Subzero timing] Convert function " << Func->getFunctionName() + << ": " << TConvert.getElapsedSec() << " sec\n"; + } +} + +void FunctionParser::ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Binary opcode " << Opcode << "not understood for type " << Ty; + Error(StrBuf.str()); +} + +void FunctionParser::ExitBlock() { + // Before translating, check for blocks without instructions, and + // insert unreachable. This shouldn't happen, but be safe. + unsigned Index = 0; + const Ice::NodeList &Nodes = Func->getNodes(); + for (std::vector<Ice::CfgNode *>::const_iterator Iter = Nodes.begin(), + IterEnd = Nodes.end(); + Iter != IterEnd; ++Iter, ++Index) { + Ice::CfgNode *Node = *Iter; + if (Node->getInsts().size() == 0) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Basic block " << Index << " contains no instructions"; + Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. + Node->appendInst(Ice::InstUnreachable::create(Func)); + } + } + getTranslator().translateFcn(Func); +} + +void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op, + Ice::Type OpTy) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Invalid operator type for " << Ice::InstArithmetic::getOpName(Op) + << ". Found " << OpTy; + Error(StrBuf.str()); +} + +void FunctionParser::ProcessRecord() { + const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); + if (InstIsTerminating) { + InstIsTerminating = false; + CurrentNode = GetBasicBlock(++CurrentBbIndex); + } + Ice::Inst *Inst = NULL; + switch (Record.GetCode()) { + case naclbitc::FUNC_CODE_DECLAREBLOCKS: { + // DECLAREBLOCKS: [n] + if (!isValidRecordSize(1, "function block count")) + break; + if (Func->getNodes().size() != 1) { + Error("Duplicate function block count record"); + return; + } + uint32_t NumBbs = Values[0]; + if (NumBbs == 0) { + Error("Functions must contain at least one basic block."); + // TODO(kschimpf) Remove error recovery once implementation complete. + NumBbs = 1; + } + // Install the basic blocks, skipping bb0 which was created in the + // constructor. + for (size_t i = 1; i < NumBbs; ++i) + InstallNextBasicBlock(); + break; + } + case naclbitc::FUNC_CODE_INST_BINOP: { + // BINOP: [opval, opval, opcode] + if (!isValidRecordSize(3, "function block binop")) + break; + Ice::Operand *Op1 = getOperand(convertRelativeToAbsIndex(Values[0])); + Ice::Operand *Op2 = getOperand(convertRelativeToAbsIndex(Values[1])); + Ice::Type Type1 = Op1->getType(); + Ice::Type Type2 = Op2->getType(); + if (Type1 != Type2) { + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << "Binop argument types differ: " << Type1 << " and " << Type2; + Error(StrBuf.str()); + // TODO(kschimpf) Remove error recovery once implementation complete. + Op2 = Op1; + } + + Ice::InstArithmetic::OpKind Opcode; + if (!convertBinopOpcode(Values[2], Type1, Opcode)) + break; + Ice::Variable *Dest = NextInstVar(Type1); + Inst = Ice::InstArithmetic::create(Func, Opcode, Dest, Op1, Op2); + break; + } + case naclbitc::FUNC_CODE_INST_RET: { + // RET: [opval?] + InstIsTerminating = true; + if (!isValidRecordSizeInRange(0, 1, "function block ret")) + break; + if (Values.size() == 0) { + Inst = Ice::InstRet::create(Func); + } else { + Inst = Ice::InstRet::create( + Func, getOperand(convertRelativeToAbsIndex(Values[0]))); + } + break; + } + default: + // Generate error message! + BlockParserBaseClass::ProcessRecord(); + break; + } + if (Inst) + CurrentNode->appendInst(Inst); +} + /// Parses the module block in the bitcode file. class ModuleParser : public BlockParserBaseClass { public: @@ -716,9 +1174,8 @@ return Parser.ParseThisBlock(); } case naclbitc::FUNCTION_BLOCK_ID: { - Error("Function block parser not yet implemented, skipping"); - SkipBlock(); - return false; + FunctionParser Parser(BlockID, this); + return Parser.ParseThisBlock(); } default: return BlockParserBaseClass::ParseBlock(BlockID); @@ -730,7 +1187,7 @@ switch (Record.GetCode()) { case naclbitc::MODULE_CODE_VERSION: { // VERSION: [version#] - if (checkRecordSize(1, "Module version")) + if (!isValidRecordSize(1, "Module version")) return; unsigned Version = Values[0]; if (Version != 1) { @@ -743,11 +1200,11 @@ } case naclbitc::MODULE_CODE_FUNCTION: { // FUNCTION: [type, callingconv, isproto, linkage] - if (checkRecordSize(4, "Function heading")) + if (!isValidRecordSize(4, "Function heading")) return; Type *Ty = Context->getTypeByID(Values[0]); FunctionType *FTy = dyn_cast<FunctionType>(Ty); - if (FTy == 0) { + if (FTy == NULL) { std::string Buffer; raw_string_ostream StrBuf(Buffer); StrBuf << "Function heading expects function type. Found: " << Ty; @@ -788,13 +1245,7 @@ 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; + return Parser.ParseThisBlock(); } // Generate error message by using default block implementation. BlockParserBaseClass Parser(BlockID, this); @@ -836,8 +1287,8 @@ NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr); NaClBitstreamCursor InputStream(InputStreamFile); - TopLevelParser Parser(MemBuf->getBufferIdentifier(), Header, InputStream, - ErrorStatus); + TopLevelParser Parser(*this, MemBuf->getBufferIdentifier(), Header, + InputStream, ErrorStatus); int TopLevelBlocks = 0; while (!InputStream.AtEndOfStream()) { if (Parser.Parse()) {