Fix a bug that would cause subzero to fail when --threads=0.

Creates a single TargetDataLowering.

BUG= None
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1179313004.
diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp
index dec40e4..aeb54ff 100644
--- a/src/IceCfgNode.cpp
+++ b/src/IceCfgNode.cpp
@@ -1256,7 +1256,10 @@
   assert(Info != nullptr);
 
   Operand *RMWI64Name = Context->getConstantExternSym(RMW_I64);
-  Constant *Counter = Context->getConstantExternSym(Var->getName());
+  constexpr RelocOffsetT Offset = 0;
+  constexpr bool SuppressMangling = true;
+  Constant *Counter =
+      Context->getConstantSym(Offset, Var->getName(), SuppressMangling);
   Constant *AtomicRMWOp = Context->getConstantInt32(Intrinsics::AtomicAdd);
   Constant *One = Context->getConstantInt64(1);
   Constant *OrderAcquireRelease =
diff --git a/src/IceCompiler.cpp b/src/IceCompiler.cpp
index 2db7abc..7619b17 100644
--- a/src/IceCompiler.cpp
+++ b/src/IceCompiler.cpp
@@ -141,21 +141,28 @@
   }
 
   Ctx.waitForWorkerThreads();
-  Translator->transferErrorCode();
-  Translator->emitConstants();
+  if (Translator->getErrorStatus()) {
+    Ctx.getErrorStatus()->assign(Translator->getErrorStatus().value());
+  } else {
+    Ctx.lowerGlobals("last");
+    Ctx.lowerProfileData();
+    Ctx.lowerConstants();
 
-  if (Ctx.getFlags().getOutFileType() == FT_Elf) {
-    TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
-    Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
-    Ctx.getObjectWriter()->writeNonUserSections();
+    if (Ctx.getFlags().getOutFileType() == FT_Elf) {
+      TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
+      Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
+      Ctx.getObjectWriter()->writeNonUserSections();
+    }
   }
+
   if (Ctx.getFlags().getSubzeroTimingEnabled())
     Ctx.dumpTimers();
+
   if (Ctx.getFlags().getTimeEachFunction()) {
     const bool DumpCumulative = false;
     Ctx.dumpTimers(GlobalContext::TSK_Funcs, DumpCumulative);
   }
-  const bool FinalStats = true;
+  constexpr bool FinalStats = true;
   Ctx.dumpStats("_FINAL_", FinalStats);
 }
 
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index edb46fa..44f4adb 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -285,7 +285,8 @@
 } // end of anonymous namespace
 
 void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
-                                       FixupKind RelocationKind) {
+                                       FixupKind RelocationKind,
+                                       const IceString &SectionSuffix) {
   assert(!SectionNumbersAssigned);
   VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
   for (auto &SectionList : VarsBySection)
@@ -294,18 +295,28 @@
                             Ctx.getFlags().getTranslateOnly());
   size_t I = 0;
   for (auto &SectionList : VarsBySection) {
-    writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind);
+    writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
+                    SectionSuffix);
   }
 }
 
+namespace {
+IceString MangleSectionName(const char Base[], const IceString &Suffix) {
+  if (Suffix.empty())
+    return Base;
+  return Base + ("." + Suffix);
+}
+} // end of anonymous namespace
+
+// TODO(jvoung): Handle fdata-sections.
 void ELFObjectWriter::writeDataOfType(SectionType ST,
                                       const VariableDeclarationList &Vars,
-                                      FixupKind RelocationKind) {
+                                      FixupKind RelocationKind,
+                                      const IceString &SectionSuffix) {
   if (Vars.empty())
     return;
   ELFDataSection *Section;
   ELFRelocationSection *RelSection;
-  // TODO(jvoung): Handle fdata-sections.
   IceString SectionName;
   Elf64_Xword ShAddralign = 1;
   for (VariableDeclaration *Var : Vars) {
@@ -316,9 +327,7 @@
   // Lift this out, so it can be re-used if we do fdata-sections?
   switch (ST) {
   case ROData: {
-    SectionName = ".rodata";
-    // Only expecting to write the data sections all in one shot for now.
-    assert(RODataSections.empty());
+    const IceString SectionName = MangleSectionName(".rodata", SectionSuffix);
     const Elf64_Xword ShFlags = SHF_ALLOC;
     Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
                                             ShAddralign, ShEntsize);
@@ -329,8 +338,7 @@
     break;
   }
   case Data: {
-    SectionName = ".data";
-    assert(DataSections.empty());
+    const IceString SectionName = MangleSectionName(".data", SectionSuffix);
     const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
     Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
                                             ShAddralign, ShEntsize);
@@ -341,8 +349,7 @@
     break;
   }
   case BSS: {
-    SectionName = ".bss";
-    assert(BSSSections.empty());
+    const IceString SectionName = MangleSectionName(".bss", SectionSuffix);
     const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
     Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
                                             ShAddralign, ShEntsize);
@@ -383,9 +390,8 @@
       for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
         switch (Init->getKind()) {
         case VariableDeclaration::Initializer::DataInitializerKind: {
-          const auto Data =
-              llvm::cast<VariableDeclaration::DataInitializer>(Init)
-                  ->getContents();
+          const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
+                                Init)->getContents();
           Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
           break;
         }
diff --git a/src/IceELFObjectWriter.h b/src/IceELFObjectWriter.h
index 1103845..a9127ac 100644
--- a/src/IceELFObjectWriter.h
+++ b/src/IceELFObjectWriter.h
@@ -30,11 +30,12 @@
 // sections and write them out.  Expected usage:
 //
 // (1) writeInitialELFHeader (invoke once)
-// (2) writeDataSection  (invoke once)
-// (3) writeFunctionCode (must invoke once per function)
-// (4) writeConstantPool (must invoke once per pooled primitive type)
-// (5) setUndefinedSyms (invoke once)
-// (6) writeNonUserSections (invoke once)
+// (2) writeDataSection      (may be invoked multiple times, as long as
+//                            SectionSuffix is unique)
+// (3) writeFunctionCode     (must invoke once per function)
+// (4) writeConstantPool     (must invoke once per pooled primitive type)
+// (5) setUndefinedSyms      (invoke once)
+// (6) writeNonUserSections  (invoke once)
 //
 // The requirement for writeDataSection to be invoked only once can
 // be relaxed if using -fdata-sections. The requirement to invoke only once
@@ -42,11 +43,6 @@
 // SectionType are contiguous in the file. With -fdata-sections, each global
 // variable is in a separate section and therefore the sections will be
 // trivially contiguous.
-//
-// The motivation for requiring that writeFunctionCode happen after
-// writeDataSection: to keep the .text and .data sections contiguous in the
-// file. Having both -fdata-sections and -ffunction-sections does allow
-// relaxing this requirement.
 class ELFObjectWriter {
   ELFObjectWriter() = delete;
   ELFObjectWriter(const ELFObjectWriter &) = delete;
@@ -64,7 +60,8 @@
   // of each global's definition in the symbol table.
   // Use the given target's RelocationKind for any relocations.
   void writeDataSection(const VariableDeclarationList &Vars,
-                        FixupKind RelocationKind);
+                        FixupKind RelocationKind,
+                        const IceString &SectionSuffix);
 
   // Copy data of a function's text section to file and note the offset of the
   // symbol's definition in the symbol table.
@@ -151,7 +148,8 @@
   // SectionType, given the global variables Vars belonging to that SectionType.
   void writeDataOfType(SectionType SectionType,
                        const VariableDeclarationList &Vars,
-                       FixupKind RelocationKind);
+                       FixupKind RelocationKind,
+                       const IceString &SectionSuffix);
 
   // Write the final relocation sections given the final symbol table.
   // May also be able to seek around the file and resolve function calls
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 8ed4d76..b23e75b 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -222,7 +222,10 @@
       OptQ(/*Sequential=*/Flags.isSequential(),
            /*MaxSize=*/Flags.getNumTranslationThreads()),
       // EmitQ is allowed unlimited size.
-      EmitQ(/*Sequential=*/Flags.isSequential()) {
+      EmitQ(/*Sequential=*/Flags.isSequential()),
+      DataLowering(TargetDataLowering::createLowering(this)),
+      HasSeenCode(false),
+      ProfileBlockInfoVarDecl(VariableDeclaration::create()) {
   assert(OsDump && "OsDump is not defined for GlobalContext");
   assert(OsEmit && "OsEmit is not defined for GlobalContext");
   assert(OsError && "OsError is not defined for GlobalContext");
@@ -254,6 +257,14 @@
   case FT_Iasm:
     break;
   }
+  ProfileBlockInfoVarDecl->setAlignment(typeWidthInBytes(IceType_i64));
+  ProfileBlockInfoVarDecl->setIsConstant(true);
+
+  // Note: if you change this symbol, make sure to update
+  // runtime/szrt_profiler.c as well.
+  ProfileBlockInfoVarDecl->setName("__Sz_block_profile_info");
+  ProfileBlockInfoVarDecl->setSuppressMangling();
+  ProfileBlockInfoVarDecl->setLinkage(llvm::GlobalValue::ExternalLinkage);
 }
 
 void GlobalContext::translateFunctions() {
@@ -322,67 +333,16 @@
 
 namespace {
 
-// Adds an array of pointers to all the profiler-generated globals. The
-// __Sz_profile_summary function iterates over this array for printing the
-// profiling counters.
-VariableDeclaration *blockProfileInfo(const VariableDeclarationList &Globals) {
-  auto *Var = VariableDeclaration::create();
-  Var->setAlignment(typeWidthInBytes(IceType_i64));
-  Var->setIsConstant(true);
-
-  // Note: if you change this symbol, make sure to update
-  // runtime/szrt_profiler.c as well.
-  Var->setName("__Sz_block_profile_info");
-  Var->setSuppressMangling();
-  Var->setLinkage(llvm::GlobalValue::ExternalLinkage);
+void addBlockInfoPtrs(const VariableDeclarationList &Globals,
+                      VariableDeclaration *ProfileBlockInfo) {
   for (const VariableDeclaration *Global : Globals) {
     if (Cfg::isProfileGlobal(*Global)) {
       constexpr RelocOffsetT BlockExecutionCounterOffset = 0;
-      Var->addInitializer(new VariableDeclaration::RelocInitializer(
-          Global, BlockExecutionCounterOffset));
+      ProfileBlockInfo->addInitializer(
+          new VariableDeclaration::RelocInitializer(
+              Global, BlockExecutionCounterOffset));
     }
   }
-
-  // This adds a 64-bit sentinel entry to the end of our array. For 32-bit
-  // architectures this will waste 4 bytes.
-  const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
-  Var->addInitializer(
-      new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr));
-
-  return Var;
-}
-
-void addBlockProfileInfoArrayToGlobals(VariableDeclarationList *Globals) {
-  // Purposefully create the Var temp to prevent bugs in case the compiler
-  // reorders instructions in a way that Globals is extended before the call
-  // to profileInfoArray.
-  VariableDeclaration *Var = blockProfileInfo(*Globals);
-  Globals->push_back(Var);
-}
-
-void lowerGlobals(GlobalContext *Ctx,
-                  std::unique_ptr<VariableDeclarationList> VariableDeclarations,
-                  TargetDataLowering *DataLowering) {
-  TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
-  const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() &&
-                                   Ctx->getFlags().getVerboseFocusOn().empty();
-  if (DumpGlobalVariables) {
-    OstreamLocker L(Ctx);
-    Ostream &Stream = Ctx->getStrDump();
-    for (const Ice::VariableDeclaration *Global : *VariableDeclarations) {
-      Global->dump(Ctx, Stream);
-    }
-  }
-  if (Ctx->getFlags().getDisableTranslation())
-    return;
-
-  // There should be no need to emit the block_profile_info array if profiling
-  // is disabled. In practice, given that szrt_profiler.o will always be
-  // embedded in the application, we need to add it. In a non-profiled build
-  // this array will only contain the nullptr terminator.
-  addBlockProfileInfoArrayToGlobals(VariableDeclarations.get());
-
-  DataLowering->lowerGlobals(std::move(VariableDeclarations));
 }
 
 // Ensure Pending is large enough that Pending[Index] is valid.
@@ -391,13 +351,6 @@
     Pending.resize(Index + 1);
 }
 
-void addAllIfNotNull(std::unique_ptr<VariableDeclarationList> src,
-                     VariableDeclarationList *dst) {
-  if (src != nullptr) {
-    dst->insert(dst->end(), src->begin(), src->end());
-  }
-}
-
 } // end of anonymous namespace
 
 void GlobalContext::emitFileHeader() {
@@ -411,6 +364,40 @@
   }
 }
 
+void GlobalContext::lowerConstants() {
+  DataLowering->lowerConstants();
+}
+
+void GlobalContext::lowerGlobals(const IceString &SectionSuffix) {
+  TimerMarker T(TimerStack::TT_emitGlobalInitializers, this);
+  const bool DumpGlobalVariables =
+      ALLOW_DUMP && Flags.getVerbose() && Flags.getVerboseFocusOn().empty();
+  if (DumpGlobalVariables) {
+    OstreamLocker L(this);
+    Ostream &Stream = getStrDump();
+    for (const Ice::VariableDeclaration *Global : Globals) {
+      Global->dump(this, Stream);
+    }
+  }
+  if (Flags.getDisableTranslation())
+    return;
+
+  addBlockInfoPtrs(Globals, ProfileBlockInfoVarDecl.get());
+  DataLowering->lowerGlobals(Globals, SectionSuffix);
+  Globals.clear();
+}
+
+void GlobalContext::lowerProfileData() {
+  // This adds a 64-bit sentinel entry to the end of our array. For 32-bit
+  // architectures this will waste 4 bytes.
+  const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
+  ProfileBlockInfoVarDecl->addInitializer(
+      new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr));
+  Globals.push_back(ProfileBlockInfoVarDecl.get());
+  constexpr char ProfileDataSection[] = "$sz_profiler$";
+  lowerGlobals(ProfileDataSection);
+}
+
 void GlobalContext::emitItems() {
   const bool Threaded = !getFlags().isSequential();
   // Pending is a vector containing the reassembled, ordered list of
@@ -419,8 +406,6 @@
   // the work queue, and if it's not the item we're waiting for, we
   // insert it into Pending and repeat.  The work item is deleted
   // after it is processed.
-  std::unique_ptr<VariableDeclarationList> GlobalInits(
-      new VariableDeclarationList());
   std::vector<EmitterWorkItem *> Pending;
   uint32_t DesiredSequenceNumber = getFirstSequenceNumber();
   while (true) {
@@ -444,10 +429,12 @@
     case EmitterWorkItem::WI_Nop:
       break;
     case EmitterWorkItem::WI_GlobalInits: {
-      addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
+      accumulateGlobals(Item->getGlobalInits());
     } break;
     case EmitterWorkItem::WI_Asm: {
-      addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
+      lowerGlobalsIfNoCodeHasBeenSeen();
+      accumulateGlobals(Item->getGlobalInits());
+
       std::unique_ptr<Assembler> Asm = Item->getAsm();
       Asm->alignFunction();
       IceString MangledName = mangleName(Asm->getFunctionName());
@@ -469,8 +456,8 @@
     case EmitterWorkItem::WI_Cfg: {
       if (!ALLOW_DUMP)
         llvm::report_fatal_error("WI_Cfg work item created inappropriately");
-
-      addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
+      lowerGlobalsIfNoCodeHasBeenSeen();
+      accumulateGlobals(Item->getGlobalInits());
 
       assert(getFlags().getOutFileType() == FT_Asm);
       std::unique_ptr<Cfg> Func = Item->getCfg();
@@ -485,8 +472,9 @@
     }
   }
 
-  lowerGlobals(this, std::move(GlobalInits),
-               TargetDataLowering::createLowering(this).get());
+  // In case there are no code to be generated, we invoke the conditional
+  // lowerGlobals again -- this is a no-op if code has been emitted.
+  lowerGlobalsIfNoCodeHasBeenSeen();
 }
 
 // Scan a string for S[0-9A-Z]*_ patterns and replace them with
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 763a75b..ff8ff25 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -303,6 +303,8 @@
   // Emit file header for output file.
   void emitFileHeader();
 
+  void lowerConstants();
+
   void emitQueueBlockingPush(EmitterWorkItem *Item);
   EmitterWorkItem *emitQueueBlockingPop();
   void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
@@ -380,6 +382,13 @@
   // until the queue is empty.
   void emitItems();
 
+  // Uses DataLowering to lower Globals. As a side effect, clears the Globals
+  // array.
+  void lowerGlobals(const IceString &SectionSuffix);
+
+  // Lowers the profile information.
+  void lowerProfileData();
+
   // Utility function to match a symbol name against a match string.
   // This is used in a few cases where we want to take some action on
   // a particular function or symbol based on a command-line argument,
@@ -432,9 +441,22 @@
   Intrinsics IntrinsicsInfo;
   const ClFlags &Flags;
   RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg.
+  // TODO(jpp): move to EmitterContext.
   std::unique_ptr<ELFObjectWriter> ObjectWriter;
   BoundedProducerConsumerQueue<Cfg> OptQ;
   BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ;
+  // DataLowering is only ever used by a single thread at a time (either in
+  // emitItems(), or in IceCompiler::run before the compilation is over.)
+  // TODO(jpp): move to EmitterContext.
+  std::unique_ptr<TargetDataLowering> DataLowering;
+  // If !HasEmittedCode, SubZero will accumulate all Globals (which are "true"
+  // program global variables) until the first code WorkItem is seen.
+  // TODO(jpp): move to EmitterContext.
+  bool HasSeenCode;
+  // TODO(jpp): move to EmitterContext.
+  VariableDeclarationList Globals;
+  // TODO(jpp): move to EmitterContext.
+  std::unique_ptr<VariableDeclaration> ProfileBlockInfoVarDecl;
 
   LockedPtr<ArenaAllocator<>> getAllocator() {
     return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock);
@@ -449,6 +471,19 @@
     return LockedPtr<TimerList>(&Timers, &TimerLock);
   }
 
+  void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
+    if (Globls != nullptr)
+      Globals.insert(Globals.end(), Globls->begin(), Globls->end());
+  }
+
+  void lowerGlobalsIfNoCodeHasBeenSeen() {
+    if (HasSeenCode)
+      return;
+    constexpr char NoSuffix[] = "";
+    lowerGlobals(NoSuffix);
+    HasSeenCode = true;
+  }
+
   llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
   llvm::SmallVector<std::thread, 128> TranslationThreads;
   llvm::SmallVector<std::thread, 128> EmitterThreads;
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 4bb035a..52017ea 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -446,40 +446,63 @@
 
 TargetDataLowering::~TargetDataLowering() {}
 
-void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
+namespace {
+
+// dataSectionSuffix decides whether to use SectionSuffix or MangledVarName as
+// data section suffix. Essentially, when using separate data sections for
+// globals SectionSuffix is not necessary.
+IceString dataSectionSuffix(const IceString &SectionSuffix,
+                            const IceString &MangledVarName,
+                            const bool DataSections) {
+  if (SectionSuffix.empty() && !DataSections) {
+    return "";
+  }
+
+  if (DataSections) {
+    // With data sections we don't need to use the SectionSuffix.
+    return "." + MangledVarName;
+  }
+
+  assert(!SectionSuffix.empty());
+  return "." + SectionSuffix;
+}
+
+} // end of anonymous namespace
+
+void TargetDataLowering::emitGlobal(const VariableDeclaration &Var,
+                                    const IceString &SectionSuffix) {
   if (!ALLOW_DUMP)
     return;
 
   // If external and not initialized, this must be a cross test.
   // Don't generate a declaration for such cases.
-  bool IsExternal = Var.isExternal() || Ctx->getFlags().getDisableInternal();
+  const bool IsExternal =
+      Var.isExternal() || Ctx->getFlags().getDisableInternal();
   if (IsExternal && !Var.hasInitializer())
     return;
 
   Ostream &Str = Ctx->getStrEmit();
-  const VariableDeclaration::InitializerListType &Initializers =
-      Var.getInitializers();
-  bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
-  bool IsConstant = Var.getIsConstant();
-  uint32_t Align = Var.getAlignment();
-  SizeT Size = Var.getNumBytes();
-  IceString MangledName = Var.mangleName(Ctx);
-  IceString SectionSuffix = "";
-  if (Ctx->getFlags().getDataSections())
-    SectionSuffix = "." + MangledName;
+  const bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
+  const bool IsConstant = Var.getIsConstant();
+  const SizeT Size = Var.getNumBytes();
+  const IceString MangledName = Var.mangleName(Ctx);
 
   Str << "\t.type\t" << MangledName << ",%object\n";
 
+  const bool UseDataSections = Ctx->getFlags().getDataSections();
+  const IceString Suffix =
+      dataSectionSuffix(SectionSuffix, MangledName, UseDataSections);
   if (IsConstant)
-    Str << "\t.section\t.rodata" << SectionSuffix << ",\"a\",%progbits\n";
+    Str << "\t.section\t.rodata" << Suffix << ",\"a\",%progbits\n";
   else if (HasNonzeroInitializer)
-    Str << "\t.section\t.data" << SectionSuffix << ",\"aw\",%progbits\n";
+    Str << "\t.section\t.data" << Suffix << ",\"aw\",%progbits\n";
   else
-    Str << "\t.section\t.bss" << SectionSuffix << ",\"aw\",%nobits\n";
+    Str << "\t.section\t.bss" << Suffix << ",\"aw\",%nobits\n";
 
   if (IsExternal)
     Str << "\t.globl\t" << MangledName << "\n";
 
+  const uint32_t Align = Var.getAlignment();
   if (Align > 1) {
     assert(llvm::isPowerOf2_32(Align));
     // Use the .p2align directive, since the .align N directive can either
@@ -490,11 +513,11 @@
   Str << MangledName << ":\n";
 
   if (HasNonzeroInitializer) {
-    for (VariableDeclaration::Initializer *Init : Initializers) {
+    for (VariableDeclaration::Initializer *Init : Var.getInitializers()) {
       switch (Init->getKind()) {
       case VariableDeclaration::Initializer::DataInitializerKind: {
-        const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(Init)
-                              ->getContents();
+        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";
         }
@@ -504,7 +527,7 @@
         Str << "\t.zero\t" << Init->getNumBytes() << "\n";
         break;
       case VariableDeclaration::Initializer::RelocInitializerKind: {
-        const auto Reloc =
+        const auto *Reloc =
             llvm::cast<VariableDeclaration::RelocInitializer>(Init);
         Str << "\t" << getEmit32Directive() << "\t";
         Str << Reloc->getDeclaration()->mangleName(Ctx);
@@ -519,12 +542,13 @@
       }
       }
     }
-  } else
+  } else {
     // NOTE: for non-constant zero initializers, this is BSS (no bits),
     // so an ELF writer would not write to the file, and only track
     // virtual offsets, but the .s writer still needs this .zero and
     // cannot simply use the .size to advance offsets.
     Str << "\t.zero\t" << Size << "\n";
+  }
 
   Str << "\t.size\t" << MangledName << ", " << Size << "\n";
 }
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 4d9598a..fa6f5b7 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -380,16 +380,18 @@
   static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx);
   virtual ~TargetDataLowering();
 
-  virtual void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) = 0;
+  virtual void lowerGlobals(const VariableDeclarationList &Vars,
+                            const IceString &SectionSuffix) = 0;
   virtual void lowerConstants() = 0;
 
 protected:
-  void emitGlobal(const VariableDeclaration &Var);
+  void emitGlobal(const VariableDeclaration &Var,
+                  const IceString &SectionSuffix);
 
   // For now, we assume .long is the right directive for emitting 4 byte
   // emit global relocations. However, LLVM MIPS usually uses .4byte instead.
   // Perhaps there is some difference when the location is unaligned.
-  const char *getEmit32Directive() { return ".long"; }
+  static const char *getEmit32Directive() { return ".long"; }
 
   explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
   GlobalContext *Ctx;
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 2d3c5c1..9bb2386 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -2207,20 +2207,20 @@
 TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
     : TargetDataLowering(Ctx) {}
 
-void TargetDataARM32::lowerGlobals(
-    std::unique_ptr<VariableDeclarationList> Vars) {
+void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
+                                   const IceString &SectionSuffix) {
   switch (Ctx->getFlags().getOutFileType()) {
   case FT_Elf: {
     ELFObjectWriter *Writer = Ctx->getObjectWriter();
-    Writer->writeDataSection(*Vars, llvm::ELF::R_ARM_ABS32);
+    Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix);
   } break;
   case FT_Asm:
   case FT_Iasm: {
     const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
     OstreamLocker L(Ctx);
-    for (const VariableDeclaration *Var : *Vars) {
+    for (const VariableDeclaration *Var : Vars) {
       if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
-        emitGlobal(*Var);
+        emitGlobal(*Var, SectionSuffix);
       }
     }
   } break;
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index 98dd20e..1fa3ce2 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -323,7 +323,8 @@
     return std::unique_ptr<TargetDataLowering>(new TargetDataARM32(Ctx));
   }
 
-  void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
+  void lowerGlobals(const VariableDeclarationList &Vars,
+                    const IceString &SectionSuffix) override;
   void lowerConstants() override;
 
 protected:
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index ee2300e..3655cb7 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -671,20 +671,20 @@
 TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx)
     : TargetDataLowering(Ctx) {}
 
-void TargetDataMIPS32::lowerGlobals(
-    std::unique_ptr<VariableDeclarationList> Vars) {
+void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
+                                    const IceString &SectionSuffix) {
   switch (Ctx->getFlags().getOutFileType()) {
   case FT_Elf: {
     ELFObjectWriter *Writer = Ctx->getObjectWriter();
-    Writer->writeDataSection(*Vars, llvm::ELF::R_MIPS_GLOB_DAT);
+    Writer->writeDataSection(Vars, llvm::ELF::R_MIPS_GLOB_DAT, SectionSuffix);
   } break;
   case FT_Asm:
   case FT_Iasm: {
     const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
     OstreamLocker L(Ctx);
-    for (const VariableDeclaration *Var : *Vars) {
+    for (const VariableDeclaration *Var : Vars) {
       if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
-        emitGlobal(*Var);
+        emitGlobal(*Var, SectionSuffix);
       }
     }
   } break;
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 9204833..cb89ffc 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -137,7 +137,8 @@
     return std::unique_ptr<TargetDataLowering>(new TargetDataMIPS32(Ctx));
   }
 
-  void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
+  void lowerGlobals(const VariableDeclarationList &Vars,
+                    const IceString &SectionSuffix) override;
   void lowerConstants() override;
 
 protected:
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index b686579..c57374b 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -3296,11 +3296,10 @@
       Func->setError("Unexpected memory ordering for AtomicRMW");
       return;
     }
-    lowerAtomicRMW(
-        Instr->getDest(),
-        static_cast<uint32_t>(
-            llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
-        Instr->getArg(1), Instr->getArg(2));
+    lowerAtomicRMW(Instr->getDest(),
+                   static_cast<uint32_t>(llvm::cast<ConstantInteger32>(
+                                             Instr->getArg(0))->getValue()),
+                   Instr->getArg(1), Instr->getArg(2));
     return;
   case Intrinsics::AtomicStore: {
     if (!Intrinsics::isMemoryOrderValid(
@@ -5021,20 +5020,20 @@
 TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
     : TargetDataLowering(Ctx) {}
 
-void TargetDataX8632::lowerGlobals(
-    std::unique_ptr<VariableDeclarationList> Vars) {
+void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
+                                   const IceString &SectionSuffix) {
   switch (Ctx->getFlags().getOutFileType()) {
   case FT_Elf: {
     ELFObjectWriter *Writer = Ctx->getObjectWriter();
-    Writer->writeDataSection(*Vars, llvm::ELF::R_386_32);
+    Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix);
   } break;
   case FT_Asm:
   case FT_Iasm: {
     const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
     OstreamLocker L(Ctx);
-    for (const VariableDeclaration *Var : *Vars) {
+    for (const VariableDeclaration *Var : Vars) {
       if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
-        emitGlobal(*Var);
+        emitGlobal(*Var, SectionSuffix);
       }
     }
   } break;
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 0b46e1b..b9a9e2b 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -587,7 +587,8 @@
     return std::unique_ptr<TargetDataLowering>(new TargetDataX8632(Ctx));
   }
 
-  void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
+  void lowerGlobals(const VariableDeclarationList &Vars,
+                    const IceString &SectionSuffix) override;
   void lowerConstants() override;
 
 protected:
diff --git a/src/IceTranslator.cpp b/src/IceTranslator.cpp
index c78bbcb..aba71e5 100644
--- a/src/IceTranslator.cpp
+++ b/src/IceTranslator.cpp
@@ -57,16 +57,6 @@
   Ctx->optQueueBlockingPush(std::move(Func));
 }
 
-void Translator::emitConstants() {
-  if (!getErrorStatus())
-    TargetDataLowering::createLowering(Ctx)->lowerConstants();
-}
-
-void Translator::transferErrorCode() const {
-  if (getErrorStatus())
-    Ctx->getErrorStatus()->assign(getErrorStatus().value());
-}
-
 void Translator::lowerGlobals(
     std::unique_ptr<VariableDeclarationList> VariableDeclarations) {
   EmitterWorkItem *Item = new EmitterWorkItem(getNextSequenceNumber(),
diff --git a/src/IceTranslator.h b/src/IceTranslator.h
index adddc32..0f7f9d7 100644
--- a/src/IceTranslator.h
+++ b/src/IceTranslator.h
@@ -48,13 +48,6 @@
   /// Takes ownership of Func.
   void translateFcn(std::unique_ptr<Cfg> Func);
 
-  /// Emits the constant pool.
-  void emitConstants();
-
-  /// If there was an error during bitcode reading/parsing, copy the
-  /// error code into the GlobalContext.
-  void transferErrorCode() const;
-
   /// Lowers the given list of global addresses to target. Generates
   /// list of corresponding variable declarations.
   void
diff --git a/tests_lit/llvm2ice_tests/elf_container.ll b/tests_lit/llvm2ice_tests/elf_container.ll
index 4c663cf..f95ed2a 100644
--- a/tests_lit/llvm2ice_tests/elf_container.ll
+++ b/tests_lit/llvm2ice_tests/elf_container.ll
@@ -270,8 +270,7 @@
 ; CHECK:     ]
 ; CHECK:     Address: 0x0
 ; CHECK:     Offset: 0x{{[1-9A-F][0-9A-F]*}}
-; Size is 56 instead of 48 due to __Sz_block_profile_info .
-; CHECK:     Size: 56
+; CHECK:     Size: 48
 ; CHECK:     Link: 0
 ; CHECK:     Info: 0
 ; CHECK:     AddressAlignment: 32