diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/RenderMachineFunction.cpp')
-rw-r--r-- | contrib/llvm/lib/CodeGen/RenderMachineFunction.cpp | 1013 |
1 files changed, 1013 insertions, 0 deletions
diff --git a/contrib/llvm/lib/CodeGen/RenderMachineFunction.cpp b/contrib/llvm/lib/CodeGen/RenderMachineFunction.cpp new file mode 100644 index 0000000..6020908 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/RenderMachineFunction.cpp @@ -0,0 +1,1013 @@ +//===-- llvm/CodeGen/RenderMachineFunction.cpp - MF->HTML -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "rendermf" + +#include "RenderMachineFunction.h" + +#include "VirtRegMap.h" + +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" + +#include <sstream> + +using namespace llvm; + +char RenderMachineFunction::ID = 0; +INITIALIZE_PASS_BEGIN(RenderMachineFunction, "rendermf", + "Render machine functions (and related info) to HTML pages", + false, false) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_END(RenderMachineFunction, "rendermf", + "Render machine functions (and related info) to HTML pages", + false, false) + +static cl::opt<std::string> +outputFileSuffix("rmf-file-suffix", + cl::desc("Appended to function name to get output file name " + "(default: \".html\")"), + cl::init(".html"), cl::Hidden); + +static cl::opt<std::string> +machineFuncsToRender("rmf-funcs", + cl::desc("Comma separated list of functions to render" + ", or \"*\"."), + cl::init(""), cl::Hidden); + +static cl::opt<std::string> +pressureClasses("rmf-classes", + cl::desc("Register classes to render pressure for."), + cl::init(""), cl::Hidden); + +static cl::opt<std::string> +showIntervals("rmf-intervals", + cl::desc("Live intervals to show alongside code."), + cl::init(""), cl::Hidden); + +static cl::opt<bool> +filterEmpty("rmf-filter-empty-intervals", + cl::desc("Don't display empty intervals."), + cl::init(true), cl::Hidden); + +static cl::opt<bool> +showEmptyIndexes("rmf-empty-indexes", + cl::desc("Render indexes not associated with instructions or " + "MBB starts."), + cl::init(false), cl::Hidden); + +static cl::opt<bool> +useFancyVerticals("rmf-fancy-verts", + cl::desc("Use SVG for vertical text."), + cl::init(true), cl::Hidden); + +static cl::opt<bool> +prettyHTML("rmf-pretty-html", + cl::desc("Pretty print HTML. For debugging the renderer only.."), + cl::init(false), cl::Hidden); + + +namespace llvm { + + bool MFRenderingOptions::renderingOptionsProcessed; + std::set<std::string> MFRenderingOptions::mfNamesToRender; + bool MFRenderingOptions::renderAllMFs = false; + + std::set<std::string> MFRenderingOptions::classNamesToRender; + bool MFRenderingOptions::renderAllClasses = false; + + std::set<std::pair<unsigned, unsigned> > + MFRenderingOptions::intervalNumsToRender; + unsigned MFRenderingOptions::intervalTypesToRender = ExplicitOnly; + + template <typename OutputItr> + void MFRenderingOptions::splitComaSeperatedList(const std::string &s, + OutputItr outItr) { + std::string::const_iterator curPos = s.begin(); + std::string::const_iterator nextComa = std::find(curPos, s.end(), ','); + while (nextComa != s.end()) { + std::string elem; + std::copy(curPos, nextComa, std::back_inserter(elem)); + *outItr = elem; + ++outItr; + curPos = llvm::next(nextComa); + nextComa = std::find(curPos, s.end(), ','); + } + + if (curPos != s.end()) { + std::string elem; + std::copy(curPos, s.end(), std::back_inserter(elem)); + *outItr = elem; + ++outItr; + } + } + + void MFRenderingOptions::processOptions() { + if (!renderingOptionsProcessed) { + processFuncNames(); + processRegClassNames(); + processIntervalNumbers(); + renderingOptionsProcessed = true; + } + } + + void MFRenderingOptions::processFuncNames() { + if (machineFuncsToRender == "*") { + renderAllMFs = true; + } else { + splitComaSeperatedList(machineFuncsToRender, + std::inserter(mfNamesToRender, + mfNamesToRender.begin())); + } + } + + void MFRenderingOptions::processRegClassNames() { + if (pressureClasses == "*") { + renderAllClasses = true; + } else { + splitComaSeperatedList(pressureClasses, + std::inserter(classNamesToRender, + classNamesToRender.begin())); + } + } + + void MFRenderingOptions::processIntervalNumbers() { + std::set<std::string> intervalRanges; + splitComaSeperatedList(showIntervals, + std::inserter(intervalRanges, + intervalRanges.begin())); + std::for_each(intervalRanges.begin(), intervalRanges.end(), + processIntervalRange); + } + + void MFRenderingOptions::processIntervalRange( + const std::string &intervalRangeStr) { + if (intervalRangeStr == "*") { + intervalTypesToRender |= All; + } else if (intervalRangeStr == "virt-nospills*") { + intervalTypesToRender |= VirtNoSpills; + } else if (intervalRangeStr == "spills*") { + intervalTypesToRender |= VirtSpills; + } else if (intervalRangeStr == "virt*") { + intervalTypesToRender |= AllVirt; + } else if (intervalRangeStr == "phys*") { + intervalTypesToRender |= AllPhys; + } else { + std::istringstream iss(intervalRangeStr); + unsigned reg1, reg2; + if ((iss >> reg1 >> std::ws)) { + if (iss.eof()) { + intervalNumsToRender.insert(std::make_pair(reg1, reg1 + 1)); + } else { + char c; + iss >> c; + if (c == '-' && (iss >> reg2)) { + intervalNumsToRender.insert(std::make_pair(reg1, reg2 + 1)); + } else { + dbgs() << "Warning: Invalid interval range \"" + << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; + } + } + } else { + dbgs() << "Warning: Invalid interval number \"" + << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; + } + } + } + + void MFRenderingOptions::setup(MachineFunction *mf, + const TargetRegisterInfo *tri, + LiveIntervals *lis, + const RenderMachineFunction *rmf) { + this->mf = mf; + this->tri = tri; + this->lis = lis; + this->rmf = rmf; + + clear(); + } + + void MFRenderingOptions::clear() { + regClassesTranslatedToCurrentFunction = false; + regClassSet.clear(); + + intervalsTranslatedToCurrentFunction = false; + intervalSet.clear(); + } + + void MFRenderingOptions::resetRenderSpecificOptions() { + intervalSet.clear(); + intervalsTranslatedToCurrentFunction = false; + } + + bool MFRenderingOptions::shouldRenderCurrentMachineFunction() const { + processOptions(); + + return (renderAllMFs || + mfNamesToRender.find(mf->getFunction()->getName()) != + mfNamesToRender.end()); + } + + const MFRenderingOptions::RegClassSet& MFRenderingOptions::regClasses() const{ + translateRegClassNamesToCurrentFunction(); + return regClassSet; + } + + const MFRenderingOptions::IntervalSet& MFRenderingOptions::intervals() const { + translateIntervalNumbersToCurrentFunction(); + return intervalSet; + } + + bool MFRenderingOptions::renderEmptyIndexes() const { + return showEmptyIndexes; + } + + bool MFRenderingOptions::fancyVerticals() const { + return useFancyVerticals; + } + + void MFRenderingOptions::translateRegClassNamesToCurrentFunction() const { + if (!regClassesTranslatedToCurrentFunction) { + processOptions(); + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + if (renderAllClasses || + classNamesToRender.find(trc->getName()) != + classNamesToRender.end()) { + regClassSet.insert(trc); + } + } + regClassesTranslatedToCurrentFunction = true; + } + } + + void MFRenderingOptions::translateIntervalNumbersToCurrentFunction() const { + if (!intervalsTranslatedToCurrentFunction) { + processOptions(); + + // If we're not just doing explicit then do a copy over all matching + // types. + if (intervalTypesToRender != ExplicitOnly) { + for (LiveIntervals::iterator liItr = lis->begin(), liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval *li = liItr->second; + + if (filterEmpty && li->empty()) + continue; + + if ((TargetRegisterInfo::isPhysicalRegister(li->reg) && + (intervalTypesToRender & AllPhys))) { + intervalSet.insert(li); + } else if (TargetRegisterInfo::isVirtualRegister(li->reg)) { + if (((intervalTypesToRender & VirtNoSpills) && !rmf->isSpill(li)) || + ((intervalTypesToRender & VirtSpills) && rmf->isSpill(li))) { + intervalSet.insert(li); + } + } + } + } + + // If we need to process the explicit list... + if (intervalTypesToRender != All) { + for (std::set<std::pair<unsigned, unsigned> >::const_iterator + regRangeItr = intervalNumsToRender.begin(), + regRangeEnd = intervalNumsToRender.end(); + regRangeItr != regRangeEnd; ++regRangeItr) { + const std::pair<unsigned, unsigned> &range = *regRangeItr; + for (unsigned reg = range.first; reg != range.second; ++reg) { + if (lis->hasInterval(reg)) { + intervalSet.insert(&lis->getInterval(reg)); + } + } + } + } + + intervalsTranslatedToCurrentFunction = true; + } + } + + // ---------- TargetRegisterExtraInformation implementation ---------- + + TargetRegisterExtraInfo::TargetRegisterExtraInfo() + : mapsPopulated(false) { + } + + void TargetRegisterExtraInfo::setup(MachineFunction *mf, + MachineRegisterInfo *mri, + const TargetRegisterInfo *tri, + LiveIntervals *lis) { + this->mf = mf; + this->mri = mri; + this->tri = tri; + this->lis = lis; + } + + void TargetRegisterExtraInfo::reset() { + if (!mapsPopulated) { + initWorst(); + //initBounds(); + initCapacity(); + mapsPopulated = true; + } + + resetPressureAndLiveStates(); + } + + void TargetRegisterExtraInfo::clear() { + prWorst.clear(); + vrWorst.clear(); + capacityMap.clear(); + pressureMap.clear(); + //liveStatesMap.clear(); + mapsPopulated = false; + } + + void TargetRegisterExtraInfo::initWorst() { + assert(!mapsPopulated && prWorst.empty() && vrWorst.empty() && + "Worst map already initialised?"); + + // Start with the physical registers. + for (unsigned preg = 1; preg < tri->getNumRegs(); ++preg) { + WorstMapLine &pregLine = prWorst[preg]; + + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + + unsigned numOverlaps = 0; + for (TargetRegisterClass::iterator rItr = trc->begin(), + rEnd = trc->end(); + rItr != rEnd; ++rItr) { + unsigned trcPReg = *rItr; + if (tri->regsOverlap(preg, trcPReg)) + ++numOverlaps; + } + + pregLine[trc] = numOverlaps; + } + } + + // Now the register classes. + for (TargetRegisterInfo::regclass_iterator rc1Itr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rc1Itr != rcEnd; ++rc1Itr) { + const TargetRegisterClass *trc1 = *rc1Itr; + WorstMapLine &classLine = vrWorst[trc1]; + + for (TargetRegisterInfo::regclass_iterator rc2Itr = tri->regclass_begin(); + rc2Itr != rcEnd; ++rc2Itr) { + const TargetRegisterClass *trc2 = *rc2Itr; + + unsigned worst = 0; + + for (TargetRegisterClass::iterator trc1Itr = trc1->begin(), + trc1End = trc1->end(); + trc1Itr != trc1End; ++trc1Itr) { + unsigned trc1Reg = *trc1Itr; + unsigned trc1RegWorst = 0; + + for (TargetRegisterClass::iterator trc2Itr = trc2->begin(), + trc2End = trc2->end(); + trc2Itr != trc2End; ++trc2Itr) { + unsigned trc2Reg = *trc2Itr; + if (tri->regsOverlap(trc1Reg, trc2Reg)) + ++trc1RegWorst; + } + if (trc1RegWorst > worst) { + worst = trc1RegWorst; + } + } + + if (worst != 0) { + classLine[trc2] = worst; + } + } + } + } + + unsigned TargetRegisterExtraInfo::getWorst( + unsigned reg, + const TargetRegisterClass *trc) const { + const WorstMapLine *wml = 0; + if (TargetRegisterInfo::isPhysicalRegister(reg)) { + PRWorstMap::const_iterator prwItr = prWorst.find(reg); + assert(prwItr != prWorst.end() && "Missing prWorst entry."); + wml = &prwItr->second; + } else { + const TargetRegisterClass *regTRC = mri->getRegClass(reg); + VRWorstMap::const_iterator vrwItr = vrWorst.find(regTRC); + assert(vrwItr != vrWorst.end() && "Missing vrWorst entry."); + wml = &vrwItr->second; + } + + WorstMapLine::const_iterator wmlItr = wml->find(trc); + if (wmlItr == wml->end()) + return 0; + + return wmlItr->second; + } + + void TargetRegisterExtraInfo::initCapacity() { + assert(!mapsPopulated && capacityMap.empty() && + "Capacity map already initialised?"); + + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + unsigned capacity = trc->getRawAllocationOrder(*mf).size(); + + if (capacity != 0) + capacityMap[trc] = capacity; + } + } + + unsigned TargetRegisterExtraInfo::getCapacity( + const TargetRegisterClass *trc) const { + CapacityMap::const_iterator cmItr = capacityMap.find(trc); + assert(cmItr != capacityMap.end() && + "vreg with unallocable register class"); + return cmItr->second; + } + + void TargetRegisterExtraInfo::resetPressureAndLiveStates() { + pressureMap.clear(); + //liveStatesMap.clear(); + + // Iterate over all slots. + + + // Iterate over all live intervals. + for (LiveIntervals::iterator liItr = lis->begin(), + liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval *li = liItr->second; + + if (TargetRegisterInfo::isPhysicalRegister(li->reg)) + continue; + + // For all ranges in the current interal. + for (LiveInterval::iterator lrItr = li->begin(), + lrEnd = li->end(); + lrItr != lrEnd; ++lrItr) { + LiveRange *lr = &*lrItr; + + // For all slots in the current range. + for (SlotIndex i = lr->start; i != lr->end; i = i.getNextSlot()) { + + // Record increased pressure at index for all overlapping classes. + for (TargetRegisterInfo::regclass_iterator + rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + + if (trc->getRawAllocationOrder(*mf).empty()) + continue; + + unsigned worstAtI = getWorst(li->reg, trc); + + if (worstAtI != 0) { + pressureMap[i][trc] += worstAtI; + } + } + } + } + } + } + + unsigned TargetRegisterExtraInfo::getPressureAtSlot( + const TargetRegisterClass *trc, + SlotIndex i) const { + PressureMap::const_iterator pmItr = pressureMap.find(i); + if (pmItr == pressureMap.end()) + return 0; + const PressureMapLine &pmLine = pmItr->second; + PressureMapLine::const_iterator pmlItr = pmLine.find(trc); + if (pmlItr == pmLine.end()) + return 0; + return pmlItr->second; + } + + bool TargetRegisterExtraInfo::classOverCapacityAtSlot( + const TargetRegisterClass *trc, + SlotIndex i) const { + return (getPressureAtSlot(trc, i) > getCapacity(trc)); + } + + // ---------- MachineFunctionRenderer implementation ---------- + + void RenderMachineFunction::Spacer::print(raw_ostream &os) const { + if (!prettyHTML) + return; + for (unsigned i = 0; i < ns; ++i) { + os << " "; + } + } + + RenderMachineFunction::Spacer RenderMachineFunction::s(unsigned ns) const { + return Spacer(ns); + } + + raw_ostream& operator<<(raw_ostream &os, const RenderMachineFunction::Spacer &s) { + s.print(os); + return os; + } + + template <typename Iterator> + std::string RenderMachineFunction::escapeChars(Iterator sBegin, Iterator sEnd) const { + std::string r; + + for (Iterator sItr = sBegin; sItr != sEnd; ++sItr) { + char c = *sItr; + + switch (c) { + case '<': r.append("<"); break; + case '>': r.append(">"); break; + case '&': r.append("&"); break; + case ' ': r.append(" "); break; + case '\"': r.append("""); break; + default: r.push_back(c); break; + } + } + + return r; + } + + RenderMachineFunction::LiveState + RenderMachineFunction::getLiveStateAt(const LiveInterval *li, + SlotIndex i) const { + const MachineInstr *mi = sis->getInstructionFromIndex(i); + + // For uses/defs recorded use/def indexes override current liveness and + // instruction operands (Only for the interval which records the indexes). + // FIXME: This is all wrong, uses and defs share the same slots. + if (i.isEarlyClobber() || i.isRegister()) { + UseDefs::const_iterator udItr = useDefs.find(li); + if (udItr != useDefs.end()) { + const SlotSet &slotSet = udItr->second; + if (slotSet.count(i)) { + if (i.isEarlyClobber()) { + return Used; + } + // else + return Defined; + } + } + } + + // If the slot is a load/store, or there's no info in the use/def set then + // use liveness and instruction operand info. + if (li->liveAt(i)) { + + if (mi == 0) { + if (vrm == 0 || + (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { + return AliveReg; + } else { + return AliveStack; + } + } else { + if (i.isRegister() && mi->definesRegister(li->reg, tri)) { + return Defined; + } else if (i.isEarlyClobber() && mi->readsRegister(li->reg)) { + return Used; + } else { + if (vrm == 0 || + (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { + return AliveReg; + } else { + return AliveStack; + } + } + } + } + return Dead; + } + + RenderMachineFunction::PressureState + RenderMachineFunction::getPressureStateAt(const TargetRegisterClass *trc, + SlotIndex i) const { + if (trei.getPressureAtSlot(trc, i) == 0) { + return Zero; + } else if (trei.classOverCapacityAtSlot(trc, i)){ + return High; + } + return Low; + } + + /// \brief Render a machine instruction. + void RenderMachineFunction::renderMachineInstr(raw_ostream &os, + const MachineInstr *mi) const { + std::string s; + raw_string_ostream oss(s); + oss << *mi; + + os << escapeChars(oss.str()); + } + + template <typename T> + void RenderMachineFunction::renderVertical(const Spacer &indent, + raw_ostream &os, + const T &t) const { + if (ro.fancyVerticals()) { + os << indent << "<object\n" + << indent + s(2) << "class=\"obj\"\n" + << indent + s(2) << "type=\"image/svg+xml\"\n" + << indent + s(2) << "width=\"14px\"\n" + << indent + s(2) << "height=\"55px\"\n" + << indent + s(2) << "data=\"data:image/svg+xml,\n" + << indent + s(4) << "<svg xmlns='http://www.w3.org/2000/svg'>\n" + << indent + s(6) << "<text x='-55' y='10' " + "font-family='Courier' font-size='12' " + "transform='rotate(-90)' " + "text-rendering='optimizeSpeed' " + "fill='#000'>" << t << "</text>\n" + << indent + s(4) << "</svg>\">\n" + << indent << "</object>\n"; + } else { + std::ostringstream oss; + oss << t; + std::string tStr(oss.str()); + + os << indent; + for (std::string::iterator tStrItr = tStr.begin(), tStrEnd = tStr.end(); + tStrItr != tStrEnd; ++tStrItr) { + os << *tStrItr << "<br/>"; + } + os << "\n"; + } + } + + void RenderMachineFunction::insertCSS(const Spacer &indent, + raw_ostream &os) const { + os << indent << "<style type=\"text/css\">\n" + << indent + s(2) << "body { font-color: black; }\n" + << indent + s(2) << "table.code td { font-family: monospace; " + "border-width: 0px; border-style: solid; " + "border-bottom: 1px solid #dddddd; white-space: nowrap; }\n" + << indent + s(2) << "table.code td.p-z { background-color: #000000; }\n" + << indent + s(2) << "table.code td.p-l { background-color: #00ff00; }\n" + << indent + s(2) << "table.code td.p-h { background-color: #ff0000; }\n" + << indent + s(2) << "table.code td.l-n { background-color: #ffffff; }\n" + << indent + s(2) << "table.code td.l-d { background-color: #ff0000; }\n" + << indent + s(2) << "table.code td.l-u { background-color: #ffff00; }\n" + << indent + s(2) << "table.code td.l-r { background-color: #000000; }\n" + << indent + s(2) << "table.code td.l-s { background-color: #770000; }\n" + << indent + s(2) << "table.code th { border-width: 0px; " + "border-style: solid; }\n" + << indent << "</style>\n"; + } + + void RenderMachineFunction::renderFunctionSummary( + const Spacer &indent, raw_ostream &os, + const char * const renderContextStr) const { + os << indent << "<h1>Function: " << mf->getFunction()->getName() + << "</h1>\n" + << indent << "<h2>Rendering context: " << renderContextStr << "</h2>\n"; + } + + + void RenderMachineFunction::renderPressureTableLegend( + const Spacer &indent, + raw_ostream &os) const { + os << indent << "<h2>Rendering Pressure Legend:</h2>\n" + << indent << "<table class=\"code\">\n" + << indent + s(2) << "<tr>\n" + << indent + s(4) << "<th>Pressure</th><th>Description</th>" + "<th>Appearance</th>\n" + << indent + s(2) << "</tr>\n" + << indent + s(2) << "<tr>\n" + << indent + s(4) << "<td>No Pressure</td>" + "<td>No physical registers of this class requested.</td>" + "<td class=\"p-z\"> </td>\n" + << indent + s(2) << "</tr>\n" + << indent + s(2) << "<tr>\n" + << indent + s(4) << "<td>Low Pressure</td>" + "<td>Sufficient physical registers to meet demand.</td>" + "<td class=\"p-l\"> </td>\n" + << indent + s(2) << "</tr>\n" + << indent + s(2) << "<tr>\n" + << indent + s(4) << "<td>High Pressure</td>" + "<td>Potentially insufficient physical registers to meet demand.</td>" + "<td class=\"p-h\"> </td>\n" + << indent + s(2) << "</tr>\n" + << indent << "</table>\n"; + } + + template <typename CellType> + void RenderMachineFunction::renderCellsWithRLE( + const Spacer &indent, raw_ostream &os, + const std::pair<CellType, unsigned> &rleAccumulator, + const std::map<CellType, std::string> &cellTypeStrs) const { + + if (rleAccumulator.second == 0) + return; + + typename std::map<CellType, std::string>::const_iterator ctsItr = + cellTypeStrs.find(rleAccumulator.first); + + assert(ctsItr != cellTypeStrs.end() && "No string for given cell type."); + + os << indent + s(4) << "<td class=\"" << ctsItr->second << "\""; + if (rleAccumulator.second > 1) + os << " colspan=" << rleAccumulator.second; + os << "></td>\n"; + } + + + void RenderMachineFunction::renderCodeTablePlusPI(const Spacer &indent, + raw_ostream &os) const { + + std::map<LiveState, std::string> lsStrs; + lsStrs[Dead] = "l-n"; + lsStrs[Defined] = "l-d"; + lsStrs[Used] = "l-u"; + lsStrs[AliveReg] = "l-r"; + lsStrs[AliveStack] = "l-s"; + + std::map<PressureState, std::string> psStrs; + psStrs[Zero] = "p-z"; + psStrs[Low] = "p-l"; + psStrs[High] = "p-h"; + + // Open the table... + + os << indent << "<table cellpadding=0 cellspacing=0 class=\"code\">\n" + << indent + s(2) << "<tr>\n"; + + // Render the header row... + + os << indent + s(4) << "<th>index</th>\n" + << indent + s(4) << "<th>instr</th>\n"; + + // Render class names if necessary... + if (!ro.regClasses().empty()) { + for (MFRenderingOptions::RegClassSet::const_iterator + rcItr = ro.regClasses().begin(), + rcEnd = ro.regClasses().end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + os << indent + s(4) << "<th>\n"; + renderVertical(indent + s(6), os, trc->getName()); + os << indent + s(4) << "</th>\n"; + } + } + + // FIXME: Is there a nicer way to insert space between columns in HTML? + if (!ro.regClasses().empty() && !ro.intervals().empty()) + os << indent + s(4) << "<th> </th>\n"; + + // Render interval numbers if necessary... + if (!ro.intervals().empty()) { + for (MFRenderingOptions::IntervalSet::const_iterator + liItr = ro.intervals().begin(), + liEnd = ro.intervals().end(); + liItr != liEnd; ++liItr) { + + const LiveInterval *li = *liItr; + os << indent + s(4) << "<th>\n"; + renderVertical(indent + s(6), os, li->reg); + os << indent + s(4) << "</th>\n"; + } + } + + os << indent + s(2) << "</tr>\n"; + + // End header row, start with the data rows... + + MachineInstr *mi = 0; + + // Data rows: + for (SlotIndex i = sis->getZeroIndex(); i != sis->getLastIndex(); + i = i.getNextSlot()) { + + // Render the slot column. + os << indent + s(2) << "<tr height=6ex>\n"; + + // Render the code column. + if (i.isBlock()) { + MachineBasicBlock *mbb = sis->getMBBFromIndex(i); + mi = sis->getInstructionFromIndex(i); + + if (i == sis->getMBBStartIdx(mbb) || mi != 0 || + ro.renderEmptyIndexes()) { + os << indent + s(4) << "<td rowspan=4>" << i << " </td>\n" + << indent + s(4) << "<td rowspan=4>\n"; + + if (i == sis->getMBBStartIdx(mbb)) { + os << indent + s(6) << "BB#" << mbb->getNumber() << ": \n"; + } else if (mi != 0) { + os << indent + s(6) << " "; + renderMachineInstr(os, mi); + } else { + // Empty interval - leave blank. + } + os << indent + s(4) << "</td>\n"; + } else { + i = i.getDeadSlot(); // <- Will be incremented to the next index. + continue; + } + } + + // Render the class columns. + if (!ro.regClasses().empty()) { + std::pair<PressureState, unsigned> psRLEAccumulator(Zero, 0); + for (MFRenderingOptions::RegClassSet::const_iterator + rcItr = ro.regClasses().begin(), + rcEnd = ro.regClasses().end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + PressureState newPressure = getPressureStateAt(trc, i); + + if (newPressure == psRLEAccumulator.first) { + ++psRLEAccumulator.second; + } else { + renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); + psRLEAccumulator.first = newPressure; + psRLEAccumulator.second = 1; + } + } + renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); + } + + // FIXME: Is there a nicer way to insert space between columns in HTML? + if (!ro.regClasses().empty() && !ro.intervals().empty()) + os << indent + s(4) << "<td width=2em></td>\n"; + + if (!ro.intervals().empty()) { + std::pair<LiveState, unsigned> lsRLEAccumulator(Dead, 0); + for (MFRenderingOptions::IntervalSet::const_iterator + liItr = ro.intervals().begin(), + liEnd = ro.intervals().end(); + liItr != liEnd; ++liItr) { + const LiveInterval *li = *liItr; + LiveState newLiveness = getLiveStateAt(li, i); + + if (newLiveness == lsRLEAccumulator.first) { + ++lsRLEAccumulator.second; + } else { + renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); + lsRLEAccumulator.first = newLiveness; + lsRLEAccumulator.second = 1; + } + } + renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); + } + os << indent + s(2) << "</tr>\n"; + } + + os << indent << "</table>\n"; + + if (!ro.regClasses().empty()) + renderPressureTableLegend(indent, os); + } + + void RenderMachineFunction::renderFunctionPage( + raw_ostream &os, + const char * const renderContextStr) const { + os << "<html>\n" + << s(2) << "<head>\n" + << s(4) << "<title>" << fqn << "</title>\n"; + + insertCSS(s(4), os); + + os << s(2) << "<head>\n" + << s(2) << "<body >\n"; + + renderFunctionSummary(s(4), os, renderContextStr); + + os << s(4) << "<br/><br/><br/>\n"; + + //renderLiveIntervalInfoTable(" ", os); + + os << s(4) << "<br/><br/><br/>\n"; + + renderCodeTablePlusPI(s(4), os); + + os << s(2) << "</body>\n" + << "</html>\n"; + } + + void RenderMachineFunction::getAnalysisUsage(AnalysisUsage &au) const { + au.addRequired<SlotIndexes>(); + au.addRequired<LiveIntervals>(); + au.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(au); + } + + bool RenderMachineFunction::runOnMachineFunction(MachineFunction &fn) { + + mf = &fn; + mri = &mf->getRegInfo(); + tri = mf->getTarget().getRegisterInfo(); + lis = &getAnalysis<LiveIntervals>(); + sis = &getAnalysis<SlotIndexes>(); + + trei.setup(mf, mri, tri, lis); + ro.setup(mf, tri, lis, this); + spillIntervals.clear(); + spillFor.clear(); + useDefs.clear(); + + fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." + + mf->getFunction()->getName().str(); + + return false; + } + + void RenderMachineFunction::releaseMemory() { + trei.clear(); + ro.clear(); + spillIntervals.clear(); + spillFor.clear(); + useDefs.clear(); + } + + void RenderMachineFunction::rememberUseDefs(const LiveInterval *li) { + + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + for (MachineRegisterInfo::reg_iterator rItr = mri->reg_begin(li->reg), + rEnd = mri->reg_end(); + rItr != rEnd; ++rItr) { + const MachineInstr *mi = &*rItr; + if (mi->readsRegister(li->reg)) { + useDefs[li].insert(lis->getInstructionIndex(mi).getRegSlot(true)); + } + if (mi->definesRegister(li->reg)) { + useDefs[li].insert(lis->getInstructionIndex(mi).getRegSlot()); + } + } + } + + void RenderMachineFunction::rememberSpills( + const LiveInterval *li, + const std::vector<LiveInterval*> &spills) { + + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + for (std::vector<LiveInterval*>::const_iterator siItr = spills.begin(), + siEnd = spills.end(); + siItr != siEnd; ++siItr) { + const LiveInterval *spill = *siItr; + spillIntervals[li].insert(spill); + spillFor[spill] = li; + } + } + + bool RenderMachineFunction::isSpill(const LiveInterval *li) const { + SpillForMap::const_iterator sfItr = spillFor.find(li); + if (sfItr == spillFor.end()) + return false; + return true; + } + + void RenderMachineFunction::renderMachineFunction( + const char *renderContextStr, + const VirtRegMap *vrm, + const char *renderSuffix) { + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + this->vrm = vrm; + trei.reset(); + + std::string rpFileName(mf->getFunction()->getName().str() + + (renderSuffix ? renderSuffix : "") + + outputFileSuffix); + + std::string errMsg; + raw_fd_ostream outFile(rpFileName.c_str(), errMsg, raw_fd_ostream::F_Binary); + + renderFunctionPage(outFile, renderContextStr); + + ro.resetRenderSpecificOptions(); + } + + std::string RenderMachineFunction::escapeChars(const std::string &s) const { + return escapeChars(s.begin(), s.end()); + } + +} |