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
= std::distance(trc
->allocation_order_begin(*mf
),
438 trc
->allocation_order_end(*mf
));
441 capacityMap
[trc
] = capacity
;
445 unsigned TargetRegisterExtraInfo::getCapacity(
446 const TargetRegisterClass
*trc
) const {
447 CapacityMap::const_iterator cmItr
= capacityMap
.find(trc
);
448 assert(cmItr
!= capacityMap
.end() &&
449 "vreg with unallocable register class");
450 return cmItr
->second
;
453 void TargetRegisterExtraInfo::resetPressureAndLiveStates() {
455 //liveStatesMap.clear();
457 // Iterate over all slots.
460 // Iterate over all live intervals.
461 for (LiveIntervals::iterator liItr
= lis
->begin(),
463 liItr
!= liEnd
; ++liItr
) {
464 LiveInterval
*li
= liItr
->second
;
466 if (TargetRegisterInfo::isPhysicalRegister(li
->reg
))
469 // For all ranges in the current interal.
470 for (LiveInterval::iterator lrItr
= li
->begin(),
472 lrItr
!= lrEnd
; ++lrItr
) {
473 LiveRange
*lr
= &*lrItr
;
475 // For all slots in the current range.
476 for (SlotIndex i
= lr
->start
; i
!= lr
->end
; i
= i
.getNextSlot()) {
478 // Record increased pressure at index for all overlapping classes.
479 for (TargetRegisterInfo::regclass_iterator
480 rcItr
= tri
->regclass_begin(),
481 rcEnd
= tri
->regclass_end();
482 rcItr
!= rcEnd
; ++rcItr
) {
483 const TargetRegisterClass
*trc
= *rcItr
;
485 if (trc
->allocation_order_begin(*mf
) ==
486 trc
->allocation_order_end(*mf
))
489 unsigned worstAtI
= getWorst(li
->reg
, trc
);
492 pressureMap
[i
][trc
] += worstAtI
;
500 unsigned TargetRegisterExtraInfo::getPressureAtSlot(
501 const TargetRegisterClass
*trc
,
503 PressureMap::const_iterator pmItr
= pressureMap
.find(i
);
504 if (pmItr
== pressureMap
.end())
506 const PressureMapLine
&pmLine
= pmItr
->second
;
507 PressureMapLine::const_iterator pmlItr
= pmLine
.find(trc
);
508 if (pmlItr
== pmLine
.end())
510 return pmlItr
->second
;
513 bool TargetRegisterExtraInfo::classOverCapacityAtSlot(
514 const TargetRegisterClass
*trc
,
516 return (getPressureAtSlot(trc
, i
) > getCapacity(trc
));
519 // ---------- MachineFunctionRenderer implementation ----------
521 void RenderMachineFunction::Spacer::print(raw_ostream
&os
) const {
524 for (unsigned i
= 0; i
< ns
; ++i
) {
529 RenderMachineFunction::Spacer
RenderMachineFunction::s(unsigned ns
) const {
533 raw_ostream
& operator<<(raw_ostream
&os
, const RenderMachineFunction::Spacer
&s
) {
538 template <typename Iterator
>
539 std::string
RenderMachineFunction::escapeChars(Iterator sBegin
, Iterator sEnd
) const {
542 for (Iterator sItr
= sBegin
; sItr
!= sEnd
; ++sItr
) {
546 case '<': r
.append("<"); break;
547 case '>': r
.append(">"); break;
548 case '&': r
.append("&"); break;
549 case ' ': r
.append(" "); break;
550 case '\"': r
.append("""); break;
551 default: r
.push_back(c
); break;
558 RenderMachineFunction::LiveState
559 RenderMachineFunction::getLiveStateAt(const LiveInterval
*li
,
561 const MachineInstr
*mi
= sis
->getInstructionFromIndex(i
);
563 // For uses/defs recorded use/def indexes override current liveness and
564 // instruction operands (Only for the interval which records the indexes).
565 if (i
.isUse() || i
.isDef()) {
566 UseDefs::const_iterator udItr
= useDefs
.find(li
);
567 if (udItr
!= useDefs
.end()) {
568 const SlotSet
&slotSet
= udItr
->second
;
569 if (slotSet
.count(i
)) {
579 // If the slot is a load/store, or there's no info in the use/def set then
580 // use liveness and instruction operand info.
585 (vrm
->getStackSlot(li
->reg
) == VirtRegMap::NO_STACK_SLOT
)) {
591 if (i
.isDef() && mi
->definesRegister(li
->reg
, tri
)) {
593 } else if (i
.isUse() && mi
->readsRegister(li
->reg
)) {
597 (vrm
->getStackSlot(li
->reg
) == VirtRegMap::NO_STACK_SLOT
)) {
608 RenderMachineFunction::PressureState
609 RenderMachineFunction::getPressureStateAt(const TargetRegisterClass
*trc
,
611 if (trei
.getPressureAtSlot(trc
, i
) == 0) {
613 } else if (trei
.classOverCapacityAtSlot(trc
, i
)){
619 /// \brief Render a machine instruction.
620 void RenderMachineFunction::renderMachineInstr(raw_ostream
&os
,
621 const MachineInstr
*mi
) const {
623 raw_string_ostream
oss(s
);
626 os
<< escapeChars(oss
.str());
629 template <typename T
>
630 void RenderMachineFunction::renderVertical(const Spacer
&indent
,
633 if (ro
.fancyVerticals()) {
634 os
<< indent
<< "<object\n"
635 << indent
+ s(2) << "class=\"obj\"\n"
636 << indent
+ s(2) << "type=\"image/svg+xml\"\n"
637 << indent
+ s(2) << "width=\"14px\"\n"
638 << indent
+ s(2) << "height=\"55px\"\n"
639 << indent
+ s(2) << "data=\"data:image/svg+xml,\n"
640 << indent
+ s(4) << "<svg xmlns='http://www.w3.org/2000/svg'>\n"
641 << indent
+ s(6) << "<text x='-55' y='10' "
642 "font-family='Courier' font-size='12' "
643 "transform='rotate(-90)' "
644 "text-rendering='optimizeSpeed' "
645 "fill='#000'>" << t
<< "</text>\n"
646 << indent
+ s(4) << "</svg>\">\n"
647 << indent
<< "</object>\n";
649 std::ostringstream oss
;
651 std::string
tStr(oss
.str());
654 for (std::string::iterator tStrItr
= tStr
.begin(), tStrEnd
= tStr
.end();
655 tStrItr
!= tStrEnd
; ++tStrItr
) {
656 os
<< *tStrItr
<< "<br/>";
662 void RenderMachineFunction::insertCSS(const Spacer
&indent
,
663 raw_ostream
&os
) const {
664 os
<< indent
<< "<style type=\"text/css\">\n"
665 << indent
+ s(2) << "body { font-color: black; }\n"
666 << indent
+ s(2) << "table.code td { font-family: monospace; "
667 "border-width: 0px; border-style: solid; "
668 "border-bottom: 1px solid #dddddd; white-space: nowrap; }\n"
669 << indent
+ s(2) << "table.code td.p-z { background-color: #000000; }\n"
670 << indent
+ s(2) << "table.code td.p-l { background-color: #00ff00; }\n"
671 << indent
+ s(2) << "table.code td.p-h { background-color: #ff0000; }\n"
672 << indent
+ s(2) << "table.code td.l-n { background-color: #ffffff; }\n"
673 << indent
+ s(2) << "table.code td.l-d { background-color: #ff0000; }\n"
674 << indent
+ s(2) << "table.code td.l-u { background-color: #ffff00; }\n"
675 << indent
+ s(2) << "table.code td.l-r { background-color: #000000; }\n"
676 << indent
+ s(2) << "table.code td.l-s { background-color: #770000; }\n"
677 << indent
+ s(2) << "table.code th { border-width: 0px; "
678 "border-style: solid; }\n"
679 << indent
<< "</style>\n";
682 void RenderMachineFunction::renderFunctionSummary(
683 const Spacer
&indent
, raw_ostream
&os
,
684 const char * const renderContextStr
) const {
685 os
<< indent
<< "<h1>Function: " << mf
->getFunction()->getName()
687 << indent
<< "<h2>Rendering context: " << renderContextStr
<< "</h2>\n";
691 void RenderMachineFunction::renderPressureTableLegend(
692 const Spacer
&indent
,
693 raw_ostream
&os
) const {
694 os
<< indent
<< "<h2>Rendering Pressure Legend:</h2>\n"
695 << indent
<< "<table class=\"code\">\n"
696 << indent
+ s(2) << "<tr>\n"
697 << indent
+ s(4) << "<th>Pressure</th><th>Description</th>"
698 "<th>Appearance</th>\n"
699 << indent
+ s(2) << "</tr>\n"
700 << indent
+ s(2) << "<tr>\n"
701 << indent
+ s(4) << "<td>No Pressure</td>"
702 "<td>No physical registers of this class requested.</td>"
703 "<td class=\"p-z\"> </td>\n"
704 << indent
+ s(2) << "</tr>\n"
705 << indent
+ s(2) << "<tr>\n"
706 << indent
+ s(4) << "<td>Low Pressure</td>"
707 "<td>Sufficient physical registers to meet demand.</td>"
708 "<td class=\"p-l\"> </td>\n"
709 << indent
+ s(2) << "</tr>\n"
710 << indent
+ s(2) << "<tr>\n"
711 << indent
+ s(4) << "<td>High Pressure</td>"
712 "<td>Potentially insufficient physical registers to meet demand.</td>"
713 "<td class=\"p-h\"> </td>\n"
714 << indent
+ s(2) << "</tr>\n"
715 << indent
<< "</table>\n";
718 template <typename CellType
>
719 void RenderMachineFunction::renderCellsWithRLE(
720 const Spacer
&indent
, raw_ostream
&os
,
721 const std::pair
<CellType
, unsigned> &rleAccumulator
,
722 const std::map
<CellType
, std::string
> &cellTypeStrs
) const {
724 if (rleAccumulator
.second
== 0)
727 typename
std::map
<CellType
, std::string
>::const_iterator ctsItr
=
728 cellTypeStrs
.find(rleAccumulator
.first
);
730 assert(ctsItr
!= cellTypeStrs
.end() && "No string for given cell type.");
732 os
<< indent
+ s(4) << "<td class=\"" << ctsItr
->second
<< "\"";
733 if (rleAccumulator
.second
> 1)
734 os
<< " colspan=" << rleAccumulator
.second
;
739 void RenderMachineFunction::renderCodeTablePlusPI(const Spacer
&indent
,
740 raw_ostream
&os
) const {
742 std::map
<LiveState
, std::string
> lsStrs
;
743 lsStrs
[Dead
] = "l-n";
744 lsStrs
[Defined
] = "l-d";
745 lsStrs
[Used
] = "l-u";
746 lsStrs
[AliveReg
] = "l-r";
747 lsStrs
[AliveStack
] = "l-s";
749 std::map
<PressureState
, std::string
> psStrs
;
750 psStrs
[Zero
] = "p-z";
752 psStrs
[High
] = "p-h";
756 os
<< indent
<< "<table cellpadding=0 cellspacing=0 class=\"code\">\n"
757 << indent
+ s(2) << "<tr>\n";
759 // Render the header row...
761 os
<< indent
+ s(4) << "<th>index</th>\n"
762 << indent
+ s(4) << "<th>instr</th>\n";
764 // Render class names if necessary...
765 if (!ro
.regClasses().empty()) {
766 for (MFRenderingOptions::RegClassSet::const_iterator
767 rcItr
= ro
.regClasses().begin(),
768 rcEnd
= ro
.regClasses().end();
769 rcItr
!= rcEnd
; ++rcItr
) {
770 const TargetRegisterClass
*trc
= *rcItr
;
771 os
<< indent
+ s(4) << "<th>\n";
772 renderVertical(indent
+ s(6), os
, trc
->getName());
773 os
<< indent
+ s(4) << "</th>\n";
777 // FIXME: Is there a nicer way to insert space between columns in HTML?
778 if (!ro
.regClasses().empty() && !ro
.intervals().empty())
779 os
<< indent
+ s(4) << "<th> </th>\n";
781 // Render interval numbers if necessary...
782 if (!ro
.intervals().empty()) {
783 for (MFRenderingOptions::IntervalSet::const_iterator
784 liItr
= ro
.intervals().begin(),
785 liEnd
= ro
.intervals().end();
786 liItr
!= liEnd
; ++liItr
) {
788 const LiveInterval
*li
= *liItr
;
789 os
<< indent
+ s(4) << "<th>\n";
790 renderVertical(indent
+ s(6), os
, li
->reg
);
791 os
<< indent
+ s(4) << "</th>\n";
795 os
<< indent
+ s(2) << "</tr>\n";
797 // End header row, start with the data rows...
799 MachineInstr
*mi
= 0;
802 for (SlotIndex i
= sis
->getZeroIndex(); i
!= sis
->getLastIndex();
803 i
= i
.getNextSlot()) {
805 // Render the slot column.
806 os
<< indent
+ s(2) << "<tr height=6ex>\n";
808 // Render the code column.
810 MachineBasicBlock
*mbb
= sis
->getMBBFromIndex(i
);
811 mi
= sis
->getInstructionFromIndex(i
);
813 if (i
== sis
->getMBBStartIdx(mbb
) || mi
!= 0 ||
814 ro
.renderEmptyIndexes()) {
815 os
<< indent
+ s(4) << "<td rowspan=4>" << i
<< " </td>\n"
816 << indent
+ s(4) << "<td rowspan=4>\n";
818 if (i
== sis
->getMBBStartIdx(mbb
)) {
819 os
<< indent
+ s(6) << "BB#" << mbb
->getNumber() << ": \n";
820 } else if (mi
!= 0) {
821 os
<< indent
+ s(6) << " ";
822 renderMachineInstr(os
, mi
);
824 // Empty interval - leave blank.
826 os
<< indent
+ s(4) << "</td>\n";
828 i
= i
.getStoreIndex(); // <- Will be incremented to the next index.
833 // Render the class columns.
834 if (!ro
.regClasses().empty()) {
835 std::pair
<PressureState
, unsigned> psRLEAccumulator(Zero
, 0);
836 for (MFRenderingOptions::RegClassSet::const_iterator
837 rcItr
= ro
.regClasses().begin(),
838 rcEnd
= ro
.regClasses().end();
839 rcItr
!= rcEnd
; ++rcItr
) {
840 const TargetRegisterClass
*trc
= *rcItr
;
841 PressureState newPressure
= getPressureStateAt(trc
, i
);
843 if (newPressure
== psRLEAccumulator
.first
) {
844 ++psRLEAccumulator
.second
;
846 renderCellsWithRLE(indent
+ s(4), os
, psRLEAccumulator
, psStrs
);
847 psRLEAccumulator
.first
= newPressure
;
848 psRLEAccumulator
.second
= 1;
851 renderCellsWithRLE(indent
+ s(4), os
, psRLEAccumulator
, psStrs
);
854 // FIXME: Is there a nicer way to insert space between columns in HTML?
855 if (!ro
.regClasses().empty() && !ro
.intervals().empty())
856 os
<< indent
+ s(4) << "<td width=2em></td>\n";
858 if (!ro
.intervals().empty()) {
859 std::pair
<LiveState
, unsigned> lsRLEAccumulator(Dead
, 0);
860 for (MFRenderingOptions::IntervalSet::const_iterator
861 liItr
= ro
.intervals().begin(),
862 liEnd
= ro
.intervals().end();
863 liItr
!= liEnd
; ++liItr
) {
864 const LiveInterval
*li
= *liItr
;
865 LiveState newLiveness
= getLiveStateAt(li
, i
);
867 if (newLiveness
== lsRLEAccumulator
.first
) {
868 ++lsRLEAccumulator
.second
;
870 renderCellsWithRLE(indent
+ s(4), os
, lsRLEAccumulator
, lsStrs
);
871 lsRLEAccumulator
.first
= newLiveness
;
872 lsRLEAccumulator
.second
= 1;
875 renderCellsWithRLE(indent
+ s(4), os
, lsRLEAccumulator
, lsStrs
);
877 os
<< indent
+ s(2) << "</tr>\n";
880 os
<< indent
<< "</table>\n";
882 if (!ro
.regClasses().empty())
883 renderPressureTableLegend(indent
, os
);
886 void RenderMachineFunction::renderFunctionPage(
888 const char * const renderContextStr
) const {
890 << s(2) << "<head>\n"
891 << s(4) << "<title>" << fqn
<< "</title>\n";
895 os
<< s(2) << "<head>\n"
896 << s(2) << "<body >\n";
898 renderFunctionSummary(s(4), os
, renderContextStr
);
900 os
<< s(4) << "<br/><br/><br/>\n";
902 //renderLiveIntervalInfoTable(" ", os);
904 os
<< s(4) << "<br/><br/><br/>\n";
906 renderCodeTablePlusPI(s(4), os
);
908 os
<< s(2) << "</body>\n"
912 void RenderMachineFunction::getAnalysisUsage(AnalysisUsage
&au
) const {
913 au
.addRequired
<SlotIndexes
>();
914 au
.addRequired
<LiveIntervals
>();
915 au
.setPreservesAll();
916 MachineFunctionPass::getAnalysisUsage(au
);
919 bool RenderMachineFunction::runOnMachineFunction(MachineFunction
&fn
) {
922 mri
= &mf
->getRegInfo();
923 tri
= mf
->getTarget().getRegisterInfo();
924 lis
= &getAnalysis
<LiveIntervals
>();
925 sis
= &getAnalysis
<SlotIndexes
>();
927 trei
.setup(mf
, mri
, tri
, lis
);
928 ro
.setup(mf
, tri
, lis
, this);
929 spillIntervals
.clear();
933 fqn
= mf
->getFunction()->getParent()->getModuleIdentifier() + "." +
934 mf
->getFunction()->getName().str();
939 void RenderMachineFunction::releaseMemory() {
942 spillIntervals
.clear();
947 void RenderMachineFunction::rememberUseDefs(const LiveInterval
*li
) {
949 if (!ro
.shouldRenderCurrentMachineFunction())
952 for (MachineRegisterInfo::reg_iterator rItr
= mri
->reg_begin(li
->reg
),
953 rEnd
= mri
->reg_end();
954 rItr
!= rEnd
; ++rItr
) {
955 const MachineInstr
*mi
= &*rItr
;
956 if (mi
->readsRegister(li
->reg
)) {
957 useDefs
[li
].insert(lis
->getInstructionIndex(mi
).getUseIndex());
959 if (mi
->definesRegister(li
->reg
)) {
960 useDefs
[li
].insert(lis
->getInstructionIndex(mi
).getDefIndex());
965 void RenderMachineFunction::rememberSpills(
966 const LiveInterval
*li
,
967 const std::vector
<LiveInterval
*> &spills
) {
969 if (!ro
.shouldRenderCurrentMachineFunction())
972 for (std::vector
<LiveInterval
*>::const_iterator siItr
= spills
.begin(),
973 siEnd
= spills
.end();
974 siItr
!= siEnd
; ++siItr
) {
975 const LiveInterval
*spill
= *siItr
;
976 spillIntervals
[li
].insert(spill
);
977 spillFor
[spill
] = li
;
981 bool RenderMachineFunction::isSpill(const LiveInterval
*li
) const {
982 SpillForMap::const_iterator sfItr
= spillFor
.find(li
);
983 if (sfItr
== spillFor
.end())
988 void RenderMachineFunction::renderMachineFunction(
989 const char *renderContextStr
,
990 const VirtRegMap
*vrm
,
991 const char *renderSuffix
) {
992 if (!ro
.shouldRenderCurrentMachineFunction())
998 std::string
rpFileName(mf
->getFunction()->getName().str() +
999 (renderSuffix
? renderSuffix
: "") +
1003 raw_fd_ostream
outFile(rpFileName
.c_str(), errMsg
, raw_fd_ostream::F_Binary
);
1005 renderFunctionPage(outFile
, renderContextStr
);
1007 ro
.resetRenderSpecificOptions();
1010 std::string
RenderMachineFunction::escapeChars(const std::string
&s
) const {
1011 return escapeChars(s
.begin(), s
.end());