diff options
author | Karl Schimpf <kschimpf@google.com> | 2013-07-02 14:36:36 -0700 |
---|---|---|
committer | Karl Schimpf <kschimpf@google.com> | 2013-07-02 14:36:36 -0700 |
commit | 4390b1a9ac86937b9f9886119b5fa0ffc77295eb (patch) | |
tree | 0ed3cbe3018c87f90bb55627066f6bdd5cfae9e0 /lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | |
parent | bdad02d55969b0963ac23e05578d28def5636ebd (diff) |
Simplify globals in PNaCl wire format based on normalized constants.
Generates simple global variable records, followed by list of records defining
byte initialization and relocations.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3504
R=mseaborn@chromium.org
Review URL: https://codereview.chromium.org/18111002
Diffstat (limited to 'lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp')
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | 257 |
1 files changed, 186 insertions, 71 deletions
diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp index be75af1e40..44aaeb3f0e 100644 --- a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp +++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp @@ -69,6 +69,15 @@ enum { 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, @@ -89,10 +98,6 @@ enum { TYPE_ARRAY_ABBREV, TYPE_MAX_ABBREV = TYPE_ARRAY_ABBREV, - // MODULE_BLOCK abbrev id's. - MODULE_GLOBALVAR_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV, - MODULE_MAX_ABBREV = MODULE_GLOBALVAR_ABBREV, - // SwitchInst Magic SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; @@ -409,15 +414,124 @@ static unsigned getEncodedVisibility(const GlobalValue *GV) { llvm_unreachable("Invalid visibility"); } -static unsigned getEncodedThreadLocalMode(const GlobalVariable *GV) { - switch (GV->getThreadLocalMode()) { - case GlobalVariable::NotThreadLocal: return 0; - case GlobalVariable::GeneralDynamicTLSModel: return 1; - case GlobalVariable::LocalDynamicTLSModel: return 2; - case GlobalVariable::InitialExecTLSModel: return 3; - case GlobalVariable::LocalExecTLSModel: return 4; +/// \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); + } } - llvm_unreachable("Invalid TLS model"); + + assert(GlobalVarID == VE.getFirstGlobalVarID() + VE.getNumGlobalVarIDs()); + Stream.ExitBlock(); } // Emit top-level description of module, including inline asm, @@ -472,65 +586,10 @@ static void WriteModuleInfo(const Module *M, const NaClValueEnumerator &VE, } } - // Emit abbrev for globals, now that we know # sections and max alignment. - // Add an abbrev for common globals with no visibility or thread localness. - // Don't bother emitting vis + thread local abbreviation. - { - NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); - Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::MODULE_CODE_GLOBALVAR)); - Abbv->Add(NaClBitCodeAbbrevOp( - NaClBitCodeAbbrevOp::Fixed, NaClBitsNeededForValue(MaxGlobalType))); - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // Constant. - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); // Initializer. - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 4)); // Linkage. - if (MaxAlignment == 0) // Alignment. - Abbv->Add(NaClBitCodeAbbrevOp(0)); - else { - unsigned MaxEncAlignment = Log2_32(MaxAlignment)+1; - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, - NaClBitsNeededForValue(MaxEncAlignment))); - } - if (SectionMap.empty()) // Section. - Abbv->Add(NaClBitCodeAbbrevOp(0)); - else - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, - NaClBitsNeededForValue(SectionMap.size()))); - if (MODULE_GLOBALVAR_ABBREV != Stream.EmitAbbrev(Abbv)) - llvm_unreachable("Unexpected abbrev ordering!"); - } - - // Emit the global variable information. + // 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_global_iterator GV = M->global_begin(),E = M->global_end(); - GV != E; ++GV) { - unsigned AbbrevToUse = 0; - - // GLOBALVAR: [type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal, - // unnamed_addr] - Vals.push_back(VE.getTypeID(GV->getType())); - Vals.push_back(GV->isConstant()); - Vals.push_back(GV->isDeclaration() ? 0 : - (VE.getValueID(GV->getInitializer()) + 1)); - Vals.push_back(getEncodedLinkage(GV)); - Vals.push_back(Log2_32(GV->getAlignment())+1); - Vals.push_back(GV->hasSection() ? SectionMap[GV->getSection()] : 0); - if (GV->isThreadLocal() || - GV->getVisibility() != GlobalValue::DefaultVisibility || - GV->hasUnnamedAddr() || GV->isExternallyInitialized()) { - Vals.push_back(getEncodedVisibility(GV)); - Vals.push_back(getEncodedThreadLocalMode(GV)); - Vals.push_back(GV->hasUnnamedAddr()); - Vals.push_back(GV->isExternallyInitialized()); - } else { - AbbrevToUse = MODULE_GLOBALVAR_ABBREV; - } - - Stream.EmitRecord(naclbitc::MODULE_CODE_GLOBALVAR, Vals, AbbrevToUse); - Vals.clear(); - } - - // Emit the function proto information. 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())); @@ -543,6 +602,9 @@ static void WriteModuleInfo(const Module *M, const NaClValueEnumerator &VE, 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) { @@ -1561,13 +1623,66 @@ static void WriteBlockInfo(const NaClValueEnumerator &VE, llvm_unreachable("Unexpected abbrev ordering!"); } + { // VAR abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_VAR)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_VAR_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // COMPOUND abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_COMPOUND)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_COMPOUND_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // ZEROFILL abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_ZEROFILL)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_ZEROFILL_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // DATA abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_DATA)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_DATA_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // RELOC abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_RELOC)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_RELOC_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // RELOC_WITH_ADDEND_ABBREV abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_RELOC)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev( + naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_RELOC_WITH_ADDEND_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + Stream.ExitBlock(); } /// WriteModule - Emit the specified module to the bitstream. static void WriteModule(const Module *M, NaClBitstreamWriter &Stream) { DEBUG(dbgs() << "-> WriteModule\n"); - Stream.EnterSubblock(naclbitc::MODULE_BLOCK_ID, MODULE_MAX_ABBREV); + Stream.EnterSubblock(naclbitc::MODULE_BLOCK_ID); SmallVector<unsigned, 1> Vals; unsigned CurVersion = 1; |