Subzero: Improve debugging controls, plus minor refactoring.

1. Decorate the list of live-in and live-out variables with register assignments in the dump() output.  This helps one to assess register pressure.

2. Fix a bug where the DisableInternal flag wasn't being honored for function definitions.

3. Add a -translate-only=<symbol> to limit translation to a single function or global variable.  This makes it easier to focus on debugging a single function.

4. Change the -no-phi-edge-split option to -phi-edge-split and invert the meaning, to better not avoid the non double negatives.

BUG= none
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/673783002
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index cc77908..ed962d1 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -65,17 +65,12 @@
 void Cfg::translate() {
   if (hasError())
     return;
-  VerboseMask OldVerboseMask = getContext()->getVerbose();
   const IceString &TimingFocusOn = getContext()->getFlags().TimingFocusOn;
   if (TimingFocusOn == "*" || TimingFocusOn == getFunctionName()) {
     setFocusedTiming();
     getContext()->resetTimer(GlobalContext::TSK_Default);
     getContext()->setTimerName(GlobalContext::TSK_Default, getFunctionName());
   }
-  bool VerboseFocus =
-      (getContext()->getFlags().VerboseFocusOn == getFunctionName());
-  if (VerboseFocus)
-    getContext()->setVerbose(IceV_All);
   TimerMarker T(TimerStack::TT_translate, this);
 
   dump("Initial CFG");
@@ -87,8 +82,6 @@
   dump("Final output");
   if (getFocusedTiming())
     getContext()->dumpTimers();
-  if (VerboseFocus)
-    getContext()->setVerbose(OldVerboseMask);
 }
 
 void Cfg::computePredecessors() {
@@ -150,9 +143,6 @@
 void Cfg::genFrame() {
   TimerMarker T(TimerStack::TT_genFrame, this);
   getTarget()->addProlog(Entry);
-  // TODO: Consider folding epilog generation into the final
-  // emission/assembly pass to avoid an extra iteration over the node
-  // list.  Or keep a separate list of exit nodes.
   for (CfgNode *Node : Nodes)
     if (Node->getHasReturn())
       getTarget()->addEpilog(Node);
@@ -323,7 +313,7 @@
   IceString MangledName = getContext()->mangleName(getFunctionName());
   if (Ctx->getFlags().FunctionSections)
     Str << "\t.section\t.text." << MangledName << ",\"ax\",@progbits\n";
-  if (!getInternal()) {
+  if (!getInternal() || Ctx->getFlags().DisableInternal) {
     Str << "\t.globl\t" << MangledName << "\n";
     Str << "\t.type\t" << MangledName << ",@function\n";
   }
@@ -347,7 +337,7 @@
   // Print function name+args
   if (getContext()->isVerbose(IceV_Instructions)) {
     Str << "define ";
-    if (getInternal())
+    if (getInternal() && !Ctx->getFlags().DisableInternal)
       Str << "internal ";
     Str << ReturnType << " @" << Ctx->mangleName(getFunctionName()) << "(";
     for (SizeT i = 0; i < Args.size(); ++i) {
diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp
index 767c9c3..4e4d36b 100644
--- a/src/IceCfgNode.cpp
+++ b/src/IceCfgNode.cpp
@@ -30,9 +30,7 @@
 IceString CfgNode::getName() const {
   if (!Name.empty())
     return Name;
-  char buf[30];
-  snprintf(buf, llvm::array_lengthof(buf), "__%u", getIndex());
-  return buf;
+  return "__" + std::to_string(getIndex());
 }
 
 // Adds an instruction to either the Phi list or the regular
@@ -65,7 +63,7 @@
   InstCountEstimate = Func->getNextInstNumber() - FirstNumber;
 }
 
-// When a node is created, the OutEdges are immediately knows, but the
+// When a node is created, the OutEdges are immediately known, but the
 // InEdges have to be built up incrementally.  After the CFG has been
 // constructed, the computePredecessors() pass finalizes it by
 // creating the InEdges list.
@@ -557,7 +555,12 @@
     Str << "    // LiveIn:";
     for (SizeT i = 0; i < LiveIn.size(); ++i) {
       if (LiveIn[i]) {
-        Str << " %" << Liveness->getVariable(i, this)->getName();
+        Variable *Var = Liveness->getVariable(i, this);
+        Str << " %" << Var->getName();
+        if (Func->getContext()->isVerbose(IceV_RegOrigins) && Var->hasReg()) {
+          Str << ":" << Func->getTarget()->getRegName(Var->getRegNum(),
+                                                      Var->getType());
+        }
       }
     }
     Str << "\n";
@@ -577,7 +580,12 @@
     Str << "    // LiveOut:";
     for (SizeT i = 0; i < LiveOut.size(); ++i) {
       if (LiveOut[i]) {
-        Str << " %" << Liveness->getVariable(i, this)->getName();
+        Variable *Var = Liveness->getVariable(i, this);
+        Str << " %" << Var->getName();
+        if (Func->getContext()->isVerbose(IceV_RegOrigins) && Var->hasReg()) {
+          Str << ":" << Func->getTarget()->getRegName(Var->getRegNum(),
+                                                      Var->getType());
+        }
       }
     }
     Str << "\n";
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index d1a71ae..d610c6a 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -35,6 +35,7 @@
   bool DataSections;
   bool UseIntegratedAssembler;
   bool UseSandboxing;
+  bool PhiEdgeSplit;
   bool DumpStats;
   bool AllowUninitializedGlobals;
   bool TimeEachFunction;
@@ -42,6 +43,7 @@
   IceString DefaultFunctionPrefix;
   IceString TimingFocusOn;
   IceString VerboseFocusOn;
+  IceString TranslateOnly;
 };
 
 } // end of namespace Ice
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index dbacd58..9419866 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -136,9 +136,7 @@
       Number(Target->makeNextLabelNumber()) {}
 
 IceString InstX8632Label::getName(const Cfg *Func) const {
-  char buf[30];
-  snprintf(buf, llvm::array_lengthof(buf), "%u", Number);
-  return ".L" + Func->getFunctionName() + "$local$__" + buf;
+  return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number);
 }
 
 InstX8632Br::InstX8632Br(Cfg *Func, const CfgNode *TargetTrue,
diff --git a/src/IceLiveness.cpp b/src/IceLiveness.cpp
index 79578a5..f16eb84 100644
--- a/src/IceLiveness.cpp
+++ b/src/IceLiveness.cpp
@@ -77,10 +77,8 @@
   assert(NumGlobals == TmpNumGlobals);
 
   // Process each node.
-  const NodeList &LNodes = Func->getNodes();
-  SizeT NumLNodes = LNodes.size();
-  for (SizeT i = 0; i < NumLNodes; ++i) {
-    LivenessNode &Node = Nodes[LNodes[i]->getIndex()];
+  for (const CfgNode *LNode : Func->getNodes()) {
+    LivenessNode &Node = Nodes[LNode->getIndex()];
     // NumLocals, LiveToVarMap already initialized
     Node.LiveIn.resize(NumGlobals);
     Node.LiveOut.resize(NumGlobals);
diff --git a/src/IceOperand.cpp b/src/IceOperand.cpp
index 98e8f6f..a2ee8f4 100644
--- a/src/IceOperand.cpp
+++ b/src/IceOperand.cpp
@@ -171,9 +171,7 @@
 IceString Variable::getName() const {
   if (!Name.empty())
     return Name;
-  char buf[30];
-  snprintf(buf, llvm::array_lengthof(buf), "__%u", getIndex());
-  return buf;
+  return "__" + std::to_string(getIndex());
 }
 
 Variable Variable::asType(Type Ty) {
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 98b18dc..8ea5882 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -4451,7 +4451,7 @@
 
   // If external and not initialized, this must be a cross test.
   // Don't generate a declaration for such cases.
-  bool IsExternal = Var.isExternal();
+  bool IsExternal = Var.isExternal() || Ctx->getFlags().DisableInternal;
   if (IsExternal && !Var.hasInitializer()) return;
 
   bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
diff --git a/src/IceTranslator.cpp b/src/IceTranslator.cpp
index dad0fa9..0391b6c 100644
--- a/src/IceTranslator.cpp
+++ b/src/IceTranslator.cpp
@@ -28,6 +28,16 @@
 
 using namespace Ice;
 
+namespace {
+
+// Match a symbol name against a match string.  An empty match string
+// means match everything.  Returns true if there is a match.
+bool matchSymbolName(const IceString &SymbolName, const IceString &Match) {
+  return Match.empty() || Match == SymbolName;
+}
+
+} // end of anonymous namespace
+
 Translator::~Translator() {}
 
 IceString Translator::createUnnamedName(const IceString &Prefix, SizeT Index) {
@@ -58,9 +68,13 @@
 void Translator::translateFcn(Cfg *Fcn) {
   Ctx->resetStats();
   Func.reset(Fcn);
-  if (Ctx->getFlags().DisableInternal)
-    Func->setInternal(false);
-  if (Ctx->getFlags().DisableTranslation) {
+  VerboseMask OldVerboseMask = Ctx->getVerbose();
+  if (!matchSymbolName(Func->getFunctionName(), Ctx->getFlags().VerboseFocusOn))
+    Ctx->setVerbose(IceV_None);
+
+  if (Ctx->getFlags().DisableTranslation ||
+      !matchSymbolName(Func->getFunctionName(),
+                       Ctx->getFlags().TranslateOnly)) {
     Func->dump();
   } else {
     Func->translate();
@@ -72,6 +86,8 @@
     Func->emit();
     Ctx->dumpStats(Func->getFunctionName());
   }
+
+  Ctx->setVerbose(OldVerboseMask);
 }
 
 void Translator::emitConstants() {
@@ -84,12 +100,15 @@
   llvm::OwningPtr<TargetGlobalInitLowering> GlobalLowering(
       TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
   bool DisableTranslation = Ctx->getFlags().DisableTranslation;
-  bool DumpGlobalVariables = Ctx->isVerbose();
+  bool DumpGlobalVariables =
+      Ctx->isVerbose() && Ctx->getFlags().VerboseFocusOn.empty();
   Ostream &Stream = Ctx->getStrDump();
+  const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly;
   for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
     if (DumpGlobalVariables)
       Global->dump(getContext(), Stream);
-    if(!DisableTranslation)
+    if (!DisableTranslation &&
+        matchSymbolName(Global->getName(), TranslateOnly))
       GlobalLowering->lower(*Global);
   }
   GlobalLowering.reset();
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 3546b84..9897740 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -93,6 +93,9 @@
                 cl::desc("Externalize all symbols"));
 static cl::opt<bool>
 DisableTranslation("notranslate", cl::desc("Disable Subzero translation"));
+static cl::opt<std::string>
+TranslateOnly("translate-only", cl::desc("Translate only the given function"),
+              cl::init(""));
 
 static cl::opt<bool> SubzeroTimingEnabled(
     "timing", cl::desc("Enable breakdown timing of Subzero translation"));
@@ -111,10 +114,10 @@
     cl::desc("Temporarily enable full verbosity for a specific function"),
     cl::init(""));
 
-// This is currently unused, and is a placeholder for lit tests.
 static cl::opt<bool>
-    DisablePhiEdgeSplit("no-phi-edge-split",
-                        cl::desc("Disable edge splitting for Phi lowering"));
+EnablePhiEdgeSplit("phi-edge-split",
+                   cl::desc("Enable edge splitting for Phi lowering"),
+                   cl::init(true));
 
 static cl::opt<bool>
 DumpStats("stats",
@@ -197,6 +200,7 @@
   Flags.DataSections = DataSections;
   Flags.UseIntegratedAssembler = UseIntegratedAssembler;
   Flags.UseSandboxing = UseSandboxing;
+  Flags.PhiEdgeSplit = EnablePhiEdgeSplit;
   Flags.DumpStats = DumpStats;
   Flags.AllowUninitializedGlobals = AllowUninitializedGlobals;
   Flags.TimeEachFunction = TimeEachFunction;
@@ -204,6 +208,7 @@
   Flags.DefaultFunctionPrefix = DefaultFunctionPrefix;
   Flags.TimingFocusOn = TimingFocusOn;
   Flags.VerboseFocusOn = VerboseFocusOn;
+  Flags.TranslateOnly = TranslateOnly;
 
   Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
                          Flags);
diff --git a/tests_lit/llvm2ice_tests/phi.ll b/tests_lit/llvm2ice_tests/phi.ll
index d0a130a..813a435 100644
--- a/tests_lit/llvm2ice_tests/phi.ll
+++ b/tests_lit/llvm2ice_tests/phi.ll
@@ -3,7 +3,7 @@
 ; compare/branch fusing.
 
 ; TODO(kschimpf) Find out why lc2i must be used.
-; RUN: %lc2i -i %s --args -O2 --verbose none --no-phi-edge-split \
+; RUN: %lc2i -i %s --args -O2 --verbose none --phi-edge-split=0 \
 ; RUN:   | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
 ; RUN:   | llvm-objdump -d -symbolize -x86-asm-syntax=intel - | FileCheck %s
 ; RUN: %lc2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s