Subzero: Add the "llvm2ice -ffunction-sections" argument.

The purpose is to enable bisection debugging of Subzero-translated functions, using objcopy to selectively splice functions from llc and Subzero into the binary.

Note that llvm-mc claims to take this argument, but actually does nothing with it, so we need to implement it in Subzero.

Also moves the ClFlags object into the GlobalContext so everyone can access it.

BUG= none
R=wala@chromium.org

Review URL: https://codereview.chromium.org/455633002
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index 3e32d75..49e9806 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -14,6 +14,7 @@
 
 #include "IceCfg.h"
 #include "IceCfgNode.h"
+#include "IceClFlags.h"
 #include "IceDefs.h"
 #include "IceInst.h"
 #include "IceLiveness.h"
@@ -300,8 +301,10 @@
         << "\n\n";
   }
   Str << "\t.text\n";
+  IceString MangledName = getContext()->mangleName(getFunctionName());
+  if (Ctx->getFlags().FunctionSections)
+    Str << "\t.section\t.text." << MangledName << "\n";
   if (!getInternal()) {
-    IceString MangledName = getContext()->mangleName(getFunctionName());
     Str << "\t.globl\t" << MangledName << "\n";
     Str << "\t.type\t" << MangledName << ",@function\n";
   }
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index 5f4f5aa..1554b1e 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -20,12 +20,15 @@
 public:
   ClFlags()
       : DisableInternal(false), SubzeroTimingEnabled(false),
-        DisableTranslation(false), DisableGlobals(false) {}
+        DisableTranslation(false), DisableGlobals(false),
+        FunctionSections(false) {}
   bool DisableInternal;
   bool SubzeroTimingEnabled;
   bool DisableTranslation;
   bool DisableGlobals;
+  bool FunctionSections;
 };
-}
+
+} // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICECLFLAGS_H
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index 106b809..65f8f66 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -676,12 +676,12 @@
   std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
 };
 
-} // end of anonymous namespace.
+} // end of anonymous namespace
 
 namespace Ice {
 
 void Converter::convertToIce(Module *Mod) {
-  if (!Flags.DisableGlobals)
+  if (!Ctx->getFlags().DisableGlobals)
     convertGlobals(Mod);
   convertFunctions(Mod);
 }
@@ -723,7 +723,8 @@
     }
 
     GlobalLowering->lower(Name, Align, IsInternal, IsConst, IsZeroInitializer,
-                          NumElements, Data, Flags.DisableTranslation);
+                          NumElements, Data,
+                          Ctx->getFlags().DisableTranslation);
   }
   GlobalLowering.reset();
 }
@@ -736,7 +737,7 @@
 
     Timer TConvert;
     Cfg *Fcn = FunctionConverter.convertFunction(I);
-    if (Flags.SubzeroTimingEnabled) {
+    if (Ctx->getFlags().SubzeroTimingEnabled) {
       std::cerr << "[Subzero timing] Convert function "
                 << Fcn->getFunctionName() << ": " << TConvert.getElapsedSec()
                 << " sec\n";
@@ -747,4 +748,4 @@
   emitConstants();
 }
 
-} // end of Ice namespace.
+} // end of namespace Ice
diff --git a/src/IceConverter.h b/src/IceConverter.h
index 30d3b60..bf81228 100644
--- a/src/IceConverter.h
+++ b/src/IceConverter.h
@@ -24,7 +24,7 @@
 
 class Converter : public Translator {
 public:
-  Converter(GlobalContext *Ctx, Ice::ClFlags &Flags) : Translator(Ctx, Flags) {}
+  Converter(GlobalContext *Ctx) : Translator(Ctx) {}
   /// Converts the LLVM Module to ICE. Sets exit status to false if successful,
   /// true otherwise.
   void convertToIce(llvm::Module *Mod);
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 5dd8b63..745f0d4 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -18,6 +18,7 @@
 #include "IceDefs.h"
 #include "IceTypes.h"
 #include "IceCfg.h"
+#include "IceClFlags.h"
 #include "IceGlobalContext.h"
 #include "IceOperand.h"
 #include "IceTargetLowering.h"
@@ -116,10 +117,10 @@
 GlobalContext::GlobalContext(llvm::raw_ostream *OsDump,
                              llvm::raw_ostream *OsEmit, VerboseMask Mask,
                              TargetArch Arch, OptLevel Opt,
-                             IceString TestPrefix)
+                             IceString TestPrefix, const ClFlags &Flags)
     : StrDump(OsDump), StrEmit(OsEmit), VMask(Mask),
       ConstPool(new ConstantPool()), Arch(Arch), Opt(Opt),
-      TestPrefix(TestPrefix), HasEmittedFirstMethod(false) {}
+      TestPrefix(TestPrefix), Flags(Flags), HasEmittedFirstMethod(false) {}
 
 // Scan a string for S[0-9A-Z]*_ patterns and replace them with
 // S<num>_ where <num> is the next base-36 value.  If a type name
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index e1b67ac..2acb8de 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -25,6 +25,8 @@
 
 namespace Ice {
 
+class ClFlags;
+
 // TODO: Accesses to all non-const fields of GlobalContext need to
 // be synchronized, especially the constant pool, the allocator, and
 // the output streams.
@@ -32,7 +34,7 @@
 public:
   GlobalContext(llvm::raw_ostream *OsDump, llvm::raw_ostream *OsEmit,
                 VerboseMask Mask, TargetArch Arch, OptLevel Opt,
-                IceString TestPrefix);
+                IceString TestPrefix, const ClFlags &Flags);
   ~GlobalContext();
 
   // Returns true if any of the specified options in the verbose mask
@@ -86,6 +88,8 @@
   // constants of a given type.
   ConstantList getConstantPool(Type Ty) const;
 
+  const ClFlags &getFlags() const { return Flags; }
+
   // Allocate data of type T using the global allocator.
   template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
 
@@ -102,6 +106,7 @@
   const TargetArch Arch;
   const OptLevel Opt;
   const IceString TestPrefix;
+  const ClFlags &Flags;
   bool HasEmittedFirstMethod;
   GlobalContext(const GlobalContext &) LLVM_DELETED_FUNCTION;
   GlobalContext &operator=(const GlobalContext &) LLVM_DELETED_FUNCTION;
diff --git a/src/IceIntrinsics.cpp b/src/IceIntrinsics.cpp
index b83513f..5b6ceac 100644
--- a/src/IceIntrinsics.cpp
+++ b/src/IceIntrinsics.cpp
@@ -179,7 +179,7 @@
   };
 const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable);
 
-} // end of namespace
+} // end of anonymous namespace
 
 Intrinsics::Intrinsics() {
   for (size_t I = 0; I < IceIntrinsicsTableSize; ++I) {
diff --git a/src/IceTranslator.cpp b/src/IceTranslator.cpp
index 4b84688..59403d2 100644
--- a/src/IceTranslator.cpp
+++ b/src/IceTranslator.cpp
@@ -26,14 +26,14 @@
 
 void Translator::translateFcn(Ice::Cfg *Fcn) {
   Func.reset(Fcn);
-  if (Flags.DisableInternal)
+  if (Ctx->getFlags().DisableInternal)
     Func->setInternal(false);
-  if (Flags.DisableTranslation) {
+  if (Ctx->getFlags().DisableTranslation) {
     Func->dump();
   } else {
     Ice::Timer TTranslate;
     Func->translate();
-    if (Flags.SubzeroTimingEnabled) {
+    if (Ctx->getFlags().SubzeroTimingEnabled) {
       std::cerr << "[Subzero timing] Translate function "
                 << Func->getFunctionName() << ": " << TTranslate.getElapsedSec()
                 << " sec\n";
@@ -45,7 +45,7 @@
 
     Ice::Timer TEmit;
     Func->emit();
-    if (Flags.SubzeroTimingEnabled) {
+    if (Ctx->getFlags().SubzeroTimingEnabled) {
       std::cerr << "[Subzero timing] Emit function " << Func->getFunctionName()
                 << ": " << TEmit.getElapsedSec() << " sec\n";
     }
@@ -53,6 +53,6 @@
 }
 
 void Translator::emitConstants() {
-  if (!Flags.DisableTranslation && Func)
+  if (!Ctx->getFlags().DisableTranslation && Func)
     Func->getTarget()->emitConstants();
 }
diff --git a/src/IceTranslator.h b/src/IceTranslator.h
index 1189951..51e4df0 100644
--- a/src/IceTranslator.h
+++ b/src/IceTranslator.h
@@ -29,15 +29,13 @@
 // machine instructions.
 class Translator {
 public:
-  Translator(GlobalContext *Ctx, ClFlags &Flags)
-      : Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
+  Translator(GlobalContext *Ctx) : Ctx(Ctx), ErrorStatus(0) {}
 
   ~Translator();
   bool getErrorStatus() const { return ErrorStatus; }
 
 protected:
   GlobalContext *Ctx;
-  ClFlags &Flags;
   // The exit status of the translation. False is successful. True
   // otherwise.
   bool ErrorStatus;
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index 7f9c514..0eb6d7c 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -801,7 +801,7 @@
   return Parser.ParseThisBlock();
 }
 
-} // end of anonymous namespace.
+} // end of anonymous namespace
 
 namespace Ice {
 
@@ -856,4 +856,4 @@
   return;
 }
 
-} // end of anonymous namespace.
+} // end of namespace Ice
diff --git a/src/PNaClTranslator.h b/src/PNaClTranslator.h
index a8ca06a..23f61cc 100644
--- a/src/PNaClTranslator.h
+++ b/src/PNaClTranslator.h
@@ -22,8 +22,7 @@
 
 class PNaClTranslator : public Translator {
 public:
-  PNaClTranslator(GlobalContext *Ctx, ClFlags &Flags)
-      : Translator(Ctx, Flags) {}
+  PNaClTranslator(GlobalContext *Ctx) : Translator(Ctx) {}
   // Reads the PNaCl bitcode file and translates to ICE, which is then
   // converted to machine code. Sets ErrorStatus to true if any
   // errors occurred.
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index dab13f0..5f421f4 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -59,6 +59,9 @@
         clEnumValN(Ice::Target_ARM32, "arm", "arm32"),
         clEnumValN(Ice::Target_ARM32, "arm32", "arm32 (same as arm)"),
         clEnumValN(Ice::Target_ARM64, "arm64", "arm64"), clEnumValEnd));
+static cl::opt<bool>
+    FunctionSections("ffunction-sections",
+                     cl::desc("Emit functions into separate sections"));
 static cl::opt<Ice::OptLevel>
 OptLevel(cl::desc("Optimization level"), cl::init(Ice::Opt_m1),
          cl::value_desc("level"),
@@ -126,16 +129,18 @@
   raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
   Ls->SetUnbuffered();
 
-  Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
-
   Ice::ClFlags Flags;
   Flags.DisableInternal = DisableInternal;
   Flags.SubzeroTimingEnabled = SubzeroTimingEnabled;
   Flags.DisableTranslation = DisableTranslation;
   Flags.DisableGlobals = DisableGlobals;
+  Flags.FunctionSections = FunctionSections;
+
+  Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
+                         Flags);
 
   if (BuildOnRead) {
-    Ice::PNaClTranslator Translator(&Ctx, Flags);
+    Ice::PNaClTranslator Translator(&Ctx);
     Translator.translate(IRFilename);
     return Translator.getErrorStatus();
   } else {
@@ -155,7 +160,7 @@
       return 1;
     }
 
-    Ice::Converter Converter(&Ctx, Flags);
+    Ice::Converter Converter(&Ctx);
     Converter.convertToIce(Mod);
     return Converter.getErrorStatus();
   }
diff --git a/tests_lit/llvm2ice_tests/mangle.ll b/tests_lit/llvm2ice_tests/mangle.ll
index 399ea2d..d486aad 100644
--- a/tests_lit/llvm2ice_tests/mangle.ll
+++ b/tests_lit/llvm2ice_tests/mangle.ll
@@ -1,11 +1,12 @@
 ; Tests the Subzero "name mangling" when using the "llvm2ice --prefix"
-; option.
+; option.  Also does a quick smoke test of -ffunction-sections.
 
-; RUN: %llvm2ice --verbose none %s | FileCheck %s
+; RUN: %llvm2ice --verbose none -ffunction-sections %s | FileCheck %s
 ; TODO: The following line causes this test to fail.
 ; RUIN: %llvm2ice --verbose none %s \
 ; RUIN:                | llvm-mc -arch=x86 -x86-asm-syntax=intel -filetype=obj
-; RUN: %llvm2ice --verbose none --prefix Subzero %s | FileCheck --check-prefix=MANGLE %s
+; RUN: %llvm2ice --verbose none --prefix Subzero -ffunction-sections %s \
+; RUN:                 | FileCheck --check-prefix=MANGLE %s
 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
@@ -16,15 +17,19 @@
   ret void
 }
 ; FuncC is a C symbol that isn't recognized as a C++ mangled symbol.
+; CHECK-LABEL: .text.FuncC
 ; CHECK: FuncC:
-; MANGLE: SubzeroFuncC
+; MANGLE-LABEL: .text.SubzeroFuncC
+; MANGLE: SubzeroFuncC:
 
 define internal void @_ZN13TestNamespace4FuncEi(i32 %i) {
 entry:
   ret void
 }
 ; This is Func(int) nested inside namespace TestNamespace.
+; CHECK-LABEL: .text._ZN13TestNamespace4FuncEi
 ; CHECK: _ZN13TestNamespace4FuncEi:
+; MANGLE-LABEL: .text._ZN7Subzero13TestNamespace4FuncEi
 ; MANGLE: _ZN7Subzero13TestNamespace4FuncEi:
 
 define internal void @_ZN13TestNamespace15NestedNamespace4FuncEi(i32 %i) {
@@ -32,7 +37,9 @@
   ret void
 }
 ; This is Func(int) nested inside two namespaces.
+; CHECK-LABEL: .text._ZN13TestNamespace15NestedNamespace4FuncEi
 ; CHECK: _ZN13TestNamespace15NestedNamespace4FuncEi:
+; MANGLE-LABEL: .text._ZN7Subzero13TestNamespace15NestedNamespace4FuncEi
 ; MANGLE: _ZN7Subzero13TestNamespace15NestedNamespace4FuncEi:
 
 define internal void @_Z13FuncCPlusPlusi(i32 %i) {
@@ -40,7 +47,9 @@
   ret void
 }
 ; This is a non-nested, mangled C++ symbol.
+; CHECK-LABEL: .text._Z13FuncCPlusPlusi
 ; CHECK: _Z13FuncCPlusPlusi:
+; MANGLE-LABEL: .text._ZN7Subzero13FuncCPlusPlusEi
 ; MANGLE: _ZN7Subzero13FuncCPlusPlusEi:
 
 define internal void @_ZN12_GLOBAL__N_18FuncAnonEi(i32 %i) {
@@ -48,7 +57,9 @@
   ret void
 }
 ; This is FuncAnon(int) nested inside an anonymous namespace.
+; CHECK-LABEL: .text._ZN12_GLOBAL__N_18FuncAnonEi
 ; CHECK: _ZN12_GLOBAL__N_18FuncAnonEi:
+; MANGLE-LABEL: .text._ZN7Subzero12_GLOBAL__N_18FuncAnonEi
 ; MANGLE: _ZN7Subzero12_GLOBAL__N_18FuncAnonEi:
 
 ; Now for the illegitimate examples.
@@ -58,6 +69,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text.Subzero_ZN
 ; MANGLE: Subzero_ZN:
 
 ; Test for _Z<len><str> where <len> is smaller than it should be.
@@ -65,6 +77,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text._ZN7Subzero12FuncCPlusPluEsi
 ; MANGLE: _ZN7Subzero12FuncCPlusPluEsi:
 
 ; Test for _Z<len><str> where <len> is slightly larger than it should be.
@@ -72,6 +85,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text._ZN7Subzero14FuncCPlusPlusiE
 ; MANGLE: _ZN7Subzero14FuncCPlusPlusiE:
 
 ; Test for _Z<len><str> where <len> is much larger than it should be.
@@ -79,6 +93,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text.Subzero_Z114FuncCPlusPlusi
 ; MANGLE: Subzero_Z114FuncCPlusPlusi:
 
 ; Test for _Z<len><str> where we try to overflow the uint32_t holding <len>.
@@ -86,6 +101,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text.Subzero_Z4294967296FuncCPlusPlusi
 ; MANGLE: Subzero_Z4294967296FuncCPlusPlusi:
 
 ; Test for _Z<len><str> where <len> is 0.
@@ -93,6 +109,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text._ZN7Subzero0EFuncCPlusPlusi
 ; MANGLE: _ZN7Subzero0EFuncCPlusPlusi:
 
 ; Test for _Z<len><str> where <len> is -1.  LLVM explicitly allows the
@@ -102,6 +119,7 @@
 entry:
   ret void
 }
+; MANGLE-LABEL: .text.Subzero_Z-1FuncCPlusPlusi
 ; MANGLE: Subzero_Z-1FuncCPlusPlusi:
 
 
@@ -115,14 +133,16 @@
 ;     (to test parser edge cases)
 
 define internal void @_Z3fooP10MyClassS1xP10MyClassS2xRS_RS1_S_S1_SZZZ_SZ9ZZ_S12345() {
-; MANGLE:   _ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345:
+; MANGLE-LABEL: .text._ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345
+; MANGLE: _ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345:
 entry:
   ret void
 }
 
 ; Test that unmangled (non-C++) strings don't have substitutions updated.
 define internal void @foo_S_S0_SZ_S() {
-; MANGLE:   Subzerofoo_S_S0_SZ_S:
+; MANGLE-LABEL: .text.Subzerofoo_S_S0_SZ_S
+; MANGLE: Subzerofoo_S_S0_SZ_S:
 entry:
   ret void
 }