|  | //===- 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. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// | 
|  | /// \file | 
|  | /// \brief Implements the interface for translation from PNaCl bitcode files to | 
|  | /// ICE to machine code. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "PNaClTranslator.h" | 
|  |  | 
|  | #include "IceCfg.h" | 
|  | #include "IceCfgNode.h" | 
|  | #include "IceClFlags.h" | 
|  | #include "IceDefs.h" | 
|  | #include "IceGlobalInits.h" | 
|  | #include "IceInst.h" | 
|  | #include "IceOperand.h" | 
|  | #include "IceRangeSpec.h" | 
|  |  | 
|  | #ifdef __clang__ | 
|  | #pragma clang diagnostic push | 
|  | #pragma clang diagnostic ignored "-Wunused-parameter" | 
|  | #endif // __clang__ | 
|  |  | 
|  | #include "llvm/ADT/Hashing.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClBitcodeDefs.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" | 
|  | #include "llvm/Support/Format.h" | 
|  | #include "llvm/Support/MemoryBuffer.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | #ifdef __clang__ | 
|  | #pragma clang diagnostic pop | 
|  | #endif // __clang__ | 
|  |  | 
|  | #include <unordered_set> | 
|  |  | 
|  | // Define a hash function for SmallString's, so that it can be used in hash | 
|  | // tables. | 
|  | namespace std { | 
|  | template <unsigned InternalLen> struct hash<llvm::SmallString<InternalLen>> { | 
|  | size_t operator()(const llvm::SmallString<InternalLen> &Key) const { | 
|  | return llvm::hash_combine_range(Key.begin(), Key.end()); | 
|  | } | 
|  | }; | 
|  | } // end of namespace std | 
|  |  | 
|  | namespace { | 
|  | using namespace llvm; | 
|  |  | 
|  | // Models elements in the list of types defined in the types block. These | 
|  | // elements can be undefined, a (simple) type, or a function type signature. | 
|  | // Note that an extended type is undefined on construction. Use methods | 
|  | // setAsSimpleType and setAsFuncSigType to define the extended type. | 
|  | class ExtendedType { | 
|  | ExtendedType &operator=(const ExtendedType &Ty) = delete; | 
|  |  | 
|  | public: | 
|  | /// Discriminator for LLVM-style RTTI. | 
|  | enum TypeKind { Undefined, Simple, FuncSig }; | 
|  |  | 
|  | ExtendedType() = default; | 
|  | ExtendedType(const ExtendedType &Ty) = default; | 
|  |  | 
|  | virtual ~ExtendedType() = default; | 
|  |  | 
|  | ExtendedType::TypeKind getKind() const { return Kind; } | 
|  | void dump(Ice::Ostream &Stream) const; | 
|  |  | 
|  | /// Changes the extended type to a simple type with the given / value. | 
|  | void setAsSimpleType(Ice::Type Ty) { | 
|  | assert(Kind == Undefined); | 
|  | Kind = Simple; | 
|  | Signature.setReturnType(Ty); | 
|  | } | 
|  |  | 
|  | /// Changes the extended type to an (empty) function signature type. | 
|  | void setAsFunctionType() { | 
|  | assert(Kind == Undefined); | 
|  | Kind = FuncSig; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // Note: For simple types, the return type of the signature will be used to | 
|  | // hold the simple type. | 
|  | Ice::FuncSigType Signature; | 
|  |  | 
|  | private: | 
|  | ExtendedType::TypeKind Kind = Undefined; | 
|  | }; | 
|  |  | 
|  | Ice::Ostream &operator<<(Ice::Ostream &Stream, const ExtendedType &Ty) { | 
|  | if (!Ice::BuildDefs::dump()) | 
|  | return Stream; | 
|  | Ty.dump(Stream); | 
|  | return Stream; | 
|  | } | 
|  |  | 
|  | Ice::Ostream &operator<<(Ice::Ostream &Stream, ExtendedType::TypeKind Kind) { | 
|  | if (!Ice::BuildDefs::dump()) | 
|  | return Stream; | 
|  | Stream << "ExtendedType::"; | 
|  | switch (Kind) { | 
|  | case ExtendedType::Undefined: | 
|  | Stream << "Undefined"; | 
|  | break; | 
|  | case ExtendedType::Simple: | 
|  | Stream << "Simple"; | 
|  | break; | 
|  | case ExtendedType::FuncSig: | 
|  | Stream << "FuncSig"; | 
|  | break; | 
|  | } | 
|  | return Stream; | 
|  | } | 
|  |  | 
|  | // Models an ICE type as an extended type. | 
|  | class SimpleExtendedType : public ExtendedType { | 
|  | SimpleExtendedType() = delete; | 
|  | SimpleExtendedType(const SimpleExtendedType &) = delete; | 
|  | SimpleExtendedType &operator=(const SimpleExtendedType &) = delete; | 
|  |  | 
|  | public: | 
|  | Ice::Type getType() const { return Signature.getReturnType(); } | 
|  |  | 
|  | static bool classof(const ExtendedType *Ty) { | 
|  | return Ty->getKind() == Simple; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Models a function signature as an extended type. | 
|  | class FuncSigExtendedType : public ExtendedType { | 
|  | FuncSigExtendedType() = delete; | 
|  | FuncSigExtendedType(const FuncSigExtendedType &) = delete; | 
|  | FuncSigExtendedType &operator=(const FuncSigExtendedType &) = delete; | 
|  |  | 
|  | public: | 
|  | const Ice::FuncSigType &getSignature() const { return Signature; } | 
|  | void setReturnType(Ice::Type ReturnType) { | 
|  | Signature.setReturnType(ReturnType); | 
|  | } | 
|  | void appendArgType(Ice::Type ArgType) { Signature.appendArgType(ArgType); } | 
|  | static bool classof(const ExtendedType *Ty) { | 
|  | return Ty->getKind() == FuncSig; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void ExtendedType::dump(Ice::Ostream &Stream) const { | 
|  | if (!Ice::BuildDefs::dump()) | 
|  | return; | 
|  | Stream << Kind; | 
|  | switch (Kind) { | 
|  | case Simple: { | 
|  | Stream << " " << Signature.getReturnType(); | 
|  | break; | 
|  | } | 
|  | case FuncSig: { | 
|  | Stream << " " << Signature; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Models integer literals as a sequence of bits. Used to read integer values | 
|  | // from bitcode files. Based on llvm::APInt. | 
|  | class BitcodeInt { | 
|  | BitcodeInt() = delete; | 
|  | BitcodeInt(const BitcodeInt &) = delete; | 
|  | BitcodeInt &operator=(const BitcodeInt &) = delete; | 
|  |  | 
|  | public: | 
|  | BitcodeInt(Ice::SizeT Bits, uint64_t Val) : BitWidth(Bits), Val(Val) { | 
|  | assert(Bits && "bitwidth too small"); | 
|  | assert(Bits <= BITS_PER_WORD && "bitwidth too big"); | 
|  | clearUnusedBits(); | 
|  | } | 
|  |  | 
|  | int64_t getSExtValue() const { | 
|  | return static_cast<int64_t>(Val << (BITS_PER_WORD - BitWidth)) >> | 
|  | (BITS_PER_WORD - BitWidth); | 
|  | } | 
|  |  | 
|  | template <typename IntType, typename FpType> | 
|  | inline FpType convertToFp() const { | 
|  | static_assert(sizeof(IntType) == sizeof(FpType), | 
|  | "IntType and FpType should be the same width"); | 
|  | assert(BitWidth == sizeof(IntType) * CHAR_BIT); | 
|  | auto V = static_cast<IntType>(Val); | 
|  | return Ice::Utils::bitCopy<FpType>(V); | 
|  | } | 
|  |  | 
|  | private: | 
|  | /// Bits in the (internal) value. | 
|  | static const Ice::SizeT BITS_PER_WORD = sizeof(uint64_t) * CHAR_BIT; | 
|  |  | 
|  | uint32_t BitWidth; /// The number of bits in the floating point number. | 
|  | uint64_t Val;      /// The (64-bit) equivalent integer value. | 
|  |  | 
|  | /// Clear unused high order bits. | 
|  | void clearUnusedBits() { | 
|  | // If all bits are used, we want to leave the value alone. | 
|  | if (BitWidth == BITS_PER_WORD) | 
|  | return; | 
|  |  | 
|  | // Mask out the high bits. | 
|  | Val &= ~static_cast<uint64_t>(0) >> (BITS_PER_WORD - BitWidth); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class BlockParserBaseClass; | 
|  |  | 
|  | // Top-level class to read PNaCl bitcode files, and translate to ICE. | 
|  | class TopLevelParser final : public NaClBitcodeParser { | 
|  | TopLevelParser() = delete; | 
|  | TopLevelParser(const TopLevelParser &) = delete; | 
|  | TopLevelParser &operator=(const TopLevelParser &) = delete; | 
|  |  | 
|  | public: | 
|  | TopLevelParser(Ice::Translator &Translator, NaClBitstreamCursor &Cursor, | 
|  | Ice::ErrorCode &ErrorStatus) | 
|  | : NaClBitcodeParser(Cursor), Translator(Translator), | 
|  | ErrorStatus(ErrorStatus), | 
|  | VariableDeclarations(new Ice::VariableDeclarationList()) {} | 
|  |  | 
|  | ~TopLevelParser() override = default; | 
|  |  | 
|  | Ice::Translator &getTranslator() const { return Translator; } | 
|  |  | 
|  | /// Generates error with given Message, occurring at BitPosition within the | 
|  | /// bitcode file. Always returns true. | 
|  | bool ErrorAt(naclbitc::ErrorLevel Level, uint64_t BitPosition, | 
|  | const std::string &Message) override; | 
|  |  | 
|  | /// Generates error message with respect to the current block parser. | 
|  | bool blockError(const std::string &Message); | 
|  |  | 
|  | /// Changes the size of the type list to the given size. | 
|  | void resizeTypeIDValues(size_t NewSize) { TypeIDValues.resize(NewSize); } | 
|  |  | 
|  | size_t getNumTypeIDValues() const { return TypeIDValues.size(); } | 
|  |  | 
|  | /// Returns a pointer to the pool where globals are allocated. | 
|  | Ice::VariableDeclarationList *getGlobalVariablesPool() { | 
|  | return VariableDeclarations.get(); | 
|  | } | 
|  |  | 
|  | /// Returns the undefined type associated with type ID. Note: Returns extended | 
|  | /// type ready to be defined. | 
|  | ExtendedType *getTypeByIDForDefining(NaClBcIndexSize_t ID) { | 
|  | // Get corresponding element, verifying the value is still undefined (and | 
|  | // hence allowed to be defined). | 
|  | ExtendedType *Ty = getTypeByIDAsKind(ID, ExtendedType::Undefined); | 
|  | if (Ty) | 
|  | return Ty; | 
|  | if (ID >= TypeIDValues.size()) { | 
|  | if (ID >= NaClBcIndexSize_t_Max) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Can't define more than " << NaClBcIndexSize_t_Max | 
|  | << " types\n"; | 
|  | blockError(StrBuf.str()); | 
|  | // Recover by using existing type slot. | 
|  | return &TypeIDValues[0]; | 
|  | } | 
|  | Ice::Utils::reserveAndResize(TypeIDValues, ID + 1); | 
|  | } | 
|  | return &TypeIDValues[ID]; | 
|  | } | 
|  |  | 
|  | /// Returns the type associated with the given index. | 
|  | Ice::Type getSimpleTypeByID(NaClBcIndexSize_t ID) { | 
|  | const ExtendedType *Ty = getTypeByIDAsKind(ID, ExtendedType::Simple); | 
|  | if (Ty == nullptr) | 
|  | // Return error recovery value. | 
|  | return Ice::IceType_void; | 
|  | return cast<SimpleExtendedType>(Ty)->getType(); | 
|  | } | 
|  |  | 
|  | /// Returns the type signature associated with the given index. | 
|  | const Ice::FuncSigType &getFuncSigTypeByID(NaClBcIndexSize_t ID) { | 
|  | const ExtendedType *Ty = getTypeByIDAsKind(ID, ExtendedType::FuncSig); | 
|  | if (Ty == nullptr) | 
|  | // Return error recovery value. | 
|  | return UndefinedFuncSigType; | 
|  | return cast<FuncSigExtendedType>(Ty)->getSignature(); | 
|  | } | 
|  |  | 
|  | /// Sets the next function ID to the given LLVM function. | 
|  | void setNextFunctionID(Ice::FunctionDeclaration *Fcn) { | 
|  | FunctionDeclarations.push_back(Fcn); | 
|  | } | 
|  |  | 
|  | /// 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. | 
|  | NaClBcIndexSize_t getNextFunctionBlockValueID() { | 
|  | size_t NumDeclaredFunctions = FunctionDeclarations.size(); | 
|  | while (NextDefiningFunctionID < NumDeclaredFunctions && | 
|  | FunctionDeclarations[NextDefiningFunctionID]->isProto()) | 
|  | ++NextDefiningFunctionID; | 
|  | if (NextDefiningFunctionID >= NumDeclaredFunctions) | 
|  | Fatal("More function blocks than defined function addresses"); | 
|  | return NextDefiningFunctionID++; | 
|  | } | 
|  |  | 
|  | /// Returns the function associated with ID. | 
|  | Ice::FunctionDeclaration *getFunctionByID(NaClBcIndexSize_t ID) { | 
|  | if (ID < FunctionDeclarations.size()) | 
|  | return FunctionDeclarations[ID]; | 
|  | return reportGetFunctionByIDError(ID); | 
|  | } | 
|  |  | 
|  | /// Returns the constant associated with the given global value ID. | 
|  | Ice::Constant *getGlobalConstantByID(NaClBcIndexSize_t ID) { | 
|  | assert(ID < ValueIDConstants.size()); | 
|  | return ValueIDConstants[ID]; | 
|  | } | 
|  |  | 
|  | /// Install names for all global values without names. Called after the global | 
|  | /// value symbol table is processed, but before any function blocks are | 
|  | /// processed. | 
|  | void installGlobalNames() { | 
|  | assert(VariableDeclarations); | 
|  | installGlobalVarNames(); | 
|  | installFunctionNames(); | 
|  | } | 
|  |  | 
|  | void verifyFunctionTypeSignatures(); | 
|  |  | 
|  | void createValueIDs() { | 
|  | assert(VariableDeclarations); | 
|  | ValueIDConstants.reserve(VariableDeclarations->size() + | 
|  | FunctionDeclarations.size()); | 
|  | createValueIDsForFunctions(); | 
|  | createValueIDsForGlobalVars(); | 
|  | } | 
|  |  | 
|  | /// Returns the number of function declarations in the bitcode file. | 
|  | size_t getNumFunctionIDs() const { return FunctionDeclarations.size(); } | 
|  |  | 
|  | /// Returns the number of global declarations (i.e. IDs) defined in the | 
|  | /// bitcode file. | 
|  | size_t getNumGlobalIDs() const { | 
|  | if (VariableDeclarations) { | 
|  | return FunctionDeclarations.size() + VariableDeclarations->size(); | 
|  | } else { | 
|  | return ValueIDConstants.size(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Adds the given global declaration to the end of the list of global | 
|  | /// declarations. | 
|  | void addGlobalDeclaration(Ice::VariableDeclaration *Decl) { | 
|  | assert(VariableDeclarations); | 
|  | VariableDeclarations->push_back(Decl); | 
|  | } | 
|  |  | 
|  | /// Returns the global variable declaration with the given index. | 
|  | Ice::VariableDeclaration *getGlobalVariableByID(NaClBcIndexSize_t Index) { | 
|  | assert(VariableDeclarations); | 
|  | if (Index < VariableDeclarations->size()) | 
|  | return VariableDeclarations->at(Index); | 
|  | return reportGetGlobalVariableByIDError(Index); | 
|  | } | 
|  |  | 
|  | /// Returns the global declaration (variable or function) with the given | 
|  | /// Index. | 
|  | Ice::GlobalDeclaration *getGlobalDeclarationByID(NaClBcIndexSize_t Index) { | 
|  | size_t NumFunctionIds = FunctionDeclarations.size(); | 
|  | if (Index < NumFunctionIds) | 
|  | return getFunctionByID(Index); | 
|  | else | 
|  | return getGlobalVariableByID(Index - NumFunctionIds); | 
|  | } | 
|  |  | 
|  | /// Returns true if a module block has been parsed. | 
|  | bool parsedModuleBlock() const { return ParsedModuleBlock; } | 
|  |  | 
|  | /// Returns the list of parsed global variable declarations. Releases | 
|  | /// ownership of the current list of global variables. Note: only returns | 
|  | /// non-null pointer on first call. All successive calls return a null | 
|  | /// pointer. | 
|  | std::unique_ptr<Ice::VariableDeclarationList> getGlobalVariables() { | 
|  | // Before returning, check that ValidIDConstants has already been built. | 
|  | assert(!VariableDeclarations || | 
|  | VariableDeclarations->size() <= ValueIDConstants.size()); | 
|  | return std::move(VariableDeclarations); | 
|  | } | 
|  |  | 
|  | // Upper limit of alignment power allowed by LLVM | 
|  | static constexpr uint32_t AlignPowerLimit = 29; | 
|  |  | 
|  | // Extracts the corresponding Alignment to use, given the AlignPower (i.e. | 
|  | // 2**(AlignPower-1), or 0 if AlignPower == 0). Parser defines the block | 
|  | // context the alignment check appears in, and Prefix defines the context the | 
|  | // alignment appears in. | 
|  | uint32_t extractAlignment(NaClBitcodeParser *Parser, const char *Prefix, | 
|  | uint32_t AlignPower) { | 
|  | if (AlignPower <= AlignPowerLimit + 1) | 
|  | return (1 << AlignPower) >> 1; | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << Prefix << " alignment greater than 2**" << AlignPowerLimit | 
|  | << ". Found: 2**" << (AlignPower - 1); | 
|  | Parser->Error(StrBuf.str()); | 
|  | // Error recover with value that is always acceptable. | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | private: | 
|  | // The translator associated with the parser. | 
|  | Ice::Translator &Translator; | 
|  |  | 
|  | // ErrorStatus should only be updated while this lock is locked. | 
|  | Ice::GlobalLockType ErrorReportingLock; | 
|  | // The exit status that should be set to true if an error occurs. | 
|  | Ice::ErrorCode &ErrorStatus; | 
|  |  | 
|  | // The types associated with each type ID. | 
|  | std::vector<ExtendedType> TypeIDValues; | 
|  | // The set of functions (prototype and defined). | 
|  | Ice::FunctionDeclarationList FunctionDeclarations; | 
|  | // The ID of the next possible defined function ID in FunctionDeclarations. | 
|  | // FunctionDeclarations is filled first. It's the set of functions (either | 
|  | // defined or isproto). Then function definitions are encountered/parsed and | 
|  | // NextDefiningFunctionID is incremented to track the next actually-defined | 
|  | // function. | 
|  | size_t NextDefiningFunctionID = 0; | 
|  | // The set of global variables. | 
|  | std::unique_ptr<Ice::VariableDeclarationList> VariableDeclarations; | 
|  | // Relocatable constants associated with global declarations. | 
|  | Ice::ConstantList ValueIDConstants; | 
|  | // Error recovery value to use when getFuncSigTypeByID fails. | 
|  | Ice::FuncSigType UndefinedFuncSigType; | 
|  | // Defines if a module block has already been parsed. | 
|  | bool ParsedModuleBlock = false; | 
|  |  | 
|  | bool ParseBlock(unsigned BlockID) override; | 
|  |  | 
|  | // Gets extended type associated with the given index, assuming the extended | 
|  | // type is of the WantedKind. Generates error message if corresponding | 
|  | // extended type of WantedKind can't be found, and returns nullptr. | 
|  | ExtendedType *getTypeByIDAsKind(NaClBcIndexSize_t ID, | 
|  | ExtendedType::TypeKind WantedKind) { | 
|  | ExtendedType *Ty = nullptr; | 
|  | if (ID < TypeIDValues.size()) { | 
|  | Ty = &TypeIDValues[ID]; | 
|  | if (Ty->getKind() == WantedKind) | 
|  | return Ty; | 
|  | } | 
|  | // Generate an error message and set ErrorStatus. | 
|  | this->reportBadTypeIDAs(ID, Ty, WantedKind); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Gives Decl a name if it doesn't already have one. Prefix and NameIndex are | 
|  | // used to generate the name. NameIndex is automatically incremented if a new | 
|  | // name is created. DeclType is literal text describing the type of name being | 
|  | // created. Also generates a warning if created names may conflict with named | 
|  | // declarations. | 
|  | void installDeclarationName(Ice::GlobalDeclaration *Decl, | 
|  | const std::string &Prefix, const char *DeclType, | 
|  | NaClBcIndexSize_t &NameIndex) { | 
|  | if (Decl->hasName()) { | 
|  | Translator.checkIfUnnamedNameSafe(Decl->getName().toString(), DeclType, | 
|  | Prefix); | 
|  | } else { | 
|  | Ice::GlobalContext *Ctx = Translator.getContext(); | 
|  | // Synthesize a dummy name if any of the following is true: | 
|  | // - DUMP is enabled | 
|  | // - The symbol is external | 
|  | // - The -timing-funcs flag is enabled | 
|  | // - Some RangeSpec is initialized with actual names | 
|  | if (Ice::BuildDefs::dump() || !Decl->isInternal() || | 
|  | Ice::RangeSpec::hasNames() || Ice::getFlags().getTimeEachFunction()) { | 
|  | Decl->setName(Ctx, Translator.createUnnamedName(Prefix, NameIndex)); | 
|  | } else { | 
|  | Decl->setName(Ctx); | 
|  | } | 
|  | ++NameIndex; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Installs names for global variables without names. | 
|  | void installGlobalVarNames() { | 
|  | assert(VariableDeclarations); | 
|  | const std::string &GlobalPrefix = Ice::getFlags().getDefaultGlobalPrefix(); | 
|  | if (!GlobalPrefix.empty()) { | 
|  | NaClBcIndexSize_t NameIndex = 0; | 
|  | for (Ice::VariableDeclaration *Var : *VariableDeclarations) { | 
|  | installDeclarationName(Var, GlobalPrefix, "global", NameIndex); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Installs names for functions without names. | 
|  | void installFunctionNames() { | 
|  | const std::string &FunctionPrefix = | 
|  | Ice::getFlags().getDefaultFunctionPrefix(); | 
|  | if (!FunctionPrefix.empty()) { | 
|  | NaClBcIndexSize_t NameIndex = 0; | 
|  | for (Ice::FunctionDeclaration *Func : FunctionDeclarations) { | 
|  | installDeclarationName(Func, FunctionPrefix, "function", NameIndex); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Builds a constant symbol named Name.  IsExternal is true iff the symbol is | 
|  | // external. | 
|  | Ice::Constant *getConstantSym(Ice::GlobalString Name, bool IsExternal) const { | 
|  | Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | if (IsExternal) { | 
|  | return Ctx->getConstantExternSym(Name); | 
|  | } else { | 
|  | const Ice::RelocOffsetT Offset = 0; | 
|  | return Ctx->getConstantSym(Offset, Name); | 
|  | } | 
|  | } | 
|  |  | 
|  | void reportLinkageError(const char *Kind, | 
|  | const Ice::GlobalDeclaration &Decl) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << Kind << " " << Decl.getName() | 
|  | << " has incorrect linkage: " << Decl.getLinkageName(); | 
|  | if (Decl.isExternal()) | 
|  | StrBuf << "\n  Use flag -allow-externally-defined-symbols to override"; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | // Converts function declarations into constant value IDs. | 
|  | void createValueIDsForFunctions() { | 
|  | Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | for (const Ice::FunctionDeclaration *Func : FunctionDeclarations) { | 
|  | if (!Func->verifyLinkageCorrect(Ctx)) | 
|  | reportLinkageError("Function", *Func); | 
|  | Ice::Constant *C = getConstantSym(Func->getName(), Func->isProto()); | 
|  | ValueIDConstants.push_back(C); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Converts global variable declarations into constant value IDs. | 
|  | void createValueIDsForGlobalVars() { | 
|  | for (const Ice::VariableDeclaration *Decl : *VariableDeclarations) { | 
|  | if (!Decl->verifyLinkageCorrect()) | 
|  | reportLinkageError("Global", *Decl); | 
|  | Ice::Constant *C = | 
|  | getConstantSym(Decl->getName(), !Decl->hasInitializer()); | 
|  | ValueIDConstants.push_back(C); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Reports that type ID is undefined, or not of the WantedType. | 
|  | void reportBadTypeIDAs(NaClBcIndexSize_t ID, const ExtendedType *Ty, | 
|  | ExtendedType::TypeKind WantedType); | 
|  |  | 
|  | // Reports that there is no function declaration for ID. Returns an error | 
|  | // recovery value to use. | 
|  | Ice::FunctionDeclaration *reportGetFunctionByIDError(NaClBcIndexSize_t ID); | 
|  |  | 
|  | // Reports that there is not global variable declaration for ID. Returns an | 
|  | // error recovery value to use. | 
|  | Ice::VariableDeclaration * | 
|  | reportGetGlobalVariableByIDError(NaClBcIndexSize_t Index); | 
|  |  | 
|  | // Reports that there is no corresponding ICE type for LLVMTy, and returns | 
|  | // Ice::IceType_void. | 
|  | Ice::Type convertToIceTypeError(Type *LLVMTy); | 
|  | }; | 
|  |  | 
|  | bool TopLevelParser::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit, | 
|  | const std::string &Message) { | 
|  | Ice::GlobalContext *Context = Translator.getContext(); | 
|  | { | 
|  | std::unique_lock<Ice::GlobalLockType> _(ErrorReportingLock); | 
|  | ErrorStatus.assign(Ice::EC_Bitcode); | 
|  | } | 
|  | { // Lock while printing out error message. | 
|  | Ice::OstreamLocker L(Context); | 
|  | raw_ostream &OldErrStream = setErrStream(Context->getStrError()); | 
|  | NaClBitcodeParser::ErrorAt(Level, Bit, Message); | 
|  | setErrStream(OldErrStream); | 
|  | } | 
|  | if (Level >= naclbitc::Error && !Ice::getFlags().getAllowErrorRecovery()) | 
|  | Fatal(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void TopLevelParser::reportBadTypeIDAs(NaClBcIndexSize_t ID, | 
|  | const ExtendedType *Ty, | 
|  | ExtendedType::TypeKind WantedType) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | if (Ty == nullptr) { | 
|  | StrBuf << "Can't find extended type for type id: " << ID; | 
|  | } else { | 
|  | StrBuf << "Type id " << ID << " not " << WantedType << ". Found: " << *Ty; | 
|  | } | 
|  | blockError(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | Ice::FunctionDeclaration * | 
|  | TopLevelParser::reportGetFunctionByIDError(NaClBcIndexSize_t ID) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function index " << ID | 
|  | << " not allowed. Out of range. Must be less than " | 
|  | << FunctionDeclarations.size(); | 
|  | blockError(StrBuf.str()); | 
|  | if (!FunctionDeclarations.empty()) | 
|  | return FunctionDeclarations[0]; | 
|  | Fatal(); | 
|  | } | 
|  |  | 
|  | Ice::VariableDeclaration * | 
|  | TopLevelParser::reportGetGlobalVariableByIDError(NaClBcIndexSize_t Index) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Global index " << Index | 
|  | << " not allowed. Out of range. Must be less than " | 
|  | << VariableDeclarations->size(); | 
|  | blockError(StrBuf.str()); | 
|  | if (!VariableDeclarations->empty()) | 
|  | return VariableDeclarations->at(0); | 
|  | Fatal(); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | void TopLevelParser::verifyFunctionTypeSignatures() { | 
|  | const Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | for (Ice::FunctionDeclaration *FuncDecl : FunctionDeclarations) { | 
|  | if (!FuncDecl->validateTypeSignature(Ctx)) | 
|  | Error(FuncDecl->getTypeSignatureError(Ctx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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 { | 
|  | BlockParserBaseClass() = delete; | 
|  | BlockParserBaseClass(const BlockParserBaseClass &) = delete; | 
|  | BlockParserBaseClass &operator=(const BlockParserBaseClass &) = delete; | 
|  |  | 
|  | public: | 
|  | // Constructor for the top-level module block parser. | 
|  | BlockParserBaseClass(unsigned BlockID, TopLevelParser *Context) | 
|  | : NaClBitcodeParser(BlockID, Context), Context(Context) {} | 
|  |  | 
|  | BlockParserBaseClass(unsigned BlockID, BlockParserBaseClass *EnclosingParser, | 
|  | NaClBitstreamCursor &Cursor) | 
|  | : NaClBitcodeParser(BlockID, EnclosingParser, Cursor), | 
|  | Context(EnclosingParser->Context) {} | 
|  |  | 
|  | ~BlockParserBaseClass() override {} | 
|  |  | 
|  | // Returns the printable name of the type of block being parsed. | 
|  | virtual const char *getBlockName() const { | 
|  | // If this class is used, it is parsing an unknown block. | 
|  | return "unknown"; | 
|  | } | 
|  |  | 
|  | // Generates an error Message with the Bit address prefixed to it. | 
|  | bool ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit, | 
|  | const std::string &Message) override; | 
|  |  | 
|  | protected: | 
|  | // The context parser that contains the decoded state. | 
|  | TopLevelParser *Context; | 
|  | // True if ErrorAt has been called in this block. | 
|  | bool BlockHasError = false; | 
|  |  | 
|  | // Constructor for nested block parsers. | 
|  | BlockParserBaseClass(unsigned BlockID, BlockParserBaseClass *EnclosingParser) | 
|  | : NaClBitcodeParser(BlockID, EnclosingParser), | 
|  | Context(EnclosingParser->Context) {} | 
|  |  | 
|  | // Gets the translator associated with the bitcode parser. | 
|  | Ice::Translator &getTranslator() const { return Context->getTranslator(); } | 
|  |  | 
|  | // Default implementation. Reports that block is unknown and skips its | 
|  | // contents. | 
|  | bool ParseBlock(unsigned BlockID) override; | 
|  |  | 
|  | // Default implementation. Reports that the record is not understood. | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | // Checks if the size of the record is Size. Return true if valid. Otherwise | 
|  | // generates an error and returns false. | 
|  | bool isValidRecordSize(size_t Size, const char *RecordName) { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | if (Values.size() == Size) | 
|  | return true; | 
|  | reportRecordSizeError(Size, RecordName, nullptr); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // 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(size_t LowerLimit, const char *RecordName) { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | 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.  Returns true if valid. Otherwise generates an error and | 
|  | // returns false. | 
|  | bool isValidRecordSizeAtMost(size_t UpperLimit, const char *RecordName) { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | 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. Returns true if valid. Otherwise | 
|  | // generates an error and returns false. | 
|  | bool isValidRecordSizeInRange(size_t LowerLimit, size_t 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 nullptr) is appended to "record expects" to | 
|  | /// describe how ExpectedSize should be interpreted. | 
|  | void reportRecordSizeError(size_t ExpectedSize, const char *RecordName, | 
|  | const char *ContextMessage); | 
|  | }; | 
|  |  | 
|  | bool TopLevelParser::blockError(const std::string &Message) { | 
|  | // TODO(kschimpf): Remove this method. This method used to redirect | 
|  | // block-level errors to the block we are in, rather than the top-level | 
|  | // block. This gave better bit location for error messages. However, with | 
|  | // parallel parsing, we can't keep a field to redirect (there could be many | 
|  | // and we don't know which block parser applies). Hence, This redirect can't | 
|  | // be applied anymore. | 
|  | return Error(Message); | 
|  | } | 
|  |  | 
|  | // Generates an error Message with the bit address prefixed to it. | 
|  | bool BlockParserBaseClass::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit, | 
|  | const std::string &Message) { | 
|  | BlockHasError = true; | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | // Note: If dump routines have been turned off, the error messages will not | 
|  | // be readable. Hence, replace with simple error. We also use the simple form | 
|  | // for unit tests. | 
|  | if (Ice::getFlags().getGenerateUnitTestMessages()) { | 
|  | StrBuf << "Invalid " << getBlockName() << " record: <" << Record.GetCode(); | 
|  | for (const uint64_t Val : Record.GetValues()) { | 
|  | StrBuf << " " << Val; | 
|  | } | 
|  | StrBuf << ">"; | 
|  | } else { | 
|  | StrBuf << Message; | 
|  | } | 
|  | return Context->ErrorAt(Level, Record.GetCursor().getErrorBitNo(Bit), | 
|  | StrBuf.str()); | 
|  | } | 
|  |  | 
|  | void BlockParserBaseClass::reportRecordSizeError(size_t ExpectedSize, | 
|  | const char *RecordName, | 
|  | const char *ContextMessage) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | const char *BlockName = getBlockName(); | 
|  | const char FirstChar = toupper(*BlockName); | 
|  | StrBuf << FirstChar << (BlockName + 1) << " " << 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. | 
|  | 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 " << getBlockName() | 
|  | << " record:" << Record; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | // Class to parse a types block. | 
|  | class TypesParser final : public BlockParserBaseClass { | 
|  | TypesParser() = delete; | 
|  | TypesParser(const TypesParser &) = delete; | 
|  | TypesParser &operator=(const TypesParser &) = delete; | 
|  |  | 
|  | public: | 
|  | TypesParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser) | 
|  | : BlockParserBaseClass(BlockID, EnclosingParser), | 
|  | Timer(Ice::TimerStack::TT_parseTypes, getTranslator().getContext()) {} | 
|  |  | 
|  | ~TypesParser() override { | 
|  | if (ExpectedNumTypes != Context->getNumTypeIDValues()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Types block expected " << ExpectedNumTypes | 
|  | << " types but found: " << NextTypeId; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | // The type ID that will be associated with the next type defining record in | 
|  | // the types block. | 
|  | NaClBcIndexSize_t NextTypeId = 0; | 
|  |  | 
|  | // The expected number of types, based on record TYPE_CODE_NUMENTRY. | 
|  | NaClBcIndexSize_t ExpectedNumTypes = 0; | 
|  |  | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | const char *getBlockName() const override { return "type"; } | 
|  |  | 
|  | void setNextTypeIDAsSimpleType(Ice::Type Ty) { | 
|  | Context->getTypeByIDForDefining(NextTypeId++)->setAsSimpleType(Ty); | 
|  | } | 
|  | }; | 
|  |  | 
|  | void TypesParser::ProcessRecord() { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | switch (Record.GetCode()) { | 
|  | case naclbitc::TYPE_CODE_NUMENTRY: { | 
|  | // NUMENTRY: [numentries] | 
|  | if (!isValidRecordSize(1, "count")) | 
|  | return; | 
|  | uint64_t Size = Values[0]; | 
|  | if (Size > NaClBcIndexSize_t_Max) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Size to big for count record: " << Size; | 
|  | Error(StrBuf.str()); | 
|  | ExpectedNumTypes = NaClBcIndexSize_t_Max; | 
|  | } | 
|  | // The code double checks that Expected size and the actual size at the end | 
|  | // of the block. To reduce allocations we preallocate the space. | 
|  | // | 
|  | // However, if the number is large, we suspect that the number is | 
|  | // (possibly) incorrect. In that case, we preallocate a smaller space. | 
|  | constexpr uint64_t DefaultLargeResizeValue = 1000000; | 
|  | Context->resizeTypeIDValues(std::min(Size, DefaultLargeResizeValue)); | 
|  | ExpectedNumTypes = Size; | 
|  | return; | 
|  | } | 
|  | case naclbitc::TYPE_CODE_VOID: | 
|  | // VOID | 
|  | if (!isValidRecordSize(0, "void")) | 
|  | return; | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_void); | 
|  | return; | 
|  | case naclbitc::TYPE_CODE_FLOAT: | 
|  | // FLOAT | 
|  | if (!isValidRecordSize(0, "float")) | 
|  | return; | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_f32); | 
|  | return; | 
|  | case naclbitc::TYPE_CODE_DOUBLE: | 
|  | // DOUBLE | 
|  | if (!isValidRecordSize(0, "double")) | 
|  | return; | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_f64); | 
|  | return; | 
|  | case naclbitc::TYPE_CODE_INTEGER: | 
|  | // INTEGER: [width] | 
|  | if (!isValidRecordSize(1, "integer")) | 
|  | return; | 
|  | switch (Values[0]) { | 
|  | case 1: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_i1); | 
|  | return; | 
|  | case 8: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_i8); | 
|  | return; | 
|  | case 16: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_i16); | 
|  | return; | 
|  | case 32: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_i32); | 
|  | return; | 
|  | case 64: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_i64); | 
|  | return; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Type integer record with invalid bitsize: " << Values[0]; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | return; | 
|  | case naclbitc::TYPE_CODE_VECTOR: { | 
|  | // VECTOR: [numelts, eltty] | 
|  | if (!isValidRecordSize(2, "vector")) | 
|  | return; | 
|  | Ice::Type BaseTy = Context->getSimpleTypeByID(Values[1]); | 
|  | Ice::SizeT Size = Values[0]; | 
|  | switch (BaseTy) { | 
|  | case Ice::IceType_i1: | 
|  | switch (Size) { | 
|  | case 4: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v4i1); | 
|  | return; | 
|  | case 8: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v8i1); | 
|  | return; | 
|  | case 16: | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v16i1); | 
|  | return; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case Ice::IceType_i8: | 
|  | if (Size == 16) { | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v16i8); | 
|  | return; | 
|  | } | 
|  | break; | 
|  | case Ice::IceType_i16: | 
|  | if (Size == 8) { | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v8i16); | 
|  | return; | 
|  | } | 
|  | break; | 
|  | case Ice::IceType_i32: | 
|  | if (Size == 4) { | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v4i32); | 
|  | return; | 
|  | } | 
|  | break; | 
|  | case Ice::IceType_f32: | 
|  | if (Size == 4) { | 
|  | setNextTypeIDAsSimpleType(Ice::IceType_v4f32); | 
|  | return; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid type vector record: <" << Values[0] << " x " << BaseTy | 
|  | << ">"; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | return; | 
|  | } | 
|  | case naclbitc::TYPE_CODE_FUNCTION: { | 
|  | // FUNCTION: [vararg, retty, paramty x N] | 
|  | if (!isValidRecordSizeAtLeast(2, "signature")) | 
|  | return; | 
|  | if (Values[0]) | 
|  | Error("Function type can't define varargs"); | 
|  | ExtendedType *Ty = Context->getTypeByIDForDefining(NextTypeId++); | 
|  | Ty->setAsFunctionType(); | 
|  | auto *FuncTy = cast<FuncSigExtendedType>(Ty); | 
|  | FuncTy->setReturnType(Context->getSimpleTypeByID(Values[1])); | 
|  | for (size_t i = 2, e = Values.size(); i != e; ++i) { | 
|  | // Check that type void not used as argument type. Note: PNaCl | 
|  | // restrictions can't be checked until we know the name, because we have | 
|  | // to check for intrinsic signatures. | 
|  | Ice::Type ArgTy = Context->getSimpleTypeByID(Values[i]); | 
|  | if (ArgTy == Ice::IceType_void) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Type for parameter " << (i - 1) | 
|  | << " not valid. Found: " << ArgTy; | 
|  | ArgTy = Ice::IceType_i32; | 
|  | } | 
|  | FuncTy->appendArgType(ArgTy); | 
|  | } | 
|  | return; | 
|  | } | 
|  | default: | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  | llvm_unreachable("Unknown type block record not processed!"); | 
|  | } | 
|  |  | 
|  | /// Parses the globals block (i.e. global variable declarations and | 
|  | /// corresponding initializers). | 
|  | class GlobalsParser final : public BlockParserBaseClass { | 
|  | GlobalsParser() = delete; | 
|  | GlobalsParser(const GlobalsParser &) = delete; | 
|  | GlobalsParser &operator=(const GlobalsParser &) = delete; | 
|  |  | 
|  | public: | 
|  | GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser) | 
|  | : BlockParserBaseClass(BlockID, EnclosingParser), | 
|  | Timer(Ice::TimerStack::TT_parseGlobals, getTranslator().getContext()), | 
|  | NumFunctionIDs(Context->getNumFunctionIDs()), | 
|  | DummyGlobalVar(Ice::VariableDeclaration::create( | 
|  | Context->getGlobalVariablesPool())), | 
|  | CurGlobalVar(DummyGlobalVar) { | 
|  | Context->getGlobalVariablesPool()->willNotBeEmitted(DummyGlobalVar); | 
|  | } | 
|  |  | 
|  | ~GlobalsParser() override = default; | 
|  |  | 
|  | const char *getBlockName() const override { return "globals"; } | 
|  |  | 
|  | private: | 
|  | using GlobalVarsMapType = | 
|  | std::unordered_map<NaClBcIndexSize_t, Ice::VariableDeclaration *>; | 
|  |  | 
|  | Ice::TimerMarker Timer; | 
|  |  | 
|  | // Holds global variables generated/referenced in the global variables block. | 
|  | GlobalVarsMapType GlobalVarsMap; | 
|  |  | 
|  | // Holds the number of defined function IDs. | 
|  | NaClBcIndexSize_t NumFunctionIDs; | 
|  |  | 
|  | // Holds the specified number of global variables by the count record in the | 
|  | // global variables block. | 
|  | NaClBcIndexSize_t SpecifiedNumberVars = 0; | 
|  |  | 
|  | // Keeps track of how many initializers are expected for the global variable | 
|  | // declaration being built. | 
|  | NaClBcIndexSize_t InitializersNeeded = 0; | 
|  |  | 
|  | // The index of the next global variable declaration. | 
|  | NaClBcIndexSize_t NextGlobalID = 0; | 
|  |  | 
|  | // Dummy global variable declaration to guarantee CurGlobalVar is always | 
|  | // defined (allowing code to not need to check if CurGlobalVar is nullptr). | 
|  | Ice::VariableDeclaration *DummyGlobalVar; | 
|  |  | 
|  | // Holds the current global variable declaration being built. | 
|  | Ice::VariableDeclaration *CurGlobalVar; | 
|  |  | 
|  | // Returns the global variable associated with the given Index. | 
|  | Ice::VariableDeclaration *getGlobalVarByID(NaClBcIndexSize_t Index) { | 
|  | Ice::VariableDeclaration *&Decl = GlobalVarsMap[Index]; | 
|  | if (Decl == nullptr) | 
|  | Decl = | 
|  | Ice::VariableDeclaration::create(Context->getGlobalVariablesPool()); | 
|  | return Decl; | 
|  | } | 
|  |  | 
|  | // Returns the global declaration associated with the given index. | 
|  | Ice::GlobalDeclaration *getGlobalDeclByID(NaClBcIndexSize_t Index) { | 
|  | if (Index < NumFunctionIDs) | 
|  | return Context->getFunctionByID(Index); | 
|  | return getGlobalVarByID(Index - NumFunctionIDs); | 
|  | } | 
|  |  | 
|  | // If global variables parsed correctly, install them into the top-level | 
|  | // context. | 
|  | void installGlobalVariables() { | 
|  | // Verify specified number of globals matches number found. | 
|  | size_t NumGlobals = GlobalVarsMap.size(); | 
|  | if (SpecifiedNumberVars != NumGlobals || | 
|  | SpecifiedNumberVars != NextGlobalID) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << getBlockName() << " block expects " << SpecifiedNumberVars | 
|  | << " global variables. Found: " << GlobalVarsMap.size(); | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | // Install global variables into top-level context. | 
|  | for (size_t I = 0; I < NumGlobals; ++I) | 
|  | Context->addGlobalDeclaration(GlobalVarsMap[I]); | 
|  | } | 
|  |  | 
|  | void ExitBlock() override { | 
|  | verifyNoMissingInitializers(); | 
|  | installGlobalVariables(); | 
|  | BlockParserBaseClass::ExitBlock(); | 
|  | } | 
|  |  | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | // Checks if the number of initializers for the CurGlobalVar 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() { | 
|  | size_t NumInits = CurGlobalVar->getInitializers().size(); | 
|  | if (InitializersNeeded != NumInits) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Global variable @g" << NextGlobalID << " expected " | 
|  | << InitializersNeeded << " initializer"; | 
|  | if (InitializersNeeded > 1) | 
|  | StrBuf << "s"; | 
|  | StrBuf << ". Found: " << NumInits; | 
|  | Error(StrBuf.str()); | 
|  | InitializersNeeded = NumInits; | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | void GlobalsParser::ProcessRecord() { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | switch (Record.GetCode()) { | 
|  | case naclbitc::GLOBALVAR_COUNT: | 
|  | // COUNT: [n] | 
|  | if (!isValidRecordSize(1, "count")) | 
|  | return; | 
|  | if (SpecifiedNumberVars || NextGlobalID) { | 
|  | Error("Globals count record not first in block."); | 
|  | return; | 
|  | } | 
|  | SpecifiedNumberVars = Values[0]; | 
|  | return; | 
|  | case naclbitc::GLOBALVAR_VAR: { | 
|  | // VAR: [align, isconst] | 
|  | if (!isValidRecordSize(2, "variable")) | 
|  | return; | 
|  | verifyNoMissingInitializers(); | 
|  | // Always build the global variable, even if IR generation is turned off. | 
|  | // This is needed because we need a placeholder in the top-level context | 
|  | // when no IR is generated. | 
|  | uint32_t Alignment = | 
|  | Context->extractAlignment(this, "Global variable", Values[0]); | 
|  | CurGlobalVar = getGlobalVarByID(NextGlobalID); | 
|  | InitializersNeeded = 1; | 
|  | CurGlobalVar->setAlignment(Alignment); | 
|  | CurGlobalVar->setIsConstant(Values[1] != 0); | 
|  | ++NextGlobalID; | 
|  | return; | 
|  | } | 
|  | case naclbitc::GLOBALVAR_COMPOUND: | 
|  | // COMPOUND: [size] | 
|  | if (!isValidRecordSize(1, "compound")) | 
|  | return; | 
|  | if (!CurGlobalVar->getInitializers().empty()) { | 
|  | Error("Globals compound record not first initializer"); | 
|  | return; | 
|  | } | 
|  | if (Values[0] < 2) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << getBlockName() | 
|  | << " compound record size invalid. Found: " << Values[0]; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | InitializersNeeded = Values[0]; | 
|  | return; | 
|  | case naclbitc::GLOBALVAR_ZEROFILL: { | 
|  | // ZEROFILL: [size] | 
|  | if (!isValidRecordSize(1, "zerofill")) | 
|  | return; | 
|  | auto *Pool = Context->getGlobalVariablesPool(); | 
|  | CurGlobalVar->addInitializer( | 
|  | Ice::VariableDeclaration::ZeroInitializer::create(Pool, Values[0])); | 
|  | return; | 
|  | } | 
|  | case naclbitc::GLOBALVAR_DATA: { | 
|  | // DATA: [b0, b1, ...] | 
|  | if (!isValidRecordSizeAtLeast(1, "data")) | 
|  | return; | 
|  | auto *Pool = Context->getGlobalVariablesPool(); | 
|  | CurGlobalVar->addInitializer( | 
|  | Ice::VariableDeclaration::DataInitializer::create(Pool, Values)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::GLOBALVAR_RELOC: { | 
|  | // RELOC: [val, [addend]] | 
|  | if (!isValidRecordSizeInRange(1, 2, "reloc")) | 
|  | return; | 
|  | NaClBcIndexSize_t Index = Values[0]; | 
|  | NaClBcIndexSize_t IndexLimit = SpecifiedNumberVars + NumFunctionIDs; | 
|  | if (Index >= IndexLimit) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Relocation index " << Index << " to big. Expect index < " | 
|  | << IndexLimit; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | uint64_t Offset = 0; | 
|  | if (Values.size() == 2) { | 
|  | Offset = Values[1]; | 
|  | if (Offset > std::numeric_limits<uint32_t>::max()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Addend of global reloc record too big: " << Offset; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | } | 
|  | auto *Pool = Context->getGlobalVariablesPool(); | 
|  | Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | CurGlobalVar->addInitializer( | 
|  | Ice::VariableDeclaration::RelocInitializer::create( | 
|  | Pool, getGlobalDeclByID(Index), | 
|  | {Ice::RelocOffset::create(Ctx, Offset)})); | 
|  | return; | 
|  | } | 
|  | default: | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Base class for parsing a valuesymtab block in the bitcode file. | 
|  | class ValuesymtabParser : public BlockParserBaseClass { | 
|  | ValuesymtabParser() = delete; | 
|  | ValuesymtabParser(const ValuesymtabParser &) = delete; | 
|  | void operator=(const ValuesymtabParser &) = delete; | 
|  |  | 
|  | public: | 
|  | ValuesymtabParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser) | 
|  | : BlockParserBaseClass(BlockID, EnclosingParser) {} | 
|  |  | 
|  | ~ValuesymtabParser() override = default; | 
|  |  | 
|  | const char *getBlockName() const override { return "valuesymtab"; } | 
|  |  | 
|  | protected: | 
|  | using StringType = SmallString<128>; | 
|  |  | 
|  | // Returns the name to identify the kind of symbol table this is | 
|  | // in error messages. | 
|  | virtual const char *getTableKind() const = 0; | 
|  |  | 
|  | // Associates Name with the value defined by the given Index. | 
|  | virtual void setValueName(NaClBcIndexSize_t Index, StringType &Name) = 0; | 
|  |  | 
|  | // Associates Name with the value defined by the given Index; | 
|  | virtual void setBbName(NaClBcIndexSize_t Index, StringType &Name) = 0; | 
|  |  | 
|  | // Reports that the assignment of Name to the value associated with | 
|  | // index is not possible, for the given Context. | 
|  | void reportUnableToAssign(const char *Context, NaClBcIndexSize_t Index, | 
|  | StringType &Name); | 
|  |  | 
|  | private: | 
|  | using NamesSetType = std::unordered_set<StringType>; | 
|  | NamesSetType ValueNames; | 
|  | NamesSetType BlockNames; | 
|  |  | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | // Extracts out ConvertedName. Returns true if unique wrt to Names. | 
|  | bool convertToString(NamesSetType &Names, 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]); | 
|  | } | 
|  | auto Pair = Names.insert(ConvertedName); | 
|  | return Pair.second; | 
|  | } | 
|  |  | 
|  | void ReportDuplicateName(const char *NameCat, StringType &Name); | 
|  | }; | 
|  |  | 
|  | void ValuesymtabParser::reportUnableToAssign(const char *Context, | 
|  | NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << getTableKind() << " " << getBlockName() << ": " << Context | 
|  | << " name '" << Name << "' can't be associated with index " << Index; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | void ValuesymtabParser::ReportDuplicateName(const char *NameCat, | 
|  | StringType &Name) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << getTableKind() << " " << getBlockName() << " defines duplicate " | 
|  | << NameCat << " name: '" << Name << "'"; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | 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 (!isValidRecordSizeAtLeast(2, "value entry")) | 
|  | return; | 
|  | if (convertToString(ValueNames, ConvertedName)) | 
|  | setValueName(Values[0], ConvertedName); | 
|  | else | 
|  | ReportDuplicateName("value", ConvertedName); | 
|  | return; | 
|  | } | 
|  | case naclbitc::VST_CODE_BBENTRY: { | 
|  | // VST_BBENTRY: [BbId, namechar x N] | 
|  | if (!isValidRecordSizeAtLeast(2, "basic block entry")) | 
|  | return; | 
|  | if (convertToString(BlockNames, ConvertedName)) | 
|  | setBbName(Values[0], ConvertedName); | 
|  | else | 
|  | ReportDuplicateName("block", ConvertedName); | 
|  | return; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | // If reached, don't know how to handle record. | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /// Parses function blocks in the bitcode file. | 
|  | class FunctionParser final : public BlockParserBaseClass { | 
|  | FunctionParser() = delete; | 
|  | FunctionParser(const FunctionParser &) = delete; | 
|  | FunctionParser &operator=(const FunctionParser &) = delete; | 
|  |  | 
|  | public: | 
|  | FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser, | 
|  | NaClBcIndexSize_t FcnId) | 
|  | : BlockParserBaseClass(BlockID, EnclosingParser), | 
|  | Timer(Ice::TimerStack::TT_parseFunctions, getTranslator().getContext()), | 
|  | Func(nullptr), FuncDecl(Context->getFunctionByID(FcnId)), | 
|  | CachedNumGlobalValueIDs(Context->getNumGlobalIDs()), | 
|  | NextLocalInstIndex(Context->getNumGlobalIDs()) {} | 
|  |  | 
|  | FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser, | 
|  | NaClBcIndexSize_t FcnId, NaClBitstreamCursor &Cursor) | 
|  | : BlockParserBaseClass(BlockID, EnclosingParser, Cursor), | 
|  | Timer(Ice::TimerStack::TT_parseFunctions, getTranslator().getContext()), | 
|  | Func(nullptr), FuncDecl(Context->getFunctionByID(FcnId)), | 
|  | CachedNumGlobalValueIDs(Context->getNumGlobalIDs()), | 
|  | NextLocalInstIndex(Context->getNumGlobalIDs()) {} | 
|  |  | 
|  | std::unique_ptr<Ice::Cfg> parseFunction(uint32_t SeqNumber) { | 
|  | bool ParserResult; | 
|  | Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | { | 
|  | Ice::TimerMarker T(Ctx, FuncDecl->getName().toStringOrEmpty()); | 
|  | // Note: The Cfg is created, even when IR generation is disabled. This is | 
|  | // done to install a CfgLocalAllocator for various internal containers. | 
|  | Ice::GlobalContext *Ctx = getTranslator().getContext(); | 
|  | Func = Ice::Cfg::create(Ctx, SeqNumber); | 
|  |  | 
|  | Ice::CfgLocalAllocatorScope _(Func.get()); | 
|  |  | 
|  | // TODO(kschimpf) Clean up API to add a function signature to a CFG. | 
|  | const Ice::FuncSigType &Signature = FuncDecl->getSignature(); | 
|  |  | 
|  | Func->setFunctionName(FuncDecl->getName()); | 
|  | Func->setReturnType(Signature.getReturnType()); | 
|  | Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage); | 
|  | CurrentNode = installNextBasicBlock(); | 
|  | Func->setEntryNode(CurrentNode); | 
|  | for (Ice::Type ArgType : Signature.getArgList()) { | 
|  | Func->addArg(getNextInstVar(ArgType)); | 
|  | } | 
|  |  | 
|  | ParserResult = ParseThisBlock(); | 
|  | } | 
|  |  | 
|  | if (ParserResult || BlockHasError) | 
|  | Func->setError("Unable to parse function"); | 
|  |  | 
|  | return std::move(Func); | 
|  | } | 
|  |  | 
|  | ~FunctionParser() override = default; | 
|  |  | 
|  | const char *getBlockName() const override { return "function"; } | 
|  |  | 
|  | Ice::Cfg *getFunc() const { return Func.get(); } | 
|  |  | 
|  | size_t getNumGlobalIDs() const { return CachedNumGlobalValueIDs; } | 
|  |  | 
|  | void setNextLocalInstIndex(Ice::Operand *Op) { | 
|  | setOperand(NextLocalInstIndex++, Op); | 
|  | } | 
|  |  | 
|  | // Set the next constant ID to the given constant C. | 
|  | void setNextConstantID(Ice::Constant *C) { setNextLocalInstIndex(C); } | 
|  |  | 
|  | // Returns the value referenced by the given value Index. | 
|  | Ice::Operand *getOperand(NaClBcIndexSize_t Index) { | 
|  | if (Index < CachedNumGlobalValueIDs) { | 
|  | return Context->getGlobalConstantByID(Index); | 
|  | } | 
|  | NaClBcIndexSize_t LocalIndex = Index - CachedNumGlobalValueIDs; | 
|  | if (LocalIndex >= LocalOperands.size()) | 
|  | reportGetOperandUndefined(Index); | 
|  | Ice::Operand *Op = LocalOperands[LocalIndex]; | 
|  | if (Op == nullptr) | 
|  | reportGetOperandUndefined(Index); | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | // The number of words in the bitstream defining the function block. | 
|  | uint64_t NumBytesDefiningFunction = 0; | 
|  | // Maximum number of records that can appear in the function block, based on | 
|  | // the number of bytes defining the function block. | 
|  | uint64_t MaxRecordsInBlock = 0; | 
|  | // The corresponding ICE function defined by the function block. | 
|  | std::unique_ptr<Ice::Cfg> Func; | 
|  | // The index to the current basic block being built. | 
|  | NaClBcIndexSize_t CurrentBbIndex = 0; | 
|  | // The number of basic blocks declared for the function block. | 
|  | NaClBcIndexSize_t DeclaredNumberBbs = 0; | 
|  | // The basic block being built. | 
|  | Ice::CfgNode *CurrentNode = nullptr; | 
|  | // The corresponding function declaration. | 
|  | Ice::FunctionDeclaration *FuncDecl; | 
|  | // Holds the dividing point between local and global absolute value indices. | 
|  | size_t CachedNumGlobalValueIDs; | 
|  | // Holds operands local to the function block, based on indices defined in | 
|  | // the bitcode file. | 
|  | Ice::OperandList LocalOperands; | 
|  | // Holds the index within LocalOperands corresponding to the next instruction | 
|  | // that generates a value. | 
|  | NaClBcIndexSize_t NextLocalInstIndex; | 
|  | // True if the last processed instruction was a terminating instruction. | 
|  | bool InstIsTerminating = false; | 
|  |  | 
|  | bool ParseBlock(unsigned BlockID) override; | 
|  |  | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | void EnterBlock(unsigned NumWords) override { | 
|  | // Note: Bitstream defines words as 32-bit values. | 
|  | NumBytesDefiningFunction = NumWords * sizeof(uint32_t); | 
|  | // We know that all records are minimally defined by a two-bit abreviation. | 
|  | MaxRecordsInBlock = NumBytesDefiningFunction * (CHAR_BIT >> 1); | 
|  | } | 
|  |  | 
|  | void ExitBlock() override; | 
|  |  | 
|  | // Creates and appends a new basic block to the list of basic blocks. | 
|  | Ice::CfgNode *installNextBasicBlock() { | 
|  | Ice::CfgNode *Node = Func->makeNode(); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | // Returns the Index-th basic block in the list of basic blocks. | 
|  | Ice::CfgNode *getBasicBlock(NaClBcIndexSize_t Index) { | 
|  | if (Index >= Func->getNumNodes()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Reference to basic block " << Index | 
|  | << " not found. Must be less than " << Func->getNumNodes(); | 
|  | Error(StrBuf.str()); | 
|  | Index = 0; | 
|  | } | 
|  | return Func->getNodes()[Index]; | 
|  | } | 
|  |  | 
|  | // Returns the Index-th basic block in the list of basic blocks. Assumes | 
|  | // Index corresponds to a branch instruction. Hence, if the branch references | 
|  | // the entry block, it also generates a corresponding error. | 
|  | Ice::CfgNode *getBranchBasicBlock(NaClBcIndexSize_t Index) { | 
|  | if (Index == 0) { | 
|  | Error("Branch to entry block not allowed"); | 
|  | } | 
|  | return getBasicBlock(Index); | 
|  | } | 
|  |  | 
|  | // Generate an instruction variable with type Ty. | 
|  | Ice::Variable *createInstVar(Ice::Type Ty) { | 
|  | if (Ty == Ice::IceType_void) { | 
|  | Error("Can't define instruction value using type void"); | 
|  | // Recover since we can't throw an exception. | 
|  | Ty = Ice::IceType_i32; | 
|  | } | 
|  | return Func->makeVariable(Ty); | 
|  | } | 
|  |  | 
|  | // Generates the next available local variable using the given type. | 
|  | Ice::Variable *getNextInstVar(Ice::Type Ty) { | 
|  | assert(NextLocalInstIndex >= CachedNumGlobalValueIDs); | 
|  | // Before creating one, see if a forwardtyperef has already defined it. | 
|  | NaClBcIndexSize_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs; | 
|  | if (LocalIndex < LocalOperands.size()) { | 
|  | Ice::Operand *Op = LocalOperands[LocalIndex]; | 
|  | if (Op != nullptr) { | 
|  | if (auto *Var = dyn_cast<Ice::Variable>(Op)) { | 
|  | if (Var->getType() == Ty) { | 
|  | ++NextLocalInstIndex; | 
|  | return Var; | 
|  | } | 
|  | } | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Illegal forward referenced instruction (" | 
|  | << NextLocalInstIndex << "): " << *Op; | 
|  | Error(StrBuf.str()); | 
|  | ++NextLocalInstIndex; | 
|  | return createInstVar(Ty); | 
|  | } | 
|  | } | 
|  | Ice::Variable *Var = createInstVar(Ty); | 
|  | setOperand(NextLocalInstIndex++, Var); | 
|  | return Var; | 
|  | } | 
|  |  | 
|  | // Converts a relative index (wrt to BaseIndex) to an absolute value index. | 
|  | NaClBcIndexSize_t convertRelativeToAbsIndex(NaClRelBcIndexSize_t Id, | 
|  | NaClRelBcIndexSize_t BaseIndex) { | 
|  | if (BaseIndex < Id) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid relative value id: " << Id | 
|  | << " (must be <= " << BaseIndex << ")"; | 
|  | Error(StrBuf.str()); | 
|  | return 0; | 
|  | } | 
|  | return BaseIndex - Id; | 
|  | } | 
|  |  | 
|  | // Sets element Index (in the local operands list) to Op. | 
|  | void setOperand(NaClBcIndexSize_t Index, Ice::Operand *Op) { | 
|  | assert(Op); | 
|  | // Check if simple push works. | 
|  | NaClBcIndexSize_t LocalIndex = Index - CachedNumGlobalValueIDs; | 
|  | if (LocalIndex == LocalOperands.size()) { | 
|  | LocalOperands.push_back(Op); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Must be forward reference, expand vector to accommodate. | 
|  | if (LocalIndex >= LocalOperands.size()) { | 
|  | if (LocalIndex > MaxRecordsInBlock) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Forward reference @" << Index << " too big. Have " | 
|  | << CachedNumGlobalValueIDs << " globals and function contains " | 
|  | << NumBytesDefiningFunction << " bytes"; | 
|  | Fatal(StrBuf.str()); | 
|  | // Recover by using index one beyond the maximal allowed. | 
|  | LocalIndex = MaxRecordsInBlock; | 
|  | } | 
|  | Ice::Utils::reserveAndResize(LocalOperands, LocalIndex + 1); | 
|  | } | 
|  |  | 
|  | // If element not defined, set it. | 
|  | Ice::Operand *OldOp = LocalOperands[LocalIndex]; | 
|  | if (OldOp == nullptr) { | 
|  | LocalOperands[LocalIndex] = Op; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // See if forward reference matches. | 
|  | if (OldOp == Op) | 
|  | return; | 
|  |  | 
|  | // Error has occurred. | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Multiple definitions for index " << Index << ": " << *Op | 
|  | << " and " << *OldOp; | 
|  | Error(StrBuf.str()); | 
|  | LocalOperands[LocalIndex] = Op; | 
|  | } | 
|  |  | 
|  | // Returns the relative operand (wrt to BaseIndex) referenced by the given | 
|  | // value Index. | 
|  | Ice::Operand *getRelativeOperand(NaClBcIndexSize_t Index, | 
|  | NaClBcIndexSize_t BaseIndex) { | 
|  | return getOperand(convertRelativeToAbsIndex(Index, BaseIndex)); | 
|  | } | 
|  |  | 
|  | // Returns the absolute index of the next value generating instruction. | 
|  | NaClBcIndexSize_t getNextInstIndex() const { return NextLocalInstIndex; } | 
|  |  | 
|  | // 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 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; | 
|  | reportInvalidBinaryOp(Op, OpTy); | 
|  | 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 = Ice::getPointerType(); | 
|  | if (Op->getType() == PtrType) | 
|  | return true; | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << InstructionName << " address not " << PtrType | 
|  | << ". Found: " << Op->getType(); | 
|  | 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(size_t Alignment, Ice::Type Ty, | 
|  | const char *InstructionName) { | 
|  | if (!isValidLoadStoreType(Ty, InstructionName)) | 
|  | return false; | 
|  | if (isAllowedAlignment(Alignment, Ty)) | 
|  | return true; | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << InstructionName << " " << Ty << "*: not allowed for alignment " | 
|  | << Alignment; | 
|  | Error(StrBuf.str()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Defines if the given alignment is valid for the given type. Simplified | 
|  | // version of PNaClABIProps::isAllowedAlignment, based on API's offered for | 
|  | // Ice::Type. | 
|  | bool isAllowedAlignment(size_t Alignment, Ice::Type Ty) const { | 
|  | return Alignment == typeAlignInBytes(Ty) || | 
|  | (Alignment == 1 && !isVectorType(Ty)); | 
|  | } | 
|  |  | 
|  | // Types of errors that can occur for insertelement and extractelement | 
|  | // instructions. | 
|  | enum VectorIndexCheckValue { | 
|  | VectorIndexNotVector, | 
|  | VectorIndexNotConstant, | 
|  | VectorIndexNotInRange, | 
|  | VectorIndexNotI32, | 
|  | VectorIndexValid | 
|  | }; | 
|  |  | 
|  | void dumpVectorIndexCheckValue(raw_ostream &Stream, | 
|  | VectorIndexCheckValue Value) const { | 
|  | if (!Ice::BuildDefs::dump()) | 
|  | return; | 
|  | switch (Value) { | 
|  | case VectorIndexNotVector: | 
|  | Stream << "Vector index on non vector"; | 
|  | break; | 
|  | case VectorIndexNotConstant: | 
|  | Stream << "Vector index not integer constant"; | 
|  | break; | 
|  | case VectorIndexNotInRange: | 
|  | Stream << "Vector index not in range of vector"; | 
|  | break; | 
|  | case VectorIndexNotI32: | 
|  | Stream << "Vector index not of type " << Ice::IceType_i32; | 
|  | break; | 
|  | case VectorIndexValid: | 
|  | Stream << "Valid vector index"; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Returns whether the given vector index (for insertelement and | 
|  | // extractelement instructions) is valid. | 
|  | VectorIndexCheckValue validateVectorIndex(const Ice::Operand *Vec, | 
|  | const Ice::Operand *Index) const { | 
|  | Ice::Type VecType = Vec->getType(); | 
|  | if (!Ice::isVectorType(VecType)) | 
|  | return VectorIndexNotVector; | 
|  | const auto *C = dyn_cast<Ice::ConstantInteger32>(Index); | 
|  | if (C == nullptr) | 
|  | return VectorIndexNotConstant; | 
|  | if (static_cast<size_t>(C->getValue()) >= typeNumElements(VecType)) | 
|  | return VectorIndexNotInRange; | 
|  | if (Index->getType() != Ice::IceType_i32) | 
|  | return VectorIndexNotI32; | 
|  | return VectorIndexValid; | 
|  | } | 
|  |  | 
|  | // 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) { | 
|  | switch (Opcode) { | 
|  | default: { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Binary opcode " << Opcode << "not understood for type " << Ty; | 
|  | Error(StrBuf.str()); | 
|  | Op = Ice::InstArithmetic::Add; | 
|  | return false; | 
|  | } | 
|  | case naclbitc::BINOP_ADD: | 
|  | if (Ice::isIntegerType(Ty)) { | 
|  | Op = Ice::InstArithmetic::Add; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | } else { | 
|  | Op = Ice::InstArithmetic::Fadd; | 
|  | return isValidFloatingArithOp(Op, Ty); | 
|  | } | 
|  | case naclbitc::BINOP_SUB: | 
|  | if (Ice::isIntegerType(Ty)) { | 
|  | Op = Ice::InstArithmetic::Sub; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | } else { | 
|  | Op = Ice::InstArithmetic::Fsub; | 
|  | return isValidFloatingArithOp(Op, Ty); | 
|  | } | 
|  | case naclbitc::BINOP_MUL: | 
|  | if (Ice::isIntegerType(Ty)) { | 
|  | Op = Ice::InstArithmetic::Mul; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | } else { | 
|  | Op = Ice::InstArithmetic::Fmul; | 
|  | return isValidFloatingArithOp(Op, Ty); | 
|  | } | 
|  | case naclbitc::BINOP_UDIV: | 
|  | Op = Ice::InstArithmetic::Udiv; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | case naclbitc::BINOP_SDIV: | 
|  | if (Ice::isIntegerType(Ty)) { | 
|  | Op = Ice::InstArithmetic::Sdiv; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | } else { | 
|  | Op = Ice::InstArithmetic::Fdiv; | 
|  | return isValidFloatingArithOp(Op, Ty); | 
|  | } | 
|  | case naclbitc::BINOP_UREM: | 
|  | Op = Ice::InstArithmetic::Urem; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | case naclbitc::BINOP_SREM: | 
|  | if (Ice::isIntegerType(Ty)) { | 
|  | Op = Ice::InstArithmetic::Srem; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | } else { | 
|  | Op = Ice::InstArithmetic::Frem; | 
|  | return isValidFloatingArithOp(Op, Ty); | 
|  | } | 
|  | case naclbitc::BINOP_SHL: | 
|  | Op = Ice::InstArithmetic::Shl; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | case naclbitc::BINOP_LSHR: | 
|  | Op = Ice::InstArithmetic::Lshr; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | case naclbitc::BINOP_ASHR: | 
|  | Op = Ice::InstArithmetic::Ashr; | 
|  | return isValidIntegerArithOp(Op, Ty); | 
|  | case naclbitc::BINOP_AND: | 
|  | Op = Ice::InstArithmetic::And; | 
|  | return isValidIntegerLogicalOp(Op, Ty); | 
|  | case naclbitc::BINOP_OR: | 
|  | Op = Ice::InstArithmetic::Or; | 
|  | return isValidIntegerLogicalOp(Op, Ty); | 
|  | case naclbitc::BINOP_XOR: | 
|  | Op = Ice::InstArithmetic::Xor; | 
|  | return isValidIntegerLogicalOp(Op, Ty); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Simplifies out vector types from Type1 and Type2, if both are vectors of | 
|  | /// the same size. Returns true iff both are vectors of the same size, or are | 
|  | /// both scalar types. | 
|  | static bool simplifyOutCommonVectorType(Ice::Type &Type1, Ice::Type &Type2) { | 
|  | bool IsType1Vector = isVectorType(Type1); | 
|  | bool IsType2Vector = isVectorType(Type2); | 
|  | if (IsType1Vector != IsType2Vector) | 
|  | return false; | 
|  | if (!IsType1Vector) | 
|  | return true; | 
|  | if (typeNumElements(Type1) != typeNumElements(Type2)) | 
|  | return false; | 
|  | Type1 = typeElementType(Type1); | 
|  | Type2 = typeElementType(Type2); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Returns true iff an integer truncation from SourceType to TargetType is | 
|  | /// valid. | 
|  | static bool isIntTruncCastValid(Ice::Type SourceType, Ice::Type TargetType) { | 
|  | return Ice::isIntegerType(SourceType) && Ice::isIntegerType(TargetType) && | 
|  | simplifyOutCommonVectorType(SourceType, TargetType) && | 
|  | getScalarIntBitWidth(SourceType) > getScalarIntBitWidth(TargetType); | 
|  | } | 
|  |  | 
|  | /// Returns true iff a floating type truncation from SourceType to TargetType | 
|  | /// is valid. | 
|  | static bool isFloatTruncCastValid(Ice::Type SourceType, | 
|  | Ice::Type TargetType) { | 
|  | return simplifyOutCommonVectorType(SourceType, TargetType) && | 
|  | SourceType == Ice::IceType_f64 && TargetType == Ice::IceType_f32; | 
|  | } | 
|  |  | 
|  | /// Returns true iff an integer extension from SourceType to TargetType is | 
|  | /// valid. | 
|  | static bool isIntExtCastValid(Ice::Type SourceType, Ice::Type TargetType) { | 
|  | return isIntTruncCastValid(TargetType, SourceType); | 
|  | } | 
|  |  | 
|  | /// Returns true iff a floating type extension from SourceType to TargetType | 
|  | /// is valid. | 
|  | static bool isFloatExtCastValid(Ice::Type SourceType, Ice::Type TargetType) { | 
|  | return isFloatTruncCastValid(TargetType, SourceType); | 
|  | } | 
|  |  | 
|  | /// Returns true iff a cast from floating type SourceType to integer type | 
|  | /// TargetType is valid. | 
|  | static bool isFloatToIntCastValid(Ice::Type SourceType, | 
|  | Ice::Type TargetType) { | 
|  | if (!(Ice::isFloatingType(SourceType) && Ice::isIntegerType(TargetType))) | 
|  | return false; | 
|  | bool IsSourceVector = isVectorType(SourceType); | 
|  | bool IsTargetVector = isVectorType(TargetType); | 
|  | if (IsSourceVector != IsTargetVector) | 
|  | return false; | 
|  | if (IsSourceVector) { | 
|  | return typeNumElements(SourceType) == typeNumElements(TargetType); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Returns true iff a cast from integer type SourceType to floating type | 
|  | /// TargetType is valid. | 
|  | static bool isIntToFloatCastValid(Ice::Type SourceType, | 
|  | Ice::Type TargetType) { | 
|  | return isFloatToIntCastValid(TargetType, SourceType); | 
|  | } | 
|  |  | 
|  | /// Returns the number of bits used to model type Ty when defining the bitcast | 
|  | /// instruction. | 
|  | static Ice::SizeT bitcastSizeInBits(Ice::Type Ty) { | 
|  | if (Ice::isVectorType(Ty)) | 
|  | return Ice::typeNumElements(Ty) * | 
|  | bitcastSizeInBits(Ice::typeElementType(Ty)); | 
|  | if (Ty == Ice::IceType_i1) | 
|  | return 1; | 
|  | return Ice::typeWidthInBytes(Ty) * CHAR_BIT; | 
|  | } | 
|  |  | 
|  | /// Returns true iff a bitcast from SourceType to TargetType is allowed. | 
|  | static bool isBitcastValid(Ice::Type SourceType, Ice::Type TargetType) { | 
|  | return bitcastSizeInBits(SourceType) == bitcastSizeInBits(TargetType); | 
|  | } | 
|  |  | 
|  | /// Returns true iff the NaCl bitcode Opcode is a valid cast opcode for | 
|  | /// converting SourceType to TargetType. Updates CastKind to the corresponding | 
|  | /// instruction cast opcode. Also generates an error message when this | 
|  | /// function returns false. | 
|  | bool convertCastOpToIceOp(uint64_t Opcode, Ice::Type SourceType, | 
|  | Ice::Type TargetType, | 
|  | Ice::InstCast::OpKind &CastKind) { | 
|  | bool Result; | 
|  | switch (Opcode) { | 
|  | default: { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Cast opcode " << Opcode << " not understood.\n"; | 
|  | Error(StrBuf.str()); | 
|  | CastKind = Ice::InstCast::Bitcast; | 
|  | return false; | 
|  | } | 
|  | case naclbitc::CAST_TRUNC: | 
|  | CastKind = Ice::InstCast::Trunc; | 
|  | Result = isIntTruncCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_ZEXT: | 
|  | CastKind = Ice::InstCast::Zext; | 
|  | Result = isIntExtCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_SEXT: | 
|  | CastKind = Ice::InstCast::Sext; | 
|  | Result = isIntExtCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_FPTOUI: | 
|  | CastKind = Ice::InstCast::Fptoui; | 
|  | Result = isFloatToIntCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_FPTOSI: | 
|  | CastKind = Ice::InstCast::Fptosi; | 
|  | Result = isFloatToIntCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_UITOFP: | 
|  | CastKind = Ice::InstCast::Uitofp; | 
|  | Result = isIntToFloatCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_SITOFP: | 
|  | CastKind = Ice::InstCast::Sitofp; | 
|  | Result = isIntToFloatCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_FPTRUNC: | 
|  | CastKind = Ice::InstCast::Fptrunc; | 
|  | Result = isFloatTruncCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_FPEXT: | 
|  | CastKind = Ice::InstCast::Fpext; | 
|  | Result = isFloatExtCastValid(SourceType, TargetType); | 
|  | break; | 
|  | case naclbitc::CAST_BITCAST: | 
|  | CastKind = Ice::InstCast::Bitcast; | 
|  | Result = isBitcastValid(SourceType, TargetType); | 
|  | break; | 
|  | } | 
|  | if (!Result) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Illegal cast: " << Ice::InstCast::getCastName(CastKind) << " " | 
|  | << SourceType << " to " << TargetType; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // Converts PNaCl bitcode Icmp operator to corresponding ICE op. Returns true | 
|  | // if able to convert, false otherwise. | 
|  | bool convertNaClBitcICmpOpToIce(uint64_t Op, | 
|  | Ice::InstIcmp::ICond &Cond) const { | 
|  | switch (Op) { | 
|  | case naclbitc::ICMP_EQ: | 
|  | Cond = Ice::InstIcmp::Eq; | 
|  | return true; | 
|  | case naclbitc::ICMP_NE: | 
|  | Cond = Ice::InstIcmp::Ne; | 
|  | return true; | 
|  | case naclbitc::ICMP_UGT: | 
|  | Cond = Ice::InstIcmp::Ugt; | 
|  | return true; | 
|  | case naclbitc::ICMP_UGE: | 
|  | Cond = Ice::InstIcmp::Uge; | 
|  | return true; | 
|  | case naclbitc::ICMP_ULT: | 
|  | Cond = Ice::InstIcmp::Ult; | 
|  | return true; | 
|  | case naclbitc::ICMP_ULE: | 
|  | Cond = Ice::InstIcmp::Ule; | 
|  | return true; | 
|  | case naclbitc::ICMP_SGT: | 
|  | Cond = Ice::InstIcmp::Sgt; | 
|  | return true; | 
|  | case naclbitc::ICMP_SGE: | 
|  | Cond = Ice::InstIcmp::Sge; | 
|  | return true; | 
|  | case naclbitc::ICMP_SLT: | 
|  | Cond = Ice::InstIcmp::Slt; | 
|  | return true; | 
|  | case naclbitc::ICMP_SLE: | 
|  | Cond = Ice::InstIcmp::Sle; | 
|  | return true; | 
|  | default: | 
|  | // Make sure Cond is always initialized. | 
|  | Cond = static_cast<Ice::InstIcmp::ICond>(0); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Converts PNaCl bitcode Fcmp operator to corresponding ICE op. Returns true | 
|  | // if able to convert, false otherwise. | 
|  | bool convertNaClBitcFCompOpToIce(uint64_t Op, | 
|  | Ice::InstFcmp::FCond &Cond) const { | 
|  | switch (Op) { | 
|  | case naclbitc::FCMP_FALSE: | 
|  | Cond = Ice::InstFcmp::False; | 
|  | return true; | 
|  | case naclbitc::FCMP_OEQ: | 
|  | Cond = Ice::InstFcmp::Oeq; | 
|  | return true; | 
|  | case naclbitc::FCMP_OGT: | 
|  | Cond = Ice::InstFcmp::Ogt; | 
|  | return true; | 
|  | case naclbitc::FCMP_OGE: | 
|  | Cond = Ice::InstFcmp::Oge; | 
|  | return true; | 
|  | case naclbitc::FCMP_OLT: | 
|  | Cond = Ice::InstFcmp::Olt; | 
|  | return true; | 
|  | case naclbitc::FCMP_OLE: | 
|  | Cond = Ice::InstFcmp::Ole; | 
|  | return true; | 
|  | case naclbitc::FCMP_ONE: | 
|  | Cond = Ice::InstFcmp::One; | 
|  | return true; | 
|  | case naclbitc::FCMP_ORD: | 
|  | Cond = Ice::InstFcmp::Ord; | 
|  | return true; | 
|  | case naclbitc::FCMP_UNO: | 
|  | Cond = Ice::InstFcmp::Uno; | 
|  | return true; | 
|  | case naclbitc::FCMP_UEQ: | 
|  | Cond = Ice::InstFcmp::Ueq; | 
|  | return true; | 
|  | case naclbitc::FCMP_UGT: | 
|  | Cond = Ice::InstFcmp::Ugt; | 
|  | return true; | 
|  | case naclbitc::FCMP_UGE: | 
|  | Cond = Ice::InstFcmp::Uge; | 
|  | return true; | 
|  | case naclbitc::FCMP_ULT: | 
|  | Cond = Ice::InstFcmp::Ult; | 
|  | return true; | 
|  | case naclbitc::FCMP_ULE: | 
|  | Cond = Ice::InstFcmp::Ule; | 
|  | return true; | 
|  | case naclbitc::FCMP_UNE: | 
|  | Cond = Ice::InstFcmp::Une; | 
|  | return true; | 
|  | case naclbitc::FCMP_TRUE: | 
|  | Cond = Ice::InstFcmp::True; | 
|  | return true; | 
|  | default: | 
|  | // Make sure Cond is always initialized. | 
|  | Cond = static_cast<Ice::InstFcmp::FCond>(0); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Creates an error instruction, generating a value of type Ty, and adds a | 
|  | // placeholder so that instruction indices line up. Some instructions, such | 
|  | // as a call, will not generate a value if the return type is void. In such | 
|  | // cases, a placeholder value for the badly formed instruction is not needed. | 
|  | // Hence, if Ty is void, an error instruction is not appended. | 
|  | void appendErrorInstruction(Ice::Type Ty) { | 
|  | // Note: we don't worry about downstream translation errors because the | 
|  | // function will not be translated if any errors occur. | 
|  | if (Ty == Ice::IceType_void) | 
|  | return; | 
|  | Ice::Variable *Var = getNextInstVar(Ty); | 
|  | CurrentNode->appendInst(Ice::InstAssign::create(Func.get(), Var, Var)); | 
|  | } | 
|  |  | 
|  | Ice::Operand *reportGetOperandUndefined(NaClBcIndexSize_t Index) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Value index " << Index << " not defined!"; | 
|  | Error(StrBuf.str()); | 
|  | // Recover and return some value. | 
|  | if (!LocalOperands.empty()) | 
|  | return LocalOperands.front(); | 
|  | return Context->getGlobalConstantByID(0); | 
|  | } | 
|  |  | 
|  | void verifyCallArgTypeMatches(Ice::FunctionDeclaration *Fcn, Ice::SizeT Index, | 
|  | Ice::Type ArgType, Ice::Type ParamType) { | 
|  | if (ArgType != ParamType) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Argument " << (Index + 1) << " of " << printName(Fcn) | 
|  | << " expects " << ParamType << ". Found: " << ArgType; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | const std::string printName(Ice::FunctionDeclaration *Fcn) { | 
|  | if (Fcn) | 
|  | return Fcn->getName().toString(); | 
|  | return "function"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void FunctionParser::ExitBlock() { | 
|  | // Check if the last instruction in the function was terminating. | 
|  | if (!InstIsTerminating) { | 
|  | Error("Last instruction in function not terminator"); | 
|  | // Recover by inserting an unreachable instruction. | 
|  | CurrentNode->appendInst(Ice::InstUnreachable::create(Func.get())); | 
|  | } | 
|  | ++CurrentBbIndex; | 
|  | if (CurrentBbIndex != DeclaredNumberBbs) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function declared " << DeclaredNumberBbs | 
|  | << " basic blocks, but defined " << CurrentBbIndex << "."; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | // Before translating, check for blocks without instructions, and insert | 
|  | // unreachable. This shouldn't happen, but be safe. | 
|  | size_t Index = 0; | 
|  | for (Ice::CfgNode *Node : Func->getNodes()) { | 
|  | if (Node->getInsts().empty()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Basic block " << Index << " contains no instructions"; | 
|  | Error(StrBuf.str()); | 
|  | Node->appendInst(Ice::InstUnreachable::create(Func.get())); | 
|  | } | 
|  | ++Index; | 
|  | } | 
|  | Func->computeInOutEdges(); | 
|  | } | 
|  |  | 
|  | 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() { | 
|  | // Note: To better separate parse/IR generation times, when IR generation is | 
|  | // disabled we do the following: | 
|  | // 1) Delay exiting until after we extract operands. | 
|  | // 2) return before we access operands, since all operands will be a nullptr. | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | if (InstIsTerminating) { | 
|  | InstIsTerminating = false; | 
|  | ++CurrentBbIndex; | 
|  | CurrentNode = getBasicBlock(CurrentBbIndex); | 
|  | } | 
|  | // The base index for relative indexing. | 
|  | NaClBcIndexSize_t BaseIndex = getNextInstIndex(); | 
|  | switch (Record.GetCode()) { | 
|  | case naclbitc::FUNC_CODE_DECLAREBLOCKS: { | 
|  | // DECLAREBLOCKS: [n] | 
|  | if (!isValidRecordSize(1, "count")) | 
|  | return; | 
|  | if (DeclaredNumberBbs > 0) { | 
|  | Error("Duplicate function block count record"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Check for bad large sizes, since they can make ridiculous memory | 
|  | // requests and hang the user for large amounts of time. | 
|  | uint64_t NumBbs = Values[0]; | 
|  | if (NumBbs > MaxRecordsInBlock) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function defines " << NumBbs | 
|  | << " basic blocks, which is too big for a function containing " | 
|  | << NumBytesDefiningFunction << " bytes"; | 
|  | Error(StrBuf.str()); | 
|  | NumBbs = MaxRecordsInBlock; | 
|  | } | 
|  |  | 
|  | if (NumBbs == 0) { | 
|  | Error("Functions must contain at least one basic block."); | 
|  | NumBbs = 1; | 
|  | } | 
|  |  | 
|  | DeclaredNumberBbs = NumBbs; | 
|  | // Install the basic blocks, skipping bb0 which was created in the | 
|  | // constructor. | 
|  | for (size_t i = 1; i < NumBbs; ++i) | 
|  | installNextBasicBlock(); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_BINOP: { | 
|  | // Note: Old bitcode files may have an additional 'flags' operand, which is | 
|  | // ignored. | 
|  |  | 
|  | // BINOP: [opval, opval, opcode, [flags]] | 
|  |  | 
|  | if (!isValidRecordSizeInRange(3, 4, "binop")) | 
|  | return; | 
|  | Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex); | 
|  | 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()); | 
|  | appendErrorInstruction(Type1); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Ice::InstArithmetic::OpKind Opcode; | 
|  | if (!convertBinopOpcode(Values[2], Type1, Opcode)) { | 
|  | appendErrorInstruction(Type1); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstArithmetic::create( | 
|  | Func.get(), Opcode, getNextInstVar(Type1), Op1, Op2)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_CAST: { | 
|  | // CAST: [opval, destty, castopc] | 
|  | if (!isValidRecordSize(3, "cast")) | 
|  | return; | 
|  | Ice::Operand *Src = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Type CastType = Context->getSimpleTypeByID(Values[1]); | 
|  | Ice::InstCast::OpKind CastKind; | 
|  | if (!convertCastOpToIceOp(Values[2], Src->getType(), CastType, CastKind)) { | 
|  | appendErrorInstruction(CastType); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstCast::create( | 
|  | Func.get(), CastKind, getNextInstVar(CastType), Src)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_VSELECT: { | 
|  | // VSELECT: [opval, opval, pred] | 
|  | if (!isValidRecordSize(3, "select")) | 
|  | return; | 
|  | Ice::Operand *ThenVal = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *ElseVal = getRelativeOperand(Values[1], BaseIndex); | 
|  | Ice::Operand *CondVal = getRelativeOperand(Values[2], BaseIndex); | 
|  | Ice::Type ThenType = ThenVal->getType(); | 
|  | Ice::Type ElseType = ElseVal->getType(); | 
|  | if (ThenType != ElseType) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Select operands not same type. Found " << ThenType << " and " | 
|  | << ElseType; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(ThenType); | 
|  | return; | 
|  | } | 
|  | Ice::Type CondType = CondVal->getType(); | 
|  | if (isVectorType(CondType)) { | 
|  | if (!isVectorType(ThenType) || | 
|  | typeElementType(CondType) != Ice::IceType_i1 || | 
|  | typeNumElements(ThenType) != typeNumElements(CondType)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Select condition type " << CondType | 
|  | << " not allowed for values of type " << ThenType; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(ThenType); | 
|  | return; | 
|  | } | 
|  | } else if (CondVal->getType() != Ice::IceType_i1) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Select condition " << CondVal | 
|  | << " not type i1. Found: " << CondVal->getType(); | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(ThenType); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstSelect::create( | 
|  | Func.get(), getNextInstVar(ThenType), CondVal, ThenVal, ElseVal)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_EXTRACTELT: { | 
|  | // EXTRACTELT: [opval, opval] | 
|  | if (!isValidRecordSize(2, "extract element")) | 
|  | return; | 
|  | Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *Index = getRelativeOperand(Values[1], BaseIndex); | 
|  | Ice::Type VecType = Vec->getType(); | 
|  | VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index); | 
|  | if (IndexCheckValue != VectorIndexValid) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | dumpVectorIndexCheckValue(StrBuf, IndexCheckValue); | 
|  | StrBuf << ": extractelement " << VecType << " " << *Vec << ", " | 
|  | << Index->getType() << " " << *Index; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(VecType); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstExtractElement::create( | 
|  | Func.get(), getNextInstVar(typeElementType(VecType)), Vec, Index)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_INSERTELT: { | 
|  | // INSERTELT: [opval, opval, opval] | 
|  | if (!isValidRecordSize(3, "insert element")) | 
|  | return; | 
|  | Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *Elt = getRelativeOperand(Values[1], BaseIndex); | 
|  | Ice::Operand *Index = getRelativeOperand(Values[2], BaseIndex); | 
|  | Ice::Type VecType = Vec->getType(); | 
|  | VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index); | 
|  | if (IndexCheckValue != VectorIndexValid) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | dumpVectorIndexCheckValue(StrBuf, IndexCheckValue); | 
|  | StrBuf << ": insertelement " << VecType << " " << *Vec << ", " | 
|  | << Elt->getType() << " " << *Elt << ", " << Index->getType() << " " | 
|  | << *Index; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(Elt->getType()); | 
|  | return; | 
|  | } | 
|  | if (Ice::typeElementType(VecType) != Elt->getType()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Insertelement: Element type " | 
|  | << Ice::typeString(Elt->getType()) << " doesn't match vector type " | 
|  | << Ice::typeString(VecType); | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(Elt->getType()); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstInsertElement::create( | 
|  | Func.get(), getNextInstVar(VecType), Vec, Elt, Index)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_CMP2: { | 
|  | // CMP2: [opval, opval, pred] | 
|  | if (!isValidRecordSize(3, "compare")) | 
|  | return; | 
|  | Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex); | 
|  | Ice::Type Op1Type = Op1->getType(); | 
|  | Ice::Type Op2Type = Op2->getType(); | 
|  | Ice::Type DestType = getCompareResultType(Op1Type); | 
|  | if (Op1Type != Op2Type) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Compare argument types differ: " << Op1Type << " and " | 
|  | << Op2Type; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(DestType); | 
|  | Op2 = Op1; | 
|  | } | 
|  | if (DestType == Ice::IceType_void) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Compare not defined for type " << Op1Type; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | Ice::Variable *Dest = getNextInstVar(DestType); | 
|  | if (isIntegerType(Op1Type)) { | 
|  | Ice::InstIcmp::ICond Cond; | 
|  | if (!convertNaClBitcICmpOpToIce(Values[2], Cond)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Compare record contains unknown integer predicate index: " | 
|  | << Values[2]; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(DestType); | 
|  | } | 
|  | CurrentNode->appendInst( | 
|  | Ice::InstIcmp::create(Func.get(), Cond, Dest, Op1, Op2)); | 
|  | } else if (isFloatingType(Op1Type)) { | 
|  | Ice::InstFcmp::FCond Cond; | 
|  | if (!convertNaClBitcFCompOpToIce(Values[2], Cond)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Compare record contains unknown float predicate index: " | 
|  | << Values[2]; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(DestType); | 
|  | } | 
|  | CurrentNode->appendInst( | 
|  | Ice::InstFcmp::create(Func.get(), Cond, Dest, Op1, Op2)); | 
|  | } else { | 
|  | // Not sure this can happen, but be safe. | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Compare on type not understood: " << Op1Type; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(DestType); | 
|  | return; | 
|  | } | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_RET: { | 
|  | // RET: [opval?] | 
|  | InstIsTerminating = true; | 
|  | if (!isValidRecordSizeInRange(0, 1, "return")) | 
|  | return; | 
|  | if (Values.empty()) { | 
|  | CurrentNode->appendInst(Ice::InstRet::create(Func.get())); | 
|  | } else { | 
|  | Ice::Operand *RetVal = getRelativeOperand(Values[0], BaseIndex); | 
|  | CurrentNode->appendInst(Ice::InstRet::create(Func.get(), RetVal)); | 
|  | } | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_BR: { | 
|  | InstIsTerminating = true; | 
|  | if (Values.size() == 1) { | 
|  | // BR: [bb#] | 
|  | Ice::CfgNode *Block = getBranchBasicBlock(Values[0]); | 
|  | if (Block == nullptr) | 
|  | return; | 
|  | CurrentNode->appendInst(Ice::InstBr::create(Func.get(), Block)); | 
|  | } else { | 
|  | // BR: [bb#, bb#, opval] | 
|  | if (!isValidRecordSize(3, "branch")) | 
|  | return; | 
|  | Ice::Operand *Cond = getRelativeOperand(Values[2], BaseIndex); | 
|  | if (Cond->getType() != Ice::IceType_i1) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Branch condition " << *Cond | 
|  | << " not i1. Found: " << Cond->getType(); | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | Ice::CfgNode *ThenBlock = getBranchBasicBlock(Values[0]); | 
|  | Ice::CfgNode *ElseBlock = getBranchBasicBlock(Values[1]); | 
|  | if (ThenBlock == nullptr || ElseBlock == nullptr) | 
|  | return; | 
|  | CurrentNode->appendInst( | 
|  | Ice::InstBr::create(Func.get(), Cond, ThenBlock, ElseBlock)); | 
|  | } | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_SWITCH: { | 
|  | // SWITCH: [Condty, Cond, BbIndex, NumCases Case ...] | 
|  | // where Case = [1, 1, Value, BbIndex]. | 
|  | // | 
|  | // Note: Unlike most instructions, we don't infer the type of Cond, but | 
|  | // provide it as a separate field. There are also unnecessary data fields | 
|  | // (i.e. constants 1). These were not cleaned up in PNaCl bitcode because | 
|  | // the bitcode format was already frozen when the problem was noticed. | 
|  | InstIsTerminating = true; | 
|  | if (!isValidRecordSizeAtLeast(4, "switch")) | 
|  | return; | 
|  |  | 
|  | Ice::Type CondTy = Context->getSimpleTypeByID(Values[0]); | 
|  | if (!Ice::isScalarIntegerType(CondTy)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Case condition must be non-wide integer. Found: " << CondTy; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | Ice::SizeT BitWidth = Ice::getScalarIntBitWidth(CondTy); | 
|  | Ice::Operand *Cond = getRelativeOperand(Values[1], BaseIndex); | 
|  |  | 
|  | if (CondTy != Cond->getType()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Case condition expects type " << CondTy | 
|  | << ". Found: " << Cond->getType(); | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | Ice::CfgNode *DefaultLabel = getBranchBasicBlock(Values[2]); | 
|  | if (DefaultLabel == nullptr) | 
|  | return; | 
|  | uint64_t NumCasesRaw = Values[3]; | 
|  | if (NumCasesRaw > std::numeric_limits<uint32_t>::max()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Too many cases specified in switch: " << NumCasesRaw; | 
|  | Error(StrBuf.str()); | 
|  | NumCasesRaw = std::numeric_limits<uint32_t>::max(); | 
|  | } | 
|  | uint32_t NumCases = NumCasesRaw; | 
|  |  | 
|  | // Now recognize each of the cases. | 
|  | if (!isValidRecordSize(4 + NumCases * 4, "switch")) | 
|  | return; | 
|  | std::unique_ptr<Ice::InstSwitch> Switch( | 
|  | Ice::InstSwitch::create(Func.get(), NumCases, Cond, DefaultLabel)); | 
|  | unsigned ValCaseIndex = 4; // index to beginning of case entry. | 
|  | for (uint32_t CaseIndex = 0; CaseIndex < NumCases; | 
|  | ++CaseIndex, ValCaseIndex += 4) { | 
|  | if (Values[ValCaseIndex] != 1 || Values[ValCaseIndex + 1] != 1) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Sequence [1, 1, value, label] expected for case entry " | 
|  | << "in switch record. (at index" << ValCaseIndex << ")"; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | BitcodeInt Value(BitWidth, | 
|  | NaClDecodeSignRotatedValue(Values[ValCaseIndex + 2])); | 
|  | Ice::CfgNode *Label = getBranchBasicBlock(Values[ValCaseIndex + 3]); | 
|  | if (Label == nullptr) | 
|  | return; | 
|  | Switch->addBranch(CaseIndex, Value.getSExtValue(), Label); | 
|  | } | 
|  | CurrentNode->appendInst(Switch.release()); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_UNREACHABLE: { | 
|  | // UNREACHABLE: [] | 
|  | InstIsTerminating = true; | 
|  | if (!isValidRecordSize(0, "unreachable")) | 
|  | return; | 
|  | CurrentNode->appendInst(Ice::InstUnreachable::create(Func.get())); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_PHI: { | 
|  | // PHI: [ty, val1, bb1, ..., valN, bbN] for n >= 2. | 
|  | if (!isValidRecordSizeAtLeast(3, "phi")) | 
|  | return; | 
|  | Ice::Type Ty = Context->getSimpleTypeByID(Values[0]); | 
|  | if ((Values.size() & 0x1) == 0) { | 
|  | // Not an odd number of values. | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "function block phi record size not valid: " << Values.size(); | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(Ty); | 
|  | return; | 
|  | } | 
|  | if (Ty == Ice::IceType_void) { | 
|  | Error("Phi record using type void not allowed"); | 
|  | return; | 
|  | } | 
|  | Ice::Variable *Dest = getNextInstVar(Ty); | 
|  | Ice::InstPhi *Phi = | 
|  | Ice::InstPhi::create(Func.get(), Values.size() >> 1, Dest); | 
|  | for (size_t i = 1; i < Values.size(); i += 2) { | 
|  | Ice::Operand *Op = | 
|  | getRelativeOperand(NaClDecodeSignRotatedValue(Values[i]), BaseIndex); | 
|  | if (Op->getType() != Ty) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Value " << *Op << " not type " << Ty | 
|  | << " in phi instruction. Found: " << Op->getType(); | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(Ty); | 
|  | return; | 
|  | } | 
|  | Phi->addArgument(Op, getBasicBlock(Values[i + 1])); | 
|  | } | 
|  | CurrentNode->appendInst(Phi); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_ALLOCA: { | 
|  | // ALLOCA: [Size, align] | 
|  | if (!isValidRecordSize(2, "alloca")) | 
|  | return; | 
|  | Ice::Operand *ByteCount = getRelativeOperand(Values[0], BaseIndex); | 
|  | uint32_t Alignment = Context->extractAlignment(this, "Alloca", Values[1]); | 
|  | Ice::Type PtrTy = Ice::getPointerType(); | 
|  | if (ByteCount->getType() != Ice::IceType_i32) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Alloca on non-i32 value. Found: " << *ByteCount; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(PtrTy); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstAlloca::create( | 
|  | Func.get(), getNextInstVar(PtrTy), ByteCount, Alignment)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_LOAD: { | 
|  | // LOAD: [address, align, ty] | 
|  | if (!isValidRecordSize(3, "load")) | 
|  | return; | 
|  | Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Type Ty = Context->getSimpleTypeByID(Values[2]); | 
|  | uint32_t Alignment = Context->extractAlignment(this, "Load", Values[1]); | 
|  | if (!isValidPointerType(Address, "Load")) { | 
|  | appendErrorInstruction(Ty); | 
|  | return; | 
|  | } | 
|  | if (!isValidLoadStoreAlignment(Alignment, Ty, "Load")) { | 
|  | appendErrorInstruction(Ty); | 
|  | return; | 
|  | } | 
|  | CurrentNode->appendInst(Ice::InstLoad::create( | 
|  | Func.get(), getNextInstVar(Ty), Address, Alignment)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_STORE: { | 
|  | // STORE: [address, value, align] | 
|  | if (!isValidRecordSize(3, "store")) | 
|  | return; | 
|  | Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex); | 
|  | Ice::Operand *Value = getRelativeOperand(Values[1], BaseIndex); | 
|  | uint32_t Alignment = Context->extractAlignment(this, "Store", Values[2]); | 
|  | if (!isValidPointerType(Address, "Store")) | 
|  | return; | 
|  | if (!isValidLoadStoreAlignment(Alignment, Value->getType(), "Store")) | 
|  | return; | 
|  | CurrentNode->appendInst( | 
|  | Ice::InstStore::create(Func.get(), Value, Address, Alignment)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_CALL: | 
|  | case naclbitc::FUNC_CODE_INST_CALL_INDIRECT: { | 
|  | // CALL: [cc, fnid, arg0, arg1...] | 
|  | // CALL_INDIRECT: [cc, fn, returnty, args...] | 
|  | // | 
|  | // Note: The difference between CALL and CALL_INDIRECT is that CALL has a | 
|  | // reference to an explicit function declaration, while the CALL_INDIRECT | 
|  | // is just an address. For CALL, we can infer the return type by looking up | 
|  | // the type signature associated with the function declaration. For | 
|  | // CALL_INDIRECT we can only infer the type signature via argument types, | 
|  | // and the corresponding return type stored in CALL_INDIRECT record. | 
|  | Ice::SizeT ParamsStartIndex = 2; | 
|  | if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) { | 
|  | if (!isValidRecordSizeAtLeast(2, "call")) | 
|  | return; | 
|  | } else { | 
|  | if (!isValidRecordSizeAtLeast(3, "call indirect")) | 
|  | return; | 
|  | ParamsStartIndex = 3; | 
|  | } | 
|  |  | 
|  | uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex); | 
|  | Ice::Operand *Callee = getOperand(CalleeIndex); | 
|  |  | 
|  | // Pull out signature/return type of call (if possible). | 
|  | Ice::FunctionDeclaration *Fcn = nullptr; | 
|  | const Ice::FuncSigType *Signature = nullptr; | 
|  | Ice::Type ReturnType = Ice::IceType_void; | 
|  | const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr; | 
|  | if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) { | 
|  | Fcn = Context->getFunctionByID(CalleeIndex); | 
|  | Signature = &Fcn->getSignature(); | 
|  | ReturnType = Signature->getReturnType(); | 
|  | Ice::SizeT NumParams = Values.size() - ParamsStartIndex; | 
|  | if (NumParams != Signature->getNumArgs()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Call to " << printName(Fcn) << " has " << NumParams | 
|  | << " parameters. Signature expects: " << Signature->getNumArgs(); | 
|  | Error(StrBuf.str()); | 
|  | if (ReturnType != Ice::IceType_void) | 
|  | setNextLocalInstIndex(nullptr); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Check if this direct call is to an Intrinsic (starts with "llvm.") | 
|  | IntrinsicInfo = Fcn->getIntrinsicInfo(getTranslator().getContext()); | 
|  | if (IntrinsicInfo && IntrinsicInfo->getNumArgs() != NumParams) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Call to " << printName(Fcn) << " has " << NumParams | 
|  | << " parameters. Intrinsic expects: " << Signature->getNumArgs(); | 
|  | Error(StrBuf.str()); | 
|  | if (ReturnType != Ice::IceType_void) | 
|  | setNextLocalInstIndex(nullptr); | 
|  | return; | 
|  | } | 
|  | } else { // Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL_INDIRECT | 
|  | // There is no signature. Assume defined by parameter types. | 
|  | ReturnType = Context->getSimpleTypeByID(Values[2]); | 
|  | if (Callee != nullptr) | 
|  | isValidPointerType(Callee, "Call indirect"); | 
|  | } | 
|  |  | 
|  | if (Callee == nullptr) | 
|  | return; | 
|  |  | 
|  | // Extract out the the call parameters. | 
|  | SmallVector<Ice::Operand *, 8> Params; | 
|  | for (Ice::SizeT Index = ParamsStartIndex; Index < Values.size(); ++Index) { | 
|  | Ice::Operand *Op = getRelativeOperand(Values[Index], BaseIndex); | 
|  | if (Op == nullptr) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Parameter " << (Index - ParamsStartIndex + 1) << " of " | 
|  | << printName(Fcn) << " is not defined"; | 
|  | Error(StrBuf.str()); | 
|  | if (ReturnType != Ice::IceType_void) | 
|  | setNextLocalInstIndex(nullptr); | 
|  | return; | 
|  | } | 
|  | Params.push_back(Op); | 
|  | } | 
|  |  | 
|  | // Check return type. | 
|  | if (IntrinsicInfo == nullptr && !isCallReturnType(ReturnType)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Return type of " << printName(Fcn) | 
|  | << " is invalid: " << ReturnType; | 
|  | Error(StrBuf.str()); | 
|  | ReturnType = Ice::IceType_i32; | 
|  | } | 
|  |  | 
|  | // Type check call parameters. | 
|  | for (Ice::SizeT Index = 0; Index < Params.size(); ++Index) { | 
|  | Ice::Operand *Op = Params[Index]; | 
|  | Ice::Type OpType = Op->getType(); | 
|  | if (Signature) | 
|  | verifyCallArgTypeMatches(Fcn, Index, OpType, | 
|  | Signature->getArgType(Index)); | 
|  | else if (!isCallParameterType(OpType)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Argument " << *Op << " of " << printName(Fcn) | 
|  | << " has invalid type: " << Op->getType(); | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(ReturnType); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Extract call information. | 
|  | uint64_t CCInfo = Values[0]; | 
|  | CallingConv::ID CallingConv; | 
|  | if (!naclbitc::DecodeCallingConv(CCInfo >> 1, CallingConv)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function call calling convention value " << (CCInfo >> 1) | 
|  | << " not understood."; | 
|  | Error(StrBuf.str()); | 
|  | appendErrorInstruction(ReturnType); | 
|  | return; | 
|  | } | 
|  | const bool IsTailCall = (CCInfo & 1); | 
|  |  | 
|  | // Create the call instruction. | 
|  | Ice::Variable *Dest = (ReturnType == Ice::IceType_void) | 
|  | ? nullptr | 
|  | : getNextInstVar(ReturnType); | 
|  | std::unique_ptr<Ice::InstCall> Instr; | 
|  | if (IntrinsicInfo) { | 
|  | Instr.reset(Ice::InstIntrinsicCall::create( | 
|  | Func.get(), Params.size(), Dest, Callee, IntrinsicInfo->Info)); | 
|  | } else { | 
|  | Instr.reset(Ice::InstCall::create(Func.get(), Params.size(), Dest, Callee, | 
|  | IsTailCall)); | 
|  | } | 
|  | for (Ice::Operand *Param : Params) | 
|  | Instr->addArg(Param); | 
|  | CurrentNode->appendInst(Instr.release()); | 
|  | return; | 
|  | } | 
|  | case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: { | 
|  | // FORWARDTYPEREF: [opval, ty] | 
|  | if (!isValidRecordSize(2, "forward type ref")) | 
|  | return; | 
|  | Ice::Type OpType = Context->getSimpleTypeByID(Values[1]); | 
|  | setOperand(Values[0], createInstVar(OpType)); | 
|  | return; | 
|  | } | 
|  | default: | 
|  | // Generate error message! | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Parses constants within a function block. | 
|  | class ConstantsParser final : public BlockParserBaseClass { | 
|  | ConstantsParser() = delete; | 
|  | ConstantsParser(const ConstantsParser &) = delete; | 
|  | ConstantsParser &operator=(const ConstantsParser &) = delete; | 
|  |  | 
|  | public: | 
|  | ConstantsParser(unsigned BlockID, FunctionParser *FuncParser) | 
|  | : BlockParserBaseClass(BlockID, FuncParser), | 
|  | Timer(Ice::TimerStack::TT_parseConstants, getTranslator().getContext()), | 
|  | FuncParser(FuncParser) {} | 
|  |  | 
|  | ~ConstantsParser() override = default; | 
|  |  | 
|  | const char *getBlockName() const override { return "constants"; } | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | // The parser of the function block this constants block appears in. | 
|  | FunctionParser *FuncParser; | 
|  | // The type to use for succeeding constants. | 
|  | Ice::Type NextConstantType = Ice::IceType_void; | 
|  |  | 
|  | void ProcessRecord() override; | 
|  |  | 
|  | Ice::GlobalContext *getContext() { return getTranslator().getContext(); } | 
|  |  | 
|  | // Returns true if the type to use for succeeding constants is defined. If | 
|  | // false, also generates an error message. | 
|  | bool isValidNextConstantType() { | 
|  | if (NextConstantType != Ice::IceType_void) | 
|  | return true; | 
|  | Error("Constant record not preceded by set type record"); | 
|  | return false; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void ConstantsParser::ProcessRecord() { | 
|  | const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); | 
|  | switch (Record.GetCode()) { | 
|  | case naclbitc::CST_CODE_SETTYPE: { | 
|  | // SETTYPE: [typeid] | 
|  | if (!isValidRecordSize(1, "set type")) | 
|  | return; | 
|  | NextConstantType = Context->getSimpleTypeByID(Values[0]); | 
|  | if (NextConstantType == Ice::IceType_void) | 
|  | Error("constants block set type not allowed for void type"); | 
|  | return; | 
|  | } | 
|  | case naclbitc::CST_CODE_UNDEF: { | 
|  | // UNDEF | 
|  | if (!isValidRecordSize(0, "undef")) | 
|  | return; | 
|  | if (!isValidNextConstantType()) | 
|  | return; | 
|  | FuncParser->setNextConstantID( | 
|  | getContext()->getConstantUndef(NextConstantType)); | 
|  | return; | 
|  | } | 
|  | case naclbitc::CST_CODE_INTEGER: { | 
|  | // INTEGER: [intval] | 
|  | if (!isValidRecordSize(1, "integer")) | 
|  | return; | 
|  | if (!isValidNextConstantType()) | 
|  | return; | 
|  | if (Ice::isScalarIntegerType(NextConstantType)) { | 
|  | BitcodeInt Value(Ice::getScalarIntBitWidth(NextConstantType), | 
|  | NaClDecodeSignRotatedValue(Values[0])); | 
|  | if (Ice::Constant *C = getContext()->getConstantInt( | 
|  | NextConstantType, Value.getSExtValue())) { | 
|  | FuncParser->setNextConstantID(C); | 
|  | return; | 
|  | } | 
|  | } | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "constant block integer record for non-integer type " | 
|  | << NextConstantType; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | case naclbitc::CST_CODE_FLOAT: { | 
|  | // FLOAT: [fpval] | 
|  | if (!isValidRecordSize(1, "float")) | 
|  | return; | 
|  | if (!isValidNextConstantType()) | 
|  | return; | 
|  | switch (NextConstantType) { | 
|  | case Ice::IceType_f32: { | 
|  | const BitcodeInt Value(32, static_cast<uint32_t>(Values[0])); | 
|  | float FpValue = Value.convertToFp<int32_t, float>(); | 
|  | FuncParser->setNextConstantID(getContext()->getConstantFloat(FpValue)); | 
|  | return; | 
|  | } | 
|  | case Ice::IceType_f64: { | 
|  | const BitcodeInt Value(64, Values[0]); | 
|  | double FpValue = Value.convertToFp<uint64_t, double>(); | 
|  | FuncParser->setNextConstantID(getContext()->getConstantDouble(FpValue)); | 
|  | return; | 
|  | } | 
|  | default: { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "constant block float record for non-floating type " | 
|  | << NextConstantType; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | default: | 
|  | // Generate error message! | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Parses valuesymtab blocks appearing in a function block. | 
|  | class FunctionValuesymtabParser final : public ValuesymtabParser { | 
|  | FunctionValuesymtabParser() = delete; | 
|  | FunctionValuesymtabParser(const FunctionValuesymtabParser &) = delete; | 
|  | void operator=(const FunctionValuesymtabParser &) = delete; | 
|  |  | 
|  | public: | 
|  | FunctionValuesymtabParser(unsigned BlockID, FunctionParser *EnclosingParser) | 
|  | : ValuesymtabParser(BlockID, EnclosingParser), | 
|  | Timer(Ice::TimerStack::TT_parseFunctionValuesymtabs, | 
|  | getTranslator().getContext()) {} | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | // Returns the enclosing function parser. | 
|  | FunctionParser *getFunctionParser() const { | 
|  | return reinterpret_cast<FunctionParser *>(GetEnclosingParser()); | 
|  | } | 
|  |  | 
|  | const char *getTableKind() const override { return "Function"; } | 
|  |  | 
|  | void setValueName(NaClBcIndexSize_t Index, StringType &Name) override; | 
|  | void setBbName(NaClBcIndexSize_t Index, StringType &Name) override; | 
|  |  | 
|  | // Reports that the assignment of Name to the value associated with index is | 
|  | // not possible, for the given Context. | 
|  | void reportUnableToAssign(const char *Context, NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function-local " << Context << " name '" << Name | 
|  | << "' can't be associated with index " << Index; | 
|  | Error(StrBuf.str()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | void FunctionValuesymtabParser::setValueName(NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | // Note: We check when Index is too small, so that we can error recover | 
|  | // (FP->getOperand will create fatal error). | 
|  | if (Index < getFunctionParser()->getNumGlobalIDs()) { | 
|  | reportUnableToAssign("Global value", Index, Name); | 
|  | return; | 
|  | } | 
|  | Ice::Operand *Op = getFunctionParser()->getOperand(Index); | 
|  | if (auto *V = dyn_cast<Ice::Variable>(Op)) { | 
|  | if (Ice::BuildDefs::dump()) { | 
|  | std::string Nm(Name.data(), Name.size()); | 
|  | V->setName(getFunctionParser()->getFunc(), Nm); | 
|  | } | 
|  | } else { | 
|  | reportUnableToAssign("Local value", Index, Name); | 
|  | } | 
|  | } | 
|  |  | 
|  | void FunctionValuesymtabParser::setBbName(NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | if (!Ice::BuildDefs::dump()) | 
|  | return; | 
|  | if (Index >= getFunctionParser()->getFunc()->getNumNodes()) { | 
|  | reportUnableToAssign("Basic block", Index, Name); | 
|  | return; | 
|  | } | 
|  | std::string Nm(Name.data(), Name.size()); | 
|  | if (Ice::BuildDefs::dump()) | 
|  | getFunctionParser()->getFunc()->getNodes()[Index]->setName(Nm); | 
|  | } | 
|  |  | 
|  | bool FunctionParser::ParseBlock(unsigned BlockID) { | 
|  | #ifndef PNACL_LLVM | 
|  | constexpr bool PNaClAllowLocalSymbolTables = true; | 
|  | #endif // !PNACL_LLVM | 
|  | switch (BlockID) { | 
|  | case naclbitc::CONSTANTS_BLOCK_ID: { | 
|  | ConstantsParser Parser(BlockID, this); | 
|  | return Parser.ParseThisBlock(); | 
|  | } | 
|  | case naclbitc::VALUE_SYMTAB_BLOCK_ID: { | 
|  | if (PNaClAllowLocalSymbolTables) { | 
|  | FunctionValuesymtabParser Parser(BlockID, this); | 
|  | return Parser.ParseThisBlock(); | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return BlockParserBaseClass::ParseBlock(BlockID); | 
|  | } | 
|  |  | 
|  | /// Parses the module block in the bitcode file. | 
|  | class ModuleParser final : public BlockParserBaseClass { | 
|  | ModuleParser() = delete; | 
|  | ModuleParser(const ModuleParser &) = delete; | 
|  | ModuleParser &operator=(const ModuleParser &) = delete; | 
|  |  | 
|  | public: | 
|  | ModuleParser(unsigned BlockID, TopLevelParser *Context) | 
|  | : BlockParserBaseClass(BlockID, Context), | 
|  | Timer(Ice::TimerStack::TT_parseModule, | 
|  | Context->getTranslator().getContext()), | 
|  | IsParseParallel(Ice::getFlags().isParseParallel()) {} | 
|  | ~ModuleParser() override = default; | 
|  | const char *getBlockName() const override { return "module"; } | 
|  | NaClBitstreamCursor &getCursor() const { return Record.GetCursor(); } | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | // True if we have already installed names for unnamed global declarations, | 
|  | // and have generated global constant initializers. | 
|  | bool GlobalDeclarationNamesAndInitializersInstalled = false; | 
|  | // True if we have already processed the symbol table for the module. | 
|  | bool FoundValuesymtab = false; | 
|  | const bool IsParseParallel; | 
|  |  | 
|  | // Generates names for unnamed global addresses (i.e. functions and global | 
|  | // variables). Then lowers global variable declaration initializers to the | 
|  | // target. May be called multiple times. Only the first call will do the | 
|  | // installation. | 
|  | void installGlobalNamesAndGlobalVarInitializers() { | 
|  | if (!GlobalDeclarationNamesAndInitializersInstalled) { | 
|  | Context->installGlobalNames(); | 
|  | Context->createValueIDs(); | 
|  | Context->verifyFunctionTypeSignatures(); | 
|  | std::unique_ptr<Ice::VariableDeclarationList> Globals = | 
|  | Context->getGlobalVariables(); | 
|  | if (Globals) | 
|  | getTranslator().lowerGlobals(std::move(Globals)); | 
|  | GlobalDeclarationNamesAndInitializersInstalled = true; | 
|  | } | 
|  | } | 
|  | bool ParseBlock(unsigned BlockID) override; | 
|  |  | 
|  | void ExitBlock() override { | 
|  | installGlobalNamesAndGlobalVarInitializers(); | 
|  | Context->getTranslator().getContext()->waitForWorkerThreads(); | 
|  | } | 
|  |  | 
|  | void ProcessRecord() override; | 
|  | }; | 
|  |  | 
|  | class ModuleValuesymtabParser : public ValuesymtabParser { | 
|  | ModuleValuesymtabParser() = delete; | 
|  | ModuleValuesymtabParser(const ModuleValuesymtabParser &) = delete; | 
|  | void operator=(const ModuleValuesymtabParser &) = delete; | 
|  |  | 
|  | public: | 
|  | ModuleValuesymtabParser(unsigned BlockID, ModuleParser *MP) | 
|  | : ValuesymtabParser(BlockID, MP), | 
|  | Timer(Ice::TimerStack::TT_parseModuleValuesymtabs, | 
|  | getTranslator().getContext()) {} | 
|  |  | 
|  | ~ModuleValuesymtabParser() override = default; | 
|  |  | 
|  | private: | 
|  | Ice::TimerMarker Timer; | 
|  | const char *getTableKind() const override { return "Module"; } | 
|  | void setValueName(NaClBcIndexSize_t Index, StringType &Name) override; | 
|  | void setBbName(NaClBcIndexSize_t Index, StringType &Name) override; | 
|  | }; | 
|  |  | 
|  | void ModuleValuesymtabParser::setValueName(NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | Ice::GlobalDeclaration *Decl = Context->getGlobalDeclarationByID(Index); | 
|  | if (llvm::isa<Ice::VariableDeclaration>(Decl) && | 
|  | Decl->isPNaClABIExternalName(Name.str())) { | 
|  | // Force linkage of (specific) Global Variables be external for the PNaCl | 
|  | // ABI. PNaCl bitcode has a linkage field for Functions, but not for | 
|  | // GlobalVariables (because the latter is not needed for pexes, so it has | 
|  | // been removed). | 
|  | Decl->setLinkage(llvm::GlobalValue::ExternalLinkage); | 
|  | } | 
|  |  | 
|  | // Unconditionally capture the name if it is provided in the input file, | 
|  | // regardless of whether dump is enabled or whether the symbol is internal vs | 
|  | // external.  This fits in well with the lit tests, and most symbols in a | 
|  | // conforming pexe are nameless and don't take this path. | 
|  | Decl->setName(getTranslator().getContext(), | 
|  | StringRef(Name.data(), Name.size())); | 
|  | } | 
|  |  | 
|  | void ModuleValuesymtabParser::setBbName(NaClBcIndexSize_t Index, | 
|  | StringType &Name) { | 
|  | reportUnableToAssign("Basic block", Index, Name); | 
|  | } | 
|  |  | 
|  | class CfgParserWorkItem final : public Ice::OptWorkItem { | 
|  | CfgParserWorkItem() = delete; | 
|  | CfgParserWorkItem(const CfgParserWorkItem &) = delete; | 
|  | CfgParserWorkItem &operator=(const CfgParserWorkItem &) = delete; | 
|  |  | 
|  | public: | 
|  | CfgParserWorkItem(unsigned BlockID, NaClBcIndexSize_t FcnId, | 
|  | ModuleParser *ModParser, std::unique_ptr<uint8_t[]> Buffer, | 
|  | uintptr_t BufferSize, uint64_t StartBit, uint32_t SeqNumber) | 
|  | : BlockID(BlockID), FcnId(FcnId), ModParser(ModParser), | 
|  | Buffer(std::move(Buffer)), BufferSize(BufferSize), StartBit(StartBit), | 
|  | SeqNumber(SeqNumber) {} | 
|  | std::unique_ptr<Ice::Cfg> getParsedCfg() override; | 
|  | ~CfgParserWorkItem() override = default; | 
|  |  | 
|  | private: | 
|  | const unsigned BlockID; | 
|  | const NaClBcIndexSize_t FcnId; | 
|  | // Note: ModParser can't be const because the function parser needs to | 
|  | // access non-const member functions (of ModuleParser and TopLevelParser). | 
|  | // TODO(kschimpf): Fix this issue. | 
|  | ModuleParser *ModParser; | 
|  | const std::unique_ptr<uint8_t[]> Buffer; | 
|  | const uintptr_t BufferSize; | 
|  | const uint64_t StartBit; | 
|  | const uint32_t SeqNumber; | 
|  | }; | 
|  |  | 
|  | std::unique_ptr<Ice::Cfg> CfgParserWorkItem::getParsedCfg() { | 
|  | NaClBitstreamCursor &OldCursor(ModParser->getCursor()); | 
|  | llvm::NaClBitstreamReader Reader(OldCursor.getStartWordByteForBit(StartBit), | 
|  | Buffer.get(), Buffer.get() + BufferSize, | 
|  | OldCursor.getBitStreamReader()); | 
|  | NaClBitstreamCursor NewCursor(Reader); | 
|  | NewCursor.JumpToBit(NewCursor.getWordBitNo(StartBit)); | 
|  | FunctionParser Parser(BlockID, ModParser, FcnId, NewCursor); | 
|  | return Parser.parseFunction(SeqNumber); | 
|  | } | 
|  |  | 
|  | bool ModuleParser::ParseBlock(unsigned BlockID) { | 
|  | 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: { | 
|  | if (FoundValuesymtab) | 
|  | Fatal("Duplicate valuesymtab in module"); | 
|  |  | 
|  | // If we have already processed a function block (i.e. we have already | 
|  | // installed global names and variable initializers) we can no longer accept | 
|  | // the value symbol table. Names have already been generated. | 
|  | if (GlobalDeclarationNamesAndInitializersInstalled) | 
|  | Fatal("Module valuesymtab not allowed after function blocks"); | 
|  |  | 
|  | FoundValuesymtab = true; | 
|  | ModuleValuesymtabParser Parser(BlockID, this); | 
|  | return Parser.ParseThisBlock(); | 
|  | } | 
|  | case naclbitc::FUNCTION_BLOCK_ID: { | 
|  | installGlobalNamesAndGlobalVarInitializers(); | 
|  | Ice::GlobalContext *Ctx = Context->getTranslator().getContext(); | 
|  | uint32_t SeqNumber = Context->getTranslator().getNextSequenceNumber(); | 
|  | NaClBcIndexSize_t FcnId = Context->getNextFunctionBlockValueID(); | 
|  | if (IsParseParallel) { | 
|  | // Skip the block and copy into a buffer. Note: We copy into a buffer | 
|  | // using the top-level parser to make sure that the underlying | 
|  | // buffer reading from the data streamer is not thread safe. | 
|  | NaClBitstreamCursor &Cursor = Record.GetCursor(); | 
|  | uint64_t StartBit = Cursor.GetCurrentBitNo(); | 
|  | if (SkipBlock()) | 
|  | return true; | 
|  | const uint64_t EndBit = Cursor.GetCurrentBitNo(); | 
|  | const uintptr_t StartByte = Cursor.getStartWordByteForBit(StartBit); | 
|  | const uintptr_t EndByte = Cursor.getEndWordByteForBit(EndBit); | 
|  | const uintptr_t BufferSize = EndByte - StartByte; | 
|  | std::unique_ptr<uint8_t[]> Buffer((uint8_t *)(new uint8_t[BufferSize])); | 
|  | for (size_t i = Cursor.fillBuffer(Buffer.get(), BufferSize, StartByte); | 
|  | i < BufferSize; ++i) { | 
|  | Buffer[i] = 0; | 
|  | } | 
|  | Ctx->optQueueBlockingPush(Ice::makeUnique<CfgParserWorkItem>( | 
|  | BlockID, FcnId, this, std::move(Buffer), BufferSize, StartBit, | 
|  | SeqNumber)); | 
|  | return false; | 
|  | } else { | 
|  | FunctionParser Parser(BlockID, this, FcnId); | 
|  | std::unique_ptr<Ice::Cfg> Func = Parser.parseFunction(SeqNumber); | 
|  | bool Failed = Func->hasError(); | 
|  | getTranslator().translateFcn(std::move(Func)); | 
|  | return Failed && !Ice::getFlags().getAllowErrorRecovery(); | 
|  | } | 
|  | } | 
|  | 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 (!isValidRecordSize(1, "version")) | 
|  | return; | 
|  | uint64_t 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 (!isValidRecordSize(4, "address")) | 
|  | return; | 
|  | const Ice::FuncSigType &Signature = Context->getFuncSigTypeByID(Values[0]); | 
|  | CallingConv::ID CallingConv; | 
|  | if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Function address 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 address has unknown linkage. Found " << Values[3]; | 
|  | Error(StrBuf.str()); | 
|  | return; | 
|  | } | 
|  | bool IsProto = Values[2] == 1; | 
|  | auto *Func = Ice::FunctionDeclaration::create( | 
|  | Context->getTranslator().getContext(), Signature, CallingConv, Linkage, | 
|  | IsProto); | 
|  | Context->setNextFunctionID(Func); | 
|  | return; | 
|  | } | 
|  | default: | 
|  | BlockParserBaseClass::ProcessRecord(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool TopLevelParser::ParseBlock(unsigned BlockID) { | 
|  | if (BlockID == naclbitc::MODULE_BLOCK_ID) { | 
|  | if (ParsedModuleBlock) | 
|  | Fatal("Input can't contain more than one module"); | 
|  | ModuleParser Parser(BlockID, this); | 
|  | bool ParseFailed = Parser.ParseThisBlock(); | 
|  | ParsedModuleBlock = true; | 
|  | return ParseFailed; | 
|  | } | 
|  | // Generate error message by using default block implementation. | 
|  | BlockParserBaseClass Parser(BlockID, this); | 
|  | return Parser.ParseThisBlock(); | 
|  | } | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | namespace Ice { | 
|  |  | 
|  | void PNaClTranslator::translateBuffer(const std::string &IRFilename, | 
|  | MemoryBuffer *MemBuf) { | 
|  | std::unique_ptr<MemoryObject> MemObj(getNonStreamedMemoryObject( | 
|  | reinterpret_cast<const unsigned char *>(MemBuf->getBufferStart()), | 
|  | reinterpret_cast<const unsigned char *>(MemBuf->getBufferEnd()))); | 
|  | translate(IRFilename, std::move(MemObj)); | 
|  | } | 
|  |  | 
|  | void PNaClTranslator::translate(const std::string &IRFilename, | 
|  | std::unique_ptr<MemoryObject> &&MemObj) { | 
|  | // On error, we report_fatal_error to avoid destroying the MemObj. That may | 
|  | // still be in use by IceBrowserCompileServer. Otherwise, we need to change | 
|  | // the MemObj to be ref-counted, or have a wrapper, or simply leak. We also | 
|  | // need a hook to tell the IceBrowserCompileServer to unblock its | 
|  | // QueueStreamer. | 
|  | // https://code.google.com/p/nativeclient/issues/detail?id=4163 | 
|  | // Read header and verify it is good. | 
|  | NaClBitcodeHeader Header; | 
|  | if (Header.Read(MemObj.get())) { | 
|  | llvm::report_fatal_error("Invalid PNaCl bitcode header"); | 
|  | } | 
|  | if (!Header.IsSupported()) { | 
|  | getContext()->getStrError() << Header.Unsupported(); | 
|  | if (!Header.IsReadable()) { | 
|  | llvm::report_fatal_error("Invalid PNaCl bitcode header"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Create a bitstream reader to read the bitcode file. | 
|  | NaClBitstreamReader InputStreamFile(MemObj.release(), Header); | 
|  | NaClBitstreamCursor InputStream(InputStreamFile); | 
|  |  | 
|  | TopLevelParser Parser(*this, InputStream, ErrorStatus); | 
|  | while (!InputStream.AtEndOfStream()) { | 
|  | if (Parser.Parse()) { | 
|  | ErrorStatus.assign(EC_Bitcode); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Parser.parsedModuleBlock()) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << IRFilename << ": Does not contain a module!"; | 
|  | llvm::report_fatal_error(StrBuf.str()); | 
|  | } | 
|  | if (InputStreamFile.getBitcodeBytes().getExtent() % 4 != 0) { | 
|  | llvm::report_fatal_error("Bitcode stream should be a multiple of 4 bytes"); | 
|  | } | 
|  | } | 
|  |  | 
|  | } // end of namespace Ice |