aboutsummaryrefslogtreecommitdiff
path: root/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp')
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp1790
1 files changed, 1790 insertions, 0 deletions
diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
new file mode 100644
index 0000000000..33d0d84cb5
--- /dev/null
+++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
@@ -0,0 +1,1790 @@
+//===--- Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp - Bitcode Writer -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Bitcode writer implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "NaClBitcodeWriter"
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+#include "NaClValueEnumerator.h"
+#include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h"
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/ValueSymbolTable.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cctype>
+#include <map>
+using namespace llvm;
+
+/// These are manifest constants used by the bitcode writer. They do
+/// not need to be kept in sync with the reader, but need to be
+/// consistent within this file.
+///
+/// Note that for each block type GROUP, the last entry should be of
+/// the form:
+///
+/// GROUP_MAX_ABBREV = GROUP_LAST_ABBREV,
+///
+/// where GROUP_LAST_ABBREV is the last defined abbreviation. See
+/// include file "llvm/Bitcode/NaCl/NaClBitCodes.h" for more
+/// information on how groups should be defined.
+enum {
+ // VALUE_SYMTAB_BLOCK abbrev id's.
+ VST_ENTRY_8_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV,
+ VST_ENTRY_7_ABBREV,
+ VST_ENTRY_6_ABBREV,
+ VST_BBENTRY_6_ABBREV,
+ VST_MAX_ABBREV = VST_BBENTRY_6_ABBREV,
+
+ // CONSTANTS_BLOCK abbrev id's.
+ CONSTANTS_SETTYPE_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV,
+ CONSTANTS_INTEGER_ABBREV,
+ CONSTANTS_CE_CAST_Abbrev,
+ CONSTANTS_NULL_Abbrev,
+ CONSTANTS_MAX_ABBREV = CONSTANTS_NULL_Abbrev,
+
+ // CONSTANTS_BLOCK abbrev id's when global (extends list above).
+ CST_CONSTANTS_AGGREGATE_ABBREV = CONSTANTS_MAX_ABBREV+1,
+ CST_CONSTANTS_STRING_ABBREV,
+ CST_CONSTANTS_CSTRING_7_ABBREV,
+ CST_CONSTANTS_CSTRING_6_ABBREV,
+ CST_CONSTANTS_MAX_ABBREV = CST_CONSTANTS_CSTRING_6_ABBREV,
+
+ // GLOBALVAR BLOCK abbrev id's.
+ GLOBALVAR_VAR_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV,
+ GLOBALVAR_COMPOUND_ABBREV,
+ GLOBALVAR_ZEROFILL_ABBREV,
+ GLOBALVAR_DATA_ABBREV,
+ GLOBALVAR_RELOC_ABBREV,
+ GLOBALVAR_RELOC_WITH_ADDEND_ABBREV,
+ GLOBALVAR_MAX_ABBREV = GLOBALVAR_RELOC_WITH_ADDEND_ABBREV,
+
+ // FUNCTION_BLOCK abbrev id's.
+ FUNCTION_INST_LOAD_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV,
+ FUNCTION_INST_BINOP_ABBREV,
+ FUNCTION_INST_BINOP_FLAGS_ABBREV,
+ FUNCTION_INST_CAST_ABBREV,
+ FUNCTION_INST_RET_VOID_ABBREV,
+ FUNCTION_INST_RET_VAL_ABBREV,
+ FUNCTION_INST_UNREACHABLE_ABBREV,
+ FUNCTION_INST_FORWARDTYPEREF_ABBREV,
+ FUNCTION_INST_MAX_ABBREV = FUNCTION_INST_FORWARDTYPEREF_ABBREV,
+
+ // TYPE_BLOCK_ID_NEW abbrev id's.
+ TYPE_POINTER_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV,
+ TYPE_FUNCTION_ABBREV,
+ TYPE_STRUCT_ANON_ABBREV,
+ TYPE_STRUCT_NAME_ABBREV,
+ TYPE_STRUCT_NAMED_ABBREV,
+ TYPE_ARRAY_ABBREV,
+ TYPE_MAX_ABBREV = TYPE_ARRAY_ABBREV,
+
+ // SwitchInst Magic
+ SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex
+};
+
+static unsigned GetEncodedCastOpcode(unsigned Opcode) {
+ switch (Opcode) {
+ default: report_fatal_error("Unknown cast instruction!");
+ case Instruction::Trunc : return naclbitc::CAST_TRUNC;
+ case Instruction::ZExt : return naclbitc::CAST_ZEXT;
+ case Instruction::SExt : return naclbitc::CAST_SEXT;
+ case Instruction::FPToUI : return naclbitc::CAST_FPTOUI;
+ case Instruction::FPToSI : return naclbitc::CAST_FPTOSI;
+ case Instruction::UIToFP : return naclbitc::CAST_UITOFP;
+ case Instruction::SIToFP : return naclbitc::CAST_SITOFP;
+ case Instruction::FPTrunc : return naclbitc::CAST_FPTRUNC;
+ case Instruction::FPExt : return naclbitc::CAST_FPEXT;
+ case Instruction::PtrToInt: return naclbitc::CAST_PTRTOINT;
+ case Instruction::IntToPtr: return naclbitc::CAST_INTTOPTR;
+ case Instruction::BitCast : return naclbitc::CAST_BITCAST;
+ }
+}
+
+static unsigned GetEncodedBinaryOpcode(unsigned Opcode) {
+ switch (Opcode) {
+ default: report_fatal_error("Unknown binary instruction!");
+ case Instruction::Add:
+ case Instruction::FAdd: return naclbitc::BINOP_ADD;
+ case Instruction::Sub:
+ case Instruction::FSub: return naclbitc::BINOP_SUB;
+ case Instruction::Mul:
+ case Instruction::FMul: return naclbitc::BINOP_MUL;
+ case Instruction::UDiv: return naclbitc::BINOP_UDIV;
+ case Instruction::FDiv:
+ case Instruction::SDiv: return naclbitc::BINOP_SDIV;
+ case Instruction::URem: return naclbitc::BINOP_UREM;
+ case Instruction::FRem:
+ case Instruction::SRem: return naclbitc::BINOP_SREM;
+ case Instruction::Shl: return naclbitc::BINOP_SHL;
+ case Instruction::LShr: return naclbitc::BINOP_LSHR;
+ case Instruction::AShr: return naclbitc::BINOP_ASHR;
+ case Instruction::And: return naclbitc::BINOP_AND;
+ case Instruction::Or: return naclbitc::BINOP_OR;
+ case Instruction::Xor: return naclbitc::BINOP_XOR;
+ }
+}
+
+static unsigned GetEncodedRMWOperation(AtomicRMWInst::BinOp Op) {
+ switch (Op) {
+ default: report_fatal_error("Unknown RMW operation!");
+ case AtomicRMWInst::Xchg: return naclbitc::RMW_XCHG;
+ case AtomicRMWInst::Add: return naclbitc::RMW_ADD;
+ case AtomicRMWInst::Sub: return naclbitc::RMW_SUB;
+ case AtomicRMWInst::And: return naclbitc::RMW_AND;
+ case AtomicRMWInst::Nand: return naclbitc::RMW_NAND;
+ case AtomicRMWInst::Or: return naclbitc::RMW_OR;
+ case AtomicRMWInst::Xor: return naclbitc::RMW_XOR;
+ case AtomicRMWInst::Max: return naclbitc::RMW_MAX;
+ case AtomicRMWInst::Min: return naclbitc::RMW_MIN;
+ case AtomicRMWInst::UMax: return naclbitc::RMW_UMAX;
+ case AtomicRMWInst::UMin: return naclbitc::RMW_UMIN;
+ }
+}
+
+static unsigned GetEncodedOrdering(AtomicOrdering Ordering) {
+ switch (Ordering) {
+ default: report_fatal_error("Invalid ordering");
+ case NotAtomic: return naclbitc::ORDERING_NOTATOMIC;
+ case Unordered: return naclbitc::ORDERING_UNORDERED;
+ case Monotonic: return naclbitc::ORDERING_MONOTONIC;
+ case Acquire: return naclbitc::ORDERING_ACQUIRE;
+ case Release: return naclbitc::ORDERING_RELEASE;
+ case AcquireRelease: return naclbitc::ORDERING_ACQREL;
+ case SequentiallyConsistent: return naclbitc::ORDERING_SEQCST;
+ }
+}
+
+static unsigned GetEncodedSynchScope(SynchronizationScope SynchScope) {
+ switch (SynchScope) {
+ default: report_fatal_error("Invalid synch scope");
+ case SingleThread: return naclbitc::SYNCHSCOPE_SINGLETHREAD;
+ case CrossThread: return naclbitc::SYNCHSCOPE_CROSSTHREAD;
+ }
+}
+
+static unsigned GetEncodedCallingConv(CallingConv::ID conv) {
+ switch (conv) {
+ default: report_fatal_error(
+ "Calling convention not supported by PNaCL bitcode");
+ case CallingConv::C: return naclbitc::C_CallingConv;
+ }
+}
+
+static void WriteStringRecord(unsigned Code, StringRef Str,
+ unsigned AbbrevToUse,
+ NaClBitstreamWriter &Stream) {
+ SmallVector<unsigned, 64> Vals;
+
+ // Code: [strchar x N]
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ if (AbbrevToUse && !NaClBitCodeAbbrevOp::isChar6(Str[i]))
+ AbbrevToUse = 0;
+ Vals.push_back(Str[i]);
+ }
+
+ // Emit the finished record.
+ Stream.EmitRecord(Code, Vals, AbbrevToUse);
+}
+
+/// WriteTypeTable - Write out the type table for a module.
+static void WriteTypeTable(const NaClValueEnumerator &VE,
+ NaClBitstreamWriter &Stream) {
+ DEBUG(dbgs() << "-> WriteTypeTable\n");
+ const NaClValueEnumerator::TypeList &TypeList = VE.getTypes();
+
+ Stream.EnterSubblock(naclbitc::TYPE_BLOCK_ID_NEW, TYPE_MAX_ABBREV);
+
+ SmallVector<uint64_t, 64> TypeVals;
+
+
+ // Note: modify to use maximum number of bits if under cutoff. Otherwise,
+ // use VBR to take advantage that frequently referenced types have
+ // small IDs.
+ //
+ // Note: Cutoff chosen based on experiments on pnacl-translate.pexe.
+ uint64_t NumBits = NaClBitsNeededForValue(VE.getTypes().size());
+ static const uint64_t TypeVBRCutoff = 6;
+ uint64_t TypeIdNumBits = (NumBits <= TypeVBRCutoff ? NumBits : TypeVBRCutoff);
+ NaClBitCodeAbbrevOp::Encoding TypeIdEncoding =
+ (NumBits <= TypeVBRCutoff
+ ? NaClBitCodeAbbrevOp::Fixed : NaClBitCodeAbbrevOp::VBR);
+
+ // Abbrev for TYPE_CODE_POINTER.
+ NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_POINTER));
+ Abbv->Add(NaClBitCodeAbbrevOp(TypeIdEncoding, TypeIdNumBits));
+ Abbv->Add(NaClBitCodeAbbrevOp(0)); // Addrspace = 0
+ if (TYPE_POINTER_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for TYPE_CODE_FUNCTION.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_FUNCTION));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // isvararg
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, NumBits));
+ if (TYPE_FUNCTION_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for TYPE_CODE_STRUCT_ANON.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_STRUCT_ANON));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // ispacked
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, NumBits));
+ if (TYPE_STRUCT_ANON_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for TYPE_CODE_STRUCT_NAME.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_STRUCT_NAME));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6));
+ if (TYPE_STRUCT_NAME_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for TYPE_CODE_STRUCT_NAMED.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_STRUCT_NAMED));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // ispacked
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, NumBits));
+ if (TYPE_STRUCT_NAMED_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for TYPE_CODE_ARRAY.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_ARRAY));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 8)); // size
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, NumBits));
+ if (TYPE_ARRAY_ABBREV != Stream.EmitAbbrev(Abbv))
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Emit an entry count so the reader can reserve space.
+ TypeVals.push_back(TypeList.size());
+ Stream.EmitRecord(naclbitc::TYPE_CODE_NUMENTRY, TypeVals);
+ TypeVals.clear();
+
+ // Loop over all of the types, emitting each in turn.
+ for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
+ Type *T = TypeList[i];
+ int AbbrevToUse = 0;
+ unsigned Code = 0;
+
+ switch (T->getTypeID()) {
+ default: llvm_unreachable("Unknown type!");
+ case Type::VoidTyID: Code = naclbitc::TYPE_CODE_VOID; break;
+ case Type::HalfTyID: Code = naclbitc::TYPE_CODE_HALF; break;
+ case Type::FloatTyID: Code = naclbitc::TYPE_CODE_FLOAT; break;
+ case Type::DoubleTyID: Code = naclbitc::TYPE_CODE_DOUBLE; break;
+ case Type::X86_FP80TyID: Code = naclbitc::TYPE_CODE_X86_FP80; break;
+ case Type::FP128TyID: Code = naclbitc::TYPE_CODE_FP128; break;
+ case Type::PPC_FP128TyID: Code = naclbitc::TYPE_CODE_PPC_FP128; break;
+ case Type::LabelTyID: Code = naclbitc::TYPE_CODE_LABEL; break;
+ case Type::X86_MMXTyID: Code = naclbitc::TYPE_CODE_X86_MMX; break;
+ case Type::IntegerTyID:
+ // INTEGER: [width]
+ Code = naclbitc::TYPE_CODE_INTEGER;
+ TypeVals.push_back(cast<IntegerType>(T)->getBitWidth());
+ break;
+ case Type::PointerTyID: {
+ PointerType *PTy = cast<PointerType>(T);
+ // POINTER: [pointee type, address space]
+ Code = naclbitc::TYPE_CODE_POINTER;
+ TypeVals.push_back(VE.getTypeID(PTy->getElementType()));
+ unsigned AddressSpace = PTy->getAddressSpace();
+ TypeVals.push_back(AddressSpace);
+ if (AddressSpace == 0) AbbrevToUse = TYPE_POINTER_ABBREV;
+ break;
+ }
+ case Type::FunctionTyID: {
+ FunctionType *FT = cast<FunctionType>(T);
+ // FUNCTION: [isvararg, retty, paramty x N]
+ Code = naclbitc::TYPE_CODE_FUNCTION;
+ TypeVals.push_back(FT->isVarArg());
+ TypeVals.push_back(VE.getTypeID(FT->getReturnType()));
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i)
+ TypeVals.push_back(VE.getTypeID(FT->getParamType(i)));
+ AbbrevToUse = TYPE_FUNCTION_ABBREV;
+ break;
+ }
+ case Type::StructTyID: {
+ StructType *ST = cast<StructType>(T);
+ // STRUCT: [ispacked, eltty x N]
+ TypeVals.push_back(ST->isPacked());
+ // Output all of the element types.
+ for (StructType::element_iterator I = ST->element_begin(),
+ E = ST->element_end(); I != E; ++I)
+ TypeVals.push_back(VE.getTypeID(*I));
+
+ if (ST->isLiteral()) {
+ Code = naclbitc::TYPE_CODE_STRUCT_ANON;
+ AbbrevToUse = TYPE_STRUCT_ANON_ABBREV;
+ } else {
+ if (ST->isOpaque()) {
+ Code = naclbitc::TYPE_CODE_OPAQUE;
+ } else {
+ Code = naclbitc::TYPE_CODE_STRUCT_NAMED;
+ AbbrevToUse = TYPE_STRUCT_NAMED_ABBREV;
+ }
+
+ // Emit the name if it is present.
+ if (!ST->getName().empty())
+ WriteStringRecord(naclbitc::TYPE_CODE_STRUCT_NAME, ST->getName(),
+ TYPE_STRUCT_NAME_ABBREV, Stream);
+ }
+ break;
+ }
+ case Type::ArrayTyID: {
+ ArrayType *AT = cast<ArrayType>(T);
+ // ARRAY: [numelts, eltty]
+ Code = naclbitc::TYPE_CODE_ARRAY;
+ TypeVals.push_back(AT->getNumElements());
+ TypeVals.push_back(VE.getTypeID(AT->getElementType()));
+ AbbrevToUse = TYPE_ARRAY_ABBREV;
+ break;
+ }
+ case Type::VectorTyID: {
+ VectorType *VT = cast<VectorType>(T);
+ // VECTOR [numelts, eltty]
+ Code = naclbitc::TYPE_CODE_VECTOR;
+ TypeVals.push_back(VT->getNumElements());
+ TypeVals.push_back(VE.getTypeID(VT->getElementType()));
+ break;
+ }
+ }
+
+ // Emit the finished record.
+ Stream.EmitRecord(Code, TypeVals, AbbrevToUse);
+ TypeVals.clear();
+ }
+
+ Stream.ExitBlock();
+ DEBUG(dbgs() << "<- WriteTypeTable\n");
+}
+
+static unsigned getEncodedLinkage(const GlobalValue *GV) {
+ switch (GV->getLinkage()) {
+ case GlobalValue::ExternalLinkage: return 0;
+ case GlobalValue::WeakAnyLinkage: return 1;
+ case GlobalValue::AppendingLinkage: return 2;
+ case GlobalValue::InternalLinkage: return 3;
+ case GlobalValue::LinkOnceAnyLinkage: return 4;
+ case GlobalValue::DLLImportLinkage: return 5;
+ case GlobalValue::DLLExportLinkage: return 6;
+ case GlobalValue::ExternalWeakLinkage: return 7;
+ case GlobalValue::CommonLinkage: return 8;
+ case GlobalValue::PrivateLinkage: return 9;
+ case GlobalValue::WeakODRLinkage: return 10;
+ case GlobalValue::LinkOnceODRLinkage: return 11;
+ case GlobalValue::AvailableExternallyLinkage: return 12;
+ case GlobalValue::LinkerPrivateLinkage: return 13;
+ case GlobalValue::LinkerPrivateWeakLinkage: return 14;
+ case GlobalValue::LinkOnceODRAutoHideLinkage: return 15;
+ }
+ llvm_unreachable("Invalid linkage");
+}
+
+static unsigned getEncodedVisibility(const GlobalValue *GV) {
+ switch (GV->getVisibility()) {
+ case GlobalValue::DefaultVisibility: return 0;
+ case GlobalValue::HiddenVisibility: return 1;
+ case GlobalValue::ProtectedVisibility: return 2;
+ }
+ llvm_unreachable("Invalid visibility");
+}
+
+/// \brief Function to convert constant initializers for global
+/// variables into corresponding bitcode. Takes advantage that these
+/// global variable initializations are normalized (see
+/// lib/Transforms/NaCl/FlattenGlobals.cpp).
+void WriteGlobalInit(const Constant *C, unsigned GlobalVarID,
+ SmallVectorImpl<uint32_t> &Vals,
+ const NaClValueEnumerator &VE,
+ NaClBitstreamWriter &Stream) {
+ if (ArrayType *Ty = dyn_cast<ArrayType>(C->getType())) {
+ if (!Ty->getElementType()->isIntegerTy(8))
+ report_fatal_error("Global array initializer not i8");
+ uint32_t Size = Ty->getNumElements();
+ if (isa<ConstantAggregateZero>(C)) {
+ Vals.push_back(Size);
+ Stream.EmitRecord(naclbitc::GLOBALVAR_ZEROFILL, Vals,
+ GLOBALVAR_ZEROFILL_ABBREV);
+ Vals.clear();
+ } else {
+ const ConstantDataSequential *CD = cast<ConstantDataSequential>(C);
+ StringRef Data = CD->getRawDataValues();
+ for (size_t i = 0; i < Size; ++i) {
+ Vals.push_back(Data[i] & 0xFF);
+ }
+ Stream.EmitRecord(naclbitc::GLOBALVAR_DATA, Vals,
+ GLOBALVAR_DATA_ABBREV);
+ Vals.clear();
+ }
+ return;
+ }
+ if (C->getType()->isIntegerTy(32)) {
+ // This constant defines a relocation. Start by verifying the
+ // relocation is of the right form.
+ const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
+ if (CE == 0)
+ report_fatal_error("Global i32 initializer not constant");
+ assert(CE);
+ int32_t Addend = 0;
+ if (CE->getOpcode() == Instruction::Add) {
+ const ConstantInt *AddendConst = dyn_cast<ConstantInt>(CE->getOperand(1));
+ if (AddendConst == 0)
+ report_fatal_error("Malformed addend in global relocation initializer");
+ Addend = AddendConst->getSExtValue();
+ CE = dyn_cast<ConstantExpr>(CE->getOperand(0));
+ if (CE == 0)
+ report_fatal_error(
+ "Base of global relocation initializer not constant");
+ }
+ if (CE->getOpcode() != Instruction::PtrToInt)
+ report_fatal_error("Global relocation base doesn't contain ptrtoint");
+ GlobalValue *GV = dyn_cast<GlobalValue>(CE->getOperand(0));
+ if (GV == 0)
+ report_fatal_error(
+ "Argument of ptrtoint in global relocation no global value");
+
+ // Now generate the corresponding relocation record.
+ unsigned RelocID = VE.getValueID(GV);
+ // This is a value index.
+ unsigned AbbrevToUse = GLOBALVAR_RELOC_ABBREV;
+ Vals.push_back(RelocID);
+ if (Addend) {
+ Vals.push_back(Addend);
+ AbbrevToUse = GLOBALVAR_RELOC_WITH_ADDEND_ABBREV;
+ }
+ Stream.EmitRecord(naclbitc::GLOBALVAR_RELOC, Vals, AbbrevToUse);
+ Vals.clear();
+ return;
+ }
+ report_fatal_error("Global initializer is not a SimpleElement");
+}
+
+// Emit global variables.
+static void WriteGlobalVars(const Module *M,
+ const NaClValueEnumerator &VE,
+ NaClBitstreamWriter &Stream) {
+ Stream.EnterSubblock(naclbitc::GLOBALVAR_BLOCK_ID);
+ SmallVector<uint32_t, 32> Vals;
+ unsigned GlobalVarID = VE.getFirstGlobalVarID();
+
+ // Emit the number of global variables.
+
+ Vals.push_back(M->getGlobalList().size());
+ Stream.EmitRecord(naclbitc::GLOBALVAR_COUNT, Vals);
+ Vals.clear();
+
+ // Now emit each global variable.
+ for (Module::const_global_iterator
+ GV = M->global_begin(), E = M->global_end();
+ GV != E; ++GV, ++GlobalVarID) {
+ // Define the global variable.
+ Vals.push_back(Log2_32(GV->getAlignment()) + 1);
+ Vals.push_back(GV->isConstant());
+ Stream.EmitRecord(naclbitc::GLOBALVAR_VAR, Vals, GLOBALVAR_VAR_ABBREV);
+ Vals.clear();
+
+ // Add the field(s).
+ const Constant *C = GV->getInitializer();
+ if (C == 0)
+ report_fatal_error("Global variable initializer not a constant");
+ if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) {
+ if (!CS->getType()->isPacked())
+ report_fatal_error("Global variable type not packed");
+ if (CS->getType()->hasName())
+ report_fatal_error("Global variable type is named");
+ Vals.push_back(CS->getNumOperands());
+ Stream.EmitRecord(naclbitc::GLOBALVAR_COMPOUND, Vals,
+ GLOBALVAR_COMPOUND_ABBREV);
+ Vals.clear();
+ for (unsigned I = 0; I < CS->getNumOperands(); ++I) {
+ WriteGlobalInit(dyn_cast<Constant>(CS->getOperand(I)), GlobalVarID,
+ Vals, VE, Stream);
+ }
+ } else {
+ WriteGlobalInit(C, GlobalVarID, Vals, VE, Stream);
+ }
+ }
+
+ assert(GlobalVarID == VE.getFirstGlobalVarID() + VE.getNumGlobalVarIDs());
+ Stream.ExitBlock();
+}
+
+// Emit top-level description of module, including inline asm,
+// descriptors for global variables, and function prototype info.
+static void WriteModuleInfo(const Module *M, const NaClValueEnumerator &VE,
+ NaClBitstreamWriter &Stream) {
+ DEBUG(dbgs() << "-> WriteModuleInfo\n");
+ // Emit various pieces of data attached to a module.
+ if (!M->getModuleInlineAsm().empty())
+ WriteStringRecord(naclbitc::MODULE_CODE_ASM, M->getModuleInlineAsm(),
+ 0/*TODO*/, Stream);
+
+ // Emit information about sections and GC, computing how many there are. Also
+ // compute the maximum alignment value.
+ // TODO(kschimpf): Remove code for SectionMap and GCMap.
+ std::map<std::string, unsigned> SectionMap;
+ std::map<std::string, unsigned> GCMap;
+ for (Module::const_global_iterator GV = M->global_begin(),E = M->global_end();
+ GV != E; ++GV) {
+ if (GV->hasSection()) {
+ // Give section names unique ID's.
+ unsigned &Entry = SectionMap[GV->getSection()];
+ if (!Entry) {
+ WriteStringRecord(naclbitc::MODULE_CODE_SECTIONNAME, GV->getSection(),
+ 0/*TODO*/, Stream);
+ Entry = SectionMap.size();
+ }
+ }
+ }
+ for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
+ if (F->hasSection()) {
+ // Give section names unique ID's.
+ unsigned &Entry = SectionMap[F->getSection()];
+ if (!Entry) {
+ WriteStringRecord(naclbitc::MODULE_CODE_SECTIONNAME, F->getSection(),
+ 0/*TODO*/, Stream);
+ Entry = SectionMap.size();
+ }
+ }
+ if (F->hasGC()) {
+ // Same for GC names.
+ unsigned &Entry = GCMap[F->getGC()];
+ if (!Entry) {
+ WriteStringRecord(naclbitc::MODULE_CODE_GCNAME, F->getGC(),
+ 0/*TODO*/, Stream);
+ Entry = GCMap.size();
+ }
+ }
+ }
+
+ // Emit the function proto information. Note: We do this before
+ // global variables, so that global variable initializations can
+ // refer to the functions without a forward reference.
+ SmallVector<unsigned, 64> Vals;
+ for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
+ // FUNCTION: [type, callingconv, isproto, linkage]
+ Vals.push_back(VE.getTypeID(F->getType()));
+ Vals.push_back(GetEncodedCallingConv(F->getCallingConv()));
+ Vals.push_back(F->isDeclaration());
+ Vals.push_back(getEncodedLinkage(F));
+
+ unsigned AbbrevToUse = 0;
+ Stream.EmitRecord(naclbitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
+ Vals.clear();
+ }
+
+ // Emit the global variable information.
+ WriteGlobalVars(M, VE, Stream);
+
+ // Emit the alias information.
+ for (Module::const_alias_iterator AI = M->alias_begin(), E = M->alias_end();
+ AI != E; ++AI) {
+ // ALIAS: [alias type, aliasee val#, linkage, visibility]
+ Vals.push_back(VE.getTypeID(AI->getType()));
+ Vals.push_back(VE.getValueID(AI->getAliasee()));
+ Vals.push_back(getEncodedLinkage(AI));
+ Vals.push_back(getEncodedVisibility(AI));
+ unsigned AbbrevToUse = 0;
+ Stream.EmitRecord(naclbitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
+ Vals.clear();
+ }
+ DEBUG(dbgs() << "<- WriteModuleInfo\n");
+}
+
+static uint64_t GetOptimizationFlags(const Value *V) {
+ uint64_t Flags = 0;
+
+ if (const OverflowingBinaryOperator *OBO =
+ dyn_cast<OverflowingBinaryOperator>(V)) {
+ if (OBO->hasNoSignedWrap())
+ Flags |= 1 << naclbitc::OBO_NO_SIGNED_WRAP;
+ if (OBO->hasNoUnsignedWrap())
+ Flags |= 1 << naclbitc::OBO_NO_UNSIGNED_WRAP;
+ } else if (const PossiblyExactOperator *PEO =
+ dyn_cast<PossiblyExactOperator>(V)) {
+ if (PEO->isExact())
+ Flags |= 1 << naclbitc::PEO_EXACT;
+ } else if (const FPMathOperator *FPMO =
+ dyn_cast<const FPMathOperator>(V)) {
+ if (FPMO->hasUnsafeAlgebra())
+ Flags |= 1 << naclbitc::FPO_UNSAFE_ALGEBRA;
+ if (FPMO->hasNoNaNs())
+ Flags |= 1 << naclbitc::FPO_NO_NANS;
+ if (FPMO->hasNoInfs())
+ Flags |= 1 << naclbitc::FPO_NO_INFS;
+ if (FPMO->hasNoSignedZeros())
+ Flags |= 1 << naclbitc::FPO_NO_SIGNED_ZEROS;
+ if (FPMO->hasAllowReciprocal())
+ Flags |= 1 << naclbitc::FPO_ALLOW_RECIPROCAL;
+ }
+
+ return Flags;
+}
+
+static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
+ Vals.push_back(NaClEncodeSignRotatedValue((int64_t)V));
+}
+
+static void EmitAPInt(SmallVectorImpl<uint64_t> &Vals,
+ unsigned &Code, unsigned &AbbrevToUse, const APInt &Val,
+ bool EmitSizeForWideNumbers = false
+ ) {
+ if (Val.getBitWidth() <= 64) {
+ uint64_t V = Val.getSExtValue();
+ emitSignedInt64(Vals, V);
+ Code = naclbitc::CST_CODE_INTEGER;
+ AbbrevToUse = CONSTANTS_INTEGER_ABBREV;
+ } else {
+ // Wide integers, > 64 bits in size.
+ // We have an arbitrary precision integer value to write whose
+ // bit width is > 64. However, in canonical unsigned integer
+ // format it is likely that the high bits are going to be zero.
+ // So, we only write the number of active words.
+ unsigned NWords = Val.getActiveWords();
+
+ if (EmitSizeForWideNumbers)
+ Vals.push_back(NWords);
+
+ const uint64_t *RawWords = Val.getRawData();
+ for (unsigned i = 0; i != NWords; ++i) {
+ emitSignedInt64(Vals, RawWords[i]);
+ }
+ Code = naclbitc::CST_CODE_WIDE_INTEGER;
+ }
+}
+
+static void WriteConstants(unsigned FirstVal, unsigned LastVal,
+ const NaClValueEnumerator &VE,
+ NaClBitstreamWriter &Stream, bool isGlobal) {
+ if (FirstVal == LastVal) return;
+
+ Stream.EnterSubblock(naclbitc::CONSTANTS_BLOCK_ID,
+ (isGlobal
+ ? CST_CONSTANTS_MAX_ABBREV
+ : CONSTANTS_MAX_ABBREV));
+
+ unsigned AggregateAbbrev = 0;
+ unsigned String8Abbrev = 0;
+ unsigned CString7Abbrev = 0;
+ unsigned CString6Abbrev = 0;
+ // If this is a constant pool for the module, emit module-specific abbrevs.
+ // Note: These abbreviations are size specific (to LastVal), and hence,
+ // can be more efficient if LastVal is known (rather then generating
+ // up-front for all constant sections).
+ if (isGlobal) {
+ // Abbrev for CST_CODE_AGGREGATE.
+ NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::CST_CODE_AGGREGATE));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed,
+ NaClBitsNeededForValue(LastVal)));
+ AggregateAbbrev = Stream.EmitAbbrev(Abbv);
+ if (CST_CONSTANTS_AGGREGATE_ABBREV != AggregateAbbrev)
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for CST_CODE_STRING.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::CST_CODE_STRING));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 8));
+ String8Abbrev = Stream.EmitAbbrev(Abbv);
+ if (CST_CONSTANTS_STRING_ABBREV != String8Abbrev)
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for CST_CODE_CSTRING.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::CST_CODE_CSTRING));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 7));
+ CString7Abbrev = Stream.EmitAbbrev(Abbv);
+ if (CST_CONSTANTS_CSTRING_7_ABBREV != CString7Abbrev)
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ // Abbrev for CST_CODE_CSTRING.
+ Abbv = new NaClBitCodeAbbrev();
+ Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::CST_CODE_CSTRING));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array));
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6));
+ CString6Abbrev = Stream.EmitAbbrev(Abbv);
+ if (CST_CONSTANTS_CSTRING_6_ABBREV != CString6Abbrev)
+ llvm_unreachable("Unexpected abbrev ordering!");
+
+ DEBUG(dbgs() << "-- emitted abbreviations\n");
+ }
+
+
+ SmallVector<uint64_t, 64> Record;
+
+ const NaClValueEnumerator::ValueList &Vals = VE.getValues();
+ Type *LastTy = 0;
+ for (unsigned i = FirstVal; i != LastVal; ++i) {
+ const Value *V = Vals[i].first;
+ // If we need to switch types, do so now.
+ if (V->getType() != LastTy) {
+ LastTy = V->getType();
+ Record.push_back(VE.getTypeID(LastTy));
+ Stream.EmitRecord(naclbitc::CST_CODE_SETTYPE, Record,
+ CONSTANTS_SETTYPE_ABBREV);
+ Record.clear();
+ }
+
+ if (const InlineAsm *IA = dyn_cast<InlineAsm>(V)) {
+ Record.push_back(unsigned(IA->hasSideEffects()) |
+ unsigned(IA->isAlignStack()) << 1 |
+ unsigned(IA->getDialect()&1) << 2);
+
+ // Add the asm string.
+ const std::string &AsmStr = IA->getAsmString();
+ Record.push_back(AsmStr.size());
+ for (unsigned i = 0, e = AsmStr.size(); i != e; ++i)
+ Record.push_back(AsmStr[i]);
+
+ // Add the constraint string.
+ const std::string &ConstraintStr = IA->getConstraintString();
+ Record.push_back(ConstraintStr.size());
+ for (unsigned i = 0, e = ConstraintStr.size(); i != e; ++i)
+ Record.push_back(ConstraintStr[i]);
+ Stream.EmitRecord(naclbitc::CST_CODE_INLINEASM, Record);
+ Record.clear();
+ continue;
+ }
+ const Constant *C = cast<Constant>(V);
+ unsigned Code = -1U;
+ unsigned AbbrevToUse = 0;
+ if (C->isNullValue()) {
+ Code = naclbitc::CST_CODE_NULL;
+ } else if (isa<UndefValue>(C)) {
+ Code = naclbitc::CST_CODE_UNDEF;
+ } else if (const ConstantInt *IV = dyn_cast<ConstantInt>(C)) {
+ EmitAPInt(Record, Code, AbbrevToUse, IV->getValue());
+ } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
+ Code = naclbitc::CST_CODE_FLOAT;
+ Type *Ty = CFP->getType();
+ if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy()) {
+ Record.push_back(CFP->getValueAPF().bitcastToAPInt().getZExtValue());
+ } else if (Ty->isX86_FP80Ty()) {
+ // api needed to prevent premature destruction
+ // bits are not in the same order as a normal i80 APInt, compensate.
+ APInt api = CFP->getValueAPF().bitcastToAPInt();
+ const uint64_t *p = api.getRawData();
+ Record.push_back((p[1] << 48) | (p[0] >> 16));
+ Record.push_back(p[0] & 0xffffLL);
+ } else if (Ty->isFP128Ty() || Ty->isPPC_FP128Ty()) {
+ APInt api = CFP->getValueAPF().bitcastToAPInt();
+ const uint64_t *p = api.getRawData();
+ Record.push_back(p[0]);
+ Record.push_back(p[1]);
+ } else {
+ assert (0 && "Unknown FP type!");
+ }
+ } else if (isa<ConstantDataSequential>(C) &&
+ cast<ConstantDataSequential>(C)->isString()) {
+ const ConstantDataSequential *Str = cast<ConstantDataSequential>(C);
+ // Emit constant strings specially.
+ unsigned NumElts = Str->getNumElements();
+ // If this is a null-terminated string, use the denser CSTRING encoding.
+ if (Str->isCString()) {
+ Code = naclbitc::CST_CODE_CSTRING;
+ --NumElts; // Don't encode the null, which isn't allowed by char6.
+ } else {
+ Code = naclbitc::CST_CODE_STRING;
+ AbbrevToUse = String8Abbrev;
+ }
+ bool isCStr7 = Code == naclbitc::CST_CODE_CSTRING;
+ bool isCStrChar6 = Code == naclbitc::CST_CODE_CSTRING;
+ for (unsigned i = 0; i != NumElts; ++i) {
+ unsigned char V = Str->getElementAsInteger(i);
+ Record.push_back(V);
+ isCStr7 &= (V & 128) == 0;
+ if (isCStrChar6)
+ isCStrChar6 = NaClBitCodeAbbrevOp::isChar6(V);
+ }
+
+ if (isCStrChar6)
+ AbbrevToUse = CString6Abbrev;
+ else if (isCStr7)
+ AbbrevToUse = CString7Abbrev;
+ } else if (const ConstantDataSequential *CDS =
+ dyn_cast<ConstantDataSequential>(C)) {
+ Code = naclbitc::CST_CODE_DATA;
+ Type *EltTy = CDS->getType()->getElementType();
+ if (isa<IntegerType>(EltTy)) {
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
+ Record.push_back(CDS->getElementAsInteger(i));
+ } else if (EltTy->isFloatTy()) {
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
+ union { float F; uint32_t I; };
+ F = CDS->getElementAsFloat(i);
+ Record.push_back(I);
+ }
+ } else {
+ assert(EltTy->isDoubleTy() && "Unknown ConstantData element type");
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
+ union { double F; uint64_t I; };
+ F = CDS->getElementAsDouble(i);
+ Record.push_back(I);
+ }
+ }
+ } else if (isa<ConstantArray>(C) || isa<ConstantStruct>(C) ||
+ isa<ConstantVector>(C)) {
+ Code = naclbitc::CST_CODE_AGGREGATE;
+ for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i)
+ Record.push_back(VE.getValueID(C->getOperand(i)));
+ AbbrevToUse = AggregateAbbrev;
+ } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
+ switch (CE->getOpcode()) {
+ default:
+ if (Instruction::isCast(CE->getOpcode())) {
+ Code = naclbitc::CST_CODE_CE_CAST;
+ Record.push_back(GetEncodedCastOpcode(CE->getOpcode()));
+ Record.push_back(VE.getTypeID(C->getOperand(0)->getType()));
+ Record.push_back(VE.getValueID(C->getOperand(0)));
+ AbbrevToUse = CONSTANTS_CE_CAST_Abbrev;
+ } else {
+ assert(CE->getNumOperands() == 2 && "Unknown constant expr!");
+ Code = naclbitc::CST_CODE_CE_BINOP;
+ Record.push_back(GetEncodedBinaryOpcode(CE->getOpcode()));
+ Record.push_back(VE.getValueID(C->getOperand(0)));
+ Record.push_back(VE.getValueID(C->getOperand(1)));
+ uint64_t Flags = GetOptimizationFlags(CE);
+ if (Flags != 0)
+ Record.push_back(Flags);
+ }
+ break;
+ case Instruction::GetElementPtr:
+ Code = naclbitc::CST_CODE_CE_GEP;
+ if (cast<GEPOperator>(C)->isInBounds())
+ Code = naclbitc::CST_CODE_CE_INBOUNDS_GEP;
+ for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) {
+ Record.push_back(VE.getTypeID(C->getOperand(i)->getType()));
+ Record.push_back(VE.getValueID(C->getOperand(i)));
+ }
+ break;
+ case Instruction::Select:
+ Code = naclbitc::CST_CODE_CE_SELECT;
+ Record.push_back(VE.getValueID(C->getOperand(0)));
+ Record.push_back(VE.getValueID(C->getOperand(1)));
+ Record.push_back(VE.getValueID(C->getOperand(2)));
+ break;
+ case Instruction::ExtractElement:
+ Code = naclbitc::CST_CODE_CE_EXTRACTELT;
+ Record.push_back(VE.getTypeID(C->getOperand(0)->getType()));
+ Record.push_back(VE.getValueID(C->getOperand(0)));
+ Record.push_back(VE.getValueID(C->getOperand(1)));
+ break;
+ case Instruction::InsertElement:
+ Code = naclbitc::CST_CODE_CE_INSERTELT;
+ Record.push_back(VE.getValueID(C->getOperand(0)));
+ Record.push_back(VE.getValueID(C->getOperand(1)));
+ Record.push_back(VE.getValueID(C->getOperand(2)));
+ break;
+ case Instruction::ShuffleVector:
+ // If the return type and argument types are the same, this is a
+ // standard shufflevector instruction. If the types are different,
+ // then the shuffle is widening or truncating the input vectors, and
+ // the argument type must also be encoded.
+ if (C->getType() == C->getOperand(0)->getType()) {
+ Code = naclbitc::CST_CODE_CE_SHUFFLEVEC;
+ } else {
+