aboutsummaryrefslogtreecommitdiff
path: root/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp')
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp2644
1 files changed, 2644 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..5f14a639ba
--- /dev/null
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
@@ -0,0 +1,2644 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "NaClBitcodeReader"
+
+#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/Debug.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();
+
+ std::vector<BasicBlock*>().swap(FunctionBBs);
+ std::vector<Function*>().swap(FunctionsWithBodies);
+ DeferredFunctionInfo.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 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;
+ }
+}
+
+static CallingConv::ID GetDecodedCallingConv(unsigned Val) {
+ switch (Val) {
+ default:
+ report_fatal_error("PNaCl bitcode contains invalid calling conventions.");
+ case naclbitc::C_CallingConv: return CallingConv::C;
+ }
+}
+
+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) {
+ assert(V);
+ 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;
+ }
+}
+
+void NaClBitcodeReaderValueList::AssignGlobalVar(GlobalVariable *GV,
+ unsigned Idx) {
+ assert(GV);
+
+ if (Idx == size()) {
+ push_back(GV);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ WeakVH &OldV = ValuePtrs[Idx];
+ if (OldV == 0) {
+ OldV = GV;
+ return;
+ }
+
+ // If there was a forward reference to this value, replace it.
+ Value *PrevVal = OldV;
+ GlobalVariable *Placeholder = cast<GlobalVariable>(PrevVal);
+ Placeholder->replaceAllUsesWith(
+ ConstantExpr::getBitCast(GV, Placeholder->getType()));
+ Placeholder->eraseFromParent();
+ ValuePtrs[Idx] = GV;
+}
+
+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) {
+ if (Idx >= size())
+ return 0;
+
+ if (Value *V = ValuePtrs[Idx])
+ return V;
+
+ return 0;
+}
+
+bool NaClBitcodeReaderValueList::createValueFwdRef(unsigned Idx, Type *Ty) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ // Return an error if this a duplicate definition of Idx.
+ if (ValuePtrs[Idx])
+ return true;
+
+ // No type specified, must be invalid reference.
+ if (Ty == 0)
+ return true;
+
+ // Create a placeholder, which will later be RAUW'd.
+ ValuePtrs[Idx] = new Argument(Ty);
+ return false;
+}
+
+Constant *NaClBitcodeReaderValueList::getOrCreateGlobalVarRef(
+ unsigned Idx, Module *M) {
+ // First make sure the element for Idx is defined.
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ // Now get its value (if applicable).
+ if (Value *V = ValuePtrs[Idx])
+ return dyn_cast<Constant>(V);
+
+ // Create a placeholder, which will later be RAUW'd.
+ Type *PlaceholderType = Type::getInt8Ty(Context);
+
+ Constant *C =
+ new GlobalVariable(*M, PlaceholderType, false,
+ GlobalValue::ExternalLinkage, 0);
+ ValuePtrs[Idx] = C;
+ return C;
+}
+
+/// 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;
+ }
+}
+
+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
+//===----------------------------------------------------------------------===//
+
+
+bool NaClBitcodeReader::ParseTypeTable() {
+ DEBUG(dbgs() << "-> ParseTypeTable\n");
+ if (Stream.EnterSubBlock(naclbitc::TYPE_BLOCK_ID_NEW))
+ return Error("Malformed block record");
+
+ bool result = ParseTypeTableBody();
+ if (!result)
+ DEBUG(dbgs() << "<- ParseTypeTable\n");
+ return result;
+}
+
+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_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::ParseGlobalVars() {
+ if (Stream.EnterSubBlock(naclbitc::GLOBALVAR_BLOCK_ID))
+ return Error("Malformed block record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // True when processing a global variable. Stays true until all records
+ // are processed, and the global variable is created.
+ bool ProcessingGlobal = false;
+ // The alignment value defined for the global variable.
+ unsigned VarAlignment = 0;
+ // True if the variable is read-only.
+ bool VarIsConstant = false;
+ // The initializer for the global variable.
+ SmallVector<Constant *, 10> VarInit;
+ // The number of initializers needed for the global variable.
+ unsigned VarInitializersNeeded = 0;
+ unsigned FirstValueNo = ValueList.size();
+ // The index of the next global variable.
+ unsigned NextValueNo = FirstValueNo;
+ // The number of expected global variable definitions.
+ unsigned NumGlobals = 0;
+
+ // Read all global variable records.
+ while (1) {
+ NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ switch (Entry.Kind) {
+ case NaClBitstreamEntry::SubBlock:
+ case NaClBitstreamEntry::Error:
+ return Error("Error in the global vars block");
+ case NaClBitstreamEntry::EndBlock:
+ if (ProcessingGlobal || NumGlobals != (NextValueNo - FirstValueNo))
+ return Error("Error in the global vars block");
+ return false;
+ case NaClBitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ unsigned Bitcode = Stream.readRecord(Entry.ID, Record);
+ switch (Bitcode) {
+ default: return Error("Unknown global variable entry");
+ case naclbitc::GLOBALVAR_VAR:
+ // Start the definition of a global variable.
+ if (ProcessingGlobal || Record.size() != 2)
+ return Error("Bad GLOBALVAR_VAR record");
+ ProcessingGlobal = true;
+ VarAlignment = (1 << Record[0]) >> 1;
+ VarIsConstant = Record[1] != 0;
+ // Assume (by default) there is a single initializer.
+ VarInitializersNeeded = 1;
+ break;
+ case naclbitc::GLOBALVAR_COMPOUND:
+ // Global variable has multiple initializers. Changes the
+ // default number of initializers to the given value in
+ // Record[0].
+ if (!ProcessingGlobal || !VarInit.empty() ||
+ VarInitializersNeeded != 1 || Record.size() != 1)
+ return Error("Bad GLOBALVAR_COMPOUND record");
+ VarInitializersNeeded = Record[0];
+ break;
+ case naclbitc::GLOBALVAR_ZEROFILL: {
+ // Define an initializer that defines a sequence of zero-filled bytes.
+ if (!ProcessingGlobal || Record.size() != 1)
+ return Error("Bad GLOBALVAR_ZEROFILL record");
+ Type *Ty = ArrayType::get(Type::getInt8Ty(Context), Record[0]);
+ Constant *Zero = ConstantAggregateZero::get(Ty);
+ VarInit.push_back(Zero);
+ break;
+ }
+ case naclbitc::GLOBALVAR_DATA: {
+ // Defines an initializer defined by a sequence of byte values.
+ if (!ProcessingGlobal || Record.size() < 1)
+ return Error("Bad GLOBALVAR_DATA record");
+ unsigned Size = Record.size();
+ uint8_t *Buf = new uint8_t[Size];
+ assert(Buf);
+ for (unsigned i = 0; i < Size; ++i)
+ Buf[i] = Record[i];
+ Constant *Init = ConstantDataArray::get(
+ Context, ArrayRef<uint8_t>(Buf, Buf + Size));
+ VarInit.push_back(Init);
+ delete[] Buf;
+ break;
+ }
+ case naclbitc::GLOBALVAR_RELOC: {
+ // Define a relocation initializer.
+ if (!ProcessingGlobal || Record.size() < 1 || Record.size() > 2)
+ return Error("Bad GLOBALVAR_RELOC record");
+ Constant *BaseVal =
+ ValueList.getOrCreateGlobalVarRef(Record[0], TheModule);
+ if (BaseVal == 0)
+ return Error("Bad base value in GLOBALVAR_RELOC record");
+ Type *IntPtrType = IntegerType::get(Context, 32);
+ Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType);
+ if (Record.size() == 2) {
+ uint32_t Addend = Record[1];
+ Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType,
+ Addend));
+ }
+ VarInit.push_back(Val);
+ break;
+ }
+ case naclbitc::GLOBALVAR_COUNT:
+ if (Record.size() != 1 || NumGlobals != 0)
+ return Error("Invalid global count record");
+ NumGlobals = Record[0];
+ break;
+ }
+
+ // If more initializers needed for global variable, continue processing.
+ if (!ProcessingGlobal || VarInit.size() < VarInitializersNeeded)
+ continue;
+
+ Constant *Init = 0;
+ switch (VarInit.size()) {
+ case 0:
+ return Error("No initializer for global variable in global vars block");
+ case 1:
+ Init = VarInit[0];
+ break;
+ default:
+ Init = ConstantStruct::getAnon(Context, VarInit, true);
+ break;
+ }
+ GlobalVariable *GV = new GlobalVariable(
+ *TheModule, Init->getType(), VarIsConstant,
+ GlobalValue::InternalLinkage, Init, "");
+ GV->setAlignment(VarAlignment);
+ ValueList.AssignGlobalVar(GV, NextValueNo);
+ ++NextValueNo;
+ ProcessingGlobal = false;
+ VarAlignment = 0;
+ VarIsConstant = false;
+ VarInitializersNeeded = 0;
+ VarInit.clear();
+ }
+}
+
+bool NaClBitcodeReader::ParseValueSymbolTable() {
+ DEBUG(dbgs() << "-> ParseValueSymbolTable\n");
+ 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:
+ DEBUG(dbgs() << "<- ParseValueSymbolTable\n");
+ 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;
+ }
+ }
+ }
+}
+
+/// ResolveAliasInits - Resolve all of the initializers for aliases that we can.
+bool NaClBitcodeReader::ResolveAliasInits() {
+ std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
+
+ AliasInitWorklist.swap(AliasInits);
+
+ while (!AliasInitWorklist.empty()) {
+ unsigned ValID = AliasInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ AliasInits.push_back(AliasInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast<Constant>(ValueList[ValID]))
+ AliasInitWorklist.back().first->setAliasee(C);
+ else
+ return Error("Alias initializer is not a constant!");
+ }
+ AliasInitWorklist.pop_back();
+ }
+ return false;
+}
+
+static APInt ReadWideAPInt(ArrayRef<uint64_t> Vals, unsigned TypeBits) {
+ SmallVector<uint64_t, 8> Words(Vals.size());
+ std::transform(Vals.begin(), Vals.end(), Words.begin(),
+ NaClDecodeSignRotatedValue);
+
+ return APInt(TypeBits, Words);
+}
+
+bool NaClBitcodeReader::ParseConstants() {
+ DEBUG(dbgs() << "-> ParseConstants\n");
+ if (Stream.EnterSubBlock(naclbitc::CONSTANTS_BLOCK_ID))
+ return Error("Malformed block record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this value table.
+ Type *CurTy = Type::getInt32Ty(Context);
+ unsigned NextCstNo = ValueList.size();
+ while (1) {
+ NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case NaClBitstreamEntry::SubBlock: // Handled for us already.
+ case NaClBitstreamEntry::Error:
+ return Error("malformed block record in AST file");
+ case NaClBitstreamEntry::EndBlock:
+ if (NextCstNo != ValueList.size())
+ return Error("Invalid constant reference!");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ DEBUG(dbgs() << "<- ParseConstants\n");
+ return false;
+ case NaClBitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ Value *V = 0;
+ unsigned BitCode = Stream.readRecord(Entry.ID, Record);
+ switch (BitCode) {
+ default: // Default behavior: unknown constant
+ case naclbitc::CST_CODE_UNDEF: // UNDEF
+ V = UndefValue::get(CurTy);
+ break;
+ case naclbitc::CST_CODE_SETTYPE: // SETTYPE: [typeid]
+ if (Record.empty())
+ return Error("Malformed CST_SETTYPE record");
+ if (Record[0] >= TypeList.size())
+ return Error("Invalid Type ID in CST_SETTYPE record");
+ CurTy = TypeList[Record[0]];
+ continue; // Skip the ValueList manipulation.
+ case naclbitc::CST_CODE_NULL: // NULL
+ V = Constant::getNullValue(CurTy);
+ break;
+ case naclbitc::CST_CODE_INTEGER: // INTEGER: [intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid CST_INTEGER record");
+ V = ConstantInt::get(CurTy, NaClDecodeSignRotatedValue(Record[0]));
+ break;
+ case naclbitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid WIDE_INTEGER record");
+
+ APInt VInt = ReadWideAPInt(Record,
+ cast<IntegerType>(CurTy)->getBitWidth());
+ V = ConstantInt::get(Context, VInt);
+
+ break;
+ }
+ case naclbitc::CST_CODE_FLOAT: { // FLOAT: [fpval]
+ if (Record.empty())
+ return Error("Invalid FLOAT record");
+ if (CurTy->isHalfTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf,
+ APInt(16, (uint16_t)Record[0])));
+ else if (CurTy->isFloatTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle,
+ APInt(32, (uint32_t)Record[0])));
+ else if (CurTy->isDoubleTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble,
+ APInt(64, Record[0])));
+ else if (CurTy->isX86_FP80Ty()) {
+ // Bits are not stored the same way as a normal i80 APInt, compensate.
+ uint64_t Rearrange[2];
+ Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16);
+ Rearrange[1] = Record[0] >> 48;
+ V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended,
+ APInt(80, Rearrange)));
+ } else if (CurTy->isFP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad,
+ APInt(128, Record)));
+ else if (CurTy->isPPC_FP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble,
+ APInt(128, Record)));
+ else
+ V = UndefValue::get(CurTy);
+ break;
+ }
+
+ case naclbitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number]
+ if (Record.empty())
+ return Error("Invalid CST_AGGREGATE record");
+
+ unsigned Size = Record.size();
+