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