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(); }
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 @@ void Cfg::translate() {
dump("Final output");
if (getFocusedTiming())
getContext()->dumpTimers();
if (VerboseFocus)
getContext()->setVerbose(OldVerboseMask);
}
void Cfg::computePredecessors() {
......@@ -150,9 +143,6 @@ void Cfg::genCode() {
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 @@ void Cfg::emit() {
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 @@ void Cfg::dump(const IceString &Message) {
// 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) {
......
......@@ -30,9 +30,7 @@ CfgNode::CfgNode(Cfg *Func, SizeT LabelNumber, IceString Name)
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 @@ void CfgNode::renumberInstructions() {
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 @@ void CfgNode::dump(Cfg *Func) const {
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 @@ void CfgNode::dump(Cfg *Func) const {
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";
......
......@@ -35,6 +35,7 @@ public:
bool DataSections;
bool UseIntegratedAssembler;
bool UseSandboxing;
bool PhiEdgeSplit;
bool DumpStats;
bool AllowUninitializedGlobals;
bool TimeEachFunction;
......@@ -42,6 +43,7 @@ public:
IceString DefaultFunctionPrefix;
IceString TimingFocusOn;
IceString VerboseFocusOn;
IceString TranslateOnly;
};
} // end of namespace Ice
......
......@@ -136,9 +136,7 @@ InstX8632Label::InstX8632Label(Cfg *Func, TargetX8632 *Target)
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,
......
......@@ -77,10 +77,8 @@ void Liveness::init() {
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);
......
......@@ -171,9 +171,7 @@ void LiveRange::trim(InstNumberT Lower) {
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) {
......
......@@ -4451,7 +4451,7 @@ void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) {
// 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();
......
......@@ -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 @@ bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
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 @@ void Translator::translateFcn(Cfg *Fcn) {
Func->emit();
Ctx->dumpStats(Func->getFunctionName());
}
Ctx->setVerbose(OldVerboseMask);
}
void Translator::emitConstants() {
......@@ -84,12 +100,15 @@ void Translator::lowerGlobals(
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();
......
......@@ -93,6 +93,9 @@ DisableInternal("externalize",
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 @@ static cl::opt<std::string> VerboseFocusOn(
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
Flags.DefaultFunctionPrefix = DefaultFunctionPrefix;
Flags.TimingFocusOn = TimingFocusOn;
Flags.VerboseFocusOn = VerboseFocusOn;
Flags.TranslateOnly = TranslateOnly;
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
Flags);
......
......@@ -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
......
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