Introduce model of global initializers in Subzero.

Modifies both LLVM to ICE converter, and Subzero's bitcode reader,
to build Subzero's global initializers. Modifies target lowering
routines for global initializers to use this new model.

Also modifies both to now handle relocations in global variable
initializers.

BUG=None
R=jvoung@chromium.org, stichnot@chromium.org

Review URL: https://codereview.chromium.org/624663002
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index f1dec0c..c434d50 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -24,18 +24,21 @@
   ClFlags()
       : DisableInternal(false), SubzeroTimingEnabled(false),
         DisableTranslation(false), DisableGlobals(false),
-        FunctionSections(false), UseIntegratedAssembler(false),
-        UseSandboxing(false), DumpStats(false), TimeEachFunction(false),
-        DefaultGlobalPrefix(""), DefaultFunctionPrefix(""), TimingFocusOn(""),
+        FunctionSections(false), DataSections(false),
+        UseIntegratedAssembler(false), UseSandboxing(false), DumpStats(false),
+        AllowUninitializedGlobals(false), TimeEachFunction(false),
+        DefaultGlobalPrefix(""), DefaultFunctionPrefix(""),TimingFocusOn(""),
         VerboseFocusOn("") {}
   bool DisableInternal;
   bool SubzeroTimingEnabled;
   bool DisableTranslation;
   bool DisableGlobals;
   bool FunctionSections;
+  bool DataSections;
   bool UseIntegratedAssembler;
   bool UseSandboxing;
   bool DumpStats;
+  bool AllowUninitializedGlobals;
   bool TimeEachFunction;
   IceString DefaultGlobalPrefix;
   IceString DefaultFunctionPrefix;
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index cdb0052..63ab7af 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -27,6 +27,7 @@
 #include "IceConverter.h"
 #include "IceDefs.h"
 #include "IceGlobalContext.h"
+#include "IceGlobalInits.h"
 #include "IceInst.h"
 #include "IceOperand.h"
 #include "IceTargetLowering.h"
@@ -45,17 +46,34 @@
   return Stream.str();
 }
 
-// Converter from LLVM to ICE. The entry point is the convertFunction method.
-//
-// Note: this currently assumes that the given IR was verified to be valid PNaCl
-// bitcode:
-// https://developers.google.com/native-client/dev/reference/pnacl-bitcode-abi
-// If not, all kinds of assertions may fire.
-//
+// Base class for converting LLVM to ICE.
 class LLVM2ICEConverter {
+  LLVM2ICEConverter(const LLVM2ICEConverter &) = delete;
+  LLVM2ICEConverter &operator=(const LLVM2ICEConverter &) = delete;
+
 public:
   LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
-      : Ctx(Ctx), Func(NULL), TypeConverter(LLVMContext) {}
+      : Ctx(Ctx), TypeConverter(LLVMContext) {}
+
+protected:
+  // Data
+  Ice::GlobalContext *Ctx;
+  const Ice::TypeConverter TypeConverter;
+};
+
+// Converter from LLVM functions to ICE. The entry point is the
+// convertFunction method.
+//
+// Note: this currently assumes that the given IR was verified to be
+// valid PNaCl bitcode. Otherwise, the behavior is undefined.
+class LLVM2ICEFunctionConverter : LLVM2ICEConverter {
+  LLVM2ICEFunctionConverter(const LLVM2ICEFunctionConverter &) = delete;
+  LLVM2ICEFunctionConverter &
+  operator=(const LLVM2ICEFunctionConverter &) = delete;
+
+public:
+  LLVM2ICEFunctionConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
+      : LLVM2ICEConverter(Ctx, LLVMContext), Func(NULL) {}
 
   // Caller is expected to delete the returned Ice::Cfg object.
   Ice::Cfg *convertFunction(const Function *F) {
@@ -91,17 +109,17 @@
   // Ice::Cfg pointer.  As such, it's suitable for e.g. constructing
   // global initializers.
   Ice::Constant *convertConstant(const Constant *Const) {
-    if (const GlobalValue *GV = dyn_cast<GlobalValue>(Const)) {
+    if (const auto GV = dyn_cast<GlobalValue>(Const)) {
       return Ctx->getConstantSym(convertToIceType(GV->getType()), 0,
                                  GV->getName());
-    } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(Const)) {
+    } else if (const auto CI = dyn_cast<ConstantInt>(Const)) {
       Ice::Type Ty = convertToIceType(CI->getType());
       if (Ty == Ice::IceType_i64) {
         return Ctx->getConstantInt64(Ty, CI->getSExtValue());
       } else {
         return Ctx->getConstantInt32(Ty, CI->getSExtValue());
       }
-    } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(Const)) {
+    } else if (const auto CFP = dyn_cast<ConstantFP>(Const)) {
       Ice::Type Type = convertToIceType(CFP->getType());
       if (Type == Ice::IceType_f32)
         return Ctx->getConstantFloat(CFP->getValueAPF().convertToFloat());
@@ -109,7 +127,7 @@
         return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble());
       llvm_unreachable("Unexpected floating point type");
       return NULL;
-    } else if (const UndefValue *CU = dyn_cast<UndefValue>(Const)) {
+    } else if (const auto CU = dyn_cast<UndefValue>(Const)) {
       return Ctx->getConstantUndef(convertToIceType(CU->getType()));
     } else {
       llvm_unreachable("Unhandled constant type");
@@ -144,8 +162,8 @@
   Ice::Type convertToIceType(Type *LLVMTy) const {
     Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy);
     if (IceTy == Ice::IceType_NUM)
-      llvm::report_fatal_error(std::string("Invalid PNaCl type ") +
-                               LLVMObjectAsString(LLVMTy));
+      report_fatal_error(std::string("Invalid PNaCl type ") +
+                         LLVMObjectAsString(LLVMTy));
     return IceTy;
   }
 
@@ -161,7 +179,7 @@
   }
 
   Ice::Operand *convertValue(const Value *Op) {
-    if (const Constant *Const = dyn_cast<Constant>(Op)) {
+    if (const auto Const = dyn_cast<Constant>(Op)) {
       return convertConstant(Const);
     } else {
       return mapValueToIceVar(Op);
@@ -291,7 +309,7 @@
 
   Ice::Inst *convertArithInstruction(const Instruction *Inst,
                                      Ice::InstArithmetic::OpKind Opcode) {
-    const BinaryOperator *BinOp = cast<BinaryOperator>(Inst);
+    const auto BinOp = cast<BinaryOperator>(Inst);
     Ice::Operand *Src0 = convertOperand(Inst, 0);
     Ice::Operand *Src1 = convertOperand(Inst, 1);
     Ice::Variable *Dest = mapValueToIceVar(BinOp);
@@ -509,8 +527,7 @@
     Ice::InstCall *NewInst = NULL;
     const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL;
 
-    if (Ice::ConstantRelocatable *Target =
-            llvm::dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
+    if (const auto Target = dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
       // Check if this direct call is to an Intrinsic (starts with "llvm.")
       static const char LLVMPrefix[] = "llvm.";
       const size_t LLVMPrefixLen = strlen(LLVMPrefix);
@@ -603,13 +620,179 @@
 
 private:
   // Data
-  Ice::GlobalContext *Ctx;
   Ice::Cfg *Func;
   std::map<const Value *, Ice::Variable *> VarMap;
   std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
-  Ice::TypeConverter TypeConverter;
 };
 
+// Converter from LLVM global variables to ICE. The entry point is the
+// convertGlobalsToIce method.
+//
+// Note: this currently assumes that the given IR was verified to be
+// valid PNaCl bitcode. Othewise, the behavior is undefined.
+class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter {
+  LLVM2ICEGlobalsConverter(const LLVM2ICEGlobalsConverter &) = delete;
+  LLVM2ICEGlobalsConverter &
+  operator-(const LLVM2ICEGlobalsConverter &) = delete;
+
+public:
+  LLVM2ICEGlobalsConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
+      : LLVM2ICEConverter(Ctx, LLVMContext) {}
+
+  ~LLVM2ICEGlobalsConverter() { DeleteContainerSeconds(GlobalVarAddressMap); }
+
+  /// Converts global variables, and their initializers into ICE global
+  /// addresses, for module Mod. Puts corresponding converted global
+  /// addresses into GlobalAddresses.
+  void convertGlobalsToIce(Module *Mod,
+                           Ice::Translator::GlobalAddressList &GlobalAddresses);
+
+private:
+  typedef std::map<const GlobalVariable *, Ice::GlobalAddress *>
+      GlobalVarAddressMapType;
+  // Map from global variables to their corresponding global address.
+  GlobalVarAddressMapType GlobalVarAddressMap;
+
+  // Adds the Initializer to the list of initializers for Global address.
+  void addGlobalInitializer(Ice::GlobalAddress &Global,
+                            const Constant *Initializer) {
+    const bool HasOffset = false;
+    const Ice::GlobalAddress::RelocOffsetType Offset = 0;
+    addGlobalInitializer(Global, Initializer, HasOffset, Offset);
+  }
+
+  // Adds Initializer to the list of initializers for Global
+  // address. HasOffset is true only if Initializer is a relocation
+  // initializer and Offset should be added to the relocation.
+  void addGlobalInitializer(Ice::GlobalAddress &Global,
+                            const Constant *Initializer, bool HasOffset,
+                            Ice::GlobalAddress::RelocOffsetType Offset);
+
+  // Returns the global address associated with global variable GV.
+  Ice::GlobalAddress *getGlobalVarAddress(const GlobalVariable *GV) {
+    if (GlobalVarAddressMap.find(GV) == GlobalVarAddressMap.end())
+      GlobalVarAddressMap[GV] = new Ice::GlobalAddress();
+    return GlobalVarAddressMap[GV];
+  }
+
+  // Converts the given constant C to the corresponding integer
+  // literal it contains.
+  Ice::GlobalAddress::RelocOffsetType
+  getIntegerLiteralConstant(const Value *C) {
+    const auto CI = dyn_cast<ConstantInt>(C);
+    if (CI && CI->getType()->isIntegerTy(32))
+      return CI->getSExtValue();
+
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << "Constant not i32 literal: " << *C;
+    report_fatal_error(StrBuf.str());
+    return 0;
+  }
+};
+
+void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
+    Module *Mod, Ice::Translator::GlobalAddressList &GlobalAddresses) {
+  for (Module::const_global_iterator I = Mod->global_begin(),
+                                     E = Mod->global_end();
+       I != E; ++I) {
+    if (!I->hasInitializer() && Ctx->getFlags().AllowUninitializedGlobals)
+      continue;
+
+    const auto GV = dyn_cast<GlobalVariable>(I);
+    assert(GV);
+    Ice::IceString Name = GV->getName();
+    if (!GV->hasInternalLinkage()) {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Can't define external global address: " << Name;
+      report_fatal_error(StrBuf.str());
+    }
+
+    Ice::GlobalAddress *Addr = getGlobalVarAddress(GV);
+    GlobalAddresses.push_back(Addr);
+    Addr->setAlignment(GV->getAlignment());
+    Addr->setIsConstant(GV->isConstant());
+    // Note: We allow external for cross tests.
+    Addr->setIsInternal(!GV->isExternallyInitialized());
+    Addr->setName(Name);
+
+    const Constant *Initializer = GV->getInitializer();
+    if (const auto CompoundInit = dyn_cast<ConstantStruct>(Initializer)) {
+      for (ConstantStruct::const_op_iterator I = CompoundInit->op_begin(),
+                                             E = CompoundInit->op_end();
+           I != E; ++I) {
+        if (const auto Init = dyn_cast<Constant>(I)) {
+          addGlobalInitializer(*Addr, Init);
+        }
+      }
+    } else {
+      addGlobalInitializer(*Addr, Initializer);
+    }
+  }
+}
+
+void LLVM2ICEGlobalsConverter::addGlobalInitializer(
+    Ice::GlobalAddress &Global, const Constant *Initializer, bool HasOffset,
+    Ice::GlobalAddress::RelocOffsetType Offset) {
+  assert(HasOffset || Offset == 0);
+
+  if (const auto CDA = dyn_cast<ConstantDataArray>(Initializer)) {
+    assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) &&
+           (cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8));
+    Global.addInitializer(new Ice::GlobalAddress::DataInitializer(
+        CDA->getRawDataValues().data(), CDA->getNumElements()));
+    return;
+  }
+
+  if (isa<ConstantAggregateZero>(Initializer)) {
+    if (const auto AT = dyn_cast<ArrayType>(Initializer->getType())) {
+      assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
+             (cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
+      Global.addInitializer(
+          new Ice::GlobalAddress::ZeroInitializer(AT->getNumElements()));
+    } else {
+      llvm_unreachable("Unhandled constant aggregate zero type");
+    }
+    return;
+  }
+
+  if (const auto Exp = dyn_cast<ConstantExpr>(Initializer)) {
+    switch (Exp->getOpcode()) {
+    case Instruction::Add:
+      assert(!HasOffset);
+      addGlobalInitializer(Global, Exp->getOperand(0), true,
+                           getIntegerLiteralConstant(Exp->getOperand(1)));
+      return;
+    case Instruction::PtrToInt: {
+      assert(TypeConverter.convertToIceType(Exp->getType()) ==
+             TypeConverter.getIcePointerType());
+      const auto GV = dyn_cast<GlobalValue>(Exp->getOperand(0));
+      assert(GV);
+      if (const auto Fcn = dyn_cast<Function>(GV)) {
+        Ice::GlobalAddress::RelocationAddress Addr(Fcn);
+        Global.addInitializer(
+            new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
+        return;
+      } else if (const auto Var = dyn_cast<GlobalVariable>(GV)) {
+        Ice::GlobalAddress::RelocationAddress Addr(getGlobalVarAddress(Var));
+        Global.addInitializer(
+            new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
+        return;
+      }
+      break;
+    }
+    default:
+      break;
+    }
+  }
+
+  std::string Buffer;
+  raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Unhandled global initializer: " << Initializer;
+  report_fatal_error(StrBuf.str());
+}
+
 } // end of anonymous namespace
 
 namespace Ice {
@@ -617,22 +800,31 @@
 void Converter::convertToIce() {
   TimerMarker T(TimerStack::TT_convertToIce, Ctx);
   nameUnnamedGlobalAddresses(Mod);
+  nameUnnamedFunctions(Mod);
   if (!Ctx->getFlags().DisableGlobals)
     convertGlobals(Mod);
   convertFunctions();
 }
 
+void Converter::convertGlobals(Module *Mod) {
+  LLVM2ICEGlobalsConverter GlobalsConverter(Ctx, Mod->getContext());
+  Translator::GlobalAddressList GlobalAddresses;
+  GlobalsConverter.convertGlobalsToIce(Mod, GlobalAddresses);
+  lowerGlobals(GlobalAddresses);
+}
+
 void Converter::convertFunctions() {
   TimerStackIdT StackID = GlobalContext::TSK_Funcs;
   for (const Function &I : *Mod) {
     if (I.empty())
       continue;
+
     TimerIdT TimerID = 0;
     if (Ctx->getFlags().TimeEachFunction) {
       TimerID = Ctx->getTimerID(StackID, I.getName());
       Ctx->pushTimer(TimerID, StackID);
     }
-    LLVM2ICEConverter FunctionConverter(Ctx, Mod->getContext());
+    LLVM2ICEFunctionConverter FunctionConverter(Ctx, Mod->getContext());
 
     Cfg *Fcn = FunctionConverter.convertFunction(&I);
     translateFcn(Fcn);
diff --git a/src/IceConverter.h b/src/IceConverter.h
index 049c036..763dcae 100644
--- a/src/IceConverter.h
+++ b/src/IceConverter.h
@@ -26,6 +26,7 @@
 public:
   Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags)
       : Translator(Ctx, Flags), Mod(Mod) {}
+
   /// Converts the LLVM Module to ICE. Sets exit status to false if successful,
   /// true otherwise.
   void convertToIce();
@@ -34,9 +35,14 @@
   llvm::Module *Mod;
   // Converts functions to ICE, and then machine code.
   void convertFunctions();
+
+  // Converts globals to ICE, and then machine code.
+  void convertGlobals(llvm::Module *Mod);
+
   Converter(const Converter &) = delete;
   Converter &operator=(const Converter &) = delete;
 };
-}
+
+} // end of namespace ICE.
 
 #endif // SUBZERO_SRC_ICECONVERTER_H
diff --git a/src/IceGlobalInits.cpp b/src/IceGlobalInits.cpp
new file mode 100644
index 0000000..4d9dadb
--- /dev/null
+++ b/src/IceGlobalInits.cpp
@@ -0,0 +1,139 @@
+//===- subzero/src/IceGlobalInits.cpp - Global initializers ---------------===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the notion of global addresses and
+// initializers in Subzero.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Value.h"
+
+#include "IceDefs.h"
+#include "IceGlobalInits.h"
+#include "IceTypes.h"
+
+namespace {
+char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
+}
+
+namespace Ice {
+
+GlobalAddress::~GlobalAddress() { llvm::DeleteContainerPointers(Initializers); }
+
+void GlobalAddress::dumpType(Ostream &Stream) const {
+  if (Initializers.size() == 1) {
+    Initializers.front()->dumpType(Stream);
+  } else {
+    Stream << "<{ ";
+    bool IsFirst = true;
+    for (Initializer *Init : Initializers) {
+      if (IsFirst) {
+        IsFirst = false;
+      } else {
+        Stream << ", ";
+      }
+      Init->dumpType(Stream);
+    }
+    Stream << " }>";
+  }
+}
+
+void GlobalAddress::dump(Ostream &Stream) const {
+  Stream << "@" << getName() << " = internal "
+         << (IsConstant ? "constant" : "global") << " ";
+
+  // Add initializer.
+  if (Initializers.size() == 1) {
+    Initializers.front()->dump(Stream);
+  } else {
+    dumpType(Stream);
+    Stream << " <{ ";
+    bool IsFirst = true;
+    for (Initializer *Init : Initializers) {
+      if (IsFirst) {
+        IsFirst = false;
+      } else {
+        Stream << ", ";
+      }
+      Init->dump(Stream);
+    }
+    Stream << " }>";
+  }
+
+  // Add alignment.
+  if (Alignment > 0)
+    Stream << ", align " << Alignment;
+  Stream << "\n";
+}
+
+void GlobalAddress::Initializer::dumpType(Ostream &Stream) const {
+  Stream << "[" << getNumBytes() << " x " << Ice::IceType_i8 << "]";
+}
+
+void GlobalAddress::DataInitializer::dump(Ostream &Stream) const {
+  dumpType(Stream);
+  Stream << " c\"";
+  // Code taken from PrintEscapedString() in AsmWriter.cpp.  Keep
+  // the strings in the same format as the .ll file for practical
+  // diffing.
+  for (uint8_t C : Contents) {
+    if (isprint(C) && C != '\\' && C != '"')
+      Stream << C;
+    else
+      Stream << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+  }
+  Stream << "\"";
+}
+
+void GlobalAddress::ZeroInitializer::dump(Ostream &Stream) const {
+  dumpType(Stream);
+  Stream << " zeroinitializer";
+}
+
+IceString GlobalAddress::RelocInitializer::getName() const {
+  switch (Address.getKind()) {
+  case FunctionRelocation:
+    return Address.getFunction()->getName();
+  case GlobalAddressRelocation:
+    return Address.getGlobalAddr()->getName();
+  default:
+    llvm::report_fatal_error("Malformed relocation address!");
+  }
+}
+
+void GlobalAddress::RelocInitializer::dumpType(Ostream &Stream) const {
+  Stream << Ice::IceType_i32;
+}
+
+void GlobalAddress::RelocInitializer::dump(Ostream &Stream) const {
+  if (Offset != 0) {
+    dumpType(Stream);
+    Stream << " add (";
+  }
+  dumpType(Stream);
+  Stream << " ptrtoint (";
+  if (Address.getKind() == FunctionRelocation) {
+    Stream << *Address.getFunction()->getType() << " @"
+           << Address.getFunction()->getName();
+  } else {
+    Address.getGlobalAddr()->dumpType(Stream);
+    Stream << "* @" << Address.getGlobalAddr()->getName();
+  }
+  Stream << " to ";
+  dumpType(Stream);
+  Stream << ")";
+  if (Offset != 0) {
+    Stream << ", ";
+    dumpType(Stream);
+    Stream << " " << Offset << ")";
+  }
+}
+}
diff --git a/src/IceGlobalInits.h b/src/IceGlobalInits.h
new file mode 100644
index 0000000..09e5574
--- /dev/null
+++ b/src/IceGlobalInits.h
@@ -0,0 +1,258 @@
+//===- subzero/src/IceGlobalInits.h - Global initializers -------*- C++ -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the representation of global addresses and
+// initializers in Subzero. Global initializers are represented as a
+// sequence of simple initializers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEGLOBALINITS_H
+#define SUBZERO_SRC_ICEGLOBALINITS_H
+
+#include "IceDefs.h"
+
+namespace llvm {
+// TODO(kschimpf): Remove this dependency on LLVM IR.
+class Value;
+}
+
+namespace Ice {
+
+/// Models a global address, and its initializers.
+class GlobalAddress {
+  GlobalAddress(const GlobalAddress &) = delete;
+  GlobalAddress &operator=(const GlobalAddress &) = delete;
+
+public:
+  /// Base class for a global variable initializer.
+  class Initializer {
+    Initializer(const Initializer &) = delete;
+    Initializer &operator=(const Initializer &) = delete;
+
+  public:
+    /// Discriminator for LLVM-style RTTI.
+    enum InitializerKind {
+      DataInitializerKind,
+      ZeroInitializerKind,
+      RelocInitializerKind
+    };
+    InitializerKind getKind() const { return Kind; }
+    virtual ~Initializer() {}
+    virtual SizeT getNumBytes() const = 0;
+    virtual void dump(Ostream &Stream) const = 0;
+    virtual void dumpType(Ostream &Stream) const;
+
+  protected:
+    explicit Initializer(InitializerKind Kind) : Kind(Kind) {}
+
+  private:
+    const InitializerKind Kind;
+  };
+
+  // Models the data in a data initializer.
+  typedef std::vector<uint8_t> DataVecType;
+
+  /// Defines a sequence of byte values as a data initializer.
+  class DataInitializer : public Initializer {
+    DataInitializer(const DataInitializer &) = delete;
+    DataInitializer &operator=(const DataInitializer &) = delete;
+
+  public:
+    template <class IntContainer>
+    DataInitializer(const IntContainer &Values)
+        : Initializer(DataInitializerKind), Contents(Values.size()) {
+      size_t i = 0;
+      for (auto &V : Values) {
+        Contents[i] = static_cast<uint8_t>(V);
+        ++i;
+      }
+    }
+    DataInitializer(const char *Str, size_t StrLen)
+        : Initializer(DataInitializerKind), Contents(StrLen) {
+      for (size_t i = 0; i < StrLen; ++i)
+        Contents[i] = static_cast<uint8_t>(Str[i]);
+    }
+    ~DataInitializer() override {}
+    const DataVecType &getContents() const { return Contents; }
+    SizeT getNumBytes() const override { return Contents.size(); }
+    void dump(Ostream &Stream) const override;
+    static bool classof(const Initializer *D) {
+      return D->getKind() == DataInitializerKind;
+    }
+
+  private:
+    // The byte contents of the data initializer.
+    DataVecType Contents;
+  };
+
+  /// Defines a sequence of bytes initialized to zero.
+  class ZeroInitializer : public Initializer {
+    ZeroInitializer(const ZeroInitializer &) = delete;
+    ZeroInitializer &operator=(const ZeroInitializer &) = delete;
+
+  public:
+    explicit ZeroInitializer(SizeT Size)
+        : Initializer(ZeroInitializerKind), Size(Size) {}
+    ~ZeroInitializer() override {}
+    SizeT getNumBytes() const override { return Size; }
+    void dump(Ostream &Stream) const override;
+    static bool classof(const Initializer *Z) {
+      return Z->getKind() == ZeroInitializerKind;
+    }
+
+  private:
+    // The number of bytes to be zero initialized.
+    SizeT Size;
+  };
+
+  /// Defines the kind of relocation addresses allowed.
+  enum RelocationKind { FunctionRelocation, GlobalAddressRelocation };
+
+  /// Defines a relocation address (i.e. reference to a function
+  /// or global variable address).
+  class RelocationAddress {
+    RelocationAddress &operator=(const RelocationAddress &) = delete;
+
+  public:
+    explicit RelocationAddress(const RelocationAddress &Addr)
+        : Kind(Addr.Kind) {
+      switch (Kind) {
+      case FunctionRelocation:
+        Address.Function = Addr.Address.Function;
+        break;
+      case GlobalAddressRelocation:
+        Address.GlobalAddr = Addr.Address.GlobalAddr;
+      }
+    }
+    explicit RelocationAddress(llvm::Value *Function)
+        : Kind(FunctionRelocation) {
+      Address.Function = Function;
+    }
+    explicit RelocationAddress(GlobalAddress *GlobalAddr)
+        : Kind(GlobalAddressRelocation) {
+      Address.GlobalAddr = GlobalAddr;
+    }
+    RelocationKind getKind() const { return Kind; }
+    llvm::Value *getFunction() const {
+      assert(Kind == FunctionRelocation);
+      return Address.Function;
+    }
+    GlobalAddress *getGlobalAddr() const {
+      assert(Kind == GlobalAddressRelocation);
+      return Address.GlobalAddr;
+    }
+  private:
+    const RelocationKind Kind;
+    union {
+      // TODO(kschimpf) Integrate Functions into ICE model.
+      llvm::Value *Function;
+      GlobalAddress *GlobalAddr;
+    } Address;
+  };
+
+  // Relocation address offsets must be 32 bit values.
+  typedef int32_t RelocOffsetType;
+  static const SizeT RelocAddrSize = 4;
+
+  /// Defines the relocation value of another address.
+  class RelocInitializer : public Initializer {
+    RelocInitializer(const RelocInitializer &) = delete;
+    RelocInitializer &operator=(const RelocInitializer &) = delete;
+
+  public:
+    RelocInitializer(const RelocationAddress &Address, RelocOffsetType Offset)
+        : Initializer(RelocInitializerKind), Address(Address), Offset(Offset) {}
+    ~RelocInitializer() override {}
+    RelocOffsetType getOffset() const { return Offset; }
+    IceString getName() const;
+    SizeT getNumBytes() const override { return RelocAddrSize; }
+    void dump(Ostream &Stream) const override;
+    virtual void dumpType(Ostream &Stream) const;
+    static bool classof(const Initializer *R) {
+      return R->getKind() == RelocInitializerKind;
+    }
+
+  private:
+    // The global address used in the relocation.
+    const RelocationAddress Address;
+    // The offset to add to the relocation.
+    const RelocOffsetType Offset;
+  };
+
+  /// Models the list of initializers.
+  typedef std::vector<Initializer *> InitializerListType;
+
+  GlobalAddress() : Alignment(0), IsConstant(false), IsInternal(true) {}
+  ~GlobalAddress();
+
+  const InitializerListType &getInitializers() const { return Initializers; }
+  bool hasName() const { return !Name.empty(); }
+  const IceString &getName() const { return Name; }
+  void setName(const IceString &NewName) { Name = NewName; }
+  bool getIsConstant() const { return IsConstant; }
+  void setIsConstant(bool NewValue) { IsConstant = NewValue; }
+  uint32_t getAlignment() const { return Alignment; }
+  void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; }
+  bool getIsInternal() const { return IsInternal; }
+  void setIsInternal(bool NewValue) { IsInternal = NewValue; }
+
+  /// Returns the number of bytes for the initializer of the global
+  /// address.
+  SizeT getNumBytes() const {
+    SizeT Count = 0;
+    for (Initializer *Init : Initializers) {
+      Count += Init->getNumBytes();
+    }
+    return Count;
+  }
+
+  /// Adds Initializer to the list of initializers. Takes ownership of
+  /// the initializer.
+  void addInitializer(Initializer *Initializer) {
+    Initializers.push_back(Initializer);
+  }
+
+  /// Prints out type for initializer associated with the global address
+  /// to Stream.
+  void dumpType(Ostream &Stream) const;
+
+  /// Prints out the definition of the global address (including
+  /// initialization).
+  void dump(Ostream &Stream) const;
+
+private:
+  // list of initializers associated with the global address.
+  InitializerListType Initializers;
+  // The name for the global.
+  IceString Name;
+  // The alignment of the initializer.
+  uint32_t Alignment;
+  // True if a constant initializer.
+  bool IsConstant;
+  // True if the address is internal.
+  bool IsInternal;
+};
+
+template <class StreamType>
+inline StreamType &operator<<(StreamType &Stream,
+                              const GlobalAddress::Initializer &Init) {
+  Init.dump(Stream);
+  return Stream;
+}
+
+template <class StreamType>
+inline StreamType &operator<<(StreamType &Stream, const GlobalAddress &Addr) {
+  Addr.dump(Stream);
+  return Stream;
+}
+
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEGLOBALINITS_H
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 82d0f59..f116cf3 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -27,6 +27,7 @@
 typedef uint8_t AsmCodeByte;
 
 class Assembler;
+class GlobalAddress;
 
 // LoweringContext makes it easy to iterate through non-deleted
 // instructions in a node, and insert new (lowered) instructions at
@@ -248,10 +249,7 @@
                                                   GlobalContext *Ctx);
   virtual ~TargetGlobalInitLowering();
 
-  // TODO: Allow relocations to be represented as part of the Data.
-  virtual void lower(const IceString &Name, SizeT Align, bool IsInternal,
-                     bool IsConst, bool IsZeroInitializer, SizeT Size,
-                     const char *Data, bool DisableTranslation) = 0;
+  virtual void lower(const GlobalAddress &Addr, bool DisableTranslation) = 0;
 
 protected:
   TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 9cac11d..e837710 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -23,6 +23,7 @@
 #include "IceCfgNode.h"
 #include "IceClFlags.h"
 #include "IceDefs.h"
+#include "IceGlobalInits.h"
 #include "IceInstX8632.h"
 #include "IceOperand.h"
 #include "IceRegistersX8632.h"
@@ -4428,38 +4429,10 @@
 TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx)
     : TargetGlobalInitLowering(Ctx) {}
 
-namespace {
-char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
-}
-
-void TargetGlobalInitX8632::lower(const IceString &Name, SizeT Align,
-                                  bool IsInternal, bool IsConst,
-                                  bool IsZeroInitializer, SizeT Size,
-                                  const char *Data, bool DisableTranslation) {
+void TargetGlobalInitX8632::lower(const GlobalAddress &Global,
+                                  bool DisableTranslation) {
   if (Ctx->isVerbose()) {
-    // TODO: Consider moving the dump output into the driver to be
-    // reused for all targets.
-    Ostream &Str = Ctx->getStrDump();
-    Str << "@" << Name << " = " << (IsInternal ? "internal" : "external");
-    Str << (IsConst ? " constant" : " global");
-    Str << " [" << Size << " x i8] ";
-    if (IsZeroInitializer) {
-      Str << "zeroinitializer";
-    } else {
-      Str << "c\"";
-      // Code taken from PrintEscapedString() in AsmWriter.cpp.  Keep
-      // the strings in the same format as the .ll file for practical
-      // diffing.
-      for (uint64_t i = 0; i < Size; ++i) {
-        unsigned char C = Data[i];
-        if (isprint(C) && C != '\\' && C != '"')
-          Str << C;
-        else
-          Str << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
-      }
-      Str << "\"";
-    }
-    Str << ", align " << Align << "\n";
+    Global.dump(Ctx->getStrDump());
   }
 
   if (DisableTranslation)
@@ -4489,35 +4462,86 @@
   //   .local NAME
   //   .comm NAME, SIZE, ALIGN
 
-  IceString MangledName = Ctx->mangleName(Name);
+  // TODO(kschimpf): Don't mangle name if external and uninitialized. This
+  // will allow us to cross test relocations for references to external
+  // global variables.
+
+  IceString MangledName = Ctx->mangleName(Global.getName());
   // Start a new section.
-  if (IsConst) {
+  if (Ctx->getFlags().DataSections) {
+    Str << "\t.section\t.rodata." << MangledName << ",\"a\",@progbits\n";
+  } else if (Global.getIsConstant()) {
     Str << "\t.section\t.rodata,\"a\",@progbits\n";
   } else {
     Str << "\t.type\t" << MangledName << ",@object\n";
     Str << "\t.data\n";
   }
-  Str << "\t" << (IsInternal ? ".local" : ".global") << "\t" << MangledName
-      << "\n";
-  if (IsZeroInitializer) {
-    if (IsConst) {
-      Str << "\t.align\t" << Align << "\n";
-      Str << MangledName << ":\n";
-      Str << "\t.zero\t" << Size << "\n";
-      Str << "\t.size\t" << MangledName << ", " << Size << "\n";
-    } else {
-      // TODO(stichnot): Put the appropriate non-constant
-      // zeroinitializers in a .bss section to reduce object size.
-      Str << "\t.comm\t" << MangledName << ", " << Size << ", " << Align
-          << "\n";
+
+  Str << "\t" << (Global.getIsInternal() ? ".local" : ".global") << "\t"
+      << MangledName << "\n";
+
+  const GlobalAddress::InitializerListType &Initializers =
+      Global.getInitializers();
+
+  // Note: Handle zero initializations specially when lowering, since
+  // we may be able to reduce object size.
+  GlobalAddress::ZeroInitializer *SimpleZeroInit = nullptr;
+  if (Initializers.size() == 1) {
+    GlobalAddress::Initializer *Init = Initializers[0];
+    if (const auto ZeroInit =
+        llvm::dyn_cast<GlobalAddress::ZeroInitializer>(Init)) {
+      SimpleZeroInit = ZeroInit;
     }
+  }
+
+  if (SimpleZeroInit && !Global.getIsConstant()) {
+    // TODO(stichnot): Put the appropriate non-constant
+    // zeroinitializers in a .bss section to reduce object size.
+    Str << "\t.comm\t" << MangledName << ", " << Global.getNumBytes() << ", "
+        << Global.getAlignment() << "\n";
+    // }
   } else {
-    Str << "\t.align\t" << Align << "\n";
+    Str << "\t.align\t" << Global.getAlignment() << "\n";
     Str << MangledName << ":\n";
-    for (SizeT i = 0; i < Size; ++i) {
-      Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
+    for (GlobalAddress::Initializer *Init : Initializers) {
+      switch (Init->getKind()) {
+      case GlobalAddress::Initializer::DataInitializerKind: {
+        const auto Data =
+            llvm::cast<GlobalAddress::DataInitializer>(Init)->getContents();
+        for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
+          Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
+        }
+        break;
+      }
+      case GlobalAddress::Initializer::ZeroInitializerKind:
+        Str << "\t.zero\t" << Init->getNumBytes() << "\n";
+        break;
+      case GlobalAddress::Initializer::RelocInitializerKind: {
+        const auto Reloc = llvm::cast<GlobalAddress::RelocInitializer>(Init);
+        Str << "\t.long\t";
+        // TODO(kschimpf): Once the representation of a relocation has
+        // been modified to reference the corresponding global
+        // address, modify to not mangle the name if the global is
+        // external and uninitialized. This will allow us to better
+        // test cross test relocations.
+        Str << Ctx->mangleName(Reloc->getName());
+        if (GlobalAddress::RelocOffsetType Offset = Reloc->getOffset()) {
+          Str << " + " << Offset;
+        }
+        Str << "\n";
+        break;
+      }
+      default: {
+        std::string Buffer;
+        llvm::raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Unable to lower initializer: ";
+        Init->dump(StrBuf);
+        llvm::report_fatal_error(StrBuf.str());
+        break;
+      }
+      }
     }
-    Str << "\t.size\t" << MangledName << ", " << Size << "\n";
+    Str << "\t.size\t" << MangledName << ", " << Global.getNumBytes() << "\n";
   }
 }
 
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index f6b305e..da79c85 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -486,9 +486,9 @@
   static TargetGlobalInitLowering *create(GlobalContext *Ctx) {
     return new TargetGlobalInitX8632(Ctx);
   }
-  void lower(const IceString &Name, SizeT Align, bool IsInternal, bool IsConst,
-             bool IsZeroInitializer, SizeT Size, const char *Data,
-             bool DisableTranslation) override;
+
+  virtual void lower(const GlobalAddress &Addr,
+                     bool DisableTranslation) override;
 
 protected:
   TargetGlobalInitX8632(GlobalContext *Ctx);
diff --git a/src/IceTranslator.cpp b/src/IceTranslator.cpp
index d11e76d..e86d60a 100644
--- a/src/IceTranslator.cpp
+++ b/src/IceTranslator.cpp
@@ -29,44 +29,61 @@
 
 Translator::~Translator() {}
 
-namespace {
-void setValueName(llvm::Value *V, const char *Kind, const IceString &Prefix,
-                  uint32_t &NameIndex, Ostream &errs) {
-  if (V->hasName()) {
-    const std::string &Name(V->getName());
-    if (Name.find(Prefix) == 0) {
-      errs << "Warning: Default " << Kind << " prefix '" << Prefix
-           << "' conflicts with name '" << Name << "'.\n";
-    }
-    return;
-  }
-  if (NameIndex == 0) {
-    V->setName(Prefix);
-    ++NameIndex;
-    return;
-  }
+IceString Translator::createUnnamedName(const IceString &Prefix, SizeT Index) {
+  if (Index == 0)
+    return Prefix;
   std::string Buffer;
   llvm::raw_string_ostream StrBuf(Buffer);
-  StrBuf << Prefix << NameIndex;
-  V->setName(StrBuf.str());
-  ++NameIndex;
+  StrBuf << Prefix << Index;
+  return StrBuf.str();
 }
-} // end of anonymous namespace
+
+bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
+                                        const IceString &Prefix,
+                                        Ostream &Stream) {
+  if (Name.find(Prefix) == 0) {
+    for (size_t i = Prefix.size(); i < Name.size(); ++i) {
+      if (!isdigit(Name[i])) {
+        return false;
+      }
+    }
+    Stream << "Warning : Default " << Kind << " prefix '" << Prefix
+           << "' potentially conflicts with name '" << Name << "'.\n";
+    return true;
+  }
+  return false;
+}
 
 void Translator::nameUnnamedGlobalAddresses(llvm::Module *Mod) {
   const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix;
+  if (GlobalPrefix.empty())
+    return;
+  uint32_t NameIndex = 0;
   Ostream &errs = Ctx->getStrDump();
-  if (!GlobalPrefix.empty()) {
-    uint32_t NameIndex = 0;
-    for (auto I = Mod->global_begin(), E = Mod->global_end(); I != E; ++I)
-      setValueName(I, "global", GlobalPrefix, NameIndex, errs);
+  for (auto V = Mod->global_begin(), E = Mod->global_end(); V != E; ++V) {
+    if (!V->hasName()) {
+      V->setName(createUnnamedName(GlobalPrefix, NameIndex));
+      ++NameIndex;
+    } else {
+      checkIfUnnamedNameSafe(V->getName(), "global", GlobalPrefix, errs);
+    }
   }
+}
+
+void Translator::nameUnnamedFunctions(llvm::Module *Mod) {
   const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix;
   if (FunctionPrefix.empty())
     return;
   uint32_t NameIndex = 0;
-  for (llvm::Function &I : *Mod)
-    setValueName(&I, "function", FunctionPrefix, NameIndex, errs);
+  Ostream &errs = Ctx->getStrDump();
+  for (llvm::Function &F : *Mod) {
+    if (!F.hasName()) {
+      F.setName(createUnnamedName(FunctionPrefix, NameIndex));
+      ++NameIndex;
+    } else {
+      checkIfUnnamedNameSafe(F.getName(), "function", FunctionPrefix, errs);
+    }
+  }
 }
 
 void Translator::translateFcn(Cfg *Fcn) {
@@ -93,46 +110,12 @@
     Func->getTarget()->emitConstants();
 }
 
-void Translator::convertGlobals(llvm::Module *Mod) {
-  std::unique_ptr<TargetGlobalInitLowering> GlobalLowering(
-      TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
-  for (auto I = Mod->global_begin(), E = Mod->global_end(); I != E; ++I) {
-    if (!I->hasInitializer())
-      continue;
-    const llvm::Constant *Initializer = I->getInitializer();
-    IceString Name = I->getName();
-    unsigned Align = I->getAlignment();
-    uint64_t NumElements = 0;
-    const char *Data = NULL;
-    bool IsInternal = I->hasInternalLinkage();
-    bool IsConst = I->isConstant();
-    bool IsZeroInitializer = false;
-
-    if (const llvm::ConstantDataArray *CDA =
-            llvm::dyn_cast<llvm::ConstantDataArray>(Initializer)) {
-      NumElements = CDA->getNumElements();
-      assert(llvm::isa<llvm::IntegerType>(CDA->getElementType()) &&
-             (llvm::cast<llvm::IntegerType>(CDA->getElementType())
-                  ->getBitWidth() == 8));
-      Data = CDA->getRawDataValues().data();
-    } else if (llvm::isa<llvm::ConstantAggregateZero>(Initializer)) {
-      if (const llvm::ArrayType *AT =
-              llvm::dyn_cast<llvm::ArrayType>(Initializer->getType())) {
-        assert(llvm::isa<llvm::IntegerType>(AT->getElementType()) &&
-               (llvm::cast<llvm::IntegerType>(AT->getElementType())
-                    ->getBitWidth() == 8));
-        NumElements = AT->getNumElements();
-        IsZeroInitializer = true;
-      } else {
-        llvm_unreachable("Unhandled constant aggregate zero type");
-      }
-    } else {
-      llvm_unreachable("Unhandled global initializer");
-    }
-
-    GlobalLowering->lower(Name, Align, IsInternal, IsConst, IsZeroInitializer,
-                          NumElements, Data,
-                          Ctx->getFlags().DisableTranslation);
+void Translator::lowerGlobals(const GlobalAddressList &GlobalAddresses) {
+  llvm::OwningPtr<Ice::TargetGlobalInitLowering> GlobalLowering(
+      Ice::TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
+  bool DisableTranslation = Ctx->getFlags().DisableTranslation;
+  for (const Ice::GlobalAddress *Addr : GlobalAddresses) {
+    GlobalLowering->lower(*Addr, DisableTranslation);
   }
   GlobalLowering.reset();
 }
diff --git a/src/IceTranslator.h b/src/IceTranslator.h
index b621ffc..8aeda94 100644
--- a/src/IceTranslator.h
+++ b/src/IceTranslator.h
@@ -25,6 +25,7 @@
 
 class ClFlags;
 class Cfg;
+class GlobalAddress;
 class GlobalContext;
 
 // Base class for translating ICE to machine code.
@@ -33,6 +34,8 @@
 // machine instructions.
 class Translator {
 public:
+  typedef std::vector<Ice::GlobalAddress *> GlobalAddressList;
+
   Translator(GlobalContext *Ctx, const ClFlags &Flags)
       : Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
 
@@ -51,15 +54,26 @@
   /// Emits the constant pool.
   void emitConstants();
 
-  // Walks module and generates names for unnamed globals and
-  // functions using prefix getFlags().DefaultGlobalPrefix, if the
-  // prefix is non-empty.
+  /// Lowers the given list of global addresses to target.
+  void lowerGlobals(const GlobalAddressList &GlobalAddresses);
+
+  /// Creates a name using the given prefix and corresponding index.
+  std::string createUnnamedName(const IceString &Prefix, SizeT Index);
+
+  /// Reports if there is a (potential) conflict between Name, and using
+  /// Prefix to name unnamed names. Errors are put on Ostream.
+  /// Returns true if there isn't a potential conflict.
+  bool checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
+                              const IceString &Prefix, Ostream &Stream);
+
+  // Walks module and generates names for unnamed globals using prefix
+  // getFlags().DefaultGlobalPrefix, if the prefix is non-empty.
   void nameUnnamedGlobalAddresses(llvm::Module *Mod);
 
-  // Converts globals to ICE, and then machine code.
-  // TODO(kschimpf) Remove this once we have ported to PNaClTranslator,
-  // and PNaClTranslator generates initializers while parsing.
-  void convertGlobals(llvm::Module *Mod);
+  // Walks module and generates names for unnamed functions using
+  // prefix getFlags().DefaultFunctionPrefix, if the prefix is
+  // non-empty.
+  void nameUnnamedFunctions(llvm::Module *Mod);
 
 protected:
   GlobalContext *Ctx;
diff --git a/src/IceTypeConverter.cpp b/src/IceTypeConverter.cpp
index 6e8138f..23e8329 100644
--- a/src/IceTypeConverter.cpp
+++ b/src/IceTypeConverter.cpp
@@ -19,25 +19,25 @@
 namespace Ice {
 
 TypeConverter::TypeConverter(llvm::LLVMContext &Context) {
-  AddLLVMType(IceType_void, llvm::Type::getVoidTy(Context));
-  AddLLVMType(IceType_i1, llvm::IntegerType::get(Context, 1));
-  AddLLVMType(IceType_i8, llvm::IntegerType::get(Context, 8));
-  AddLLVMType(IceType_i16, llvm::IntegerType::get(Context, 16));
-  AddLLVMType(IceType_i32, llvm::IntegerType::get(Context, 32));
-  AddLLVMType(IceType_i64, llvm::IntegerType::get(Context, 64));
-  AddLLVMType(IceType_f32, llvm::Type::getFloatTy(Context));
-  AddLLVMType(IceType_f64, llvm::Type::getDoubleTy(Context));
-  AddLLVMType(IceType_v4i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 4));
-  AddLLVMType(IceType_v8i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 8));
-  AddLLVMType(IceType_v16i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 16));
-  AddLLVMType(IceType_v16i8, llvm::VectorType::get(LLVMTypes[IceType_i8], 16));
-  AddLLVMType(IceType_v8i16, llvm::VectorType::get(LLVMTypes[IceType_i16], 8));
-  AddLLVMType(IceType_v4i32, llvm::VectorType::get(LLVMTypes[IceType_i32], 4));
-  AddLLVMType(IceType_v4f32, llvm::VectorType::get(LLVMTypes[IceType_f32], 4));
+  addLLVMType(IceType_void, llvm::Type::getVoidTy(Context));
+  addLLVMType(IceType_i1, llvm::IntegerType::get(Context, 1));
+  addLLVMType(IceType_i8, llvm::IntegerType::get(Context, 8));
+  addLLVMType(IceType_i16, llvm::IntegerType::get(Context, 16));
+  addLLVMType(IceType_i32, llvm::IntegerType::get(Context, 32));
+  addLLVMType(IceType_i64, llvm::IntegerType::get(Context, 64));
+  addLLVMType(IceType_f32, llvm::Type::getFloatTy(Context));
+  addLLVMType(IceType_f64, llvm::Type::getDoubleTy(Context));
+  addLLVMType(IceType_v4i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 4));
+  addLLVMType(IceType_v8i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 8));
+  addLLVMType(IceType_v16i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 16));
+  addLLVMType(IceType_v16i8, llvm::VectorType::get(LLVMTypes[IceType_i8], 16));
+  addLLVMType(IceType_v8i16, llvm::VectorType::get(LLVMTypes[IceType_i16], 8));
+  addLLVMType(IceType_v4i32, llvm::VectorType::get(LLVMTypes[IceType_i32], 4));
+  addLLVMType(IceType_v4f32, llvm::VectorType::get(LLVMTypes[IceType_f32], 4));
   assert(LLVMTypes.size() == static_cast<size_t>(IceType_NUM));
 }
 
-void TypeConverter::AddLLVMType(Type Ty, llvm::Type *LLVMTy) {
+void TypeConverter::addLLVMType(Type Ty, llvm::Type *LLVMTy) {
   assert(static_cast<size_t>(Ty) == LLVMTypes.size());
   LLVMTypes.push_back(LLVMTy);
   LLVM2IceMap[LLVMTy] = Ty;
diff --git a/src/IceTypeConverter.h b/src/IceTypeConverter.h
index 59709ce..a1dffeb 100644
--- a/src/IceTypeConverter.h
+++ b/src/IceTypeConverter.h
@@ -68,7 +68,7 @@
   std::map<llvm::Type *, Type> LLVM2IceMap;
 
   // Add LLVM/ICE pair to internal tables.
-  void AddLLVMType(Type Ty, llvm::Type *LLVMTy);
+  void addLLVMType(Type Ty, llvm::Type *LLVMTy);
 
   // Converts types not in LLVM2IceMap.
   Type convertToIceTypeOther(llvm::Type *LLVMTy) const;
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index f05835a..76368d9 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -12,10 +12,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <cassert>
-#include <memory>
-#include <vector>
-
 #include "llvm/Analysis/NaCl/PNaClABIProps.h"
 #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
@@ -34,6 +30,7 @@
 #include "IceCfgNode.h"
 #include "IceClFlags.h"
 #include "IceDefs.h"
+#include "IceGlobalInits.h"
 #include "IceInst.h"
 #include "IceOperand.h"
 #include "IceTypeConverter.h"
@@ -62,13 +59,12 @@
         Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
         Header(Header), TypeConverter(getLLVMContext()),
         ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
-        NumFunctionBlocks(0),
-        GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
+        NumFunctionBlocks(0) {
     Mod->setDataLayout(PNaClDataLayout);
     setErrStream(Translator.getContext()->getStrDump());
   }
 
-  ~TopLevelParser() override {}
+  ~TopLevelParser() override { DeleteContainerPointers(GlobalIDAddresses); }
 
   Ice::Translator &getTranslator() { return Translator; }
 
@@ -103,8 +99,8 @@
   /// Returns the type associated with the given index.
   Type *getTypeByID(unsigned ID) {
     // Note: method resizeTypeIDValues expands TypeIDValues
-    // to the specified size, and fills elements with NULL.
-    Type *Ty = ID < TypeIDValues.size() ? TypeIDValues[ID] : NULL;
+    // to the specified size, and fills elements with nullptr.
+    Type *Ty = ID < TypeIDValues.size() ? TypeIDValues[ID] : nullptr;
     if (Ty)
       return Ty;
     return reportTypeIDAsUndefined(ID);
@@ -112,7 +108,7 @@
 
   /// Defines type for ID.
   void setTypeID(unsigned ID, Type *Ty) {
-    if (ID < TypeIDValues.size() && TypeIDValues[ID] == NULL) {
+    if (ID < TypeIDValues.size() && TypeIDValues[ID] == nullptr) {
       TypeIDValues[ID] = Ty;
       return;
     }
@@ -122,13 +118,13 @@
   /// Sets the next function ID to the given LLVM function.
   void setNextFunctionID(Function *Fcn) {
     ++NumFunctionIds;
-    ValueIDValues.push_back(Fcn);
+    FunctionIDValues.push_back(Fcn);
   }
 
   /// Defines the next function ID as one that has an implementation
   /// (i.e a corresponding function block in the bitcode).
   void setNextValueIDAsImplementedFunction() {
-    DefiningFunctionsList.push_back(ValueIDValues.size());
+    DefiningFunctionsList.push_back(FunctionIDValues.size());
   }
 
   /// Returns the value id that should be associated with the the
@@ -142,28 +138,48 @@
   }
 
   /// Returns the LLVM IR value associatd with the global value ID.
-  Value *getGlobalValueByID(unsigned ID) const {
-    if (ID >= ValueIDValues.size())
-      return NULL;
-    return ValueIDValues[ID];
+  Function *getFunctionByID(unsigned ID) const {
+    if (ID >= FunctionIDValues.size())
+      return nullptr;
+    Value *V = FunctionIDValues[ID];
+    return cast<Function>(V);
   }
 
   /// Returns the corresponding constant associated with a global value
   /// (i.e. relocatable).
   Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) {
     // TODO(kschimpf): Can this be built when creating global initializers?
+    Ice::Constant *C;
     if (ID >= ValueIDConstants.size()) {
-      if (ID >= ValueIDValues.size())
-        return NULL;
-      ValueIDConstants.resize(ValueIDValues.size());
+      C = nullptr;
+      unsigned ExpectedSize =
+          FunctionIDValues.size() + GlobalIDAddresses.size();
+      if (ID >= ExpectedSize)
+        ExpectedSize = ID;
+      ValueIDConstants.resize(ExpectedSize);
+    } else {
+      C = ValueIDConstants[ID];
     }
-    Ice::Constant *C = ValueIDConstants[ID];
-    if (C != NULL)
+    if (C != nullptr)
       return C;
-    Value *V = ValueIDValues[ID];
-    assert(isa<GlobalValue>(V));
-    C = getTranslator().getContext()->getConstantSym(getIcePointerType(), 0,
-                                                     V->getName());
+
+    // If reached, no such constant exists, create one.
+    std::string Name;
+    unsigned FcnIDSize = FunctionIDValues.size();
+    if (ID < FcnIDSize) {
+      Name = FunctionIDValues[ID]->getName();
+    } else if ((ID - FcnIDSize) < GlobalIDAddresses.size()) {
+      Name = GlobalIDAddresses[ID - FcnIDSize]->getName();
+    } else {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Reference to global not defined: " << ID;
+      Error(StrBuf.str());
+      Name = "??";
+    }
+    const uint64_t Offset = 0;
+    C = getTranslator().getContext()->getConstantSym(
+        getIcePointerType(), Offset, Name);
     ValueIDConstants[ID] = C;
     return C;
   }
@@ -172,51 +188,43 @@
   /// the bitcode file.
   unsigned getNumFunctionIDs() const { return NumFunctionIds; }
 
-  /// Returns the number of global values defined in the bitcode
-  /// file.
-  unsigned getNumGlobalValueIDs() const { return ValueIDValues.size(); }
-
-  /// Resizes the list of value IDs to include Count global variable
-  /// IDs.
-  void resizeValueIDsForGlobalVarCount(unsigned Count) {
-    ValueIDValues.resize(ValueIDValues.size() + Count);
+  /// Returns the number of global IDs (function and global addresses)
+  /// defined in the bitcode file.
+  unsigned getNumGlobalIDs() const {
+    return FunctionIDValues.size() + GlobalIDAddresses.size();
   }
 
-  /// Returns the global variable address associated with the given
-  /// value ID. If the ID refers to a global variable address not yet
-  /// defined, a placeholder is created so that we can fix it up
-  /// later.
-  Constant *getOrCreateGlobalVarRef(unsigned ID) {
-    if (ID >= ValueIDValues.size())
-      return NULL;
-    if (Value *C = ValueIDValues[ID])
-      return dyn_cast<Constant>(C);
-    Constant *C = new GlobalVariable(*Mod, GlobalVarPlaceHolderType, false,
-                                     GlobalValue::ExternalLinkage, 0);
-    ValueIDValues[ID] = C;
-    return C;
-  }
-
-  /// Assigns the given global variable (address) to the given value
-  /// ID.  Returns true if ID is a valid global variable ID. Otherwise
-  /// returns false.
-  bool assignGlobalVariable(GlobalVariable *GV, unsigned ID) {
-    if (ID < NumFunctionIds || ID >= ValueIDValues.size())
-      return false;
-    WeakVH &OldV = ValueIDValues[ID];
-    if (OldV == NULL) {
-      ValueIDValues[ID] = GV;
-      return true;
+  /// Creates Count global addresses.
+  void CreateGlobalAddresses(size_t Count) {
+    assert(GlobalIDAddresses.empty());
+    for (size_t i = 0; i < Count; ++i) {
+      GlobalIDAddresses.push_back(new Ice::GlobalAddress());
     }
+  }
 
-    // If reached, 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();
-    ValueIDValues[ID] = GV;
-    return true;
+  /// Returns the number of global addresses (i.e. ID's) defined in
+  /// the bitcode file.
+  Ice::SizeT getNumGlobalAddresses() const { return GlobalIDAddresses.size(); }
+
+  /// Returns the global address with the given index.
+  Ice::GlobalAddress *getGlobalAddress(size_t Index) {
+    if (Index < GlobalIDAddresses.size())
+      return GlobalIDAddresses[Index];
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << "Global index " << Index
+           << " not allowed. Out of range. Must be less than "
+           << GlobalIDAddresses.size();
+    Error(StrBuf.str());
+    // TODO(kschimpf) Remove error recovery once implementation complete.
+    if (!GlobalIDAddresses.empty())
+      return GlobalIDAddresses[0];
+    report_fatal_error("Unable to continue");
+  }
+
+  /// Returns the list of read global addresses.
+  const Ice::Translator::GlobalAddressList &getGlobalIDAddresses() {
+    return GlobalIDAddresses;
   }
 
   /// Returns the corresponding ICE type for LLVMTy.
@@ -234,13 +242,13 @@
   }
 
   /// Returns the LLVM integer type with the given number of Bits.  If
-  /// Bits is not a valid PNaCl type, returns NULL.
+  /// Bits is not a valid PNaCl type, returns nullptr.
   Type *getLLVMIntegerType(unsigned Bits) const {
     return TypeConverter.getLLVMIntegerType(Bits);
   }
 
   /// Returns the LLVM vector with the given Size and Ty. If not a
-  /// valid PNaCl vector type, returns NULL.
+  /// valid PNaCl vector type, returns nullptr.
   Type *getLLVMVectorType(unsigned Size, Ice::Type Ty) const {
     return TypeConverter.getLLVMVectorType(Size, Ty);
   }
@@ -267,9 +275,12 @@
   unsigned NumErrors;
   // The types associated with each type ID.
   std::vector<Type *> TypeIDValues;
-  // The (global) value IDs.
-  std::vector<WeakVH> ValueIDValues;
-  // Relocatable constants associated with ValueIDValues.
+  // The set of function value IDs.
+  std::vector<WeakVH> FunctionIDValues;
+  // The set of global addresses IDs.
+  Ice::Translator::GlobalAddressList GlobalIDAddresses;
+  // Relocatable constants associated with FunctionIDValues and
+  // GlobalIDAddresses.
   std::vector<Ice::Constant *> ValueIDConstants;
   // The number of function IDs.
   unsigned NumFunctionIds;
@@ -278,9 +289,6 @@
   // The list of value IDs (in the order found) of defining function
   // addresses.
   std::vector<unsigned> DefiningFunctionsList;
-  // Cached global variable placeholder type. Used for all forward
-  // references to global variable addresses.
-  Type *GlobalVarPlaceHolderType;
 
   bool ParseBlock(unsigned BlockID) override;
 
@@ -380,7 +388,7 @@
     const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
     if (Values.size() == Size)
       return true;
-    ReportRecordSizeError(Size, RecordName, NULL);
+    ReportRecordSizeError(Size, RecordName, nullptr);
     return false;
   }
 
@@ -418,7 +426,7 @@
 private:
   /// Generates a record size error. ExpectedSize is the number
   /// of elements expected. RecordName is the name of the kind of
-  /// record that has incorrect size. ContextMessage (if not NULL)
+  /// record that has incorrect size. ContextMessage (if not nullptr)
   /// is appended to "record expects" to describe how ExpectedSize
   /// should be interpreted.
   void ReportRecordSizeError(unsigned ExpectedSize, const char *RecordName,
@@ -477,7 +485,7 @@
 };
 
 void TypesParser::ProcessRecord() {
-  Type *Ty = NULL;
+  Type *Ty = nullptr;
   const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
   switch (Record.GetCode()) {
   case naclbitc::TYPE_CODE_NUMENTRY:
@@ -509,7 +517,7 @@
     if (!isValidRecordSize(1, "Type integer"))
       return;
     Ty = Context->getLLVMIntegerType(Values[0]);
-    if (Ty == NULL) {
+    if (Ty == nullptr) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Type integer record with invalid bitsize: " << Values[0];
@@ -526,7 +534,7 @@
     Type *BaseTy = Context->getTypeByID(Values[1]);
     Ty = Context->getLLVMVectorType(Values[0],
                                     Context->convertToIceType(BaseTy));
-    if (Ty == NULL) {
+    if (Ty == nullptr) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Invalid type vector record: <" << Values[0] << " x " << *BaseTy
@@ -552,7 +560,7 @@
     return;
   }
   // If Ty not defined, assume error. Use void as filler.
-  if (Ty == NULL)
+  if (Ty == nullptr)
     Ty = Context->convertToLLVMType(Ice::IceType_void);
   Context->setTypeID(NextTypeId++, Ty);
 }
@@ -562,38 +570,33 @@
 public:
   GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
       : BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0),
-        Alignment(1), IsConstant(false) {
-    NextGlobalID = Context->getNumFunctionIDs();
-  }
+        NextGlobalID(0), CurrentAddress(&DummyAddress) {}
 
   ~GlobalsParser() override {}
 
 private:
-  // Holds the sequence of initializers for the global.
-  SmallVector<Constant *, 10> Initializers;
-
-  // Keeps track of how many initializers are expected for
-  // the global variable being built.
+  // Keeps track of how many initializers are expected for the global variable
+  // being built.
   unsigned InitializersNeeded;
 
-  // The alignment assumed for the global variable being built.
-  unsigned Alignment;
-
-  // True if the global variable being built is a constant.
-  bool IsConstant;
-
   // The index of the next global variable.
   unsigned NextGlobalID;
 
+  // Holds the current global address whose initializer is being defined.
+  Ice::GlobalAddress *CurrentAddress;
+
+  // Dummy global address to guarantee CurrentAddress is always defined
+  // (allowing code to not need to check if CurrentAddress is nullptr).
+  Ice::GlobalAddress DummyAddress;
+
   void ExitBlock() override {
     verifyNoMissingInitializers();
-    unsigned NumIDs = Context->getNumGlobalValueIDs();
+    unsigned NumIDs = Context->getNumGlobalAddresses();
     if (NextGlobalID < NumIDs) {
-      unsigned NumFcnIDs = Context->getNumFunctionIDs();
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Globals block expects " << (NumIDs - NumFcnIDs)
-             << " global definitions. Found: " << (NextGlobalID - NumFcnIDs);
+      StrBuf << "Globals block expects " << NumIDs
+             << " global definitions. Found: " << NextGlobalID;
       Error(StrBuf.str());
     }
     BlockParserBaseClass::ExitBlock();
@@ -601,70 +604,22 @@
 
   void ProcessRecord() override;
 
-  // Checks if the number of initializers needed is the same as the
-  // number found in the bitcode file. If different, and error message
-  // is generated, and the internal state of the parser is fixed so
-  // this condition is no longer violated.
+  // Checks if the number of initializers for the CurrentAddress is the same as
+  // the number found in the bitcode file. If different, and error message is
+  // generated, and the internal state of the parser is fixed so this condition
+  // is no longer violated.
   void verifyNoMissingInitializers() {
-    if (InitializersNeeded != Initializers.size()) {
+    size_t NumInits = CurrentAddress->getInitializers().size();
+    if (InitializersNeeded != NumInits) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Global variable @g"
-             << (NextGlobalID - Context->getNumFunctionIDs()) << " expected "
+      StrBuf << "Global variable @g" << NextGlobalID << " expected "
              << InitializersNeeded << " initializer";
       if (InitializersNeeded > 1)
         StrBuf << "s";
-      StrBuf << ". Found: " << Initializers.size();
-      Error(StrBuf.str());
-      // TODO(kschimpf) Remove error recovery once implementation complete.
-      // Fix up state so that we can continue.
-      InitializersNeeded = Initializers.size();
-      installGlobalVar();
-    }
-  }
-
-  // Reserves a slot in the list of initializers being built. If there
-  // isn't room for the slot, an error message is generated.
-  void reserveInitializer(const char *RecordName) {
-    if (InitializersNeeded <= Initializers.size()) {
-      Error(std::string(RecordName) +
-            " record: Too many initializers, ignoring.");
-    }
-  }
-
-  // Takes the initializers (and other parser state values) and
-  // installs a global variable (with the initializers) into the list
-  // of ValueIDs.
-  void installGlobalVar() {
-    Constant *Init = NULL;
-    switch (Initializers.size()) {
-    case 0:
-      Error("No initializer for global variable in global vars block");
-      return;
-    case 1:
-      Init = Initializers[0];
-      break;
-    default:
-      Init = ConstantStruct::getAnon(Context->getLLVMContext(), Initializers,
-                                     true);
-      break;
-    }
-    GlobalVariable *GV =
-        new GlobalVariable(*Context->getModule(), Init->getType(), IsConstant,
-                           GlobalValue::InternalLinkage, Init, "");
-    GV->setAlignment(Alignment);
-    if (!Context->assignGlobalVariable(GV, NextGlobalID)) {
-      std::string Buffer;
-      raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Defining global V[" << NextGlobalID
-             << "] not allowed. Out of range.";
+      StrBuf << ". Found: " << NumInits;
       Error(StrBuf.str());
     }
-    ++NextGlobalID;
-    Initializers.clear();
-    InitializersNeeded = 0;
-    Alignment = 1;
-    IsConstant = false;
   }
 };
 
@@ -675,12 +630,11 @@
     // COUNT: [n]
     if (!isValidRecordSize(1, "Globals count"))
       return;
-    if (NextGlobalID != Context->getNumFunctionIDs()) {
+    if (NextGlobalID != Context->getNumGlobalAddresses()) {
       Error("Globals count record not first in block.");
       return;
     }
-    verifyNoMissingInitializers();
-    Context->resizeValueIDsForGlobalVarCount(Values[0]);
+    Context->CreateGlobalAddresses(Values[0]);
     return;
   case naclbitc::GLOBALVAR_VAR: {
     // VAR: [align, isconst]
@@ -688,16 +642,17 @@
       return;
     verifyNoMissingInitializers();
     InitializersNeeded = 1;
-    Initializers.clear();
-    Alignment = (1 << Values[0]) >> 1;
-    IsConstant = Values[1] != 0;
+    CurrentAddress = Context->getGlobalAddress(NextGlobalID);
+    CurrentAddress->setAlignment((1 << Values[0]) >> 1);
+    CurrentAddress->setIsConstant(Values[1] != 0);
+    ++NextGlobalID;
     return;
   }
   case naclbitc::GLOBALVAR_COMPOUND:
     // COMPOUND: [size]
     if (!isValidRecordSize(1, "globals compound"))
       return;
-    if (Initializers.size() > 0 || InitializersNeeded != 1) {
+    if (!CurrentAddress->getInitializers().empty()) {
       Error("Globals compound record not first initializer");
       return;
     }
@@ -714,55 +669,44 @@
     // ZEROFILL: [size]
     if (!isValidRecordSize(1, "Globals zerofill"))
       return;
-    reserveInitializer("Globals zerofill");
-    Type *Ty =
-        ArrayType::get(Context->convertToLLVMType(Ice::IceType_i8), Values[0]);
-    Constant *Zero = ConstantAggregateZero::get(Ty);
-    Initializers.push_back(Zero);
+    CurrentAddress->addInitializer(
+        new Ice::GlobalAddress::ZeroInitializer(Values[0]));
     break;
   }
   case naclbitc::GLOBALVAR_DATA: {
     // DATA: [b0, b1, ...]
     if (!isValidRecordSizeAtLeast(1, "Globals data"))
       return;
-    reserveInitializer("Globals data");
-    unsigned Size = Values.size();
-    SmallVector<uint8_t, 32> Buf;
-    for (unsigned i = 0; i < Size; ++i)
-      Buf.push_back(static_cast<uint8_t>(Values[i]));
-    Constant *Init = ConstantDataArray::get(
-        Context->getLLVMContext(), ArrayRef<uint8_t>(Buf.data(), Buf.size()));
-    Initializers.push_back(Init);
+    CurrentAddress->addInitializer(
+        new Ice::GlobalAddress::DataInitializer(Values));
     break;
   }
   case naclbitc::GLOBALVAR_RELOC: {
     // RELOC: [val, [addend]]
     if (!isValidRecordSizeInRange(1, 2, "Globals reloc"))
       return;
-    Constant *BaseVal = Context->getOrCreateGlobalVarRef(Values[0]);
-    if (BaseVal == NULL) {
-      std::string Buffer;
-      raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Can't find global relocation value: " << Values[0];
-      Error(StrBuf.str());
-      return;
+    unsigned Index = Values[0];
+    Ice::SizeT Offset = 0;
+    if (Values.size() == 2)
+      Offset = Values[1];
+    unsigned NumFunctions = Context->getNumFunctionIDs();
+    if (Index < NumFunctions) {
+      llvm::Function *Fcn = Context->getFunctionByID(Index);
+      Ice::GlobalAddress::RelocationAddress Addr(Fcn);
+      CurrentAddress->addInitializer(
+          new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
+    } else {
+      Ice::GlobalAddress::RelocationAddress Addr(
+          Context->getGlobalAddress(Index - NumFunctions));
+      CurrentAddress->addInitializer(
+          new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
     }
-    Type *IntPtrType = Context->convertToLLVMType(Context->getIcePointerType());
-    Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType);
-    if (Values.size() == 2) {
-      Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, Values[1]));
-    }
-    Initializers.push_back(Val);
     break;
   }
   default:
     BlockParserBaseClass::ProcessRecord();
     return;
   }
-  // If reached, just processed another initializer. See if time
-  // to install global.
-  if (InitializersNeeded == Initializers.size())
-    installGlobalVar();
 }
 
 /// Base class for parsing a valuesymtab block in the bitcode file.
@@ -838,9 +782,9 @@
       : BlockParserBaseClass(BlockID, EnclosingParser),
         Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
         FcnId(Context->getNextFunctionBlockValueID()),
-        LLVMFunc(cast<Function>(Context->getGlobalValueByID(FcnId))),
-        CachedNumGlobalValueIDs(Context->getNumGlobalValueIDs()),
-        NextLocalInstIndex(Context->getNumGlobalValueIDs()),
+        LLVMFunc(Context->getFunctionByID(FcnId)),
+        CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
+        NextLocalInstIndex(Context->getNumGlobalIDs()),
         InstIsTerminating(false) {
     Func->setFunctionName(LLVMFunc->getName());
     if (getFlags().TimeEachFunction)
@@ -961,7 +905,7 @@
     uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs;
     if (LocalIndex < LocalOperands.size()) {
       Ice::Operand *Op = LocalOperands[LocalIndex];
-      if (Op != NULL) {
+      if (Op != nullptr) {
         if (Ice::Variable *Var = dyn_cast<Ice::Variable>(Op)) {
           if (Var->getType() == Ty) {
             ++NextLocalInstIndex;
@@ -1012,7 +956,7 @@
       report_fatal_error("Unable to continue");
     }
     Ice::Operand *Op = LocalOperands[LocalIndex];
-    if (Op == NULL) {
+    if (Op == nullptr) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Value index " << Index << " not defined!";
@@ -1038,7 +982,7 @@
 
     // If element not defined, set it.
     Ice::Operand *OldOp = LocalOperands[LocalIndex];
-    if (OldOp == NULL) {
+    if (OldOp == nullptr) {
       LocalOperands[LocalIndex] = Op;
       return;
     }
@@ -1688,7 +1632,7 @@
     if (Values.size() == 1) {
       // BR: [bb#]
       Ice::CfgNode *Block = getBranchBasicBlock(Values[0]);
-      if (Block == NULL)
+      if (Block == nullptr)
         return;
       CurrentNode->appendInst(Ice::InstBr::create(Func, Block));
     } else {
@@ -1706,7 +1650,7 @@
       }
       Ice::CfgNode *ThenBlock = getBranchBasicBlock(Values[0]);
       Ice::CfgNode *ElseBlock = getBranchBasicBlock(Values[1]);
-      if (ThenBlock == NULL || ElseBlock == NULL)
+      if (ThenBlock == nullptr || ElseBlock == nullptr)
         return;
       CurrentNode->appendInst(
           Ice::InstBr::create(Func, Cond, ThenBlock, ElseBlock));
@@ -1907,11 +1851,10 @@
     uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex);
     Ice::Operand *Callee = getOperand(CalleeIndex);
     Ice::Type ReturnType = Ice::IceType_void;
-    const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = NULL;
+    const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
     if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
-      Function *Fcn =
-          dyn_cast<Function>(Context->getGlobalValueByID(CalleeIndex));
-      if (Fcn == NULL) {
+      Function *Fcn = Context->getFunctionByID(CalleeIndex);
+      if (Fcn == nullptr) {
         std::string Buffer;
         raw_string_ostream StrBuf(Buffer);
         StrBuf << "Function call to non-function: " << *Callee;
@@ -1942,10 +1885,11 @@
     }
 
     // Create the call instruction.
-    Ice::Variable *Dest =
-        (ReturnType == Ice::IceType_void) ? NULL : getNextInstVar(ReturnType);
+    Ice::Variable *Dest = (ReturnType == Ice::IceType_void)
+                              ? nullptr
+                              : getNextInstVar(ReturnType);
     Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
-    Ice::InstCall *Inst = NULL;
+    Ice::InstCall *Inst = nullptr;
     if (IntrinsicInfo) {
       Inst =
           Ice::InstIntrinsicCall::create(Func, NumParams, Dest, Callee,
@@ -2225,15 +2169,29 @@
   // and generated global constant initializers.
   bool GlobalAddressNamesAndInitializersInstalled;
 
-  // Temporary hack to generate names for unnamed global addresses,
-  // and generate global constant initializers. May be called multiple
+  // Generates names for unnamed global addresses, and lowers global
+  // constant initializers to the target. May be called multiple
   // times. Only the first call will do the installation.
-  // NOTE: Doesn't handle relocations for global constant initializers.
   void InstallGlobalAddressNamesAndInitializers() {
     if (!GlobalAddressNamesAndInitializersInstalled) {
-      getTranslator().nameUnnamedGlobalAddresses(Context->getModule());
+      Ice::Translator &Trans = getTranslator();
+      const Ice::IceString &GlobalPrefix = getFlags().DefaultGlobalPrefix;
+      if (!GlobalPrefix.empty()) {
+        uint32_t NameIndex = 0;
+        for (Ice::GlobalAddress *Address : Context->getGlobalIDAddresses()) {
+          if (!Address->hasName()) {
+            Address->setName(Trans.createUnnamedName(GlobalPrefix, NameIndex));
+            ++NameIndex;
+          } else {
+            Trans.checkIfUnnamedNameSafe(Address->getName(), "global",
+                                         GlobalPrefix,
+                                         Trans.getContext()->getStrDump());
+          }
+        }
+      }
+      Trans.nameUnnamedFunctions(Context->getModule());
       if (!getFlags().DisableGlobals)
-        getTranslator().convertGlobals(Context->getModule());
+        getTranslator().lowerGlobals(Context->getGlobalIDAddresses());
       GlobalAddressNamesAndInitializersInstalled = true;
     }
   }
@@ -2264,15 +2222,26 @@
 };
 
 void ModuleValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
-  Value *V = Context->getGlobalValueByID(Index);
-  if (V == NULL) {
-    std::string Buffer;
-    raw_string_ostream StrBuf(Buffer);
-    StrBuf << "Invalid global address ID in valuesymtab: " << Index;
-    Error(StrBuf.str());
+  if (Index < Context->getNumFunctionIDs()) {
+    Function *Fcn = Context->getFunctionByID(Index);
+    if (Fcn != nullptr) {
+      Fcn->setName(StringRef(Name.data(), Name.size()));
+      return;
+    }
+  } else {
+    unsigned NumFunctions = Context->getNumFunctionIDs();
+    if (Index >= NumFunctions) {
+      Context->getGlobalAddress(Index - NumFunctions)
+          ->setName(StringRef(Name.data(), Name.size()));
+    }
     return;
   }
-  V->setName(StringRef(Name.data(), Name.size()));
+
+  std::string Buffer;
+  raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Invalid global address ID in valuesymtab: " << Index;
+  Error(StrBuf.str());
+  return;
 }
 
 void ModuleValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
@@ -2331,7 +2300,7 @@
       return;
     Type *Ty = Context->getTypeByID(Values[0]);
     FunctionType *FTy = dyn_cast<FunctionType>(Ty);
-    if (FTy == NULL) {
+    if (FTy == nullptr) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Function heading expects function type. Found: " << Ty;
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index f392b7e..637eb16 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -65,6 +65,9 @@
 static cl::opt<bool>
     FunctionSections("ffunction-sections",
                      cl::desc("Emit functions into separate sections"));
+static cl::opt<bool>
+    DataSections("fdata-sections",
+                 cl::desc("Emit (global) data into separate sections"));
 static cl::opt<Ice::OptLevel>
 OptLevel(cl::desc("Optimization level"), cl::init(Ice::Opt_m1),
          cl::value_desc("level"),
@@ -121,6 +124,11 @@
 DumpStats("stats",
           cl::desc("Print statistics after translating each function"));
 
+// This is currently needed by crosstest.py.
+static cl::opt<bool> AllowUninitializedGlobals(
+    "allow-uninitialized-globals",
+    cl::desc("Allow global variables to be uninitialized"));
+
 static cl::opt<NaClFileFormat> InputFileFormat(
     "bitcode-format", cl::desc("Define format of input file:"),
     cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
@@ -149,9 +157,20 @@
     UseIntegratedAssembler("integrated-as",
                            cl::desc("Use integrated assembler (default yes)"),
                            cl::init(true));
+
 static cl::alias UseIas("ias", cl::desc("Alias for -integrated-as"),
                         cl::NotHidden, cl::aliasopt(UseIntegratedAssembler));
 
+static cl::opt<bool> AlwaysExitSuccess(
+    "exit-success", cl::desc("Exit with success status, even if errors found"),
+    cl::init(false));
+
+static int GetReturnValue(int Val) {
+  if (AlwaysExitSuccess)
+    return 0;
+  return Val;
+}
+
 int main(int argc, char **argv) {
 
   cl::ParseCommandLineOptions(argc, argv);
@@ -180,9 +199,11 @@
   Flags.DisableTranslation = DisableTranslation;
   Flags.DisableGlobals = DisableGlobals;
   Flags.FunctionSections = FunctionSections;
+  Flags.DataSections = DataSections;
   Flags.UseIntegratedAssembler = UseIntegratedAssembler;
   Flags.UseSandboxing = UseSandboxing;
   Flags.DumpStats = DumpStats;
+  Flags.AllowUninitializedGlobals = AllowUninitializedGlobals;
   Flags.TimeEachFunction = TimeEachFunction;
   Flags.DefaultGlobalPrefix = DefaultGlobalPrefix;
   Flags.DefaultFunctionPrefix = DefaultFunctionPrefix;
@@ -207,7 +228,7 @@
 
     if (!Mod) {
       Err.print(argv[0], errs());
-      return 1;
+      return GetReturnValue(1);
     }
 
     Ice::Converter Converter(Mod, &Ctx, Flags);
@@ -222,5 +243,5 @@
     Ctx.dumpTimers();
   const bool FinalStats = true;
   Ctx.dumpStats("_FINAL_", FinalStats);
-  return ErrorStatus;
+  return GetReturnValue(ErrorStatus);
 }