blob: 6520449a79a613ab8d87b1e9f5efd953c9697154 [file] [log] [blame]
Lang Hames54cc2ef2010-07-19 15:22:28 +00001//===-- llvm/CodeGen/RenderMachineFunction.cpp - MF->HTML -----s-----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#define DEBUG_TYPE "rendermf"
11
12#include "RenderMachineFunction.h"
13
14#include "llvm/Function.h"
15#include "llvm/Module.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/CodeGen/LiveIntervalAnalysis.h"
18#include "llvm/CodeGen/MachineFunction.h"
19#include "llvm/CodeGen/MachineInstr.h"
20#include "llvm/CodeGen/MachineRegisterInfo.h"
21#include "llvm/Support/CommandLine.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/raw_ostream.h"
24#include "llvm/Target/TargetMachine.h"
25
26#include <sstream>
27
28using namespace llvm;
29
30char RenderMachineFunction::ID = 0;
31static RegisterPass<RenderMachineFunction>
32X("rendermf", "Render machine functions (and related info) to HTML pages");
33
34static cl::opt<std::string>
35outputFileSuffix("rmf-file-suffix",
36 cl::desc("Appended to function name to get output file name "
37 "(default: \".html\")"),
38 cl::init(".html"), cl::Hidden);
39
40static cl::opt<std::string>
41machineFuncsToRender("rmf-funcs",
42 cl::desc("Coma seperated list of functions to render"
43 ", or \"*\"."),
44 cl::init(""), cl::Hidden);
45
46static cl::opt<std::string>
47pressureClasses("rmf-classes",
48 cl::desc("Register classes to render pressure for."),
49 cl::init(""), cl::Hidden);
50
51static cl::opt<std::string>
52showIntervals("rmf-intervals",
53 cl::desc("Live intervals to show alongside code."),
54 cl::init(""), cl::Hidden);
55
56static cl::opt<bool>
57showEmptyIndexes("rmf-empty-indexes",
58 cl::desc("Render indexes not associated with instructions or "
59 "MBB starts."),
60 cl::init(false), cl::Hidden);
61
62static cl::opt<bool>
63useFancyVerticals("rmf-fancy-verts",
64 cl::desc("Use SVG for vertical text."),
65 cl::init(true), cl::Hidden);
66
67namespace llvm {
68
69 bool MFRenderingOptions::renderingOptionsProcessed;
70 std::set<std::string> MFRenderingOptions::mfNamesToRender;
71 bool MFRenderingOptions::renderAllMFs = false;
72
73 std::set<std::string> MFRenderingOptions::classNamesToRender;
74 bool MFRenderingOptions::renderAllClasses = false;
75
76 std::set<std::pair<unsigned, unsigned> >
77 MFRenderingOptions::intervalNumsToRender;
78 unsigned MFRenderingOptions::intervalTypesToRender = ExplicitOnly;
79
80 template <typename OutputItr>
81 void MFRenderingOptions::splitComaSeperatedList(const std::string &s,
82 OutputItr outItr) {
83 std::string::const_iterator curPos = s.begin();
84 std::string::const_iterator nextComa = std::find(curPos, s.end(), ',');
85 while (nextComa != s.end()) {
86 std::string elem;
87 std::copy(curPos, nextComa, std::back_inserter(elem));
88 *outItr = elem;
89 ++outItr;
90 curPos = llvm::next(nextComa);
91 nextComa = std::find(curPos, s.end(), ',');
92 }
93
94 if (curPos != s.end()) {
95 std::string elem;
96 std::copy(curPos, s.end(), std::back_inserter(elem));
97 *outItr = elem;
98 ++outItr;
99 }
100 }
101
102 void MFRenderingOptions::processOptions() {
103 if (!renderingOptionsProcessed) {
104 processFuncNames();
105 processRegClassNames();
106 processIntervalNumbers();
107 renderingOptionsProcessed = true;
108 }
109 }
110
111 void MFRenderingOptions::processFuncNames() {
112 if (machineFuncsToRender == "*") {
113 renderAllMFs = true;
114 } else {
115 splitComaSeperatedList(machineFuncsToRender,
116 std::inserter(mfNamesToRender,
117 mfNamesToRender.begin()));
118 }
119 }
120
121 void MFRenderingOptions::processRegClassNames() {
122 if (pressureClasses == "*") {
123 renderAllClasses = true;
124 } else {
125 splitComaSeperatedList(pressureClasses,
126 std::inserter(classNamesToRender,
127 classNamesToRender.begin()));
128 }
129 }
130
131 void MFRenderingOptions::processIntervalNumbers() {
132 std::set<std::string> intervalRanges;
133 splitComaSeperatedList(showIntervals,
134 std::inserter(intervalRanges,
135 intervalRanges.begin()));
136 std::for_each(intervalRanges.begin(), intervalRanges.end(),
137 processIntervalRange);
138 }
139
140 void MFRenderingOptions::processIntervalRange(
141 const std::string &intervalRangeStr) {
142 if (intervalRangeStr == "*") {
143 intervalTypesToRender |= All;
144 } else if (intervalRangeStr == "virt*") {
145 intervalTypesToRender |= VirtPlusExplicit;
146 } else if (intervalRangeStr == "phys*") {
147 intervalTypesToRender |= PhysPlusExplicit;
148 } else {
149 std::istringstream iss(intervalRangeStr);
150 unsigned reg1, reg2;
151 if ((iss >> reg1 >> std::ws)) {
152 if (iss.eof()) {
153 intervalNumsToRender.insert(std::make_pair(reg1, reg1 + 1));
154 } else {
155 char c;
156 iss >> c;
157 if (c == '-' && (iss >> reg2)) {
158 intervalNumsToRender.insert(std::make_pair(reg1, reg2 + 1));
159 } else {
160 dbgs() << "Warning: Invalid interval range \""
161 << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n";
162 }
163 }
164 } else {
165 dbgs() << "Warning: Invalid interval number \""
166 << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n";
167 }
168 }
169 }
170
171 void MFRenderingOptions::setup(MachineFunction *mf,
172 const TargetRegisterInfo *tri,
173 LiveIntervals *lis) {
174 this->mf = mf;
175 this->tri = tri;
176 this->lis = lis;
177
178 clear();
179 }
180
181 void MFRenderingOptions::clear() {
182 regClassesTranslatedToCurrentFunction = false;
183 regClassSet.clear();
184
185 intervalsTranslatedToCurrentFunction = false;
186 intervalSet.clear();
187 }
188
189 void MFRenderingOptions::resetRenderSpecificOptions() {
190 intervalSet.clear();
191 intervalsTranslatedToCurrentFunction = false;
192 }
193
194 bool MFRenderingOptions::shouldRenderCurrentMachineFunction() const {
195 processOptions();
196
197 return (renderAllMFs ||
198 mfNamesToRender.find(mf->getFunction()->getName()) !=
199 mfNamesToRender.end());
200 }
201
202 const MFRenderingOptions::RegClassSet& MFRenderingOptions::regClasses() const{
203 translateRegClassNamesToCurrentFunction();
204 return regClassSet;
205 }
206
207 const MFRenderingOptions::IntervalSet& MFRenderingOptions::intervals() const {
208 translateIntervalNumbersToCurrentFunction();
209 return intervalSet;
210 }
211
212 bool MFRenderingOptions::renderEmptyIndexes() const {
213 return showEmptyIndexes;
214 }
215
216 bool MFRenderingOptions::fancyVerticals() const {
217 return useFancyVerticals;
218 }
219
220 void MFRenderingOptions::translateRegClassNamesToCurrentFunction() const {
221 if (!regClassesTranslatedToCurrentFunction) {
222 processOptions();
223 for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(),
224 rcEnd = tri->regclass_end();
225 rcItr != rcEnd; ++rcItr) {
226 const TargetRegisterClass *trc = *rcItr;
227 if (renderAllClasses ||
228 classNamesToRender.find(trc->getName()) !=
229 classNamesToRender.end()) {
230 regClassSet.insert(trc);
231 }
232 }
233 regClassesTranslatedToCurrentFunction = true;
234 }
235 }
236
237 void MFRenderingOptions::translateIntervalNumbersToCurrentFunction() const {
238 if (!intervalsTranslatedToCurrentFunction) {
239 processOptions();
240
241 // If we're not just doing explicit then do a copy over all matching
242 // types.
243 if (intervalTypesToRender != ExplicitOnly) {
244 for (LiveIntervals::iterator liItr = lis->begin(), liEnd = lis->end();
245 liItr != liEnd; ++liItr) {
246
247 if ((TargetRegisterInfo::isPhysicalRegister(liItr->first) &&
248 (intervalTypesToRender & PhysPlusExplicit)) ||
249 (TargetRegisterInfo::isVirtualRegister(liItr->first) &&
250 (intervalTypesToRender & VirtPlusExplicit))) {
251 intervalSet.insert(liItr->second);
252 }
253 }
254 }
255
256 // If we need to process the explicit list...
257 if (intervalTypesToRender != All) {
258 for (std::set<std::pair<unsigned, unsigned> >::const_iterator
259 regRangeItr = intervalNumsToRender.begin(),
260 regRangeEnd = intervalNumsToRender.end();
261 regRangeItr != regRangeEnd; ++regRangeItr) {
262 const std::pair<unsigned, unsigned> &range = *regRangeItr;
263 for (unsigned reg = range.first; reg != range.second; ++reg) {
264 if (lis->hasInterval(reg)) {
265 intervalSet.insert(&lis->getInterval(reg));
266 }
267 }
268 }
269 }
270
271 intervalsTranslatedToCurrentFunction = true;
272 }
273 }
274
275 // ---------- TargetRegisterExtraInformation implementation ----------
276
277 TargetRegisterExtraInfo::TargetRegisterExtraInfo()
278 : mapsPopulated(false) {
279 }
280
281 void TargetRegisterExtraInfo::setup(MachineFunction *mf,
282 MachineRegisterInfo *mri,
283 const TargetRegisterInfo *tri,
284 LiveIntervals *lis) {
285 this->mf = mf;
286 this->mri = mri;
287 this->tri = tri;
288 this->lis = lis;
289 }
290
291 void TargetRegisterExtraInfo::reset() {
292 if (!mapsPopulated) {
293 initWorst();
294 //initBounds();
295 initCapacity();
296 mapsPopulated = true;
297 }
298
299 resetPressureAndLiveStates();
300 }
301
302 void TargetRegisterExtraInfo::clear() {
303 prWorst.clear();
304 vrWorst.clear();
305 capacityMap.clear();
306 pressureMap.clear();
307 //liveStatesMap.clear();
308 mapsPopulated = false;
309 }
310
311 void TargetRegisterExtraInfo::initWorst() {
312 assert(!mapsPopulated && prWorst.empty() && vrWorst.empty() &&
313 "Worst map already initialised?");
314
315 // Start with the physical registers.
316 for (unsigned preg = 1; preg < tri->getNumRegs(); ++preg) {
317 WorstMapLine &pregLine = prWorst[preg];
318
319 for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(),
320 rcEnd = tri->regclass_end();
321 rcItr != rcEnd; ++rcItr) {
322 const TargetRegisterClass *trc = *rcItr;
323
324 unsigned numOverlaps = 0;
325 for (TargetRegisterClass::iterator rItr = trc->begin(),
326 rEnd = trc->end();
327 rItr != rEnd; ++rItr) {
328 unsigned trcPReg = *rItr;
329 if (tri->regsOverlap(preg, trcPReg))
330 ++numOverlaps;
331 }
332
333 pregLine[trc] = numOverlaps;
334 }
335 }
336
337 // Now the register classes.
338 for (TargetRegisterInfo::regclass_iterator rc1Itr = tri->regclass_begin(),
339 rcEnd = tri->regclass_end();
340 rc1Itr != rcEnd; ++rc1Itr) {
341 const TargetRegisterClass *trc1 = *rc1Itr;
342 WorstMapLine &classLine = vrWorst[trc1];
343
344 for (TargetRegisterInfo::regclass_iterator rc2Itr = tri->regclass_begin();
345 rc2Itr != rcEnd; ++rc2Itr) {
346 const TargetRegisterClass *trc2 = *rc2Itr;
347
348 unsigned worst = 0;
349
350 for (TargetRegisterClass::iterator trc1Itr = trc1->begin(),
351 trc1End = trc1->end();
352 trc1Itr != trc1End; ++trc1Itr) {
353 unsigned trc1Reg = *trc1Itr;
354 unsigned trc1RegWorst = 0;
355
356 for (TargetRegisterClass::iterator trc2Itr = trc2->begin(),
357 trc2End = trc2->end();
358 trc2Itr != trc2End; ++trc2Itr) {
359 unsigned trc2Reg = *trc2Itr;
360 if (tri->regsOverlap(trc1Reg, trc2Reg))
361 ++trc1RegWorst;
362 }
363 if (trc1RegWorst > worst) {
364 worst = trc1RegWorst;
365 }
366 }
367
368 if (worst != 0) {
369 classLine[trc2] = worst;
370 }
371 }
372 }
373 }
374
375 unsigned TargetRegisterExtraInfo::getWorst(
376 unsigned reg,
377 const TargetRegisterClass *trc) const {
378 const WorstMapLine *wml = 0;
379 if (TargetRegisterInfo::isPhysicalRegister(reg)) {
380 PRWorstMap::const_iterator prwItr = prWorst.find(reg);
381 assert(prwItr != prWorst.end() && "Missing prWorst entry.");
382 wml = &prwItr->second;
383 } else {
384 const TargetRegisterClass *regTRC = mri->getRegClass(reg);
385 VRWorstMap::const_iterator vrwItr = vrWorst.find(regTRC);
386 assert(vrwItr != vrWorst.end() && "Missing vrWorst entry.");
387 wml = &vrwItr->second;
388 }
389
390 WorstMapLine::const_iterator wmlItr = wml->find(trc);
391 if (wmlItr == wml->end())
392 return 0;
393
394 return wmlItr->second;
395 }
396
397 void TargetRegisterExtraInfo::initCapacity() {
398 assert(!mapsPopulated && capacityMap.empty() &&
399 "Capacity map already initialised?");
400
401 for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(),
402 rcEnd = tri->regclass_end();
403 rcItr != rcEnd; ++rcItr) {
404 const TargetRegisterClass *trc = *rcItr;
405 unsigned capacity = std::distance(trc->allocation_order_begin(*mf),
406 trc->allocation_order_end(*mf));
407
408 if (capacity != 0)
409 capacityMap[trc] = capacity;
410 }
411 }
412
413 unsigned TargetRegisterExtraInfo::getCapacity(
414 const TargetRegisterClass *trc) const {
415 CapacityMap::const_iterator cmItr = capacityMap.find(trc);
416 assert(cmItr != capacityMap.end() &&
417 "vreg with unallocable register class");
418 return cmItr->second;
419 }
420
421 void TargetRegisterExtraInfo::resetPressureAndLiveStates() {
422 pressureMap.clear();
423 //liveStatesMap.clear();
424
425 // Iterate over all slots.
426
427
428 // Iterate over all live intervals.
429 for (LiveIntervals::iterator liItr = lis->begin(),
430 liEnd = lis->end();
431 liItr != liEnd; ++liItr) {
432 LiveInterval *li = liItr->second;
433
434 const TargetRegisterClass *liTRC;
435
436 if (TargetRegisterInfo::isPhysicalRegister(li->reg))
437 continue;
438
439 liTRC = mri->getRegClass(li->reg);
440
441
442 // For all ranges in the current interal.
443 for (LiveInterval::iterator lrItr = li->begin(),
444 lrEnd = li->end();
445 lrItr != lrEnd; ++lrItr) {
446 LiveRange *lr = &*lrItr;
447
448 // For all slots in the current range.
449 for (SlotIndex i = lr->start; i != lr->end; i = i.getNextSlot()) {
450
451 // Record increased pressure at index for all overlapping classes.
452 for (TargetRegisterInfo::regclass_iterator
453 rcItr = tri->regclass_begin(),
454 rcEnd = tri->regclass_end();
455 rcItr != rcEnd; ++rcItr) {
456 const TargetRegisterClass *trc = *rcItr;
457
458 if (trc->allocation_order_begin(*mf) ==
459 trc->allocation_order_end(*mf))
460 continue;
461
462 unsigned worstAtI = getWorst(li->reg, trc);
463
464 if (worstAtI != 0) {
465 pressureMap[i][trc] += worstAtI;
466 }
467 }
468 }
469 }
470 }
471 }
472
473 unsigned TargetRegisterExtraInfo::getPressureAtSlot(
474 const TargetRegisterClass *trc,
475 SlotIndex i) const {
476 PressureMap::const_iterator pmItr = pressureMap.find(i);
477 if (pmItr == pressureMap.end())
478 return 0;
479 const PressureMapLine &pmLine = pmItr->second;
480 PressureMapLine::const_iterator pmlItr = pmLine.find(trc);
481 if (pmlItr == pmLine.end())
482 return 0;
483 return pmlItr->second;
484 }
485
486 bool TargetRegisterExtraInfo::classOverCapacityAtSlot(
487 const TargetRegisterClass *trc,
488 SlotIndex i) const {
489 return (getPressureAtSlot(trc, i) > getCapacity(trc));
490 }
491
492 // ---------- MachineFunctionRenderer implementation ----------
493
494 template <typename Iterator>
495 std::string RenderMachineFunction::escapeChars(Iterator sBegin, Iterator sEnd) const {
496 std::string r;
497
498 for (Iterator sItr = sBegin; sItr != sEnd; ++sItr) {
499 char c = *sItr;
500
501 switch (c) {
502 case '<': r.append("&lt;"); break;
503 case '>': r.append("&gt;"); break;
504 case '&': r.append("&amp;"); break;
505 case ' ': r.append("&nbsp;"); break;
506 case '\"': r.append("&quot;"); break;
507 default: r.push_back(c); break;
508 }
509 }
510
511 return r;
512 }
513
514 template <typename OStream, typename T>
515 void RenderMachineFunction::renderVertical(const std::string &indent,
516 OStream &os,
517 const T &t) const {
518 if (ro.fancyVerticals()) {
519 os << indent << "<object\n"
520 << indent << " class=\"obj\"\n"
521 << indent << " type=\"image/svg+xml\"\n"
522 << indent << " width=\"14px\"\n"
523 << indent << " height=\"55px\"\n"
524 << indent << " data=\"data:image/svg+xml,\n"
525 << indent << " <svg xmlns='http://www.w3.org/2000/svg'>\n"
526 << indent << " <text x='-55' y='10' "
527 "font-family='Courier' font-size='12' "
528 "transform='rotate(-90)' text-rendering='optimizeSpeed' "
529 "fill='#000'>" << t << "</text>\n"
530 << indent << " </svg>\">\n"
531 << indent << "</object>\n";
532 } else {
533 std::ostringstream oss;
534 oss << t;
535 std::string tStr(oss.str());
536
537 os << indent;
538 for (std::string::iterator tStrItr = tStr.begin(), tStrEnd = tStr.end();
539 tStrItr != tStrEnd; ++tStrItr) {
540 os << *tStrItr << "<br/> ";
541 }
542 os << "\n";
543 }
544 }
545
546 template <typename OStream>
547 void RenderMachineFunction::insertCSS(const std::string &indent,
548 OStream &os) const {
549 os << indent << "<style type=\"text/css\">\n"
550 << indent << " body { font-color: black; }\n"
551 << indent << " table.code td { font-family: monospace; "
552 "border-width: 0px; border-style: solid; "
553 "border-bottom: 1px solid #dddddd; white-space: nowrap; }\n"
554 << indent << " table.code td.s-zp { background-color: #000000; }\n"
555 << indent << " table.code td.s-up { background-color: #00ff00; }\n"
556 << indent << " table.code td.s-op { background-color: #ff0000; }\n"
557 << indent << " table.code td.l-na { background-color: #ffffff; }\n"
558 << indent << " table.code td.l-def { background-color: #ff0000; }\n"
559 << indent << " table.code td.l-use { background-color: #ffff00; }\n"
560 << indent << " table.code td.l-sa { background-color: #000000; }\n"
561 << indent << " table.code th { border-width: 0px; "
562 "border-style: solid; }\n"
563 << indent << "</style>\n";
564 }
565
566 template <typename OStream>
567 void RenderMachineFunction::renderFunctionSummary(
568 const std::string &indent, OStream &os,
569 const char * const renderContextStr) const {
570 os << indent << "<h1>Function: " << mf->getFunction()->getName()
571 << "</h1>\n"
572 << indent << "<h2>Rendering context: " << renderContextStr << "</h2>\n";
573 }
574
575
576 template <typename OStream>
577 void RenderMachineFunction::renderPressureTableLegend(
578 const std::string &indent,
579 OStream &os) const {
580 os << indent << "<h2>Rendering Pressure Legend:</h2>\n"
581 << indent << "<table class=\"code\">\n"
582 << indent << " <tr>\n"
583 << indent << " <th>Pressure</th><th>Description</th>"
584 "<th>Appearance</th>\n"
585 << indent << " </tr>\n"
586 << indent << " <tr>\n"
587 << indent << " <td>No Pressure</td>"
588 " <td>No physical registers of this class requested.</td>"
589 " <td class=\"s-zp\">&nbsp;&nbsp;</td>\n"
590 << indent << " </tr>\n"
591 << indent << " <tr>\n"
592 << indent << " <td>Low Pressure</td>"
593 " <td>Sufficient physical registers to meet demand.</td>"
594 " <td class=\"s-up\">&nbsp;&nbsp;</td>\n"
595 << indent << " </tr>\n"
596 << indent << " <tr>\n"
597 << indent << " <td>High Pressure</td>"
598 " <td>Potentially insufficient physical registers to meet demand.</td>"
599 " <td class=\"s-op\">&nbsp;&nbsp;</td>\n"
600 << indent << " </tr>\n"
601 << indent << "</table>\n";
602 }
603
604 template <typename OStream>
605 void RenderMachineFunction::renderCodeTablePlusPI(const std::string & indent,
606 OStream &os) const {
607
608 os << indent << "<table cellpadding=0 cellspacing=0 class=\"code\">\n"
609 << indent << " <tr>\n"
610 << indent << " <th>index</th>\n"
611 << indent << " <th>instr</th>\n";
612
613 // Header row:
614
615 if (!ro.regClasses().empty()) {
616 for (MFRenderingOptions::RegClassSet::const_iterator
617 rcItr = ro.regClasses().begin(),
618 rcEnd = ro.regClasses().end();
619 rcItr != rcEnd; ++rcItr) {
620 const TargetRegisterClass *trc = *rcItr;
621 os << indent << " <th>\n";
622 renderVertical(indent + " ", os, trc->getName());
623 os << indent << " </th>\n";
624 }
625 }
626
627 // FIXME: Is there a nicer way to insert space between columns in HTML?
628 if (!ro.regClasses().empty() && !ro.intervals().empty())
629 os << indent << " <th>&nbsp;&nbsp;</th>\n";
630
631 if (!ro.intervals().empty()) {
632 for (MFRenderingOptions::IntervalSet::const_iterator
633 liItr = ro.intervals().begin(),
634 liEnd = ro.intervals().end();
635 liItr != liEnd; ++liItr) {
636
637 const LiveInterval *li = *liItr;
638 os << indent << " <th>\n";
639 renderVertical(indent + " ", os, li->reg);
640 os << indent << " </th>\n";
641 }
642 }
643
644 os << indent << " </tr>\n";
645
646 MachineInstr *mi = 0;
647
648 // Data rows:
649 for (SlotIndex i = sis->getZeroIndex(); i != sis->getLastIndex();
650 i = i.getNextSlot()) {
651
652 os << indent << " <tr height=6ex>\n";
653
654 if (i.getSlot() == SlotIndex::LOAD) {
655 MachineBasicBlock *mbb = sis->getMBBFromIndex(i);
656 mi = sis->getInstructionFromIndex(i);
657
658 if (i == sis->getMBBStartIdx(mbb) || mi != 0 ||
659 ro.renderEmptyIndexes()) {
660 os << indent << " <td rowspan=4>" << i << "&nbsp;</td>\n"
661 << indent << " <td rowspan=4>\n";
662
663 if (i == sis->getMBBStartIdx(mbb)) {
664 os << indent << " BB#" << mbb->getNumber() << ":&nbsp;\n";
665 } else if (mi != 0) {
666 os << indent << " &nbsp;&nbsp;" << escapeChars(mi) << "\n";
667 } else {
668 os << indent << " &nbsp;\n";
669 }
670 os << indent << " </td>\n";
671 } else {
672 i = i.getStoreIndex(); // <- Will be incremented to the next index.
673 continue;
674 }
675 }
676
677 if (!ro.regClasses().empty()) {
678 for (MFRenderingOptions::RegClassSet::const_iterator
679 rcItr = ro.regClasses().begin(),
680 rcEnd = ro.regClasses().end();
681 rcItr != rcEnd; ++rcItr) {
682 const TargetRegisterClass *trc = *rcItr;
683
684 os << indent << " <td class=\"";
685
686 if (trei.getPressureAtSlot(trc, i) == 0) {
687 os << "s-zp";
688 } else if (trei.classOverCapacityAtSlot(trc, i)){
689 os << "s-op";
690 } else {
691 os << "s-up";
692 }
693
694 os << "\"></td>\n";
695 }
696 }
697
698 // FIXME: Is there a nicer way to insert space between columns in HTML?
699 if (!ro.regClasses().empty() && !ro.intervals().empty())
700 os << indent << " <td width=2em></td>\n";
701
702 if (!ro.intervals().empty()) {
703 for (MFRenderingOptions::IntervalSet::const_iterator
704 liItr = ro.intervals().begin(),
705 liEnd = ro.intervals().end();
706 liItr != liEnd; ++liItr) {
707 const LiveInterval *li = *liItr;
708 os << indent << " <td class=\"";
709 if (li->liveAt(i)) {
710 if (mi == 0) {
711 os << "l-sa";
712 } else {
713 if (i.getSlot() == SlotIndex::DEF &&
714 mi->definesRegister(li->reg, tri)) {
715 os << "l-def";
716 } else if (i.getSlot() == SlotIndex::USE &&
717 mi->readsRegister(li->reg)) {
718 os << "l-use";
719 } else {
720 os << "l-sa";
721 }
722 }
723 } else {
724 os << "l-na";
725 }
726 os << "\"></td>\n";
727 }
728 }
729 os << indent << " </tr>\n";
730 }
731
732 os << indent << "</table>\n";
733
734 if (!ro.regClasses().empty())
735 renderPressureTableLegend(indent, os);
736 }
737
738 template <typename OStream>
739 void RenderMachineFunction::renderWarnings(const std::string &indent,
740 OStream &os) const {
741 }
742
743 template <typename OStream>
744 void RenderMachineFunction::renderFunctionPage(
745 OStream &os,
746 const char * const renderContextStr) const {
747 os << "<html>\n"
748 << " <head>\n"
749 << " <title>" << fqn << "</title>\n";
750
751 insertCSS(" ", os);
752
753 os << " <head>\n"
754 << " <body >\n";
755
756 renderFunctionSummary(" ", os, renderContextStr);
757
758 os << " <br/><br/><br/>\n";
759
760 //renderLiveIntervalInfoTable(" ", os);
761
762 os << " <br/><br/><br/>\n";
763
764 renderCodeTablePlusPI(" ", os);
765
766 os << " </body>\n"
767 << "</html>\n";
768 }
769
770 void RenderMachineFunction::getAnalysisUsage(AnalysisUsage &au) const {
771 au.addRequired<SlotIndexes>();
772 au.addRequired<LiveIntervals>();
773 au.setPreservesAll();
774 MachineFunctionPass::getAnalysisUsage(au);
775 }
776
777 bool RenderMachineFunction::runOnMachineFunction(MachineFunction &fn) {
778 mf = &fn;
779 mri = &mf->getRegInfo();
780 tri = mf->getTarget().getRegisterInfo();
781 lis = &getAnalysis<LiveIntervals>();
782 sis = &getAnalysis<SlotIndexes>();
783
784 trei.setup(mf, mri, tri, lis);
785 ro.setup(mf, tri, lis);
786
787 fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." +
788 mf->getFunction()->getName().str();
789
790 return false;
791 }
792
793 void RenderMachineFunction::releaseMemory() {
794 trei.clear();
795 ro.clear();
796 }
797
798 void RenderMachineFunction::renderMachineFunction(
799 const char *renderContextStr,
800 const char *renderSuffix) {
801 if (!ro.shouldRenderCurrentMachineFunction())
802 return;
803
804 trei.reset();
805
806 std::string rpFileName(mf->getFunction()->getName().str() +
807 (renderSuffix ? renderSuffix : "") +
808 outputFileSuffix);
809
810 std::string errMsg;
811 raw_fd_ostream outFile(rpFileName.c_str(), errMsg, raw_fd_ostream::F_Binary);
812
813 renderFunctionPage(outFile, renderContextStr);
814
815 ro.resetRenderSpecificOptions();
816 }
817
818 void RenderMachineFunction::setupRenderingOptions() {
819
820 }
821
822 std::string RenderMachineFunction::escapeChars(const std::string &s) const {
823 return escapeChars(s.begin(), s.end());
824 }
825
826 std::string RenderMachineFunction::escapeChars(const MachineInstr *mi) const {
827 std::string s;
828 raw_string_ostream os(s);
829 os << *mi;
830 std::string s2 = os.str();
831 return escapeChars(s2);
832 }
833
834}