diff options
author | Karl Schimpf <kschimpf@google.com> | 2013-05-01 10:42:30 -0700 |
---|---|---|
committer | Karl Schimpf <kschimpf@google.com> | 2013-05-01 10:42:30 -0700 |
commit | f42b26d0d46034cb2b91df810477fc0df2e67b27 (patch) | |
tree | bc8749b8fa6e36670df3171a27d9db2bfab608a7 /lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | |
parent | 595239b2b7297b62d9f804770f5f43d8bf637a0f (diff) |
Copy LLVM bitcode reader to generate a PNaCl wire format reader.
Copy classes for LLVM BitcodeReader into a NaCl subdirectory, to create a wire
format version. Renames classes/functions to include NaCl prefix, so that
they don't conflict with the LLVM Bitcode reader.
Also implements pnacl-thaw, showing that we can read the PNaCl wire format
files.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3405
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/14314016
Diffstat (limited to 'lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp')
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | 3124 |
1 files changed, 3124 insertions, 0 deletions
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp new file mode 100644 index 0000000000..79b6ea6cca --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp @@ -0,0 +1,3124 @@ +//===- NaClBitcodeReader.cpp ----------------------------------------------===// +// Internal NaClBitcodeReader implementation +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" +#include "NaClBitcodeReader.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/AutoUpgrade.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Operator.h" +#include "llvm/Support/DataStream.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +using namespace llvm; + +enum { + SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex +}; + +void NaClBitcodeReader::materializeForwardReferencedFunctions() { + while (!BlockAddrFwdRefs.empty()) { + Function *F = BlockAddrFwdRefs.begin()->first; + F->Materialize(); + } +} + +void NaClBitcodeReader::FreeState() { + if (BufferOwned) + delete Buffer; + Buffer = 0; + std::vector<Type*>().swap(TypeList); + ValueList.clear(); + MDValueList.clear(); + + std::vector<AttributeSet>().swap(MAttributes); + std::vector<BasicBlock*>().swap(FunctionBBs); + std::vector<Function*>().swap(FunctionsWithBodies); + DeferredFunctionInfo.clear(); + MDKindMap.clear(); + + assert(BlockAddrFwdRefs.empty() && "Unresolved blockaddress fwd references"); +} + +//===----------------------------------------------------------------------===// +// Helper functions to implement forward reference resolution, etc. +//===----------------------------------------------------------------------===// + +/// ConvertToString - Convert a string from a record into an std::string, return +/// true on failure. +template<typename StrTy> +static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx, + StrTy &Result) { + if (Idx > Record.size()) + return true; + + for (unsigned i = Idx, e = Record.size(); i != e; ++i) + Result += (char)Record[i]; + return false; +} + +static GlobalValue::LinkageTypes GetDecodedLinkage(unsigned Val) { + switch (Val) { + default: // Map unknown/new linkages to external + case 0: return GlobalValue::ExternalLinkage; + case 1: return GlobalValue::WeakAnyLinkage; + case 2: return GlobalValue::AppendingLinkage; + case 3: return GlobalValue::InternalLinkage; + case 4: return GlobalValue::LinkOnceAnyLinkage; + case 5: return GlobalValue::DLLImportLinkage; + case 6: return GlobalValue::DLLExportLinkage; + case 7: return GlobalValue::ExternalWeakLinkage; + case 8: return GlobalValue::CommonLinkage; + case 9: return GlobalValue::PrivateLinkage; + case 10: return GlobalValue::WeakODRLinkage; + case 11: return GlobalValue::LinkOnceODRLinkage; + case 12: return GlobalValue::AvailableExternallyLinkage; + case 13: return GlobalValue::LinkerPrivateLinkage; + case 14: return GlobalValue::LinkerPrivateWeakLinkage; + case 15: return GlobalValue::LinkOnceODRAutoHideLinkage; + } +} + +static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { + switch (Val) { + default: // Map unknown visibilities to default. + case 0: return GlobalValue::DefaultVisibility; + case 1: return GlobalValue::HiddenVisibility; + case 2: return GlobalValue::ProtectedVisibility; + } +} + +static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) { + switch (Val) { + case 0: return GlobalVariable::NotThreadLocal; + default: // Map unknown non-zero value to general dynamic. + case 1: return GlobalVariable::GeneralDynamicTLSModel; + case 2: return GlobalVariable::LocalDynamicTLSModel; + case 3: return GlobalVariable::InitialExecTLSModel; + case 4: return GlobalVariable::LocalExecTLSModel; + } +} + +static int GetDecodedCastOpcode(unsigned Val) { + switch (Val) { + default: return -1; + case naclbitc::CAST_TRUNC : return Instruction::Trunc; + case naclbitc::CAST_ZEXT : return Instruction::ZExt; + case naclbitc::CAST_SEXT : return Instruction::SExt; + case naclbitc::CAST_FPTOUI : return Instruction::FPToUI; + case naclbitc::CAST_FPTOSI : return Instruction::FPToSI; + case naclbitc::CAST_UITOFP : return Instruction::UIToFP; + case naclbitc::CAST_SITOFP : return Instruction::SIToFP; + case naclbitc::CAST_FPTRUNC : return Instruction::FPTrunc; + case naclbitc::CAST_FPEXT : return Instruction::FPExt; + case naclbitc::CAST_PTRTOINT: return Instruction::PtrToInt; + case naclbitc::CAST_INTTOPTR: return Instruction::IntToPtr; + case naclbitc::CAST_BITCAST : return Instruction::BitCast; + } +} +static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) { + switch (Val) { + default: return -1; + case naclbitc::BINOP_ADD: + return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add; + case naclbitc::BINOP_SUB: + return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub; + case naclbitc::BINOP_MUL: + return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul; + case naclbitc::BINOP_UDIV: return Instruction::UDiv; + case naclbitc::BINOP_SDIV: + return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv; + case naclbitc::BINOP_UREM: return Instruction::URem; + case naclbitc::BINOP_SREM: + return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem; + case naclbitc::BINOP_SHL: return Instruction::Shl; + case naclbitc::BINOP_LSHR: return Instruction::LShr; + case naclbitc::BINOP_ASHR: return Instruction::AShr; + case naclbitc::BINOP_AND: return Instruction::And; + case naclbitc::BINOP_OR: return Instruction::Or; + case naclbitc::BINOP_XOR: return Instruction::Xor; + } +} + +static AtomicRMWInst::BinOp GetDecodedRMWOperation(unsigned Val) { + switch (Val) { + default: return AtomicRMWInst::BAD_BINOP; + case naclbitc::RMW_XCHG: return AtomicRMWInst::Xchg; + case naclbitc::RMW_ADD: return AtomicRMWInst::Add; + case naclbitc::RMW_SUB: return AtomicRMWInst::Sub; + case naclbitc::RMW_AND: return AtomicRMWInst::And; + case naclbitc::RMW_NAND: return AtomicRMWInst::Nand; + case naclbitc::RMW_OR: return AtomicRMWInst::Or; + case naclbitc::RMW_XOR: return AtomicRMWInst::Xor; + case naclbitc::RMW_MAX: return AtomicRMWInst::Max; + case naclbitc::RMW_MIN: return AtomicRMWInst::Min; + case naclbitc::RMW_UMAX: return AtomicRMWInst::UMax; + case naclbitc::RMW_UMIN: return AtomicRMWInst::UMin; + } +} + +static AtomicOrdering GetDecodedOrdering(unsigned Val) { + switch (Val) { + case naclbitc::ORDERING_NOTATOMIC: return NotAtomic; + case naclbitc::ORDERING_UNORDERED: return Unordered; + case naclbitc::ORDERING_MONOTONIC: return Monotonic; + case naclbitc::ORDERING_ACQUIRE: return Acquire; + case naclbitc::ORDERING_RELEASE: return Release; + case naclbitc::ORDERING_ACQREL: return AcquireRelease; + default: // Map unknown orderings to sequentially-consistent. + case naclbitc::ORDERING_SEQCST: return SequentiallyConsistent; + } +} + +static SynchronizationScope GetDecodedSynchScope(unsigned Val) { + switch (Val) { + case naclbitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; + default: // Map unknown scopes to cross-thread. + case naclbitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; + } +} + +namespace llvm { +namespace { + /// @brief A class for maintaining the slot number definition + /// as a placeholder for the actual definition for forward constants defs. + class ConstantPlaceHolder : public ConstantExpr { + void operator=(const ConstantPlaceHolder &) LLVM_DELETED_FUNCTION; + public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context) + : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) { + Op<0>() = UndefValue::get(Type::getInt32Ty(Context)); + } + + /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return isa<ConstantExpr>(V) && + cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1; + } + + + /// Provide fast operand accessors + //DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + }; +} + +// FIXME: can we inherit this from ConstantExpr? +template <> +struct OperandTraits<ConstantPlaceHolder> : + public FixedNumOperandTraits<ConstantPlaceHolder, 1> { +}; +} + + +void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { + if (Idx == size()) { + push_back(V); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (OldV == 0) { + OldV = V; + return; + } + + // Handle constants and non-constants (e.g. instrs) differently for + // efficiency. + if (Constant *PHC = dyn_cast<Constant>(&*OldV)) { + ResolveConstants.push_back(std::make_pair(PHC, Idx)); + OldV = V; + } else { + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + OldV->replaceAllUsesWith(V); + delete PrevVal; + } +} + + +Constant *NaClBitcodeReaderValueList::getConstantFwdRef(unsigned Idx, + Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert(Ty == V->getType() && "Type mismatch in constant table!"); + return cast<Constant>(V); + } + + // Create and return a placeholder, which will later be RAUW'd. + Constant *C = new ConstantPlaceHolder(Ty, Context); + ValuePtrs[Idx] = C; + return C; +} + +Value *NaClBitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert((Ty == 0 || Ty == V->getType()) && "Type mismatch in value table!"); + return V; + } + + // No type specified, must be invalid reference. + if (Ty == 0) return 0; + + // Create and return a placeholder, which will later be RAUW'd. + Value *V = new Argument(Ty); + ValuePtrs[Idx] = V; + return V; +} + +/// ResolveConstantForwardRefs - Once all constants are read, this method bulk +/// resolves any forward references. The idea behind this is that we sometimes +/// get constants (such as large arrays) which reference *many* forward ref +/// constants. Replacing each of these causes a lot of thrashing when +/// building/reuniquing the constant. Instead of doing this, we look at all the +/// uses and rewrite all the place holders at once for any constant that uses +/// a placeholder. +void NaClBitcodeReaderValueList::ResolveConstantForwardRefs() { + // Sort the values by-pointer so that they are efficient to look up with a + // binary search. + std::sort(ResolveConstants.begin(), ResolveConstants.end()); + + SmallVector<Constant*, 64> NewOps; + + while (!ResolveConstants.empty()) { + Value *RealVal = operator[](ResolveConstants.back().second); + Constant *Placeholder = ResolveConstants.back().first; + ResolveConstants.pop_back(); + + // Loop over all users of the placeholder, updating them to reference the + // new value. If they reference more than one placeholder, update them all + // at once. + while (!Placeholder->use_empty()) { + Value::use_iterator UI = Placeholder->use_begin(); + User *U = *UI; + + // If the using object isn't uniqued, just update the operands. This + // handles instructions and initializers for global variables. + if (!isa<Constant>(U) || isa<GlobalValue>(U)) { + UI.getUse().set(RealVal); + continue; + } + + // Otherwise, we have a constant that uses the placeholder. Replace that + // constant with a new constant that has *all* placeholder uses updated. + Constant *UserC = cast<Constant>(U); + for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end(); + I != E; ++I) { + Value *NewOp; + if (!isa<ConstantPlaceHolder>(*I)) { + // Not a placeholder reference. + NewOp = *I; + } else if (*I == Placeholder) { + // Common case is that it just references this one placeholder. + NewOp = RealVal; + } else { + // Otherwise, look up the placeholder in ResolveConstants. + ResolveConstantsTy::iterator It = + std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(), + std::pair<Constant*, unsigned>(cast<Constant>(*I), + 0)); + assert(It != ResolveConstants.end() && It->first == *I); + NewOp = operator[](It->second); + } + + NewOps.push_back(cast<Constant>(NewOp)); + } + + // Make the new constant. + Constant *NewC; + if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) { + NewC = ConstantArray::get(UserCA->getType(), NewOps); + } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) { + NewC = ConstantStruct::get(UserCS->getType(), NewOps); + } else if (isa<ConstantVector>(UserC)) { + NewC = ConstantVector::get(NewOps); + } else { + assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr."); + NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps); + } + + UserC->replaceAllUsesWith(NewC); + UserC->destroyConstant(); + NewOps.clear(); + } + + // Update all ValueHandles, they should be the only users at this point. + Placeholder->replaceAllUsesWith(RealVal); + delete Placeholder; + } +} + +void NaClBitcodeReaderMDValueList::AssignValue(Value *V, unsigned Idx) { + if (Idx == size()) { + push_back(V); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = MDValuePtrs[Idx]; + if (OldV == 0) { + OldV = V; + return; + } + + // If there was a forward reference to this value, replace it. + MDNode *PrevVal = cast<MDNode>(OldV); + OldV->replaceAllUsesWith(V); + MDNode::deleteTemporary(PrevVal); + // Deleting PrevVal sets Idx value in MDValuePtrs to null. Set new + // value for Idx. + MDValuePtrs[Idx] = V; +} + +Value *NaClBitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = MDValuePtrs[Idx]) { + assert(V->getType()->isMetadataTy() && "Type mismatch in value table!"); + return V; + } + + // Create and return a placeholder, which will later be RAUW'd. + Value *V = MDNode::getTemporary(Context, ArrayRef<Value*>()); + MDValuePtrs[Idx] = V; + return V; +} + +Type *NaClBitcodeReader::getTypeByID(unsigned ID) { + // The type table size is always specified correctly. + if (ID >= TypeList.size()) + return 0; + + if (Type *Ty = TypeList[ID]) + return Ty; + + // If we have a forward reference, the only possible case is when it is to a + // named struct. Just create a placeholder for now. + return TypeList[ID] = StructType::create(Context); +} + + +//===----------------------------------------------------------------------===// +// Functions for parsing blocks from the bitcode file +//===----------------------------------------------------------------------===// + + +/// \brief This fills an AttrBuilder object with the LLVM attributes that have +/// been decoded from the given integer. This function must stay in sync with +/// 'encodeLLVMAttributesForBitcode'. +static void decodeLLVMAttributesForBitcode(AttrBuilder &B, + uint64_t EncodedAttrs) { + // FIXME: Remove in 4.0. + + // The alignment is stored as a 16-bit raw value from bits 31--16. We shift + // the bits above 31 down by 11 bits. + unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; + assert((!Alignment || isPowerOf2_32(Alignment)) && + "Alignment must be a power of two."); + + if (Alignment) + B.addAlignmentAttr(Alignment); + B.addRawValue(((EncodedAttrs & (0xfffffULL << 32)) >> 11) | + (EncodedAttrs & 0xffff)); +} + +bool NaClBitcodeReader::ParseAttributeBlock() { + if (Stream.EnterSubBlock(naclbitc::PARAMATTR_BLOCK_ID)) + return Error("Malformed block record"); + + if (!MAttributes.empty()) + return Error("Multiple PARAMATTR blocks found!"); + + SmallVector<uint64_t, 64> Record; + + SmallVector<AttributeSet, 8> Attrs; + + // Read all the records. + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: // Handled for us already. + case NaClBitstreamEntry::Error: + return Error("Error at end of PARAMATTR block"); + case NaClBitstreamEntry::EndBlock: + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case naclbitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...] + // FIXME: Remove in 4.0. + if (Record.size() & 1) + return Error("Invalid ENTRY record"); + + for (unsigned i = 0, e = Record.size(); i != e; i += 2) { + AttrBuilder B; + decodeLLVMAttributesForBitcode(B, Record[i+1]); + Attrs.push_back(AttributeSet::get(Context, Record[i], B)); + } + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + case naclbitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...] + for (unsigned i = 0, e = Record.size(); i != e; ++i) + Attrs.push_back(MAttributeGroups[Record[i]]); + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + } + } +} + +bool NaClBitcodeReader::ParseAttributeGroupBlock() { + if (Stream.EnterSubBlock(naclbitc::PARAMATTR_GROUP_BLOCK_ID)) + return Error("Malformed block record"); + + if (!MAttributeGroups.empty()) + return Error("Multiple PARAMATTR_GROUP blocks found!"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records. + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: // Handled for us already. + case NaClBitstreamEntry::Error: + return Error("Error at end of PARAMATTR_GROUP block"); + case NaClBitstreamEntry::EndBlock: + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case naclbitc::PARAMATTR_GRP_CODE_ENTRY: { + // ENTRY: [grpid, idx, a0, a1, ...] + if (Record.size() < 3) + return Error("Invalid ENTRY record"); + + uint64_t GrpID = Record[0]; + uint64_t Idx = Record[1]; // Index of the object this attribute refers to. + + AttrBuilder B; + for (unsigned i = 2, e = Record.size(); i != e; ++i) { + if (Record[i] == 0) { // Enum attribute + B.addAttribute(Attribute::AttrKind(Record[++i])); + } else if (Record[i] == 1) { // Align attribute + if (Attribute::AttrKind(Record[++i]) == Attribute::Alignment) + B.addAlignmentAttr(Record[++i]); + else + B.addStackAlignmentAttr(Record[++i]); + } else { // String attribute + assert((Record[i] == 3 || Record[i] == 4) && + "Invalid attribute group entry"); + bool HasValue = (Record[i++] == 4); + SmallString<64> KindStr; + SmallString<64> ValStr; + + while (Record[i] != 0 && i != e) + KindStr += Record[i++]; + assert(Record[i] == 0 && "Kind string not null terminated"); + + if (HasValue) { + // Has a value associated with it. + ++i; // Skip the '0' that terminates the "kind" string. + while (Record[i] != 0 && i != e) + ValStr += Record[i++]; + assert(Record[i] == 0 && "Value string not null terminated"); + } + + B.addAttribute(KindStr.str(), ValStr.str()); + } + } + + MAttributeGroups[GrpID] = AttributeSet::get(Context, Idx, B); + break; + } + } + } +} + +bool NaClBitcodeReader::ParseTypeTable() { + if (Stream.EnterSubBlock(naclbitc::TYPE_BLOCK_ID_NEW)) + return Error("Malformed block record"); + + return ParseTypeTableBody(); +} + +bool NaClBitcodeReader::ParseTypeTableBody() { + if (!TypeList.empty()) + return Error("Multiple TYPE_BLOCKs found!"); + + SmallVector<uint64_t, 64> Record; + unsigned NumRecords = 0; + + SmallString<64> TypeName; + + // Read all the records for this type table. + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: // Handled for us already. + case NaClBitstreamEntry::Error: + Error("Error in the type table block"); + return true; + case NaClBitstreamEntry::EndBlock: + if (NumRecords != TypeList.size()) + return Error("Invalid type forward reference in TYPE_BLOCK"); + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + Type *ResultTy = 0; + switch (Stream.readRecord(Entry.ID, Record)) { + default: return Error("unknown type in type table"); + case naclbitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] + // TYPE_CODE_NUMENTRY contains a count of the number of types in the + // type list. This allows us to reserve space. + if (Record.size() < 1) + return Error("Invalid TYPE_CODE_NUMENTRY record"); + TypeList.resize(Record[0]); + continue; + case naclbitc::TYPE_CODE_VOID: // VOID + ResultTy = Type::getVoidTy(Context); + break; + case naclbitc::TYPE_CODE_HALF: // HALF + ResultTy = Type::getHalfTy(Context); + break; + case naclbitc::TYPE_CODE_FLOAT: // FLOAT + ResultTy = Type::getFloatTy(Context); + break; + case naclbitc::TYPE_CODE_DOUBLE: // DOUBLE + ResultTy = Type::getDoubleTy(Context); + break; + case naclbitc::TYPE_CODE_X86_FP80: // X86_FP80 + ResultTy = Type::getX86_FP80Ty(Context); + break; + case naclbitc::TYPE_CODE_FP128: // FP128 + ResultTy = Type::getFP128Ty(Context); + break; + case naclbitc::TYPE_CODE_PPC_FP128: // PPC_FP128 + ResultTy = Type::getPPC_FP128Ty(Context); + break; + case naclbitc::TYPE_CODE_LABEL: // LABEL + ResultTy = Type::getLabelTy(Context); + break; + case naclbitc::TYPE_CODE_METADATA: // METADATA + ResultTy = Type::getMetadataTy(Context); + break; + case naclbitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; + case naclbitc::TYPE_CODE_INTEGER: // INTEGER: [width] + if (Record.size() < 1) + return Error("Invalid Integer type record"); + + ResultTy = IntegerType::get(Context, Record[0]); + break; + case naclbitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or + // [pointee type, address space] + if (Record.size() < 1) + return Error("Invalid POINTER type record"); + unsigned AddressSpace = 0; + if (Record.size() == 2) + AddressSpace = Record[1]; + ResultTy = getTypeByID(Record[0]); + if (ResultTy == 0) return Error("invalid element type in pointer type"); + ResultTy = PointerType::get(ResultTy, AddressSpace); + break; + } + case naclbitc::TYPE_CODE_FUNCTION_OLD: { + // FIXME: attrid is dead, remove it in LLVM 4.0 + // FUNCTION: [vararg, attrid, retty, paramty x N] + if (Record.size() < 3) + return Error("Invalid FUNCTION type record"); + SmallVector<Type*, 8> ArgTys; + for (unsigned i = 3, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + ArgTys.push_back(T); + else + break; + } + + ResultTy = getTypeByID(Record[2]); + if (ResultTy == 0 || ArgTys.size() < Record.size()-3) + return Error("invalid type in function type"); + + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case naclbitc::TYPE_CODE_FUNCTION: { + // FUNCTION: [vararg, retty, paramty x N] + if (Record.size() < 2) + return Error("Invalid FUNCTION type record"); + SmallVector<Type*, 8> ArgTys; + for (unsigned i = 2, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + ArgTys.push_back(T); + else + break; + } + + ResultTy = getTypeByID(Record[1]); + if (ResultTy == 0 || ArgTys.size() < Record.size()-2) + return Error("invalid type in function type"); + + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case naclbitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid STRUCT type record"); + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("invalid type in struct type"); + ResultTy = StructType::get(Context, EltTys, Record[0]); + break; + } + case naclbitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] + if (ConvertToString(Record, 0, TypeName)) + return Error("Invalid STRUCT_NAME record"); + continue; + + case naclbitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid STRUCT type record"); + + if (NumRecords >= TypeList.size()) + return Error("invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = 0; + } else // Otherwise, create a new struct. + Res = StructType::create(Context, TypeName); + TypeName.clear(); + + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("invalid STRUCT type record"); + Res->setBody(EltTys, Record[0]); + ResultTy = Res; + break; + } + case naclbitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] + if (Record.size() != 1) + return Error("Invalid OPAQUE type record"); + + if (NumRecords >= TypeList.size()) + return Error("invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = 0; + } else // Otherwise, create a new struct with no body. + Res = StructType::create(Context, TypeName); + TypeName.clear(); + ResultTy = Res; + break; + } + case naclbitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid ARRAY type record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = ArrayType::get(ResultTy, Record[0]); + else + return Error("Invalid ARRAY type element"); + break; + case naclbitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid VECTOR type record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = VectorType::get(ResultTy, Record[0]); + else + return Error("Invalid ARRAY type element"); + break; + } + + if (NumRecords >= TypeList.size()) + return Error("invalid TYPE table"); + assert(ResultTy && "Didn't read a type?"); + assert(TypeList[NumRecords] == 0 && "Already read type?"); + TypeList[NumRecords++] = ResultTy; + } +} + +bool NaClBitcodeReader::ParseValueSymbolTable() { + if (Stream.EnterSubBlock(naclbitc::VALUE_SYMTAB_BLOCK_ID)) + return Error("Malformed block record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this value table. + SmallString<128> ValueName; + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: // Handled for us already. + case NaClBitstreamEntry::Error: + return Error("malformed value symbol table block"); + case NaClBitstreamEntry::EndBlock: + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: unknown type. + break; + case naclbitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N] + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid VST_ENTRY record"); + unsigned ValueID = Record[0]; + if (ValueID >= ValueList.size()) + return Error("Invalid Value ID in VST_ENTRY record"); + Value *V = ValueList[ValueID]; + + V->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + case naclbitc::VST_CODE_BBENTRY: { + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid VST_BBENTRY record"); + BasicBlock *BB = getBasicBlock(Record[0]); + if (BB == 0) + return Error("Invalid BB ID in VST_BBENTRY record"); + + BB->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + } + } +} + +bool NaClBitcodeReader::ParseMetadata() { + unsigned NextMDValueNo = MDValueList.size(); + + if (Stream.EnterSubBlock(naclbitc::METADATA_BLOCK_ID)) + return Error("Malformed block record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records. + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: // Handled for us already. + case NaClBitstreamEntry::Error: + Error("malformed metadata block"); + return true; + case NaClBitstreamEntry::EndBlock: + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + bool IsFunctionLocal = false; + // Read a record. + Record.clear(); + unsigned Code = Stream.readRecord(Entry.ID, Record); + switch (Code) { + default: // Default behavior: ignore. + break; + case naclbitc::METADATA_NAME: { + // Read name of the named metadata. + SmallString<8> Name(Record.begin(), Record.end()); + Record.clear(); + Code = Stream.ReadCode(); + + // METADATA_NAME is always followed by METADATA_NAMED_NODE. + unsigned NextBitCode = Stream.readRecord(Code, Record); + assert(NextBitCode == naclbitc::METADATA_NAMED_NODE); (void)NextBitCode; + + // Read named metadata elements. + unsigned Size = Record.size(); + NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name); + for (unsigned i = 0; i != Size; ++i) { + MDNode *MD = dyn_cast<MDNode>(MDValueList.getValueFwdRef(Record[i])); + if (MD == 0) + return Error("Malformed metadata record"); + NMD->addOperand(MD); + } + break; + } + case naclbitc::METADATA_FN_NODE: + IsFunctionLocal = true; + // fall-through + case naclbitc::METADATA_NODE: { + if (Record.size() % 2 == 1) + return Error("Invalid METADATA_NODE record"); + + unsigned Size = Record.size(); + SmallVector<Value*, 8> Elts; + for (unsigned i = 0; i != Size; i += 2) { + Type *Ty = getTypeByID(Record[i]); + if (!Ty) return Error("Invalid METADATA_NODE record"); + if (Ty->isMetadataTy()) + Elts.push_back(MDValueList.getValueFwdRef(Record[i+1])); + else if (!Ty->isVoidTy()) + Elts.push_back(ValueList.getValueFwdRef(Record[i+1], Ty)); + else + Elts.push_back(NULL); + } + Value *V = MDNode::getWhenValsUnresolved(Context, Elts, IsFunctionLocal); + IsFunctionLocal = false; + MDValueList.AssignValue(V, NextMDValueNo++); + break; + } + case naclbitc::METADATA_STRING: { + SmallString<8> String(Record.begin(), Record.end()); + Value *V = MDString::get(Context, String); + MDValueList.AssignValue(V, NextMDValueNo++); + break; + } + case naclbitc::METADATA_KIND: { + if (Record.size() < 2) + return Error("Invalid METADATA_KIND record"); + + unsigned Kind = Record[0]; + SmallString<8> Name(Record.begin()+1, Record.end()); + + unsigned NewKind = TheModule->getMDKindID(Name.str()); + if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second) + return Error("Conflicting METADATA_KIND records"); + break; + } + } + } +} + +/// decodeSignRotatedValue - Decode a signed value stored with the sign bit in +/// the LSB for dense VBR encoding. +uint64_t NaClBitcodeReader::decodeSignRotatedValue(uint64_t V) { + if ((V & 1) == 0) + return V >> 1; + if (V != 1) + return -(V >> 1); + // There is no such thing as -0 with integers. "-0" really means MININT. + return 1ULL << 63; +} + +/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global +/// values and aliases that we can. +bool NaClBitcodeReader::ResolveGlobalAndAliasInits() { + std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist; + std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist; + + GlobalInitWorklist.swap(GlobalInits); + AliasInitWorklist.swap(AliasInits); + + while (!GlobalInitWorklist.empty()) { + unsigned ValID = GlobalInitWorklist.back().second; + if (ValID >= ValueList.siz |