Introduce the notion of function addresses in Subzero.

Introduces the notion of a function address, to replace using LLVM
IR's Function class. Modifies Ice converter, and Subzero's bitcode
reader, to build function addresses.

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

Review URL: https://codereview.chromium.org/641193002
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index 380f1a0..a97cb68 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -34,6 +34,7 @@
 #include "IceTypes.h"
 #include "IceTypeConverter.h"
 
+// TODO(kschimpf): Remove two namespaces being visible at once.
 using namespace llvm;
 
 namespace {
@@ -52,11 +53,14 @@
   LLVM2ICEConverter &operator=(const LLVM2ICEConverter &) = delete;
 
 public:
-  LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
-      : Ctx(Ctx), TypeConverter(LLVMContext) {}
+  LLVM2ICEConverter(Ice::Converter &Converter)
+      : Converter(Converter), Ctx(Converter.getContext()),
+        TypeConverter(Converter.getModule()->getContext()) {}
+
+  Ice::Converter &getConverter() const { return Converter; }
 
 protected:
-  // Data
+  Ice::Converter &Converter;
   Ice::GlobalContext *Ctx;
   const Ice::TypeConverter TypeConverter;
 };
@@ -72,8 +76,8 @@
   operator=(const LLVM2ICEFunctionConverter &) = delete;
 
 public:
-  LLVM2ICEFunctionConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
-      : LLVM2ICEConverter(Ctx, LLVMContext), Func(NULL) {}
+  LLVM2ICEFunctionConverter(Ice::Converter &Converter)
+      : LLVM2ICEConverter(Converter), Func(nullptr) {}
 
   // Caller is expected to delete the returned Ice::Cfg object.
   Ice::Cfg *convertFunction(const Function *F) {
@@ -126,12 +130,12 @@
       else if (Type == Ice::IceType_f64)
         return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble());
       llvm_unreachable("Unexpected floating point type");
-      return NULL;
+      return nullptr;
     } else if (const auto CU = dyn_cast<UndefValue>(Const)) {
       return Ctx->getConstantUndef(convertToIceType(CU->getType()));
     } else {
       llvm_unreachable("Unhandled constant type");
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -141,7 +145,7 @@
   // and a version that just uses convertToIceType on V.
   Ice::Variable *mapValueToIceVar(const Value *V, Ice::Type IceTy) {
     if (IceTy == Ice::IceType_void)
-      return NULL;
+      return nullptr;
     if (VarMap.find(V) == VarMap.end()) {
       VarMap[V] = Func->makeVariable(IceTy, V->getName());
     }
@@ -169,10 +173,10 @@
 
   // Given an LLVM instruction and an operand number, produce the
   // Ice::Operand this refers to. If there's no such operand, return
-  // NULL.
+  // nullptr.
   Ice::Operand *convertOperand(const Instruction *Inst, unsigned OpNum) {
     if (OpNum >= Inst->getNumOperands()) {
-      return NULL;
+      return nullptr;
     }
     const Value *Op = Inst->getOperand(OpNum);
     return convertValue(Op);
@@ -292,7 +296,7 @@
     }
 
     llvm_unreachable("convertInstruction");
-    return NULL;
+    return nullptr;
   }
 
   Ice::Inst *convertLoadInstruction(const LoadInst *Inst) {
@@ -524,8 +528,8 @@
     unsigned NumArgs = Inst->getNumArgOperands();
     // Note: Subzero doesn't (yet) do anything special with the Tail
     // flag in the bitcode, i.e. CallInst::isTailCall().
-    Ice::InstCall *NewInst = NULL;
-    const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL;
+    Ice::InstCall *NewInst = nullptr;
+    const Ice::Intrinsics::FullIntrinsicInfo *Info = nullptr;
 
     if (const auto Target = dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
       // Check if this direct call is to an Intrinsic (starts with "llvm.")
@@ -545,7 +549,7 @@
     }
 
     // Not an intrinsic call.
-    if (NewInst == NULL) {
+    if (NewInst == nullptr) {
       NewInst = Ice::InstCall::create(Func, NumArgs, Dest, CallTarget,
                                       Inst->isTailCall());
     }
@@ -636,48 +640,37 @@
   operator-(const LLVM2ICEGlobalsConverter &) = delete;
 
 public:
-  LLVM2ICEGlobalsConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
-      : LLVM2ICEConverter(Ctx, LLVMContext) {}
+  LLVM2ICEGlobalsConverter(Ice::Converter &Converter)
+      : LLVM2ICEConverter(Converter) {}
 
-  ~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);
+  /// Converts global variables, and their initializers into ICE
+  /// global variable declarations, for module Mod. Puts corresponding
+  /// converted declarations into VariableDeclarations.
+  void convertGlobalsToIce(
+      Module *Mod,
+      Ice::Translator::VariableDeclarationListType &VariableDeclarations);
 
 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,
+  // Adds the Initializer to the list of initializers for the Global
+  // variable declaraation.
+  void addGlobalInitializer(Ice::VariableDeclaration &Global,
                             const Constant *Initializer) {
     const bool HasOffset = false;
-    const Ice::GlobalAddress::RelocOffsetType Offset = 0;
+    const Ice::VariableDeclaration::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,
+  // Adds Initializer to the list of initializers for Global variable
+  // declaration.  HasOffset is true only if Initializer is a
+  // relocation initializer and Offset should be added to the
+  // relocation.
+  void addGlobalInitializer(Ice::VariableDeclaration &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];
-  }
+                            Ice::VariableDeclaration::RelocOffsetType Offset);
 
   // Converts the given constant C to the corresponding integer
   // literal it contains.
-  Ice::GlobalAddress::RelocOffsetType
+  Ice::VariableDeclaration::RelocOffsetType
   getIntegerLiteralConstant(const Value *C) {
     const auto CI = dyn_cast<ConstantInt>(C);
     if (CI && CI->getType()->isIntegerTy(32))
@@ -692,30 +685,26 @@
 };
 
 void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
-    Module *Mod, Ice::Translator::GlobalAddressList &GlobalAddresses) {
+    Module *Mod,
+    Ice::Translator::VariableDeclarationListType &VariableDeclarations) {
   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);
+    const GlobalVariable *GV = I;
     Ice::IceString Name = GV->getName();
     if (!GV->hasInternalLinkage()) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Can't define external global address: " << Name;
+      StrBuf << "Can't define external global declaration: " << 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);
+    Ice::GlobalDeclaration *Var = getConverter().getGlobalDeclaration(GV);
+    Ice::VariableDeclaration* VarDecl = cast<Ice::VariableDeclaration>(Var);
+    VariableDeclarations.push_back(VarDecl);
 
     const Constant *Initializer = GV->getInitializer();
     if (const auto CompoundInit = dyn_cast<ConstantStruct>(Initializer)) {
@@ -723,24 +712,25 @@
                                              E = CompoundInit->op_end();
            I != E; ++I) {
         if (const auto Init = dyn_cast<Constant>(I)) {
-          addGlobalInitializer(*Addr, Init);
+          addGlobalInitializer(*VarDecl, Init);
         }
       }
     } else {
-      addGlobalInitializer(*Addr, Initializer);
+      addGlobalInitializer(*VarDecl, Initializer);
     }
   }
 }
 
 void LLVM2ICEGlobalsConverter::addGlobalInitializer(
-    Ice::GlobalAddress &Global, const Constant *Initializer, bool HasOffset,
-    Ice::GlobalAddress::RelocOffsetType Offset) {
+    Ice::VariableDeclaration &Global, const Constant *Initializer,
+    bool HasOffset, Ice::VariableDeclaration::RelocOffsetType Offset) {
+  (void)HasOffset;
   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(
+    Global.addInitializer(new Ice::VariableDeclaration::DataInitializer(
         CDA->getRawDataValues().data(), CDA->getNumElements()));
     return;
   }
@@ -750,7 +740,7 @@
       assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
              (cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
       Global.addInitializer(
-          new Ice::GlobalAddress::ZeroInitializer(AT->getNumElements()));
+          new Ice::VariableDeclaration::ZeroInitializer(AT->getNumElements()));
     } else {
       llvm_unreachable("Unhandled constant aggregate zero type");
     }
@@ -769,18 +759,11 @@
              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;
+      const Ice::GlobalDeclaration *Addr =
+          getConverter().getGlobalDeclaration(GV);
+      Global.addInitializer(
+          new Ice::VariableDeclaration::RelocInitializer(Addr, Offset));
+      return;
     }
     default:
       break;
@@ -797,19 +780,96 @@
 
 namespace Ice {
 
+void Converter::nameUnnamedGlobalVariables(Module *Mod) {
+  const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix;
+  if (GlobalPrefix.empty())
+    return;
+  uint32_t NameIndex = 0;
+  Ostream &errs = Ctx->getStrDump();
+  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 Converter::nameUnnamedFunctions(Module *Mod) {
+  const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix;
+  if (FunctionPrefix.empty())
+    return;
+  uint32_t NameIndex = 0;
+  Ostream &errs = Ctx->getStrDump();
+  for (Function &F : *Mod) {
+    if (!F.hasName()) {
+      F.setName(createUnnamedName(FunctionPrefix, NameIndex));
+      ++NameIndex;
+    } else {
+      checkIfUnnamedNameSafe(F.getName(), "function", FunctionPrefix, errs);
+    }
+  }
+}
+
 void Converter::convertToIce() {
   TimerMarker T(TimerStack::TT_convertToIce, Ctx);
-  nameUnnamedGlobalAddresses(Mod);
+  nameUnnamedGlobalVariables(Mod);
   nameUnnamedFunctions(Mod);
+  installGlobalDeclarations(Mod);
   convertGlobals(Mod);
   convertFunctions();
 }
 
+GlobalDeclaration *Converter::getGlobalDeclaration(const GlobalValue *V) {
+  GlobalDeclarationMapType::const_iterator Pos = GlobalDeclarationMap.find(V);
+  if (Pos == GlobalDeclarationMap.end()) {
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << "Can't find global declaration for: " << V->getName();
+    report_fatal_error(StrBuf.str());
+  }
+  return Pos->second;
+}
+
+void Converter::installGlobalDeclarations(Module *Mod) {
+  const TypeConverter Converter(Mod->getContext());
+  // Install function declarations.
+  for (const Function &Func : *Mod) {
+    FuncSigType Signature;
+    FunctionType *FuncType = Func.getFunctionType();
+    Signature.setReturnType(
+        Converter.convertToIceType(FuncType->getReturnType()));
+    for (size_t I = 0; I < FuncType->getNumParams(); ++I) {
+      Signature.appendArgType(
+          Converter.convertToIceType(FuncType->getParamType(I)));
+    }
+    FunctionDeclaration *IceFunc = FunctionDeclaration::create(
+        Ctx, Signature, Func.getCallingConv(), Func.getLinkage(), Func.empty());
+    IceFunc->setName(Func.getName());
+    GlobalDeclarationMap[&Func] = IceFunc;
+  }
+  // Install global variable declarations.
+  for (Module::const_global_iterator I = Mod->global_begin(),
+                                     E = Mod->global_end();
+       I != E; ++I) {
+    const GlobalVariable *GV = I;
+    VariableDeclaration *Var = VariableDeclaration::create(Ctx);
+    Var->setName(GV->getName());
+    Var->setAlignment(GV->getAlignment());
+    Var->setIsConstant(GV->isConstant());
+    // Note: We allow external for cross tests.
+    // TODO(kschimpf) Put behind flag AllowUninitializedGlobals.
+    Var->setIsInternal(!GV->isExternallyInitialized());
+    GlobalDeclarationMap[GV] = Var;
+  }
+}
+
 void Converter::convertGlobals(Module *Mod) {
-  LLVM2ICEGlobalsConverter GlobalsConverter(Ctx, Mod->getContext());
-  Translator::GlobalAddressList GlobalAddresses;
-  GlobalsConverter.convertGlobalsToIce(Mod, GlobalAddresses);
-  lowerGlobals(GlobalAddresses);
+  LLVM2ICEGlobalsConverter GlobalsConverter(*this);
+  Translator::VariableDeclarationListType VariableDeclarations;
+  GlobalsConverter.convertGlobalsToIce(Mod, VariableDeclarations);
+  lowerGlobals(VariableDeclarations);
 }
 
 void Converter::convertFunctions() {
@@ -823,7 +883,7 @@
       TimerID = Ctx->getTimerID(StackID, I.getName());
       Ctx->pushTimer(TimerID, StackID);
     }
-    LLVM2ICEFunctionConverter FunctionConverter(Ctx, Mod->getContext());
+    LLVM2ICEFunctionConverter FunctionConverter(*this);
 
     Cfg *Fcn = FunctionConverter.convertFunction(&I);
     translateFcn(Fcn);
diff --git a/src/IceConverter.h b/src/IceConverter.h
index 763dcae..d26c34c 100644
--- a/src/IceConverter.h
+++ b/src/IceConverter.h
@@ -14,9 +14,11 @@
 #ifndef SUBZERO_SRC_ICECONVERTER_H
 #define SUBZERO_SRC_ICECONVERTER_H
 
+#include "IceDefs.h"
 #include "IceTranslator.h"
 
 namespace llvm {
+class GlobalValue;
 class Module;
 }
 
@@ -27,18 +29,42 @@
   Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags)
       : Translator(Ctx, Flags), Mod(Mod) {}
 
+  ~Converter() {}
+
   /// Converts the LLVM Module to ICE. Sets exit status to false if successful,
   /// true otherwise.
   void convertToIce();
 
+  llvm::Module *getModule() const { return Mod; }
+
+  // Returns the global declaration associated with the corresponding
+  // global value V. If no such global address, generates fatal error.
+  GlobalDeclaration *getGlobalDeclaration(const llvm::GlobalValue *V);
+
 private:
   llvm::Module *Mod;
+  typedef std::map<const llvm::GlobalValue *, GlobalDeclaration *>
+      GlobalDeclarationMapType;
+  GlobalDeclarationMapType GlobalDeclarationMap;
+
+  // Walks module and generates names for unnamed globals using prefix
+  // getFlags().DefaultGlobalPrefix, if the prefix is non-empty.
+  void nameUnnamedGlobalVariables(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);
+
   // Converts functions to ICE, and then machine code.
   void convertFunctions();
 
   // Converts globals to ICE, and then machine code.
   void convertGlobals(llvm::Module *Mod);
 
+  // Installs global declarations into GlobalDeclarationMap.
+  void installGlobalDeclarations(llvm::Module *Mod);
+
   Converter(const Converter &) = delete;
   Converter &operator=(const Converter &) = delete;
 };
diff --git a/src/IceDefs.h b/src/IceDefs.h
index 29ed5d8..62665e7 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -26,7 +26,6 @@
 #include <set>
 #include <string>
 #include <vector>
-
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/SmallBitVector.h"
@@ -39,7 +38,9 @@
 class Cfg;
 class CfgNode;
 class Constant;
+class FunctionDeclaration;
 class GlobalContext;
+class GlobalDeclaration;
 class Inst;
 class InstPhi;
 class InstTarget;
@@ -48,6 +49,7 @@
 class Operand;
 class TargetLowering;
 class Variable;
+class VariableDeclaration;
 class VariablesMetadata;
 
 // TODO: Switch over to LLVM's ADT container classes.
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index c8b429f..b724433 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -19,6 +19,7 @@
 #include "IceClFlags.h"
 #include "IceDefs.h"
 #include "IceGlobalContext.h"
+#include "IceGlobalInits.h"
 #include "IceOperand.h"
 #include "IceTargetLowering.h"
 #include "IceTimerTree.h"
@@ -289,7 +290,9 @@
   return getTestPrefix() + Name;
 }
 
-GlobalContext::~GlobalContext() {}
+GlobalContext::~GlobalContext() {
+  llvm::DeleteContainerPointers(GlobalDeclarations);
+}
 
 Constant *GlobalContext::getConstantInt64(Type Ty, uint64_t ConstantInt64) {
   assert(Ty == IceType_i64);
@@ -385,6 +388,23 @@
   llvm_unreachable("Unknown type");
 }
 
+FunctionDeclaration *
+GlobalContext::newFunctionDeclaration(const FuncSigType *Signature,
+                                      unsigned CallingConv, unsigned Linkage,
+                                      bool IsProto) {
+  FunctionDeclaration *Func = new FunctionDeclaration(
+      *Signature, static_cast<llvm::CallingConv::ID>(CallingConv),
+      static_cast<llvm::GlobalValue::LinkageTypes>(Linkage), IsProto);
+  GlobalDeclarations.push_back(Func);
+  return Func;
+}
+
+VariableDeclaration *GlobalContext::newVariableDeclaration() {
+  VariableDeclaration *Var = new VariableDeclaration();
+  GlobalDeclarations.push_back(Var);
+  return Var;
+}
+
 TimerIdT GlobalContext::getTimerID(TimerStackIdT StackID,
                                    const IceString &Name) {
   assert(StackID < Timers.size());
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index cc5da58..026cb7f 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -21,6 +21,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 #include "IceDefs.h"
+#include "IceClFlags.h"
 #include "IceIntrinsics.h"
 #include "IceRNG.h"
 #include "IceTimerTree.h"
@@ -29,6 +30,7 @@
 namespace Ice {
 
 class ClFlags;
+class FuncSigType;
 
 // This class collects rudimentary statistics during translation.
 class CodeStats {
@@ -117,6 +119,17 @@
   // getConstantPool() returns a copy of the constant pool for
   // constants of a given type.
   ConstantList getConstantPool(Type Ty) const;
+  // Returns a new function declaration, allocated in an internal
+  // memory pool.  Ownership of the function is maintained by this
+  // class instance.
+  FunctionDeclaration *newFunctionDeclaration(const FuncSigType *Signature,
+                                              unsigned CallingConv,
+                                              unsigned Linkage, bool IsProto);
+
+  // Returns a new global variable declaration, allocated in an
+  // internal memory pool.  Ownership of the function is maintained by
+  // this class instance.
+  VariableDeclaration *newVariableDeclaration();
 
   const ClFlags &getFlags() const { return Flags; }
 
@@ -186,6 +199,7 @@
   CodeStats StatsFunction;
   CodeStats StatsCumulative;
   std::vector<TimerStack> Timers;
+  std::vector<GlobalDeclaration *> GlobalDeclarations;
   GlobalContext(const GlobalContext &) = delete;
   GlobalContext &operator=(const GlobalContext &) = delete;
 
diff --git a/src/IceGlobalInits.cpp b/src/IceGlobalInits.cpp
index 4d9dadb..d9cea26 100644
--- a/src/IceGlobalInits.cpp
+++ b/src/IceGlobalInits.cpp
@@ -1,4 +1,4 @@
-//===- subzero/src/IceGlobalInits.cpp - Global initializers ---------------===//
+//===- subzero/src/IceGlobalInits.cpp - Global declarations ---------------===//
 //
 //                        The Subzero Code Generator
 //
@@ -7,8 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the notion of global addresses and
-// initializers in Subzero.
+// This file implements the notion of function declarations, global
+// variable declarations, and the corresponding variable initializers
+// in Subzero.
 //
 //===----------------------------------------------------------------------===//
 
@@ -17,18 +18,82 @@
 #include "llvm/IR/Value.h"
 
 #include "IceDefs.h"
+#include "IceGlobalContext.h"
 #include "IceGlobalInits.h"
 #include "IceTypes.h"
 
 namespace {
 char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
+
+void dumpLinkage(Ice::Ostream &Stream,
+                 llvm::GlobalValue::LinkageTypes Linkage) {
+  switch (Linkage) {
+  case llvm::GlobalValue::ExternalLinkage:
+    Stream << "external";
+    return;
+  case llvm::GlobalValue::InternalLinkage:
+    Stream << "internal";
+    return;
+  default:
+    break;
+  }
+  std::string Buffer;
+  llvm::raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Unknown linkage value: " << Linkage;
+  llvm::report_fatal_error(StrBuf.str());
 }
 
+void dumpCallingConv(Ice::Ostream &, llvm::CallingConv::ID CallingConv) {
+  if (CallingConv == llvm::CallingConv::C)
+    return;
+  std::string Buffer;
+  llvm::raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Unknown calling convention: " << CallingConv;
+  llvm::report_fatal_error(StrBuf.str());
+}
+
+} // end of anonymous namespace
+
 namespace Ice {
 
-GlobalAddress::~GlobalAddress() { llvm::DeleteContainerPointers(Initializers); }
+FunctionDeclaration *
+FunctionDeclaration::create(GlobalContext *Ctx, const FuncSigType &Signature,
+                            llvm::CallingConv::ID CallingConv,
+                            llvm::GlobalValue::LinkageTypes Linkage,
+                            bool IsProto) {
+  return Ctx->newFunctionDeclaration(&Signature, CallingConv, Linkage, IsProto);
+}
 
-void GlobalAddress::dumpType(Ostream &Stream) const {
+void FunctionDeclaration::dumpType(Ostream &Stream) const {
+  Stream << Signature;
+}
+
+void FunctionDeclaration::dump(Ostream &Stream) const {
+  if (IsProto)
+    Stream << "declare ";
+  ::dumpLinkage(Stream, Linkage);
+  ::dumpCallingConv(Stream, CallingConv);
+  Stream << Signature.getReturnType() << " @" << Name << "(";
+  bool IsFirst = true;
+  for (Type ArgTy : Signature.getArgList()) {
+    if (IsFirst)
+      IsFirst = false;
+    else
+      Stream << ", ";
+    Stream << ArgTy;
+  }
+  Stream << ")";
+}
+
+VariableDeclaration *VariableDeclaration::create(GlobalContext *Ctx) {
+  return Ctx->newVariableDeclaration();
+}
+
+VariableDeclaration::~VariableDeclaration() {
+  llvm::DeleteContainerPointers(Initializers);
+}
+
+void VariableDeclaration::dumpType(Ostream &Stream) const {
   if (Initializers.size() == 1) {
     Initializers.front()->dumpType(Stream);
   } else {
@@ -46,8 +111,8 @@
   }
 }
 
-void GlobalAddress::dump(Ostream &Stream) const {
-  Stream << "@" << getName() << " = internal "
+void VariableDeclaration::dump(Ostream &Stream) const {
+  Stream << "@" << Name << " = internal "
          << (IsConstant ? "constant" : "global") << " ";
 
   // Add initializer.
@@ -74,11 +139,11 @@
   Stream << "\n";
 }
 
-void GlobalAddress::Initializer::dumpType(Ostream &Stream) const {
+void VariableDeclaration::Initializer::dumpType(Ostream &Stream) const {
   Stream << "[" << getNumBytes() << " x " << Ice::IceType_i8 << "]";
 }
 
-void GlobalAddress::DataInitializer::dump(Ostream &Stream) const {
+void VariableDeclaration::DataInitializer::dump(Ostream &Stream) const {
   dumpType(Stream);
   Stream << " c\"";
   // Code taken from PrintEscapedString() in AsmWriter.cpp.  Keep
@@ -93,41 +158,24 @@
   Stream << "\"";
 }
 
-void GlobalAddress::ZeroInitializer::dump(Ostream &Stream) const {
+void VariableDeclaration::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 {
+void VariableDeclaration::RelocInitializer::dumpType(Ostream &Stream) const {
   Stream << Ice::IceType_i32;
 }
 
-void GlobalAddress::RelocInitializer::dump(Ostream &Stream) const {
+void VariableDeclaration::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 ";
+  Declaration->dumpType(Stream);
+  Stream << "* @" << Declaration->getName() << " to ";
   dumpType(Stream);
   Stream << ")";
   if (Offset != 0) {
@@ -136,4 +184,5 @@
     Stream << " " << Offset << ")";
   }
 }
-}
+
+} // end of namespace Ice
diff --git a/src/IceGlobalInits.h b/src/IceGlobalInits.h
index 09e5574..0f6565c 100644
--- a/src/IceGlobalInits.h
+++ b/src/IceGlobalInits.h
@@ -1,4 +1,4 @@
-//===- subzero/src/IceGlobalInits.h - Global initializers -------*- C++ -*-===//
+//===- subzero/src/IceGlobalInits.h - Global declarations -------*- C++ -*-===//
 //
 //                        The Subzero Code Generator
 //
@@ -7,30 +7,118 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file declares the representation of global addresses and
-// initializers in Subzero. Global initializers are represented as a
-// sequence of simple initializers.
+// This file declares the representation of function declarations,
+// global variable declarations, and the corresponding variable
+// initializers in Subzero. Global variable initializers are
+// represented as a sequence of simple initializers.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef SUBZERO_SRC_ICEGLOBALINITS_H
 #define SUBZERO_SRC_ICEGLOBALINITS_H
 
-#include "IceDefs.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes
 
-namespace llvm {
-// TODO(kschimpf): Remove this dependency on LLVM IR.
-class Value;
-}
+#include "IceDefs.h"
+#include "IceTypes.h"
+
+// TODO(kschimpf): Remove ourselves from using LLVM representation for calling
+// conventions and linkage types.
 
 namespace Ice {
 
-/// Models a global address, and its initializers.
-class GlobalAddress {
-  GlobalAddress(const GlobalAddress &) = delete;
-  GlobalAddress &operator=(const GlobalAddress &) = delete;
+/// Base class for global variable and function declarations.
+class GlobalDeclaration {
+  GlobalDeclaration(const GlobalDeclaration &) = delete;
+  GlobalDeclaration &operator=(const GlobalDeclaration &) = delete;
 
 public:
+  /// Discriminator for LLVM-style RTTI.
+  enum GlobalDeclarationKind {
+    FunctionDeclarationKind,
+    VariableDeclarationKind
+  };
+  GlobalDeclarationKind getKind() const { return Kind; }
+  const IceString &getName() const { return Name; }
+  void setName(const IceString &NewName) { Name = NewName; }
+  bool hasName() const { return !Name.empty(); }
+  virtual ~GlobalDeclaration() {}
+
+  /// Returns true if the declaration is external.
+  virtual bool getIsExternal() const = 0;
+
+  /// Prints out type of the global declaration.
+  virtual void dumpType(Ostream &Stream) const = 0;
+
+  /// Prints out the global declaration.
+  virtual void dump(Ostream &Stream) const = 0;
+
+  // Mangles name for cross tests, unless external and not defined locally
+  // (so that relocations accross llvm2ice and pnacl-llc will work).
+  virtual IceString mangleName(GlobalContext *Ctx) const = 0;
+
+protected:
+  GlobalDeclaration(GlobalDeclarationKind Kind) : Kind(Kind) {}
+
+  const GlobalDeclarationKind Kind;
+  IceString Name;
+};
+
+// Models a function declaration. This includes the type signature of
+// the function, its calling conventions, and its linkage.
+class FunctionDeclaration : public GlobalDeclaration {
+  FunctionDeclaration(const FunctionDeclaration &) = delete;
+  FunctionDeclaration &operator=(const FunctionDeclaration &) = delete;
+  friend class GlobalContext;
+
+public:
+  static FunctionDeclaration *create(GlobalContext *Ctx,
+                                     const FuncSigType &Signature,
+                                     llvm::CallingConv::ID CallingConv,
+                                     llvm::GlobalValue::LinkageTypes Linkage,
+                                     bool IsProto);
+  ~FunctionDeclaration() final {}
+  const FuncSigType &getSignature() const { return Signature; }
+  llvm::CallingConv::ID getCallingConv() const { return CallingConv; }
+  llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; }
+  // isProto implies that there isn't a (local) definition for the function.
+  bool isProto() const { return IsProto; }
+  static bool classof(const GlobalDeclaration *Addr) {
+    return Addr->getKind() == FunctionDeclarationKind;
+  }
+  void dumpType(Ostream &Stream) const final;
+  void dump(Ostream &Stream) const final;
+  bool getIsExternal() const final {
+    return Linkage == llvm::GlobalValue::ExternalLinkage;
+  }
+
+  virtual IceString mangleName(GlobalContext *Ctx) const final {
+    return (getIsExternal() && IsProto) ? Name : Ctx->mangleName(Name);
+  }
+
+private:
+  const Ice::FuncSigType Signature;
+  llvm::CallingConv::ID CallingConv;
+  llvm::GlobalValue::LinkageTypes Linkage;
+  bool IsProto;
+
+  FunctionDeclaration(const FuncSigType &Signature,
+                      llvm::CallingConv::ID CallingConv,
+                      llvm::GlobalValue::LinkageTypes Linkage, bool IsProto)
+      : GlobalDeclaration(FunctionDeclarationKind), Signature(Signature),
+        CallingConv(CallingConv), Linkage(Linkage), IsProto(IsProto) {}
+};
+
+/// Models a global variable declaration, and its initializers.
+class VariableDeclaration : public GlobalDeclaration {
+  VariableDeclaration(const VariableDeclaration &) = delete;
+  VariableDeclaration &operator=(const VariableDeclaration &) = delete;
+  friend class GlobalContext;
+  // TODO(kschimpf) Factor out allocation of initializers into the
+  // global context, so that memory allocation/collection can be
+  // optimized.
+public:
   /// Base class for a global variable initializer.
   class Initializer {
     Initializer(const Initializer &) = delete;
@@ -81,8 +169,8 @@
     }
     ~DataInitializer() override {}
     const DataVecType &getContents() const { return Contents; }
-    SizeT getNumBytes() const override { return Contents.size(); }
-    void dump(Ostream &Stream) const override;
+    SizeT getNumBytes() const final { return Contents.size(); }
+    void dump(Ostream &Stream) const final;
     static bool classof(const Initializer *D) {
       return D->getKind() == DataInitializerKind;
     }
@@ -101,8 +189,8 @@
     explicit ZeroInitializer(SizeT Size)
         : Initializer(ZeroInitializerKind), Size(Size) {}
     ~ZeroInitializer() override {}
-    SizeT getNumBytes() const override { return Size; }
-    void dump(Ostream &Stream) const override;
+    SizeT getNumBytes() const final { return Size; }
+    void dump(Ostream &Stream) const final;
     static bool classof(const Initializer *Z) {
       return Z->getKind() == ZeroInitializerKind;
     }
@@ -112,76 +200,33 @@
     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.
+  /// Defines the relocation value of another global declaration.
   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(const GlobalDeclaration *Declaration,
+                     RelocOffsetType Offset)
+        : Initializer(RelocInitializerKind), Declaration(Declaration),
+          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;
+    const GlobalDeclaration *getDeclaration() const { return Declaration; }
+    SizeT getNumBytes() const final { return RelocAddrSize; }
+    void dump(Ostream &Stream) const final;
+    void dumpType(Ostream &Stream) const final;
     static bool classof(const Initializer *R) {
       return R->getKind() == RelocInitializerKind;
     }
 
   private:
-    // The global address used in the relocation.
-    const RelocationAddress Address;
+    // The global declaration used in the relocation.
+    const GlobalDeclaration *Declaration;
     // The offset to add to the relocation.
     const RelocOffsetType Offset;
   };
@@ -189,19 +234,21 @@
   /// Models the list of initializers.
   typedef std::vector<Initializer *> InitializerListType;
 
-  GlobalAddress() : Alignment(0), IsConstant(false), IsInternal(true) {}
-  ~GlobalAddress();
+  static VariableDeclaration *create(GlobalContext *Ctx);
+  ~VariableDeclaration() final;
 
   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; }
+  bool getIsExternal() const final { return !getIsInternal(); }
+  bool hasInitializer() const {
+    return !(Initializers.size() == 1 &&
+             llvm::isa<ZeroInitializer>(Initializers[0]));
+  }
 
   /// Returns the number of bytes for the initializer of the global
   /// address.
@@ -219,36 +266,49 @@
     Initializers.push_back(Initializer);
   }
 
-  /// Prints out type for initializer associated with the global address
+  /// Prints out type for initializer associated with the declaration
   /// to Stream.
-  void dumpType(Ostream &Stream) const;
+  void dumpType(Ostream &Stream) const final;
 
-  /// Prints out the definition of the global address (including
-  /// initialization).
-  void dump(Ostream &Stream) const;
+  /// Prints out the definition of the global variable declaration
+  /// (including initialization).
+  void dump(Ostream &Stream) const final;
+
+  static bool classof(const GlobalDeclaration *Addr) {
+    return Addr->getKind() == VariableDeclarationKind;
+  }
+
+  IceString mangleName(GlobalContext *Ctx) const final {
+    return (getIsExternal() && !hasInitializer())
+        ? Name : Ctx->mangleName(Name);
+  }
+
 
 private:
-  // list of initializers associated with the global address.
+  // list of initializers for the declared variable.
   InitializerListType Initializers;
-  // The name for the global.
-  IceString Name;
-  // The alignment of the initializer.
+  // The alignment of the declared variable.
   uint32_t Alignment;
-  // True if a constant initializer.
+  // True if a declared (global) constant.
   bool IsConstant;
-  // True if the address is internal.
+  // True if the declaration is internal.
   bool IsInternal;
+
+  VariableDeclaration()
+      : GlobalDeclaration(VariableDeclarationKind), Alignment(0),
+        IsConstant(false), IsInternal(true) {}
 };
 
 template <class StreamType>
 inline StreamType &operator<<(StreamType &Stream,
-                              const GlobalAddress::Initializer &Init) {
+                              const VariableDeclaration::Initializer &Init) {
   Init.dump(Stream);
   return Stream;
 }
 
 template <class StreamType>
-inline StreamType &operator<<(StreamType &Stream, const GlobalAddress &Addr) {
+inline StreamType &operator<<(StreamType &Stream,
+                              const GlobalDeclaration &Addr) {
   Addr.dump(Stream);
   return Stream;
 }
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index f116cf3..bbda1f8 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -27,7 +27,6 @@
 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
@@ -249,7 +248,7 @@
                                                   GlobalContext *Ctx);
   virtual ~TargetGlobalInitLowering();
 
-  virtual void lower(const GlobalAddress &Addr, bool DisableTranslation) = 0;
+  virtual void lower(const VariableDeclaration &Var) = 0;
 
 protected:
   TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index eb41b84..4e04186 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -4427,32 +4427,19 @@
 TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx)
     : TargetGlobalInitLowering(Ctx) {}
 
-void TargetGlobalInitX8632::lower(const GlobalAddress &Global,
-                                  bool DisableTranslation) {
-  if (Ctx->isVerbose()) {
-    Global.dump(Ctx->getStrDump());
-  }
-
-  if (DisableTranslation)
-    return;
+void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) {
 
   Ostream &Str = Ctx->getStrEmit();
 
-  // TODO(kschimpf): Don't mangle name if external and uninitialized. This
-  // will allow us to cross test relocations for references to external
-  // global variables.
-
-  const GlobalAddress::InitializerListType &Initializers =
-      Global.getInitializers();
+  const VariableDeclaration::InitializerListType &Initializers =
+      Var.getInitializers();
   assert(Initializers.size());
-  bool HasInitializer =
-      !(Initializers.size() == 1 &&
-        llvm::isa<GlobalAddress::ZeroInitializer>(Initializers[0]));
-  bool IsConstant = Global.getIsConstant();
-  bool IsExternal = !Global.getIsInternal();
-  uint32_t Align = Global.getAlignment();
-  SizeT Size = Global.getNumBytes();
-  IceString MangledName = Ctx->mangleName(Global.getName());
+  bool HasInitializer = Var.hasInitializer();
+  bool IsConstant = Var.getIsConstant();
+  bool IsExternal = Var.getIsExternal();
+  uint32_t Align = Var.getAlignment();
+  SizeT Size = Var.getNumBytes();
+  IceString MangledName = Var.mangleName(Ctx);
   IceString SectionSuffix = "";
   if (Ctx->getFlags().DataSections)
     SectionSuffix = "." + MangledName;
@@ -4483,30 +4470,29 @@
     Str << "\t.comm\t" << MangledName << "," << Size << "," << Align << "\n";
 
   if (HasInitializer) {
-    for (GlobalAddress::Initializer *Init : Initializers) {
+    for (VariableDeclaration::Initializer *Init : Initializers) {
       switch (Init->getKind()) {
-      case GlobalAddress::Initializer::DataInitializerKind: {
-        const auto Data =
-            llvm::cast<GlobalAddress::DataInitializer>(Init)->getContents();
+      case VariableDeclaration::Initializer::DataInitializerKind: {
+        const auto Data = llvm::cast<VariableDeclaration::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:
+      case VariableDeclaration::Initializer::ZeroInitializerKind:
         Str << "\t.zero\t" << Init->getNumBytes() << "\n";
         break;
-      case GlobalAddress::Initializer::RelocInitializerKind: {
-        const auto Reloc = llvm::cast<GlobalAddress::RelocInitializer>(Init);
+      case VariableDeclaration::Initializer::RelocInitializerKind: {
+        const auto Reloc =
+            llvm::cast<VariableDeclaration::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 << Reloc->getDeclaration()->mangleName(Ctx);
+        if (VariableDeclaration::RelocOffsetType Offset = Reloc->getOffset()) {
+          if (Offset >= 0 || (Offset == INT32_MIN))
+            Str << " + " << Offset;
+          else
+            Str << " - " << -Offset;
         }
         Str << "\n";
         break;
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 82a8208..bb57740 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -482,8 +482,7 @@
     return new TargetGlobalInitX8632(Ctx);
   }
 
-  virtual void lower(const GlobalAddress &Addr,
-                     bool DisableTranslation) override;
+  virtual void lower(const VariableDeclaration &Var) final;
 
 protected:
   TargetGlobalInitX8632(GlobalContext *Ctx);
diff --git a/src/IceTranslator.cpp b/src/IceTranslator.cpp
index e86d60a..6d4af11 100644
--- a/src/IceTranslator.cpp
+++ b/src/IceTranslator.cpp
@@ -22,6 +22,7 @@
 #include "IceCfg.h"
 #include "IceClFlags.h"
 #include "IceDefs.h"
+#include "IceGlobalInits.h"
 #include "IceTargetLowering.h"
 #include "IceTranslator.h"
 
@@ -54,38 +55,6 @@
   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();
-  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;
-  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) {
   Ctx->resetStats();
   Func.reset(Fcn);
@@ -110,12 +79,18 @@
     Func->getTarget()->emitConstants();
 }
 
-void Translator::lowerGlobals(const GlobalAddressList &GlobalAddresses) {
-  llvm::OwningPtr<Ice::TargetGlobalInitLowering> GlobalLowering(
-      Ice::TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
+void Translator::lowerGlobals(
+    const VariableDeclarationListType &VariableDeclarations) {
+  llvm::OwningPtr<TargetGlobalInitLowering> GlobalLowering(
+      TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
   bool DisableTranslation = Ctx->getFlags().DisableTranslation;
-  for (const Ice::GlobalAddress *Addr : GlobalAddresses) {
-    GlobalLowering->lower(*Addr, DisableTranslation);
+  bool DumpGlobalVariables = Ctx->isVerbose();
+  Ostream &Stream = Ctx->getStrDump();
+  for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
+    if (DumpGlobalVariables)
+      Global->dump(Stream);
+    if(!DisableTranslation)
+      GlobalLowering->lower(*Global);
   }
   GlobalLowering.reset();
 }
diff --git a/src/IceTranslator.h b/src/IceTranslator.h
index 8aeda94..8134697 100644
--- a/src/IceTranslator.h
+++ b/src/IceTranslator.h
@@ -25,16 +25,15 @@
 
 class ClFlags;
 class Cfg;
-class GlobalAddress;
+class VariableDeclaration;
 class GlobalContext;
 
-// Base class for translating ICE to machine code.
-// Derived classes convert other intermediate representations down to ICE,
-// and then call the appropriate (inherited) methods to convert ICE into
-// machine instructions.
+// Base class for translating ICE to machine code.  Derived classes convert
+// other intermediate representations down to ICE, and then call the appropriate
+// (inherited) methods to convert ICE into machine instructions.
 class Translator {
 public:
-  typedef std::vector<Ice::GlobalAddress *> GlobalAddressList;
+  typedef std::vector<VariableDeclaration *> VariableDeclarationListType;
 
   Translator(GlobalContext *Ctx, const ClFlags &Flags)
       : Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
@@ -54,8 +53,9 @@
   /// Emits the constant pool.
   void emitConstants();
 
-  /// Lowers the given list of global addresses to target.
-  void lowerGlobals(const GlobalAddressList &GlobalAddresses);
+  /// Lowers the given list of global addresses to target. Generates
+  /// list of corresponding variable declarations.
+  void lowerGlobals(const VariableDeclarationListType &VariableDeclarations);
 
   /// Creates a name using the given prefix and corresponding index.
   std::string createUnnamedName(const IceString &Prefix, SizeT Index);
@@ -66,15 +66,6 @@
   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);
-
-  // 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;
   const ClFlags &Flags;
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index 6642ba9..4f7a745 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -24,7 +24,6 @@
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ValueHandle.h"
 
 #include "IceCfg.h"
 #include "IceCfgNode.h"
@@ -36,9 +35,8 @@
 #include "IceTypeConverter.h"
 #include "PNaClTranslator.h"
 
-using namespace llvm;
-
 namespace {
+using namespace llvm;
 
 // TODO(kschimpf) Remove error recovery once implementation complete.
 static cl::opt<bool> AllowErrorRecovery(
@@ -160,19 +158,21 @@
   TopLevelParser &operator=(const TopLevelParser &) = delete;
 
 public:
+  typedef std::vector<Ice::FunctionDeclaration *> FunctionDeclarationListType;
+
   TopLevelParser(Ice::Translator &Translator, const std::string &InputName,
                  NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor,
                  bool &ErrorStatus)
       : NaClBitcodeParser(Cursor), Translator(Translator),
         Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
-        Header(Header), TypeConverter(getLLVMContext()),
+        Header(Header), TypeConverter(Mod->getContext()),
         ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
         NumFunctionBlocks(0) {
     Mod->setDataLayout(PNaClDataLayout);
     setErrStream(Translator.getContext()->getStrDump());
   }
 
-  ~TopLevelParser() override { DeleteContainerPointers(GlobalIDAddresses); }
+  ~TopLevelParser() override {}
 
   Ice::Translator &getTranslator() { return Translator; }
 
@@ -198,9 +198,6 @@
   /// Returns the number of bytes in the bitcode header.
   size_t getHeaderSize() const { return Header.getHeaderSize(); }
 
-  /// Returns the llvm context to use.
-  LLVMContext &getLLVMContext() const { return Mod->getContext(); }
-
   /// Changes the size of the type list to the given size.
   void resizeTypeIDValues(unsigned NewSize) { TypeIDValues.resize(NewSize); }
 
@@ -236,36 +233,40 @@
   }
 
   /// Sets the next function ID to the given LLVM function.
-  void setNextFunctionID(Function *Fcn) {
+  void setNextFunctionID(Ice::FunctionDeclaration *Fcn) {
     ++NumFunctionIds;
-    FunctionIDValues.push_back(Fcn);
+    FunctionDeclarationList.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(FunctionIDValues.size());
+    DefiningFunctionDeclarationsList.push_back(FunctionDeclarationList.size());
   }
 
   /// Returns the value id that should be associated with the the
   /// current function block. Increments internal counters during call
   /// so that it will be in correct position for next function block.
   unsigned getNextFunctionBlockValueID() {
-    if (NumFunctionBlocks >= DefiningFunctionsList.size())
+    if (NumFunctionBlocks >= DefiningFunctionDeclarationsList.size())
       report_fatal_error(
           "More function blocks than defined function addresses");
-    return DefiningFunctionsList[NumFunctionBlocks++];
+    return DefiningFunctionDeclarationsList[NumFunctionBlocks++];
   }
 
-  /// Returns the LLVM Function address associated with ID.
-  Function *getFunctionByID(unsigned ID) const {
-    if (ID >= FunctionIDValues.size())
-      return nullptr;
-    Value *V = FunctionIDValues[ID];
-    return cast<Function>(V);
+  /// Returns the function associated with ID.
+  Ice::FunctionDeclaration *getFunctionByID(unsigned ID) {
+    if (ID < FunctionDeclarationList.size())
+      return FunctionDeclarationList[ID];
+    return reportGetFunctionByIDError(ID);
   }
 
-  /// Returns the corresponding constant associated with a global value
+  /// Returns the list of function declarations.
+  const FunctionDeclarationListType &getFunctionDeclarationList() const {
+    return FunctionDeclarationList;
+  }
+
+  /// Returns the corresponding constant associated with a global declaration.
   /// (i.e. relocatable).
   Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) {
     // TODO(kschimpf): Can this be built when creating global initializers?
@@ -273,7 +274,7 @@
     if (ID >= ValueIDConstants.size()) {
       C = nullptr;
       unsigned ExpectedSize =
-          FunctionIDValues.size() + GlobalIDAddresses.size();
+          FunctionDeclarationList.size() + VariableDeclarations.size();
       if (ID >= ExpectedSize)
         ExpectedSize = ID;
       ValueIDConstants.resize(ExpectedSize);
@@ -284,12 +285,13 @@
       return C;
 
     // If reached, no such constant exists, create one.
+    // TODO(kschimpf) Don't get addresses of intrinsic function declarations.
     std::string Name;
-    unsigned FcnIDSize = FunctionIDValues.size();
+    unsigned FcnIDSize = FunctionDeclarationList.size();
     if (ID < FcnIDSize) {
-      Name = FunctionIDValues[ID]->getName();
-    } else if ((ID - FcnIDSize) < GlobalIDAddresses.size()) {
-      Name = GlobalIDAddresses[ID - FcnIDSize]->getName();
+      Name = FunctionDeclarationList[ID]->getName();
+    } else if ((ID - FcnIDSize) < VariableDeclarations.size()) {
+      Name = VariableDeclarations[ID - FcnIDSize]->getName();
     } else {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
@@ -304,47 +306,49 @@
     return C;
   }
 
-  /// Returns the number of function addresses (i.e. ID's) defined in
-  /// the bitcode file.
+  /// Returns the number of function declarations in the bitcode file.
   unsigned getNumFunctionIDs() const { return NumFunctionIds; }
 
-  /// Returns the number of global IDs (function and global addresses)
-  /// defined in the bitcode file.
+  /// Returns the number of global declarations (i.e. IDs) defined in
+  /// the bitcode file.
   unsigned getNumGlobalIDs() const {
-    return FunctionIDValues.size() + GlobalIDAddresses.size();
+    return FunctionDeclarationList.size() + VariableDeclarations.size();
   }
 
-  /// Creates Count global addresses.
-  void CreateGlobalAddresses(size_t Count) {
-    assert(GlobalIDAddresses.empty());
+  /// Creates Count global variable declarations.
+  void CreateGlobalVariables(size_t Count) {
+    assert(VariableDeclarations.empty());
+    Ice::GlobalContext *Context = getTranslator().getContext();
     for (size_t i = 0; i < Count; ++i) {
-      GlobalIDAddresses.push_back(new Ice::GlobalAddress());
+      VariableDeclarations.push_back(Ice::VariableDeclaration::create(Context));
     }
   }
 
-  /// 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 number of global variable declarations in the
+  /// bitcode file.
+  Ice::SizeT getNumGlobalVariables() const {
+    return VariableDeclarations.size();
   }
 
-  /// Returns the list of read global addresses.
-  const Ice::Translator::GlobalAddressList &getGlobalIDAddresses() {
-    return GlobalIDAddresses;
+  /// Returns the global variable declaration with the given index.
+  Ice::VariableDeclaration *getGlobalVariableByID(unsigned Index) {
+    if (Index < VariableDeclarations.size())
+      return VariableDeclarations[Index];
+    return reportGetGlobalVariableByIDError(Index);
+  }
+
+  /// Returns the global declaration (variable or function) with the
+  /// given Index.
+  Ice::GlobalDeclaration *getGlobalDeclarationByID(size_t Index) {
+    if (Index < NumFunctionIds)
+      return getFunctionByID(Index);
+    else
+      return getGlobalVariableByID(Index - NumFunctionIds);
+  }
+
+  /// Returns the list of parsed global variable declarations.
+  const Ice::Translator::VariableDeclarationListType &getGlobalVariables() {
+    return VariableDeclarations;
   }
 
   /// Returns the corresponding ICE type for LLVMTy.
@@ -383,20 +387,21 @@
   unsigned NumErrors;
   // The types associated with each type ID.
   std::vector<ExtendedType> TypeIDValues;
-  // 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.
+  // The set of functions.
+  FunctionDeclarationListType FunctionDeclarationList;
+  // The set of global variables.
+  Ice::Translator::VariableDeclarationListType VariableDeclarations;
+  // Relocatable constants associated with global declarations.
   std::vector<Ice::Constant *> ValueIDConstants;
-  // The number of function IDs.
+  // The number of function declarations (i.e. IDs).
   unsigned NumFunctionIds;
   // The number of function blocks (processed so far).
   unsigned NumFunctionBlocks;
-  // The list of value IDs (in the order found) of defining function
-  // addresses.
-  std::vector<unsigned> DefiningFunctionsList;
+  // The list of function declaration IDs (in the order found) that
+  // aren't just proto declarations.
+  // TODO(kschimpf): Instead of using this list, just use
+  // FunctionDeclarationList, and the isProto member function.
+  std::vector<unsigned> DefiningFunctionDeclarationsList;
   // Error recovery value to use when getFuncSigTypeByID fails.
   Ice::FuncSigType UndefinedFuncSigType;
 
@@ -423,6 +428,14 @@
   void reportBadTypeIDAs(unsigned ID, const ExtendedType *Ty,
                          ExtendedType::TypeKind WantedType);
 
+  // Reports that there is no function declaration for ID. Returns an
+  // error recovery value to use.
+  Ice::FunctionDeclaration *reportGetFunctionByIDError(unsigned ID);
+
+  // Reports that there is not global variable declaration for
+  // ID. Returns an error recovery value to use.
+  Ice::VariableDeclaration *reportGetGlobalVariableByIDError(unsigned Index);
+
   // Reports that there is no corresponding ICE type for LLVMTy, and
   // returns ICE::IceType_void.
   Ice::Type convertToIceTypeError(Type *LLVMTy);
@@ -440,6 +453,34 @@
   Error(StrBuf.str());
 }
 
+Ice::FunctionDeclaration *
+TopLevelParser::reportGetFunctionByIDError(unsigned ID) {
+  std::string Buffer;
+  raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Function index " << ID
+         << " not allowed. Out of range. Must be less than "
+         << FunctionDeclarationList.size();
+  Error(StrBuf.str());
+  // TODO(kschimpf) Remove error recovery once implementation complete.
+  if (!FunctionDeclarationList.empty())
+    return FunctionDeclarationList[0];
+  report_fatal_error("Unable to continue");
+}
+
+Ice::VariableDeclaration *
+TopLevelParser::reportGetGlobalVariableByIDError(unsigned Index) {
+  std::string Buffer;
+  raw_string_ostream StrBuf(Buffer);
+  StrBuf << "Global index " << Index
+         << " not allowed. Out of range. Must be less than "
+         << VariableDeclarations.size();
+  Error(StrBuf.str());
+  // TODO(kschimpf) Remove error recovery once implementation complete.
+  if (!VariableDeclarations.empty())
+    return VariableDeclarations[0];
+  report_fatal_error("Unable to continue");
+}
+
 Ice::Type TopLevelParser::convertToIceTypeError(Type *LLVMTy) {
   std::string Buffer;
   raw_string_ostream StrBuf(Buffer);
@@ -747,38 +788,40 @@
   llvm_unreachable("Unknown type block record not processed!");
 }
 
-/// Parses the globals block (i.e. global variables).
+/// Parses the globals block (i.e. global variable declarations and
+/// corresponding initializers).
 class GlobalsParser : public BlockParserBaseClass {
 public:
   GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
       : BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0),
-        NextGlobalID(0), CurrentAddress(&DummyAddress) {}
-
-  ~GlobalsParser() override {}
+        NextGlobalID(0), DummyGlobalVar(Ice::VariableDeclaration::create(
+                             getTranslator().getContext())),
+        CurGlobalVar(DummyGlobalVar) {}
 
 private:
   // Keeps track of how many initializers are expected for the global variable
-  // being built.
+  // declaration being built.
   unsigned InitializersNeeded;
 
-  // The index of the next global variable.
+  // The index of the next global variable declaration.
   unsigned NextGlobalID;
 
-  // Holds the current global address whose initializer is being defined.
-  Ice::GlobalAddress *CurrentAddress;
+  // Dummy global variable declaration to guarantee CurGlobalVar is
+  // always defined (allowing code to not need to check if
+  // CurGlobalVar is nullptr).
+  Ice::VariableDeclaration *DummyGlobalVar;
 
-  // Dummy global address to guarantee CurrentAddress is always defined
-  // (allowing code to not need to check if CurrentAddress is nullptr).
-  Ice::GlobalAddress DummyAddress;
+  // Holds the current global variable declaration being built.
+  Ice::VariableDeclaration *CurGlobalVar;
 
   void ExitBlock() override {
     verifyNoMissingInitializers();
-    unsigned NumIDs = Context->getNumGlobalAddresses();
+    unsigned NumIDs = Context->getNumGlobalVariables();
     if (NextGlobalID < NumIDs) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Globals block expects " << NumIDs
-             << " global definitions. Found: " << NextGlobalID;
+             << " global variable declarations. Found: " << NextGlobalID;
       Error(StrBuf.str());
     }
     BlockParserBaseClass::ExitBlock();
@@ -786,12 +829,12 @@
 
   void ProcessRecord() override;
 
-  // Checks if the number of initializers for the CurrentAddress is the same as
+  // Checks if the number of initializers for the CurGlobalVar 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() {
-    size_t NumInits = CurrentAddress->getInitializers().size();
+    size_t NumInits = CurGlobalVar->getInitializers().size();
     if (InitializersNeeded != NumInits) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
@@ -801,6 +844,7 @@
         StrBuf << "s";
       StrBuf << ". Found: " << NumInits;
       Error(StrBuf.str());
+      InitializersNeeded = NumInits;
     }
   }
 };
@@ -812,11 +856,11 @@
     // COUNT: [n]
     if (!isValidRecordSize(1, "Globals count"))
       return;
-    if (NextGlobalID != Context->getNumGlobalAddresses()) {
+    if (NextGlobalID != Context->getNumGlobalVariables()) {
       Error("Globals count record not first in block.");
       return;
     }
-    Context->CreateGlobalAddresses(Values[0]);
+    Context->CreateGlobalVariables(Values[0]);
     return;
   case naclbitc::GLOBALVAR_VAR: {
     // VAR: [align, isconst]
@@ -824,9 +868,9 @@
       return;
     verifyNoMissingInitializers();
     InitializersNeeded = 1;
-    CurrentAddress = Context->getGlobalAddress(NextGlobalID);
-    CurrentAddress->setAlignment((1 << Values[0]) >> 1);
-    CurrentAddress->setIsConstant(Values[1] != 0);
+    CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
+    CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
+    CurGlobalVar->setIsConstant(Values[1] != 0);
     ++NextGlobalID;
     return;
   }
@@ -834,7 +878,7 @@
     // COMPOUND: [size]
     if (!isValidRecordSize(1, "globals compound"))
       return;
-    if (!CurrentAddress->getInitializers().empty()) {
+    if (!CurGlobalVar->getInitializers().empty()) {
       Error("Globals compound record not first initializer");
       return;
     }
@@ -851,17 +895,17 @@
     // ZEROFILL: [size]
     if (!isValidRecordSize(1, "Globals zerofill"))
       return;
-    CurrentAddress->addInitializer(
-        new Ice::GlobalAddress::ZeroInitializer(Values[0]));
-    break;
+    CurGlobalVar->addInitializer(
+        new Ice::VariableDeclaration::ZeroInitializer(Values[0]));
+    return;
   }
   case naclbitc::GLOBALVAR_DATA: {
     // DATA: [b0, b1, ...]
     if (!isValidRecordSizeAtLeast(1, "Globals data"))
       return;
-    CurrentAddress->addInitializer(
-        new Ice::GlobalAddress::DataInitializer(Values));
-    break;
+    CurGlobalVar->addInitializer(
+        new Ice::VariableDeclaration::DataInitializer(Values));
+    return;
   }
   case naclbitc::GLOBALVAR_RELOC: {
     // RELOC: [val, [addend]]
@@ -871,19 +915,9 @@
     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));
-    }
-    break;
+    CurGlobalVar->addInitializer(new Ice::VariableDeclaration::RelocInitializer(
+        Context->getGlobalDeclarationByID(Index), Offset));
+    return;
   }
   default:
     BlockParserBaseClass::ProcessRecord();
@@ -964,23 +998,25 @@
       : BlockParserBaseClass(BlockID, EnclosingParser),
         Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
         FcnId(Context->getNextFunctionBlockValueID()),
-        LLVMFunc(Context->getFunctionByID(FcnId)),
+        FuncDecl(Context->getFunctionByID(FcnId)),
         CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
         NextLocalInstIndex(Context->getNumGlobalIDs()),
         InstIsTerminating(false) {
-    Func->setFunctionName(LLVMFunc->getName());
+    Func->setFunctionName(FuncDecl->getName());
     if (getFlags().TimeEachFunction)
       getTranslator().getContext()->pushTimer(
           getTranslator().getContext()->getTimerID(
               Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
           Ice::GlobalContext::TSK_Funcs);
-    Func->setReturnType(Context->convertToIceType(LLVMFunc->getReturnType()));
-    Func->setInternal(LLVMFunc->hasInternalLinkage());
+    // TODO(kschimpf) Clean up API to add a function signature to
+    // a CFG.
+    const Ice::FuncSigType &Signature = FuncDecl->getSignature();
+    Func->setReturnType(Signature.getReturnType());
+    Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
     CurrentNode = InstallNextBasicBlock();
     Func->setEntryNode(CurrentNode);
-    for (auto ArgI = LLVMFunc->arg_begin(), ArgE = LLVMFunc->arg_end();
-         ArgI != ArgE; ++ArgI) {
-      Func->addArg(getNextInstVar(Context->convertToIceType(ArgI->getType())));
+    for (Ice::Type ArgType : Signature.getArgList()) {
+      Func->addArg(getNextInstVar(ArgType));
     }
   }
 
@@ -1000,8 +1036,8 @@
   Ice::CfgNode *CurrentNode;
   // The ID for the function.
   unsigned FcnId;
-  // The corresponding LLVM function.
-  Function *LLVMFunc;
+  // The corresponding function declaration.
+  Ice::FunctionDeclaration *FuncDecl;
   // Holds the dividing point between local and global absolute value indices.
   uint32_t CachedNumGlobalValueIDs;
   // Holds operands local to the function block, based on indices
@@ -1999,12 +2035,12 @@
     // CALL_INDIRECT: [cc, fn, returnty, args...]
     //
     // Note: The difference between CALL and CALL_INDIRECT is that
-    // CALL has an explicit function address, while the CALL_INDIRECT
-    // is just an address. For CALL, we can infer the return type by
-    // looking up the type signature associated with the function
-    // address. For CALL_INDIRECT we can only infer the type signature
-    // via argument types, and the corresponding return type stored in
-    // CALL_INDIRECT record.
+    // CALL has a reference to an explicit function declaration, while
+    // the CALL_INDIRECT is just an address. For CALL, we can infer
+    // the return type by looking up the type signature associated
+    // with the function declaration. For CALL_INDIRECT we can only
+    // infer the type signature via argument types, and the
+    // corresponding return type stored in CALL_INDIRECT record.
     Ice::SizeT ParamsStartIndex = 2;
     if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
       if (!isValidRecordSizeAtLeast(2, "function block call"))
@@ -2034,17 +2070,9 @@
     Ice::Type ReturnType = Ice::IceType_void;
     const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
     if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
-      Function *Fcn = Context->getFunctionByID(CalleeIndex);
-      if (Fcn == nullptr) {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Function call to non-function: " << *Callee;
-        Error(StrBuf.str());
-        return;
-      }
-
-      FunctionType *FcnTy = Fcn->getFunctionType();
-      ReturnType = Context->convertToIceType(FcnTy->getReturnType());
+      Ice::FunctionDeclaration *Fcn = Context->getFunctionByID(CalleeIndex);
+      const Ice::FuncSigType &Signature = Fcn->getSignature();
+      ReturnType = Signature.getReturnType();
 
       // Check if this direct call is to an Intrinsic (starts with "llvm.")
       static Ice::IceString LLVMPrefix("llvm.");
@@ -2339,45 +2367,60 @@
 public:
   ModuleParser(unsigned BlockID, TopLevelParser *Context)
       : BlockParserBaseClass(BlockID, Context),
-        GlobalAddressNamesAndInitializersInstalled(false) {}
+        GlobalDeclarationNamesAndInitializersInstalled(false) {}
 
   ~ModuleParser() override {}
 
 private:
-  // True if we have already instaledl names for unnamed global addresses,
-  // and generated global constant initializers.
-  bool GlobalAddressNamesAndInitializersInstalled;
+  // True if we have already installed names for unnamed global declarations,
+  // and have generated global constant initializers.
+  bool GlobalDeclarationNamesAndInitializersInstalled;
 
-  // 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.
-  void InstallGlobalAddressNamesAndInitializers() {
-    if (!GlobalAddressNamesAndInitializersInstalled) {
+  // Generates names for unnamed global addresses (i.e. functions and
+  // global variables). Then lowers global variable declaration
+  // initializers to the target. May be called multiple times. Only
+  // the first call will do the installation.
+  void InstallGlobalNamesAndGlobalVarInitializers() {
+    if (!GlobalDeclarationNamesAndInitializersInstalled) {
       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());
-          }
+        for (Ice::VariableDeclaration *Var : Context->getGlobalVariables()) {
+          installDeclarationName(Trans, Var, GlobalPrefix, "global", NameIndex);
         }
       }
-      Trans.nameUnnamedFunctions(Context->getModule());
-      getTranslator().lowerGlobals(Context->getGlobalIDAddresses());
-      GlobalAddressNamesAndInitializersInstalled = true;
+      const Ice::IceString &FunctionPrefix = getFlags().DefaultFunctionPrefix;
+      if (!FunctionPrefix.empty()) {
+        uint32_t NameIndex = 0;
+        for (Ice::FunctionDeclaration *Func :
+             Context->getFunctionDeclarationList()) {
+          installDeclarationName(Trans, Func, FunctionPrefix, "function",
+                                 NameIndex);
+        }
+      }
+      getTranslator().lowerGlobals(Context->getGlobalVariables());
+      GlobalDeclarationNamesAndInitializersInstalled = true;
+    }
+  }
+
+  void installDeclarationName(Ice::Translator &Trans,
+                              Ice::GlobalDeclaration *Decl,
+                              const Ice::IceString &Prefix, const char *Context,
+                              uint32_t &NameIndex) {
+    if (!Decl->hasName()) {
+      Decl->setName(Trans.createUnnamedName(Prefix, NameIndex));
+      ++NameIndex;
+    } else {
+      Trans.checkIfUnnamedNameSafe(Decl->getName(), Context, Prefix,
+                                   Trans.getContext()->getStrDump());
     }
   }
 
   bool ParseBlock(unsigned BlockID) override;
 
   void ExitBlock() override {
-    InstallGlobalAddressNamesAndInitializers();
+    InstallGlobalNamesAndGlobalVarInitializers();
     getTranslator().emitConstants();
   }
 
@@ -2400,26 +2443,8 @@
 };
 
 void ModuleValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
-  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;
-  }
-
-  std::string Buffer;
-  raw_string_ostream StrBuf(Buffer);
-  StrBuf << "Invalid global address ID in valuesymtab: " << Index;
-  Error(StrBuf.str());
-  return;
+  Context->getGlobalDeclarationByID(Index)
+      ->setName(StringRef(Name.data(), Name.size()));
 }
 
 void ModuleValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
@@ -2447,7 +2472,7 @@
     return Parser.ParseThisBlock();
   }
   case naclbitc::FUNCTION_BLOCK_ID: {
-    InstallGlobalAddressNamesAndInitializers();
+    InstallGlobalNamesAndGlobalVarInitializers();
     FunctionParser Parser(BlockID, this);
     return Parser.ParseThisBlock();
   }
@@ -2476,7 +2501,7 @@
     // FUNCTION:  [type, callingconv, isproto, linkage]
     if (!isValidRecordSize(4, "Function heading"))
       return;
-    const Ice::FuncSigType &Ty = Context->getFuncSigTypeByID(Values[0]);
+    const Ice::FuncSigType &Signature = Context->getFuncSigTypeByID(Values[0]);
     CallingConv::ID CallingConv;
     if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) {
       std::string Buffer;
@@ -2494,19 +2519,12 @@
       Error(StrBuf.str());
       return;
     }
-    SmallVector<Type *, 8> ArgTys;
-    for (Ice::Type ArgType : Ty.getArgList()) {
-      ArgTys.push_back(Context->convertToLLVMType(ArgType));
-    }
-    Function *Func = Function::Create(
-        FunctionType::get(Context->convertToLLVMType(Ty.getReturnType()),
-                          ArgTys, false),
-        Linkage, "", Context->getModule());
-    Func->setCallingConv(CallingConv);
+    Ice::FunctionDeclaration *Func = Ice::FunctionDeclaration::create(
+        getTranslator().getContext(), Signature, CallingConv, Linkage,
+        Values[2] == 0);
     if (Values[2] == 0)
       Context->setNextValueIDAsImplementedFunction();
     Context->setNextFunctionID(Func);
-    // TODO(kschimpf) verify if Func matches PNaCl ABI.
     return;
   }
   default: