Add load and store instructions to Subzero bitcode reader. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3892 R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/561883002
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp index bde906a..c83898d 100644 --- a/src/PNaClTranslator.cpp +++ b/src/PNaClTranslator.cpp
@@ -20,11 +20,13 @@ #include "IceInst.h" #include "IceOperand.h" #include "IceTypeConverter.h" +#include "llvm/Analysis/NaCl/PNaClABIProps.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/DataLayout.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/Format.h" @@ -55,9 +57,10 @@ NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor, bool &ErrorStatus) : NaClBitcodeParser(Cursor), Translator(Translator), - Mod(new Module(InputName, getGlobalContext())), Header(Header), - TypeConverter(getLLVMContext()), ErrorStatus(ErrorStatus), NumErrors(0), - NumFunctionIds(0), NumFunctionBlocks(0), + Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout), + Header(Header), TypeConverter(getLLVMContext()), + ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0), + NumFunctionBlocks(0), GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) { Mod->setDataLayout(PNaClDataLayout); } @@ -84,6 +87,8 @@ /// Returns the LLVM module associated with the translation. Module *getModule() const { return Mod.get(); } + const DataLayout &getDataLayout() const { return DL; } + /// Returns the number of bytes in the bitcode header. size_t getHeaderSize() const { return Header.getHeaderSize(); } @@ -228,6 +233,8 @@ Ice::Translator &Translator; // The parsed module. OwningPtr<Module> Mod; + // The data layout to use. + DataLayout DL; // The bitcode header. NaClBitcodeHeader &Header; // Converter between LLVM and ICE types. @@ -848,6 +855,24 @@ // Upper limit of alignment power allowed by LLVM static const uint64_t AlignPowerLimit = 29; + // Extracts the corresponding Alignment to use, given the AlignPower + // (i.e. 2**AlignPower, or 0 if AlignPower == 0). InstName is the + // name of the instruction the alignment appears in. + void extractAlignment(const char *InstName, uint64_t AlignPower, + unsigned &Alignment) { + if (AlignPower <= AlignPowerLimit) { + Alignment = (1 << static_cast<unsigned>(AlignPower)) >> 1; + return; + } + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << InstName << " alignment greater than 2**" << AlignPowerLimit + << ". Found: 2**" << AlignPower; + Error(StrBuf.str()); + // Error recover with value that is always acceptable. + Alignment = 1; + } + virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE; virtual void ProcessRecord() LLVM_OVERRIDE; @@ -959,8 +984,8 @@ } // Checks if floating arithmetic Op, for type OpTy, is valid. - // Returns false if valid. Otherwise generates an error message and - // returns true. + // Returns true if valid. Otherwise generates an error message and + // returns false; bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) { if (Ice::isFloatingType(OpTy)) return true; @@ -968,6 +993,52 @@ return false; } + // Checks if the type of operand Op is the valid pointer type, for + // the given InstructionName. Returns true if valid. Otherwise + // generates an error message and returns false. + bool isValidPointerType(Ice::Operand *Op, const char *InstructionName) { + Ice::Type PtrType = Context->getIcePointerType(); + if (Op->getType() == PtrType) + return true; + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << InstructionName << " address not " << PtrType + << ". Found: " << Op; + Error(StrBuf.str()); + return false; + } + + // Checks if loading/storing a value of type Ty is allowed. + // Returns true if Valid. Otherwise generates an error message and + // returns false. + bool isValidLoadStoreType(Ice::Type Ty, const char *InstructionName) { + if (isLoadStoreType(Ty)) + return true; + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << InstructionName << " type not allowed: " << Ty << "*"; + Error(StrBuf.str()); + return false; + } + + // Checks if loading/storing a value of type Ty is allowed for + // the given Alignment. Otherwise generates an error message and + // returns false. + bool isValidLoadStoreAlignment(unsigned Alignment, Ice::Type Ty, + const char *InstructionName) { + if (!isValidLoadStoreType(Ty, InstructionName)) + return false; + if (PNaClABIProps::isAllowedAlignment(&Context->getDataLayout(), Alignment, + Context->convertToLLVMType(Ty))) + return true; + std::string Buffer; + raw_string_ostream StrBuf(Buffer); + StrBuf << InstructionName << " " << Ty << "*: not allowed for alignment " + << Alignment; + Error(StrBuf.str()); + return false; + } + // Reports that the given binary Opcode, for the given type Ty, // is not understood. void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty); @@ -1529,22 +1600,46 @@ Error(StrBuf.str()); return; } - uint64_t AlignPower = Values[1]; - unsigned Alignment = 1; - if (AlignPower <= AlignPowerLimit) { - Alignment = (1 << static_cast<unsigned>(AlignPower)) >> 1; - } else { - std::string Buffer; - raw_string_ostream StrBuf(Buffer); - StrBuf << "Alloca on alignment greater than 2**" << AlignPowerLimit - << ". Found: 2**" << AlignPower; - Error(StrBuf.str()); - // TODO(kschimpf) Remove error recovery once implementation complete. - } + unsigned Alignment; + extractAlignment("Alloca", Values[1], Alignment); Ice::Variable *Dest = NextInstVar(Context->getIcePointerType()); Inst = Ice::InstAlloca::create(Func, ByteCount, Alignment, Dest); break; } + case naclbitc::FUNC_CODE_INST_LOAD: { + // LOAD: [address, align, ty] + if (!isValidRecordSize(3, "function block load")) + return; + Ice::Operand *Address = getRelativeOperand(Values[0]); + if (!isValidPointerType(Address, "Load")) + return; + unsigned Alignment; + extractAlignment("Load", Values[1], Alignment); + Ice::Type Ty = Context->convertToIceType(Context->getTypeByID(Values[2])); + if (!isValidLoadStoreAlignment(Alignment, Ty, "Load")) + return; + Ice::Variable *Dest = NextInstVar(Ty); + Inst = Ice::InstLoad::create(Func, Dest, Address, Alignment); + break; + } + case naclbitc::FUNC_CODE_INST_STORE: { + // STORE: [address, value, align] + if (!isValidRecordSize(3, "function block store")) + return; + Ice::Operand *Address = getRelativeOperand(Values[0]); + if (!isValidPointerType(Address, "Store")) + return; + Ice::Operand *Value = getRelativeOperand(Values[1]); + unsigned Alignment; + if (!extractAlignment("Store", Values[2], Alignment)) { + // TODO(kschimpf) Remove error recovery once implementation complete. + Alignment = 1; + } + if (!isValidLoadStoreAlignment(Alignment, Value->getType(), "Store")) + return; + Inst = Ice::InstStore::create(Func, Value, Address, Alignment); + break; + } default: // Generate error message! BlockParserBaseClass::ProcessRecord();