1 //===-- llvm/CodeGen/RenderMachineFunction.cpp - MF->HTML -----s-----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #define DEBUG_TYPE "rendermf"
12 #include "RenderMachineFunction.h"
14 #include "VirtRegMap.h"
16 #include "llvm/Function.h"
17 #include "llvm/Module.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/CodeGen/LiveIntervalAnalysis.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineRegisterInfo.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/Target/TargetMachine.h"
32 char RenderMachineFunction::ID
= 0;
33 INITIALIZE_PASS_BEGIN(RenderMachineFunction
, "rendermf",
34 "Render machine functions (and related info) to HTML pages",
36 INITIALIZE_PASS_DEPENDENCY(SlotIndexes
)
37 INITIALIZE_PASS_DEPENDENCY(LiveIntervals
)
38 INITIALIZE_PASS_END(RenderMachineFunction
, "rendermf",
39 "Render machine functions (and related info) to HTML pages",
42 static cl::opt
<std::string
>
43 outputFileSuffix("rmf-file-suffix",
44 cl::desc("Appended to function name to get output file name "
45 "(default: \".html\")"),
46 cl::init(".html"), cl::Hidden
);
48 static cl::opt
<std::string
>
49 machineFuncsToRender("rmf-funcs",
50 cl::desc("Comma separated list of functions to render"
52 cl::init(""), cl::Hidden
);
54 static cl::opt
<std::string
>
55 pressureClasses("rmf-classes",
56 cl::desc("Register classes to render pressure for."),
57 cl::init(""), cl::Hidden
);
59 static cl::opt
<std::string
>
60 showIntervals("rmf-intervals",
61 cl::desc("Live intervals to show alongside code."),
62 cl::init(""), cl::Hidden
);
65 filterEmpty("rmf-filter-empty-intervals",
66 cl::desc("Don't display empty intervals."),
67 cl::init(true), cl::Hidden
);
70 showEmptyIndexes("rmf-empty-indexes",
71 cl::desc("Render indexes not associated with instructions or "
73 cl::init(false), cl::Hidden
);
76 useFancyVerticals("rmf-fancy-verts",
77 cl::desc("Use SVG for vertical text."),
78 cl::init(true), cl::Hidden
);
81 prettyHTML("rmf-pretty-html",
82 cl::desc("Pretty print HTML. For debugging the renderer only.."),
83 cl::init(false), cl::Hidden
);
88 bool MFRenderingOptions::renderingOptionsProcessed
;
89 std::set
<std::string
> MFRenderingOptions::mfNamesToRender
;
90 bool MFRenderingOptions::renderAllMFs
= false;
92 std::set
<std::string
> MFRenderingOptions::classNamesToRender
;
93 bool MFRenderingOptions::renderAllClasses
= false;
95 std::set
<std::pair
<unsigned, unsigned> >
96 MFRenderingOptions::intervalNumsToRender
;
97 unsigned MFRenderingOptions::intervalTypesToRender
= ExplicitOnly
;
99 template <typename OutputItr
>
100 void MFRenderingOptions::splitComaSeperatedList(const std::string
&s
,
102 std::string::const_iterator curPos
= s
.begin();
103 std::string::const_iterator nextComa
= std::find(curPos
, s
.end(), ',');
104 while (nextComa
!= s
.end()) {
106 std::copy(curPos
, nextComa
, std::back_inserter(elem
));
109 curPos
= llvm::next(nextComa
);
110 nextComa
= std::find(curPos
, s
.end(), ',');
113 if (curPos
!= s
.end()) {
115 std::copy(curPos
, s
.end(), std::back_inserter(elem
));
121 void MFRenderingOptions::processOptions() {
122 if (!renderingOptionsProcessed
) {
124 processRegClassNames();
125 processIntervalNumbers();
126 renderingOptionsProcessed
= true;
130 void MFRenderingOptions::processFuncNames() {
131 if (machineFuncsToRender
== "*") {
134 splitComaSeperatedList(machineFuncsToRender
,
135 std::inserter(mfNamesToRender
,
136 mfNamesToRender
.begin()));
140 void MFRenderingOptions::processRegClassNames() {
141 if (pressureClasses
== "*") {
142 renderAllClasses
= true;
144 splitComaSeperatedList(pressureClasses
,
145 std::inserter(classNamesToRender
,
146 classNamesToRender
.begin()));
150 void MFRenderingOptions::processIntervalNumbers() {
151 std::set
<std::string
> intervalRanges
;
152 splitComaSeperatedList(showIntervals
,
153 std::inserter(intervalRanges
,
154 intervalRanges
.begin()));
155 std::for_each(intervalRanges
.begin(), intervalRanges
.end(),
156 processIntervalRange
);
159 void MFRenderingOptions::processIntervalRange(
160 const std::string
&intervalRangeStr
) {
161 if (intervalRangeStr
== "*") {
162 intervalTypesToRender
|= All
;
163 } else if (intervalRangeStr
== "virt-nospills*") {
164 intervalTypesToRender
|= VirtNoSpills
;
165 } else if (intervalRangeStr
== "spills*") {
166 intervalTypesToRender
|= VirtSpills
;
167 } else if (intervalRangeStr
== "virt*") {
168 intervalTypesToRender
|= AllVirt
;
169 } else if (intervalRangeStr
== "phys*") {
170 intervalTypesToRender
|= AllPhys
;
172 std::istringstream
iss(intervalRangeStr
);
174 if ((iss
>> reg1
>> std::ws
)) {
176 intervalNumsToRender
.insert(std::make_pair(reg1
, reg1
+ 1));
180 if (c
== '-' && (iss
>> reg2
)) {
181 intervalNumsToRender
.insert(std::make_pair(reg1
, reg2
+ 1));
183 dbgs() << "Warning: Invalid interval range \""
184 << intervalRangeStr
<< "\" in -rmf-intervals. Skipping.\n";
188 dbgs() << "Warning: Invalid interval number \""
189 << intervalRangeStr
<< "\" in -rmf-intervals. Skipping.\n";
194 void MFRenderingOptions::setup(MachineFunction
*mf
,
195 const TargetRegisterInfo
*tri
,
197 const RenderMachineFunction
*rmf
) {
206 void MFRenderingOptions::clear() {
207 regClassesTranslatedToCurrentFunction
= false;
210 intervalsTranslatedToCurrentFunction
= false;
214 void MFRenderingOptions::resetRenderSpecificOptions() {
216 intervalsTranslatedToCurrentFunction
= false;
219 bool MFRenderingOptions::shouldRenderCurrentMachineFunction() const {
222 return (renderAllMFs
||
223 mfNamesToRender
.find(mf
->getFunction()->getName()) !=
224 mfNamesToRender
.end());
227 const MFRenderingOptions::RegClassSet
& MFRenderingOptions::regClasses() const{
228 translateRegClassNamesToCurrentFunction();
232 const MFRenderingOptions::IntervalSet
& MFRenderingOptions::intervals() const {
233 translateIntervalNumbersToCurrentFunction();
237 bool MFRenderingOptions::renderEmptyIndexes() const {
238 return showEmptyIndexes
;
241 bool MFRenderingOptions::fancyVerticals() const {
242 return useFancyVerticals
;
245 void MFRenderingOptions::translateRegClassNamesToCurrentFunction() const {
246 if (!regClassesTranslatedToCurrentFunction
) {
248 for (TargetRegisterInfo::regclass_iterator rcItr
= tri
->regclass_begin(),
249 rcEnd
= tri
->regclass_end();
250 rcItr
!= rcEnd
; ++rcItr
) {
251 const TargetRegisterClass
*trc
= *rcItr
;
252 if (renderAllClasses
||
253 classNamesToRender
.find(trc
->getName()) !=
254 classNamesToRender
.end()) {
255 regClassSet
.insert(trc
);
258 regClassesTranslatedToCurrentFunction
= true;
262 void MFRenderingOptions::translateIntervalNumbersToCurrentFunction() const {
263 if (!intervalsTranslatedToCurrentFunction
) {
266 // If we're not just doing explicit then do a copy over all matching
268 if (intervalTypesToRender
!= ExplicitOnly
) {
269 for (LiveIntervals::iterator liItr
= lis
->begin(), liEnd
= lis
->end();
270 liItr
!= liEnd
; ++liItr
) {
271 LiveInterval
*li
= liItr
->second
;
273 if (filterEmpty
&& li
->empty())
276 if ((TargetRegisterInfo::isPhysicalRegister(li
->reg
) &&
277 (intervalTypesToRender
& AllPhys
))) {
278 intervalSet
.insert(li
);
279 } else if (TargetRegisterInfo::isVirtualRegister(li
->reg
)) {
280 if (((intervalTypesToRender
& VirtNoSpills
) && !rmf
->isSpill(li
)) ||
281 ((intervalTypesToRender
& VirtSpills
) && rmf
->isSpill(li
))) {
282 intervalSet
.insert(li
);
288 // If we need to process the explicit list...
289 if (intervalTypesToRender
!= All
) {
290 for (std::set
<std::pair
<unsigned, unsigned> >::const_iterator
291 regRangeItr
= intervalNumsToRender
.begin(),
292 regRangeEnd
= intervalNumsToRender
.end();
293 regRangeItr
!= regRangeEnd
; ++regRangeItr
) {
294 const std::pair
<unsigned, unsigned> &range
= *regRangeItr
;
295 for (unsigned reg
= range
.first
; reg
!= range
.second
; ++reg
) {
296 if (lis
->hasInterval(reg
)) {
297 intervalSet
.insert(&lis
->getInterval(reg
));
303 intervalsTranslatedToCurrentFunction
= true;
307 // ---------- TargetRegisterExtraInformation implementation ----------
309 TargetRegisterExtraInfo::TargetRegisterExtraInfo()
310 : mapsPopulated(false) {
313 void TargetRegisterExtraInfo::setup(MachineFunction
*mf
,
314 MachineRegisterInfo
*mri
,
315 const TargetRegisterInfo
*tri
,
316 LiveIntervals
*lis
) {
323 void TargetRegisterExtraInfo::reset() {
324 if (!mapsPopulated
) {
328 mapsPopulated
= true;
331 resetPressureAndLiveStates();
334 void TargetRegisterExtraInfo::clear() {
339 //liveStatesMap.clear();
340 mapsPopulated
= false;
343 void TargetRegisterExtraInfo::initWorst() {
344 assert(!mapsPopulated
&& prWorst
.empty() && vrWorst
.empty() &&
345 "Worst map already initialised?");
347 // Start with the physical registers.
348 for (unsigned preg
= 1; preg
< tri
->getNumRegs(); ++preg
) {
349 WorstMapLine
&pregLine
= prWorst
[preg
];
351 for (TargetRegisterInfo::regclass_iterator rcItr
= tri
->regclass_begin(),
352 rcEnd
= tri
->regclass_end();
353 rcItr
!= rcEnd
; ++rcItr
) {
354 const TargetRegisterClass
*trc
= *rcItr
;
356 unsigned numOverlaps
= 0;
357 for (TargetRegisterClass::iterator rItr
= trc
->begin(),
359 rItr
!= rEnd
; ++rItr
) {
360 unsigned trcPReg
= *rItr
;
361 if (tri
->regsOverlap(preg
, trcPReg
))
365 pregLine
[trc
] = numOverlaps
;
369 // Now the register classes.
370 for (TargetRegisterInfo::regclass_iterator rc1Itr
= tri
->regclass_begin(),
371 rcEnd
= tri
->regclass_end();
372 rc1Itr
!= rcEnd
; ++rc1Itr
) {
373 const TargetRegisterClass
*trc1
= *rc1Itr
;
374 WorstMapLine
&classLine
= vrWorst
[trc1
];
376 for (TargetRegisterInfo::regclass_iterator rc2Itr
= tri
->regclass_begin();
377 rc2Itr
!= rcEnd
; ++rc2Itr
) {
378 const TargetRegisterClass
*trc2
= *rc2Itr
;
382 for (TargetRegisterClass::iterator trc1Itr
= trc1
->begin(),
383 trc1End
= trc1
->end();
384 trc1Itr
!= trc1End
; ++trc1Itr
) {
385 unsigned trc1Reg
= *trc1Itr
;
386 unsigned trc1RegWorst
= 0;
388 for (TargetRegisterClass::iterator trc2Itr
= trc2
->begin(),
389 trc2End
= trc2
->end();
390 trc2Itr
!= trc2End
; ++trc2Itr
) {
391 unsigned trc2Reg
= *trc2Itr
;
392 if (tri
->regsOverlap(trc1Reg
, trc2Reg
))
395 if (trc1RegWorst
> worst
) {
396 worst
= trc1RegWorst
;
401 classLine
[trc2
] = worst
;
407 unsigned TargetRegisterExtraInfo::getWorst(
409 const TargetRegisterClass
*trc
) const {
410 const WorstMapLine
*wml
= 0;
411 if (TargetRegisterInfo::isPhysicalRegister(reg
)) {
412 PRWorstMap::const_iterator prwItr
= prWorst
.find(reg
);
413 assert(prwItr
!= prWorst
.end() && "Missing prWorst entry.");
414 wml
= &prwItr
->second
;
416 const TargetRegisterClass
*regTRC
= mri
->getRegClass(reg
);
417 VRWorstMap::const_iterator vrwItr
= vrWorst
.find(regTRC
);
418 assert(vrwItr
!= vrWorst
.end() && "Missing vrWorst entry.");
419 wml
= &vrwItr
->second
;
422 WorstMapLine::const_iterator wmlItr
= wml
->find(trc
);
423 if (wmlItr
== wml
->end())
426 return wmlItr
->second
;
429 void TargetRegisterExtraInfo::initCapacity() {
430 assert(!mapsPopulated
&& capacityMap
.empty() &&
431 "Capacity map already initialised?");
433 for (TargetRegisterInfo::regclass_iterator rcItr
= tri
->regclass_begin(),
434 rcEnd
= tri
->regclass_end();
435 rcItr
!= rcEnd
; ++rcItr
) {
436 const TargetRegisterClass
*trc
= *rcItr
;
437 unsigned capacity
= trc
->getRawAllocationOrder(*mf
).size();
440 capacityMap
[trc
] = capacity
;
444 unsigned TargetRegisterExtraInfo::getCapacity(
445 const TargetRegisterClass
*trc
) const {
446 CapacityMap::const_iterator cmItr
= capacityMap
.find(trc
);
447 assert(cmItr
!= capacityMap
.end() &&
448 "vreg with unallocable register class");
449 return cmItr
->second
;
452 void TargetRegisterExtraInfo::resetPressureAndLiveStates() {
454 //liveStatesMap.clear();
456 // Iterate over all slots.
459 // Iterate over all live intervals.
460 for (LiveIntervals::iterator liItr
= lis
->begin(),
462 liItr
!= liEnd
; ++liItr
) {
463 LiveInterval
*li
= liItr
->second
;
465 if (TargetRegisterInfo::isPhysicalRegister(li
->reg
))
468 // For all ranges in the current interal.
469 for (LiveInterval::iterator lrItr
= li
->begin(),
471 lrItr
!= lrEnd
; ++lrItr
) {
472 LiveRange
*lr
= &*lrItr
;
474 // For all slots in the current range.
475 for (SlotIndex i
= lr
->start
; i
!= lr
->end
; i
= i
.getNextSlot()) {
477 // Record increased pressure at index for all overlapping classes.
478 for (TargetRegisterInfo::regclass_iterator
479 rcItr
= tri
->regclass_begin(),
480 rcEnd
= tri
->regclass_end();
481 rcItr
!= rcEnd
; ++rcItr
) {
482 const TargetRegisterClass
*trc
= *rcItr
;
484 if (trc
->getRawAllocationOrder(*mf
).empty())
487 unsigned worstAtI
= getWorst(li
->reg
, trc
);
490 pressureMap
[i
][trc
] += worstAtI
;
498 unsigned TargetRegisterExtraInfo::getPressureAtSlot(
499 const TargetRegisterClass
*trc
,
501 PressureMap::const_iterator pmItr
= pressureMap
.find(i
);
502 if (pmItr
== pressureMap
.end())
504 const PressureMapLine
&pmLine
= pmItr
->second
;
505 PressureMapLine::const_iterator pmlItr
= pmLine
.find(trc
);
506 if (pmlItr
== pmLine
.end())
508 return pmlItr
->second
;
511 bool TargetRegisterExtraInfo::classOverCapacityAtSlot(
512 const TargetRegisterClass
*trc
,
514 return (getPressureAtSlot(trc
, i
) > getCapacity(trc
));
517 // ---------- MachineFunctionRenderer implementation ----------
519 void RenderMachineFunction::Spacer::print(raw_ostream
&os
) const {
522 for (unsigned i
= 0; i
< ns
; ++i
) {
527 RenderMachineFunction::Spacer
RenderMachineFunction::s(unsigned ns
) const {
531 raw_ostream
& operator<<(raw_ostream
&os
, const RenderMachineFunction::Spacer
&s
) {
536 template <typename Iterator
>
537 std::string
RenderMachineFunction::escapeChars(Iterator sBegin
, Iterator sEnd
) const {
540 for (Iterator sItr
= sBegin
; sItr
!= sEnd
; ++sItr
) {
544 case '<': r
.append("<"); break;
545 case '>': r
.append(">"); break;
546 case '&': r
.append("&"); break;
547 case ' ': r
.append(" "); break;
548 case '\"': r
.append("""); break;
549 default: r
.push_back(c
); break;
556 RenderMachineFunction::LiveState
557 RenderMachineFunction::getLiveStateAt(const LiveInterval
*li
,
559 const MachineInstr
*mi
= sis
->getInstructionFromIndex(i
);
561 // For uses/defs recorded use/def indexes override current liveness and
562 // instruction operands (Only for the interval which records the indexes).
563 if (i
.isUse() || i
.isDef()) {
564 UseDefs::const_iterator udItr
= useDefs
.find(li
);
565 if (udItr
!= useDefs
.end()) {
566 const SlotSet
&slotSet
= udItr
->second
;
567 if (slotSet
.count(i
)) {
577 // If the slot is a load/store, or there's no info in the use/def set then
578 // use liveness and instruction operand info.
583 (vrm
->getStackSlot(li
->reg
) == VirtRegMap::NO_STACK_SLOT
)) {
589 if (i
.isDef() && mi
->definesRegister(li
->reg
, tri
)) {
591 } else if (i
.isUse() && mi
->readsRegister(li
->reg
)) {
595 (vrm
->getStackSlot(li
->reg
) == VirtRegMap::NO_STACK_SLOT
)) {
606 RenderMachineFunction::PressureState
607 RenderMachineFunction::getPressureStateAt(const TargetRegisterClass
*trc
,
609 if (trei
.getPressureAtSlot(trc
, i
) == 0) {
611 } else if (trei
.classOverCapacityAtSlot(trc
, i
)){
617 /// \brief Render a machine instruction.
618 void RenderMachineFunction::renderMachineInstr(raw_ostream
&os
,
619 const MachineInstr
*mi
) const {
621 raw_string_ostream
oss(s
);
624 os
<< escapeChars(oss
.str());
627 template <typename T
>
628 void RenderMachineFunction::renderVertical(const Spacer
&indent
,
631 if (ro
.fancyVerticals()) {
632 os
<< indent
<< "<object\n"
633 << indent
+ s(2) << "class=\"obj\"\n"
634 << indent
+ s(2) << "type=\"image/svg+xml\"\n"
635 << indent
+ s(2) << "width=\"14px\"\n"
636 << indent
+ s(2) << "height=\"55px\"\n"
637 << indent
+ s(2) << "data=\"data:image/svg+xml,\n"
638 << indent
+ s(4) << "<svg xmlns='http://www.w3.org/2000/svg'>\n"
639 << indent
+ s(6) << "<text x='-55' y='10' "
640 "font-family='Courier' font-size='12' "
641 "transform='rotate(-90)' "
642 "text-rendering='optimizeSpeed' "
643 "fill='#000'>" << t
<< "</text>\n"
644 << indent
+ s(4) << "</svg>\">\n"
645 << indent
<< "</object>\n";
647 std::ostringstream oss
;
649 std::string
tStr(oss
.str());
652 for (std::string::iterator tStrItr
= tStr
.begin(), tStrEnd
= tStr
.end();
653 tStrItr
!= tStrEnd
; ++tStrItr
) {
654 os
<< *tStrItr
<< "<br/>";
660 void RenderMachineFunction::insertCSS(const Spacer
&indent
,
661 raw_ostream
&os
) const {
662 os
<< indent
<< "<style type=\"text/css\">\n"
663 << indent
+ s(2) << "body { font-color: black; }\n"
664 << indent
+ s(2) << "table.code td { font-family: monospace; "
665 "border-width: 0px; border-style: solid; "
666 "border-bottom: 1px solid #dddddd; white-space: nowrap; }\n"
667 << indent
+ s(2) << "table.code td.p-z { background-color: #000000; }\n"
668 << indent
+ s(2) << "table.code td.p-l { background-color: #00ff00; }\n"
669 << indent
+ s(2) << "table.code td.p-h { background-color: #ff0000; }\n"
670 << indent
+ s(2) << "table.code td.l-n { background-color: #ffffff; }\n"
671 << indent
+ s(2) << "table.code td.l-d { background-color: #ff0000; }\n"
672 << indent
+ s(2) << "table.code td.l-u { background-color: #ffff00; }\n"
673 << indent
+ s(2) << "table.code td.l-r { background-color: #000000; }\n"
674 << indent
+ s(2) << "table.code td.l-s { background-color: #770000; }\n"
675 << indent
+ s(2) << "table.code th { border-width: 0px; "
676 "border-style: solid; }\n"
677 << indent
<< "</style>\n";
680 void RenderMachineFunction::renderFunctionSummary(
681 const Spacer
&indent
, raw_ostream
&os
,
682 const char * const renderContextStr
) const {
683 os
<< indent
<< "<h1>Function: " << mf
->getFunction()->getName()
685 << indent
<< "<h2>Rendering context: " << renderContextStr
<< "</h2>\n";
689 void RenderMachineFunction::renderPressureTableLegend(
690 const Spacer
&indent
,
691 raw_ostream
&os
) const {
692 os
<< indent
<< "<h2>Rendering Pressure Legend:</h2>\n"
693 << indent
<< "<table class=\"code\">\n"
694 << indent
+ s(2) << "<tr>\n"
695 << indent
+ s(4) << "<th>Pressure</th><th>Description</th>"
696 "<th>Appearance</th>\n"
697 << indent
+ s(2) << "</tr>\n"
698 << indent
+ s(2) << "<tr>\n"
699 << indent
+ s(4) << "<td>No Pressure</td>"
700 "<td>No physical registers of this class requested.</td>"
701 "<td class=\"p-z\"> </td>\n"
702 << indent
+ s(2) << "</tr>\n"
703 << indent
+ s(2) << "<tr>\n"
704 << indent
+ s(4) << "<td>Low Pressure</td>"
705 "<td>Sufficient physical registers to meet demand.</td>"
706 "<td class=\"p-l\"> </td>\n"
707 << indent
+ s(2) << "</tr>\n"
708 << indent
+ s(2) << "<tr>\n"
709 << indent
+ s(4) << "<td>High Pressure</td>"
710 "<td>Potentially insufficient physical registers to meet demand.</td>"
711 "<td class=\"p-h\"> </td>\n"
712 << indent
+ s(2) << "</tr>\n"
713 << indent
<< "</table>\n";
716 template <typename CellType
>
717 void RenderMachineFunction::renderCellsWithRLE(
718 const Spacer
&indent
, raw_ostream
&os
,
719 const std::pair
<CellType
, unsigned> &rleAccumulator
,
720 const std::map
<CellType
, std::string
> &cellTypeStrs
) const {
722 if (rleAccumulator
.second
== 0)
725 typename
std::map
<CellType
, std::string
>::const_iterator ctsItr
=
726 cellTypeStrs
.find(rleAccumulator
.first
);
728 assert(ctsItr
!= cellTypeStrs
.end() && "No string for given cell type.");
730 os
<< indent
+ s(4) << "<td class=\"" << ctsItr
->second
<< "\"";
731 if (rleAccumulator
.second
> 1)
732 os
<< " colspan=" << rleAccumulator
.second
;
737 void RenderMachineFunction::renderCodeTablePlusPI(const Spacer
&indent
,
738 raw_ostream
&os
) const {
740 std::map
<LiveState
, std::string
> lsStrs
;
741 lsStrs
[Dead
] = "l-n";
742 lsStrs
[Defined
] = "l-d";
743 lsStrs
[Used
] = "l-u";
744 lsStrs
[AliveReg
] = "l-r";
745 lsStrs
[AliveStack
] = "l-s";
747 std::map
<PressureState
, std::string
> psStrs
;
748 psStrs
[Zero
] = "p-z";
750 psStrs
[High
] = "p-h";
754 os
<< indent
<< "<table cellpadding=0 cellspacing=0 class=\"code\">\n"
755 << indent
+ s(2) << "<tr>\n";
757 // Render the header row...
759 os
<< indent
+ s(4) << "<th>index</th>\n"
760 << indent
+ s(4) << "<th>instr</th>\n";
762 // Render class names if necessary...
763 if (!ro
.regClasses().empty()) {
764 for (MFRenderingOptions::RegClassSet::const_iterator
765 rcItr
= ro
.regClasses().begin(),
766 rcEnd
= ro
.regClasses().end();
767 rcItr
!= rcEnd
; ++rcItr
) {
768 const TargetRegisterClass
*trc
= *rcItr
;
769 os
<< indent
+ s(4) << "<th>\n";
770 renderVertical(indent
+ s(6), os
, trc
->getName());
771 os
<< indent
+ s(4) << "</th>\n";
775 // FIXME: Is there a nicer way to insert space between columns in HTML?
776 if (!ro
.regClasses().empty() && !ro
.intervals().empty())
777 os
<< indent
+ s(4) << "<th> </th>\n";
779 // Render interval numbers if necessary...
780 if (!ro
.intervals().empty()) {
781 for (MFRenderingOptions::IntervalSet::const_iterator
782 liItr
= ro
.intervals().begin(),
783 liEnd
= ro
.intervals().end();
784 liItr
!= liEnd
; ++liItr
) {
786 const LiveInterval
*li
= *liItr
;
787 os
<< indent
+ s(4) << "<th>\n";
788 renderVertical(indent
+ s(6), os
, li
->reg
);
789 os
<< indent
+ s(4) << "</th>\n";
793 os
<< indent
+ s(2) << "</tr>\n";
795 // End header row, start with the data rows...
797 MachineInstr
*mi
= 0;
800 for (SlotIndex i
= sis
->getZeroIndex(); i
!= sis
->getLastIndex();
801 i
= i
.getNextSlot()) {
803 // Render the slot column.
804 os
<< indent
+ s(2) << "<tr height=6ex>\n";
806 // Render the code column.
808 MachineBasicBlock
*mbb
= sis
->getMBBFromIndex(i
);
809 mi
= sis
->getInstructionFromIndex(i
);
811 if (i
== sis
->getMBBStartIdx(mbb
) || mi
!= 0 ||
812 ro
.renderEmptyIndexes()) {
813 os
<< indent
+ s(4) << "<td rowspan=4>" << i
<< " </td>\n"
814 << indent
+ s(4) << "<td rowspan=4>\n";
816 if (i
== sis
->getMBBStartIdx(mbb
)) {
817 os
<< indent
+ s(6) << "BB#" << mbb
->getNumber() << ": \n";
818 } else if (mi
!= 0) {
819 os
<< indent
+ s(6) << " ";
820 renderMachineInstr(os
, mi
);
822 // Empty interval - leave blank.
824 os
<< indent
+ s(4) << "</td>\n";
826 i
= i
.getStoreIndex(); // <- Will be incremented to the next index.
831 // Render the class columns.
832 if (!ro
.regClasses().empty()) {
833 std::pair
<PressureState
, unsigned> psRLEAccumulator(Zero
, 0);
834 for (MFRenderingOptions::RegClassSet::const_iterator
835 rcItr
= ro
.regClasses().begin(),
836 rcEnd
= ro
.regClasses().end();
837 rcItr
!= rcEnd
; ++rcItr
) {
838 const TargetRegisterClass
*trc
= *rcItr
;
839 PressureState newPressure
= getPressureStateAt(trc
, i
);
841 if (newPressure
== psRLEAccumulator
.first
) {
842 ++psRLEAccumulator
.second
;
844 renderCellsWithRLE(indent
+ s(4), os
, psRLEAccumulator
, psStrs
);
845 psRLEAccumulator
.first
= newPressure
;
846 psRLEAccumulator
.second
= 1;
849 renderCellsWithRLE(indent
+ s(4), os
, psRLEAccumulator
, psStrs
);
852 // FIXME: Is there a nicer way to insert space between columns in HTML?
853 if (!ro
.regClasses().empty() && !ro
.intervals().empty())
854 os
<< indent
+ s(4) << "<td width=2em></td>\n";
856 if (!ro
.intervals().empty()) {
857 std::pair
<LiveState
, unsigned> lsRLEAccumulator(Dead
, 0);
858 for (MFRenderingOptions::IntervalSet::const_iterator
859 liItr
= ro
.intervals().begin(),
860 liEnd
= ro
.intervals().end();
861 liItr
!= liEnd
; ++liItr
) {
862 const LiveInterval
*li
= *liItr
;
863 LiveState newLiveness
= getLiveStateAt(li
, i
);
865 if (newLiveness
== lsRLEAccumulator
.first
) {
866 ++lsRLEAccumulator
.second
;
868 renderCellsWithRLE(indent
+ s(4), os
, lsRLEAccumulator
, lsStrs
);
869 lsRLEAccumulator
.first
= newLiveness
;
870 lsRLEAccumulator
.second
= 1;
873 renderCellsWithRLE(indent
+ s(4), os
, lsRLEAccumulator
, lsStrs
);
875 os
<< indent
+ s(2) << "</tr>\n";
878 os
<< indent
<< "</table>\n";
880 if (!ro
.regClasses().empty())
881 renderPressureTableLegend(indent
, os
);
884 void RenderMachineFunction::renderFunctionPage(
886 const char * const renderContextStr
) const {
888 << s(2) << "<head>\n"
889 << s(4) << "<title>" << fqn
<< "</title>\n";
893 os
<< s(2) << "<head>\n"
894 << s(2) << "<body >\n";
896 renderFunctionSummary(s(4), os
, renderContextStr
);
898 os
<< s(4) << "<br/><br/><br/>\n";
900 //renderLiveIntervalInfoTable(" ", os);
902 os
<< s(4) << "<br/><br/><br/>\n";
904 renderCodeTablePlusPI(s(4), os
);
906 os
<< s(2) << "</body>\n"
910 void RenderMachineFunction::getAnalysisUsage(AnalysisUsage
&au
) const {
911 au
.addRequired
<SlotIndexes
>();
912 au
.addRequired
<LiveIntervals
>();
913 au
.setPreservesAll();
914 MachineFunctionPass::getAnalysisUsage(au
);
917 bool RenderMachineFunction::runOnMachineFunction(MachineFunction
&fn
) {
920 mri
= &mf
->getRegInfo();
921 tri
= mf
->getTarget().getRegisterInfo();
922 lis
= &getAnalysis
<LiveIntervals
>();
923 sis
= &getAnalysis
<SlotIndexes
>();
925 trei
.setup(mf
, mri
, tri
, lis
);
926 ro
.setup(mf
, tri
, lis
, this);
927 spillIntervals
.clear();
931 fqn
= mf
->getFunction()->getParent()->getModuleIdentifier() + "." +
932 mf
->getFunction()->getName().str();
937 void RenderMachineFunction::releaseMemory() {
940 spillIntervals
.clear();
945 void RenderMachineFunction::rememberUseDefs(const LiveInterval
*li
) {
947 if (!ro
.shouldRenderCurrentMachineFunction())
950 for (MachineRegisterInfo::reg_iterator rItr
= mri
->reg_begin(li
->reg
),
951 rEnd
= mri
->reg_end();
952 rItr
!= rEnd
; ++rItr
) {
953 const MachineInstr
*mi
= &*rItr
;
954 if (mi
->readsRegister(li
->reg
)) {
955 useDefs
[li
].insert(lis
->getInstructionIndex(mi
).getUseIndex());
957 if (mi
->definesRegister(li
->reg
)) {
958 useDefs
[li
].insert(lis
->getInstructionIndex(mi
).getDefIndex());
963 void RenderMachineFunction::rememberSpills(
964 const LiveInterval
*li
,
965 const std::vector
<LiveInterval
*> &spills
) {
967 if (!ro
.shouldRenderCurrentMachineFunction())
970 for (std::vector
<LiveInterval
*>::const_iterator siItr
= spills
.begin(),
971 siEnd
= spills
.end();
972 siItr
!= siEnd
; ++siItr
) {
973 const LiveInterval
*spill
= *siItr
;
974 spillIntervals
[li
].insert(spill
);
975 spillFor
[spill
] = li
;
979 bool RenderMachineFunction::isSpill(const LiveInterval
*li
) const {
980 SpillForMap::const_iterator sfItr
= spillFor
.find(li
);
981 if (sfItr
== spillFor
.end())
986 void RenderMachineFunction::renderMachineFunction(
987 const char *renderContextStr
,
988 const VirtRegMap
*vrm
,
989 const char *renderSuffix
) {
990 if (!ro
.shouldRenderCurrentMachineFunction())
996 std::string
rpFileName(mf
->getFunction()->getName().str() +
997 (renderSuffix
? renderSuffix
: "") +
1001 raw_fd_ostream
outFile(rpFileName
.c_str(), errMsg
, raw_fd_ostream::F_Binary
);
1003 renderFunctionPage(outFile
, renderContextStr
);
1005 ro
.resetRenderSpecificOptions();
1008 std::string
RenderMachineFunction::escapeChars(const std::string
&s
) const {
1009 return escapeChars(s
.begin(), s
.end());