aboutsummaryrefslogtreecommitdiff
path: root/lib/Bitcode
diff options
context:
space:
mode:
authorKarl Schimpf <kschimpf@google.com>2013-07-02 14:36:36 -0700
committerKarl Schimpf <kschimpf@google.com>2013-07-02 14:36:36 -0700
commit4390b1a9ac86937b9f9886119b5fa0ffc77295eb (patch)
tree0ed3cbe3018c87f90bb55627066f6bdd5cfae9e0 /lib/Bitcode
parentbdad02d55969b0963ac23e05578d28def5636ebd (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')
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp291
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h24
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp257
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp22
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h13
5 files changed, 434 insertions, 173 deletions
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
index 9f36a73654..5f14a639ba 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
@@ -101,17 +101,6 @@ static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) {
}
}
-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;
@@ -236,6 +225,7 @@ struct OperandTraits<ConstantPlaceHolder> :
void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) {
+ assert(V);
if (Idx == size()) {
push_back(V);
return;
@@ -263,9 +253,35 @@ void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) {
}
}
+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) {
+ Type *Ty) {
if (Idx >= size())
resize(Idx + 1);
@@ -307,6 +323,26 @@ bool NaClBitcodeReaderValueList::createValueFwdRef(unsigned Idx, Type *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
@@ -635,6 +671,147 @@ bool NaClBitcodeReader::ParseTypeTableBody() {
}
}
+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))
@@ -691,29 +868,12 @@ bool NaClBitcodeReader::ParseValueSymbolTable() {
}
}
-/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global
-/// values and aliases that we can.
-bool NaClBitcodeReader::ResolveGlobalAndAliasInits() {
- std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist;
+/// ResolveAliasInits - Resolve all of the initializers for aliases that we can.
+bool NaClBitcodeReader::ResolveAliasInits() {
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
- GlobalInitWorklist.swap(GlobalInits);
AliasInitWorklist.swap(AliasInits);
- while (!GlobalInitWorklist.empty()) {
- unsigned ValID = GlobalInitWorklist.back().second;
- if (ValID >= ValueList.size()) {
- // Not ready to resolve this yet, it requires something later in the file.
- GlobalInits.push_back(GlobalInitWorklist.back());
- } else {
- if (Constant *C = dyn_cast<Constant>(ValueList[ValID]))
- GlobalInitWorklist.back().first->setInitializer(C);
- else
- return Error("Global variable initializer is not a constant!");
- }
- GlobalInitWorklist.pop_back();
- }
-
while (!AliasInitWorklist.empty()) {
unsigned ValID = AliasInitWorklist.back().second;
if (ValID >= ValueList.size()) {
@@ -1199,9 +1359,10 @@ bool NaClBitcodeReader::RememberAndSkipFunctionBody() {
bool NaClBitcodeReader::GlobalCleanup() {
// Patch the initializers for globals and aliases up.
- ResolveGlobalAndAliasInits();
- if (!GlobalInits.empty() || !AliasInits.empty())
- return Error("Malformed global initializer set");
+ ResolveAliasInits();
+
+ if (!AliasInits.empty())
+ return Error("Malformed Alias Initializer");
// Look for intrinsic functions which need to be upgraded at some point
for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
@@ -1216,9 +1377,6 @@ bool NaClBitcodeReader::GlobalCleanup() {
GI = TheModule->global_begin(), GE = TheModule->global_end();
GI != GE; ++GI)
UpgradeGlobalVariable(GI);
- // Force deallocation of memory for these vectors to favor the client that
- // want lazy deserialization.
- std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits);
return false;
}
@@ -1261,13 +1419,17 @@ bool NaClBitcodeReader::ParseModule(bool Resume) {
if (ParseTypeTable())
return true;
break;
+ case naclbitc::GLOBALVAR_BLOCK_ID:
+ if (ParseGlobalVars())
+ return true;
+ break;
case naclbitc::VALUE_SYMTAB_BLOCK_ID:
if (ParseValueSymbolTable())
return true;
SeenValueSymbolTable = true;
break;
case naclbitc::CONSTANTS_BLOCK_ID:
- if (ParseConstants() || ResolveGlobalAndAliasInits())
+ if (ParseConstants() || ResolveAliasInits())
return true;
break;
case naclbitc::FUNCTION_BLOCK_ID:
@@ -1359,57 +1521,8 @@ bool NaClBitcodeReader::ParseModule(bool Resume) {
// GLOBALVAR: [pointer type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal,
// unnamed_addr]
- case naclbitc::MODULE_CODE_GLOBALVAR: {
- if (Record.size() < 6)
- return Error("Invalid MODULE_CODE_GLOBALVAR record");
- Type *Ty = getTypeByID(Record[0]);
- if (!Ty) return Error("Invalid MODULE_CODE_GLOBALVAR record");
- if (!Ty->isPointerTy())
- return Error("Global not a pointer type!");
- unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace();
- Ty = cast<PointerType>(Ty)->getElementType();
-
- bool isConstant = Record[1];
- GlobalValue::LinkageTypes Linkage = GetDecodedLinkage(Record[3]);
- unsigned Alignment = (1 << Record[4]) >> 1;
- std::string Section;
- if (Record[5]) {
- if (Record[5]-1 >= SectionTable.size())
- return Error("Invalid section ID");
- Section = SectionTable[Record[5]-1];
- }
- GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
- if (Record.size() > 6)
- Visibility = GetDecodedVisibility(Record[6]);
-
- GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal;
- if (Record.size() > 7)
- TLM = GetDecodedThreadLocalMode(Record[7]);
-
- bool UnnamedAddr = false;
- if (Record.size() > 8)
- UnnamedAddr = Record[8];
-
- bool ExternallyInitialized = false;
- if (Record.size() > 9)
- ExternallyInitialized = Record[9];
-
- GlobalVariable *NewGV =
- new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0,
- TLM, AddressSpace, ExternallyInitialized);
- NewGV->setAlignment(Alignment);
- if (!Section.empty())
- NewGV->setSection(Section);
- NewGV->setVisibility(Visibility);
- NewGV->setUnnamedAddr(UnnamedAddr);
-
- ValueList.push_back(NewGV);
-
- // Remember which value to use for the global initializer.
- if (unsigned InitID = Record[2])
- GlobalInits.push_back(std::make_pair(NewGV, InitID-1));
- break;
- }
+ case naclbitc::MODULE_CODE_GLOBALVAR:
+ return Error("Invalid MODULE_CODE_GLOBALVAR record");
// FUNCTION: [type, callingconv, isproto, linkage]
case naclbitc::MODULE_CODE_FUNCTION: {
if (Record.size() < 4)
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
index 9320de92ea..454875796a 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
@@ -82,13 +82,32 @@ public:
// already been declared.
bool createValueFwdRef(unsigned Idx, Type *Ty);
+ // Declares the type of the forward-referenced constant Idx. Returns
+ // 0 if an error occurred.
+ // TODO(kschimpf) Convert these to be like createValueFwdRef and
+ // getValueFwdRef.
Constant *getConstantFwdRef(unsigned Idx, Type *Ty);
// Gets the forward reference value for Idx.
Value *getValueFwdRef(unsigned Idx);
+ // Gets the corresponding constant defining the address of the
+ // corresponding global variable defined by Idx, if already defined.
+ // Otherwise, creates a forward reference for Idx, and returns the
+ // placeholder constant for the address of the corresponding global
+ // variable defined by Idx.
+ Constant *getOrCreateGlobalVarRef(unsigned Idx, Module* M);
+
+ // Assigns Idx to the given value (if new), or assigns V to Idx (if Idx
+ // was forward referenced).
void AssignValue(Value *V, unsigned Idx);
+ // Assigns Idx to the given global variable. If the Idx currently has
+ // a forward reference (built by createGlobalVarFwdRef(unsigned Idx)),
+ // replaces uses of the global variable forward reference with the
+ // value GV.
+ void AssignGlobalVar(GlobalVariable *GV, unsigned Idx);
+
/// ResolveConstantForwardRefs - Once all constants are read, this method bulk
/// resolves any forward references.
void ResolveConstantForwardRefs();
@@ -114,7 +133,6 @@ class NaClBitcodeReader : public GVMaterializer {
SmallVector<Instruction *, 64> InstructionList;
SmallVector<SmallVector<uint64_t, 64>, 64> UseListRecords;
- std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
/// FunctionBBs - While parsing a function body, this is a list of the basic
@@ -259,13 +277,13 @@ private:
bool ParseModule(bool Resume);
bool ParseTypeTable();
bool ParseTypeTableBody();
-
+ bool ParseGlobalVars();
bool ParseValueSymbolTable();
bool ParseConstants();
bool RememberAndSkipFunctionBody();
bool ParseFunctionBody(Function *F);
bool GlobalCleanup();
- bool ResolveGlobalAndAliasInits();
+ bool ResolveAliasInits();
bool ParseUseLists();
bool InitStream();
bool InitStreamFromBuffer();
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;
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
index feb14cdb0c..393c5bc934 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
@@ -42,16 +42,21 @@ NaClValueEnumerator::NaClValueEnumerator(const Module *M) {
// constructor completes.
TypeCountMapType count_map;
TypeCountMap = &count_map;
- // Enumerate the global variables.
- for (Module::const_global_iterator I = M->global_begin(),
- E = M->global_end(); I != E; ++I)
- EnumerateValue(I);
- // Enumerate the functions.
+ // Enumerate the functions. Note: We do this before global
+ // variables, so that global variable initializations can refer to
+ // the functions without a forward reference.
for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) {
EnumerateValue(I);
}
+ // Enumerate the global variables.
+ FirstGlobalVarID = Values.size();
+ for (Module::const_global_iterator I = M->global_begin(),
+ E = M->global_end(); I != E; ++I)
+ EnumerateValue(I);
+ NumGlobalVarIDs = Values.size() - FirstGlobalVarID;
+
// Enumerate the aliases.
for (Module::const_alias_iterator I = M->alias_begin(), E = M->alias_end();
I != E; ++I)
@@ -60,11 +65,8 @@ NaClValueEnumerator::NaClValueEnumerator(const Module *M) {
// Remember what is the cutoff between globalvalue's and other constants.
unsigned FirstConstant = Values.size();
- // Enumerate the global variable initializers.
- for (Module::const_global_iterator I = M->global_begin(),
- E = M->global_end(); I != E; ++I)
- if (I->hasInitializer())
- EnumerateValue(I->getInitializer());
+ // Skip global variable initializers since they are handled within
+ // WriteGlobalVars of file NaClBitcodeWriter.cpp.
// Enumerate the aliasees.
for (Module::const_alias_iterator I = M->alias_begin(), E = M->alias_end();
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
index 90946551f5..e98a091ba8 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
@@ -79,6 +79,11 @@ private:
/// than necessary.
SmallSet<unsigned, 32> FnForwardTypeRefs;
+ // The index of the first global variable ID in the bitcode file.
+ unsigned FirstGlobalVarID;
+ // The number of global variable IDs defined in the bitcode file.
+ unsigned NumGlobalVarIDs;
+
NaClValueEnumerator(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION;
void operator=(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION;
public:
@@ -87,6 +92,14 @@ public:
void dump() const;
void print(raw_ostream &OS, const ValueMapType &Map, const char *Name) const;
+ unsigned getFirstGlobalVarID() const {
+ return FirstGlobalVarID;
+ }
+
+ unsigned getNumGlobalVarIDs() const {
+ return NumGlobalVarIDs;
+ }
+
unsigned getValueID(const Value *V) const;
unsigned getTypeID(Type *T) const {