Commit 088b2be2 by Jim Stichnoth

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
parent d8d67f4d
...@@ -65,17 +65,12 @@ bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } ...@@ -65,17 +65,12 @@ bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); }
void Cfg::translate() { void Cfg::translate() {
if (hasError()) if (hasError())
return; return;
VerboseMask OldVerboseMask = getContext()->getVerbose();
const IceString &TimingFocusOn = getContext()->getFlags().TimingFocusOn; const IceString &TimingFocusOn = getContext()->getFlags().TimingFocusOn;
if (TimingFocusOn == "*" || TimingFocusOn == getFunctionName()) { if (TimingFocusOn == "*" || TimingFocusOn == getFunctionName()) {
setFocusedTiming(); setFocusedTiming();
getContext()->resetTimer(GlobalContext::TSK_Default); getContext()->resetTimer(GlobalContext::TSK_Default);
getContext()->setTimerName(GlobalContext::TSK_Default, getFunctionName()); getContext()->setTimerName(GlobalContext::TSK_Default, getFunctionName());
} }
bool VerboseFocus =
(getContext()->getFlags().VerboseFocusOn == getFunctionName());
if (VerboseFocus)
getContext()->setVerbose(IceV_All);
TimerMarker T(TimerStack::TT_translate, this); TimerMarker T(TimerStack::TT_translate, this);
dump("Initial CFG"); dump("Initial CFG");
...@@ -87,8 +82,6 @@ void Cfg::translate() { ...@@ -87,8 +82,6 @@ void Cfg::translate() {
dump("Final output"); dump("Final output");
if (getFocusedTiming()) if (getFocusedTiming())
getContext()->dumpTimers(); getContext()->dumpTimers();
if (VerboseFocus)
getContext()->setVerbose(OldVerboseMask);
} }
void Cfg::computePredecessors() { void Cfg::computePredecessors() {
...@@ -150,9 +143,6 @@ void Cfg::genCode() { ...@@ -150,9 +143,6 @@ void Cfg::genCode() {
void Cfg::genFrame() { void Cfg::genFrame() {
TimerMarker T(TimerStack::TT_genFrame, this); TimerMarker T(TimerStack::TT_genFrame, this);
getTarget()->addProlog(Entry); 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) for (CfgNode *Node : Nodes)
if (Node->getHasReturn()) if (Node->getHasReturn())
getTarget()->addEpilog(Node); getTarget()->addEpilog(Node);
...@@ -323,7 +313,7 @@ void Cfg::emit() { ...@@ -323,7 +313,7 @@ void Cfg::emit() {
IceString MangledName = getContext()->mangleName(getFunctionName()); IceString MangledName = getContext()->mangleName(getFunctionName());
if (Ctx->getFlags().FunctionSections) if (Ctx->getFlags().FunctionSections)
Str << "\t.section\t.text." << MangledName << ",\"ax\",@progbits\n"; Str << "\t.section\t.text." << MangledName << ",\"ax\",@progbits\n";
if (!getInternal()) { if (!getInternal() || Ctx->getFlags().DisableInternal) {
Str << "\t.globl\t" << MangledName << "\n"; Str << "\t.globl\t" << MangledName << "\n";
Str << "\t.type\t" << MangledName << ",@function\n"; Str << "\t.type\t" << MangledName << ",@function\n";
} }
...@@ -347,7 +337,7 @@ void Cfg::dump(const IceString &Message) { ...@@ -347,7 +337,7 @@ void Cfg::dump(const IceString &Message) {
// Print function name+args // Print function name+args
if (getContext()->isVerbose(IceV_Instructions)) { if (getContext()->isVerbose(IceV_Instructions)) {
Str << "define "; Str << "define ";
if (getInternal()) if (getInternal() && !Ctx->getFlags().DisableInternal)
Str << "internal "; Str << "internal ";
Str << ReturnType << " @" << Ctx->mangleName(getFunctionName()) << "("; Str << ReturnType << " @" << Ctx->mangleName(getFunctionName()) << "(";
for (SizeT i = 0; i < Args.size(); ++i) { for (SizeT i = 0; i < Args.size(); ++i) {
......
...@@ -30,9 +30,7 @@ CfgNode::CfgNode(Cfg *Func, SizeT LabelNumber, IceString Name) ...@@ -30,9 +30,7 @@ CfgNode::CfgNode(Cfg *Func, SizeT LabelNumber, IceString Name)
IceString CfgNode::getName() const { IceString CfgNode::getName() const {
if (!Name.empty()) if (!Name.empty())
return Name; return Name;
char buf[30]; return "__" + std::to_string(getIndex());
snprintf(buf, llvm::array_lengthof(buf), "__%u", getIndex());
return buf;
} }
// Adds an instruction to either the Phi list or the regular // Adds an instruction to either the Phi list or the regular
...@@ -65,7 +63,7 @@ void CfgNode::renumberInstructions() { ...@@ -65,7 +63,7 @@ void CfgNode::renumberInstructions() {
InstCountEstimate = Func->getNextInstNumber() - FirstNumber; 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 // InEdges have to be built up incrementally. After the CFG has been
// constructed, the computePredecessors() pass finalizes it by // constructed, the computePredecessors() pass finalizes it by
// creating the InEdges list. // creating the InEdges list.
...@@ -557,7 +555,12 @@ void CfgNode::dump(Cfg *Func) const { ...@@ -557,7 +555,12 @@ void CfgNode::dump(Cfg *Func) const {
Str << " // LiveIn:"; Str << " // LiveIn:";
for (SizeT i = 0; i < LiveIn.size(); ++i) { for (SizeT i = 0; i < LiveIn.size(); ++i) {
if (LiveIn[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"; Str << "\n";
...@@ -577,7 +580,12 @@ void CfgNode::dump(Cfg *Func) const { ...@@ -577,7 +580,12 @@ void CfgNode::dump(Cfg *Func) const {
Str << " // LiveOut:"; Str << " // LiveOut:";
for (SizeT i = 0; i < LiveOut.size(); ++i) { for (SizeT i = 0; i < LiveOut.size(); ++i) {
if (LiveOut[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"; Str << "\n";
......
...@@ -35,6 +35,7 @@ public: ...@@ -35,6 +35,7 @@ public:
bool DataSections; bool DataSections;
bool UseIntegratedAssembler; bool UseIntegratedAssembler;
bool UseSandboxing; bool UseSandboxing;
bool PhiEdgeSplit;
bool DumpStats; bool DumpStats;
bool AllowUninitializedGlobals; bool AllowUninitializedGlobals;
bool TimeEachFunction; bool TimeEachFunction;
...@@ -42,6 +43,7 @@ public: ...@@ -42,6 +43,7 @@ public:
IceString DefaultFunctionPrefix; IceString DefaultFunctionPrefix;
IceString TimingFocusOn; IceString TimingFocusOn;
IceString VerboseFocusOn; IceString VerboseFocusOn;
IceString TranslateOnly;
}; };
} // end of namespace Ice } // end of namespace Ice
......
...@@ -136,9 +136,7 @@ InstX8632Label::InstX8632Label(Cfg *Func, TargetX8632 *Target) ...@@ -136,9 +136,7 @@ InstX8632Label::InstX8632Label(Cfg *Func, TargetX8632 *Target)
Number(Target->makeNextLabelNumber()) {} Number(Target->makeNextLabelNumber()) {}
IceString InstX8632Label::getName(const Cfg *Func) const { IceString InstX8632Label::getName(const Cfg *Func) const {
char buf[30]; return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number);
snprintf(buf, llvm::array_lengthof(buf), "%u", Number);
return ".L" + Func->getFunctionName() + "$local$__" + buf;
} }
InstX8632Br::InstX8632Br(Cfg *Func, const CfgNode *TargetTrue, InstX8632Br::InstX8632Br(Cfg *Func, const CfgNode *TargetTrue,
......
...@@ -77,10 +77,8 @@ void Liveness::init() { ...@@ -77,10 +77,8 @@ void Liveness::init() {
assert(NumGlobals == TmpNumGlobals); assert(NumGlobals == TmpNumGlobals);
// Process each node. // Process each node.
const NodeList &LNodes = Func->getNodes(); for (const CfgNode *LNode : Func->getNodes()) {
SizeT NumLNodes = LNodes.size(); LivenessNode &Node = Nodes[LNode->getIndex()];
for (SizeT i = 0; i < NumLNodes; ++i) {
LivenessNode &Node = Nodes[LNodes[i]->getIndex()];
// NumLocals, LiveToVarMap already initialized // NumLocals, LiveToVarMap already initialized
Node.LiveIn.resize(NumGlobals); Node.LiveIn.resize(NumGlobals);
Node.LiveOut.resize(NumGlobals); Node.LiveOut.resize(NumGlobals);
......
...@@ -171,9 +171,7 @@ void LiveRange::trim(InstNumberT Lower) { ...@@ -171,9 +171,7 @@ void LiveRange::trim(InstNumberT Lower) {
IceString Variable::getName() const { IceString Variable::getName() const {
if (!Name.empty()) if (!Name.empty())
return Name; return Name;
char buf[30]; return "__" + std::to_string(getIndex());
snprintf(buf, llvm::array_lengthof(buf), "__%u", getIndex());
return buf;
} }
Variable Variable::asType(Type Ty) { Variable Variable::asType(Type Ty) {
......
...@@ -4451,7 +4451,7 @@ void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) { ...@@ -4451,7 +4451,7 @@ void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) {
// If external and not initialized, this must be a cross test. // If external and not initialized, this must be a cross test.
// Don't generate a declaration for such cases. // Don't generate a declaration for such cases.
bool IsExternal = Var.isExternal(); bool IsExternal = Var.isExternal() || Ctx->getFlags().DisableInternal;
if (IsExternal && !Var.hasInitializer()) return; if (IsExternal && !Var.hasInitializer()) return;
bool HasNonzeroInitializer = Var.hasNonzeroInitializer(); bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
......
...@@ -28,6 +28,16 @@ ...@@ -28,6 +28,16 @@
using namespace Ice; 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() {} Translator::~Translator() {}
IceString Translator::createUnnamedName(const IceString &Prefix, SizeT Index) { IceString Translator::createUnnamedName(const IceString &Prefix, SizeT Index) {
...@@ -58,9 +68,13 @@ bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind, ...@@ -58,9 +68,13 @@ bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
void Translator::translateFcn(Cfg *Fcn) { void Translator::translateFcn(Cfg *Fcn) {
Ctx->resetStats(); Ctx->resetStats();
Func.reset(Fcn); Func.reset(Fcn);
if (Ctx->getFlags().DisableInternal) VerboseMask OldVerboseMask = Ctx->getVerbose();
Func->setInternal(false); if (!matchSymbolName(Func->getFunctionName(), Ctx->getFlags().VerboseFocusOn))
if (Ctx->getFlags().DisableTranslation) { Ctx->setVerbose(IceV_None);
if (Ctx->getFlags().DisableTranslation ||
!matchSymbolName(Func->getFunctionName(),
Ctx->getFlags().TranslateOnly)) {
Func->dump(); Func->dump();
} else { } else {
Func->translate(); Func->translate();
...@@ -72,6 +86,8 @@ void Translator::translateFcn(Cfg *Fcn) { ...@@ -72,6 +86,8 @@ void Translator::translateFcn(Cfg *Fcn) {
Func->emit(); Func->emit();
Ctx->dumpStats(Func->getFunctionName()); Ctx->dumpStats(Func->getFunctionName());
} }
Ctx->setVerbose(OldVerboseMask);
} }
void Translator::emitConstants() { void Translator::emitConstants() {
...@@ -84,12 +100,15 @@ void Translator::lowerGlobals( ...@@ -84,12 +100,15 @@ void Translator::lowerGlobals(
llvm::OwningPtr<TargetGlobalInitLowering> GlobalLowering( llvm::OwningPtr<TargetGlobalInitLowering> GlobalLowering(
TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx)); TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
bool DisableTranslation = Ctx->getFlags().DisableTranslation; bool DisableTranslation = Ctx->getFlags().DisableTranslation;
bool DumpGlobalVariables = Ctx->isVerbose(); bool DumpGlobalVariables =
Ctx->isVerbose() && Ctx->getFlags().VerboseFocusOn.empty();
Ostream &Stream = Ctx->getStrDump(); Ostream &Stream = Ctx->getStrDump();
const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly;
for (const Ice::VariableDeclaration *Global : VariableDeclarations) { for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
if (DumpGlobalVariables) if (DumpGlobalVariables)
Global->dump(getContext(), Stream); Global->dump(getContext(), Stream);
if(!DisableTranslation) if (!DisableTranslation &&
matchSymbolName(Global->getName(), TranslateOnly))
GlobalLowering->lower(*Global); GlobalLowering->lower(*Global);
} }
GlobalLowering.reset(); GlobalLowering.reset();
......
...@@ -93,6 +93,9 @@ DisableInternal("externalize", ...@@ -93,6 +93,9 @@ DisableInternal("externalize",
cl::desc("Externalize all symbols")); cl::desc("Externalize all symbols"));
static cl::opt<bool> static cl::opt<bool>
DisableTranslation("notranslate", cl::desc("Disable Subzero translation")); 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( static cl::opt<bool> SubzeroTimingEnabled(
"timing", cl::desc("Enable breakdown timing of Subzero translation")); "timing", cl::desc("Enable breakdown timing of Subzero translation"));
...@@ -111,10 +114,10 @@ static cl::opt<std::string> VerboseFocusOn( ...@@ -111,10 +114,10 @@ static cl::opt<std::string> VerboseFocusOn(
cl::desc("Temporarily enable full verbosity for a specific function"), cl::desc("Temporarily enable full verbosity for a specific function"),
cl::init("")); cl::init(""));
// This is currently unused, and is a placeholder for lit tests.
static cl::opt<bool> static cl::opt<bool>
DisablePhiEdgeSplit("no-phi-edge-split", EnablePhiEdgeSplit("phi-edge-split",
cl::desc("Disable edge splitting for Phi lowering")); cl::desc("Enable edge splitting for Phi lowering"),
cl::init(true));
static cl::opt<bool> static cl::opt<bool>
DumpStats("stats", DumpStats("stats",
...@@ -197,6 +200,7 @@ int main(int argc, char **argv) { ...@@ -197,6 +200,7 @@ int main(int argc, char **argv) {
Flags.DataSections = DataSections; Flags.DataSections = DataSections;
Flags.UseIntegratedAssembler = UseIntegratedAssembler; Flags.UseIntegratedAssembler = UseIntegratedAssembler;
Flags.UseSandboxing = UseSandboxing; Flags.UseSandboxing = UseSandboxing;
Flags.PhiEdgeSplit = EnablePhiEdgeSplit;
Flags.DumpStats = DumpStats; Flags.DumpStats = DumpStats;
Flags.AllowUninitializedGlobals = AllowUninitializedGlobals; Flags.AllowUninitializedGlobals = AllowUninitializedGlobals;
Flags.TimeEachFunction = TimeEachFunction; Flags.TimeEachFunction = TimeEachFunction;
...@@ -204,6 +208,7 @@ int main(int argc, char **argv) { ...@@ -204,6 +208,7 @@ int main(int argc, char **argv) {
Flags.DefaultFunctionPrefix = DefaultFunctionPrefix; Flags.DefaultFunctionPrefix = DefaultFunctionPrefix;
Flags.TimingFocusOn = TimingFocusOn; Flags.TimingFocusOn = TimingFocusOn;
Flags.VerboseFocusOn = VerboseFocusOn; Flags.VerboseFocusOn = VerboseFocusOn;
Flags.TranslateOnly = TranslateOnly;
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix, Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
Flags); Flags);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
; compare/branch fusing. ; compare/branch fusing.
; TODO(kschimpf) Find out why lc2i must be used. ; 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-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
; RUN: | llvm-objdump -d -symbolize -x86-asm-syntax=intel - | FileCheck %s ; RUN: | llvm-objdump -d -symbolize -x86-asm-syntax=intel - | FileCheck %s
; RUN: %lc2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s ; RUN: %lc2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment