1 //===-- 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 "VirtRegMap.h" 15 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" 27 28 #include <sstream> 29 30 using namespace llvm; 31 32 char RenderMachineFunction::ID = 0; 33 INITIALIZE_PASS_BEGIN(RenderMachineFunction, "rendermf", 34 "Render machine functions (and related info) to HTML pages", 35 false, false) 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", 40 false, false) 41 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); 47 48 static cl::opt<std::string> 49 machineFuncsToRender("rmf-funcs", 50 cl::desc("Comma separated list of functions to render" 51 ", or \"*\"."), 52 cl::init(""), cl::Hidden); 53 54 static cl::opt<std::string> 55 pressureClasses("rmf-classes", 56 cl::desc("Register classes to render pressure for."), 57 cl::init(""), cl::Hidden); 58 59 static cl::opt<std::string> 60 showIntervals("rmf-intervals", 61 cl::desc("Live intervals to show alongside code."), 62 cl::init(""), cl::Hidden); 63 64 static cl::opt<bool> 65 filterEmpty("rmf-filter-empty-intervals", 66 cl::desc("Don't display empty intervals."), 67 cl::init(true), cl::Hidden); 68 69 static cl::opt<bool> 70 showEmptyIndexes("rmf-empty-indexes", 71 cl::desc("Render indexes not associated with instructions or " 72 "MBB starts."), 73 cl::init(false), cl::Hidden); 74 75 static cl::opt<bool> 76 useFancyVerticals("rmf-fancy-verts", 77 cl::desc("Use SVG for vertical text."), 78 cl::init(true), cl::Hidden); 79 80 static cl::opt<bool> 81 prettyHTML("rmf-pretty-html", 82 cl::desc("Pretty print HTML. For debugging the renderer only.."), 83 cl::init(false), cl::Hidden); 84 85 86 namespace llvm { 87 88 bool MFRenderingOptions::renderingOptionsProcessed; 89 std::set<std::string> MFRenderingOptions::mfNamesToRender; 90 bool MFRenderingOptions::renderAllMFs = false; 91 92 std::set<std::string> MFRenderingOptions::classNamesToRender; 93 bool MFRenderingOptions::renderAllClasses = false; 94 95 std::set<std::pair<unsigned, unsigned> > 96 MFRenderingOptions::intervalNumsToRender; 97 unsigned MFRenderingOptions::intervalTypesToRender = ExplicitOnly; 98 99 template <typename OutputItr> 100 void MFRenderingOptions::splitComaSeperatedList(const std::string &s, 101 OutputItr outItr) { 102 std::string::const_iterator curPos = s.begin(); 103 std::string::const_iterator nextComa = std::find(curPos, s.end(), ','); 104 while (nextComa != s.end()) { 105 std::string elem; 106 std::copy(curPos, nextComa, std::back_inserter(elem)); 107 *outItr = elem; 108 ++outItr; 109 curPos = llvm::next(nextComa); 110 nextComa = std::find(curPos, s.end(), ','); 111 } 112 113 if (curPos != s.end()) { 114 std::string elem; 115 std::copy(curPos, s.end(), std::back_inserter(elem)); 116 *outItr = elem; 117 ++outItr; 118 } 119 } 120 121 void MFRenderingOptions::processOptions() { 122 if (!renderingOptionsProcessed) { 123 processFuncNames(); 124 processRegClassNames(); 125 processIntervalNumbers(); 126 renderingOptionsProcessed = true; 127 } 128 } 129 130 void MFRenderingOptions::processFuncNames() { 131 if (machineFuncsToRender == "*") { 132 renderAllMFs = true; 133 } else { 134 splitComaSeperatedList(machineFuncsToRender, 135 std::inserter(mfNamesToRender, 136 mfNamesToRender.begin())); 137 } 138 } 139 140 void MFRenderingOptions::processRegClassNames() { 141 if (pressureClasses == "*") { 142 renderAllClasses = true; 143 } else { 144 splitComaSeperatedList(pressureClasses, 145 std::inserter(classNamesToRender, 146 classNamesToRender.begin())); 147 } 148 } 149 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); 157 } 158 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; 171 } else { 172 std::istringstream iss(intervalRangeStr); 173 unsigned reg1, reg2; 174 if ((iss >> reg1 >> std::ws)) { 175 if (iss.eof()) { 176 intervalNumsToRender.insert(std::make_pair(reg1, reg1 + 1)); 177 } else { 178 char c; 179 iss >> c; 180 if (c == '-' && (iss >> reg2)) { 181 intervalNumsToRender.insert(std::make_pair(reg1, reg2 + 1)); 182 } else { 183 dbgs() << "Warning: Invalid interval range \"" 184 << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; 185 } 186 } 187 } else { 188 dbgs() << "Warning: Invalid interval number \"" 189 << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; 190 } 191 } 192 } 193 194 void MFRenderingOptions::setup(MachineFunction *mf, 195 const TargetRegisterInfo *tri, 196 LiveIntervals *lis, 197 const RenderMachineFunction *rmf) { 198 this->mf = mf; 199 this->tri = tri; 200 this->lis = lis; 201 this->rmf = rmf; 202 203 clear(); 204 } 205 206 void MFRenderingOptions::clear() { 207 regClassesTranslatedToCurrentFunction = false; 208 regClassSet.clear(); 209 210 intervalsTranslatedToCurrentFunction = false; 211 intervalSet.clear(); 212 } 213 214 void MFRenderingOptions::resetRenderSpecificOptions() { 215 intervalSet.clear(); 216 intervalsTranslatedToCurrentFunction = false; 217 } 218 219 bool MFRenderingOptions::shouldRenderCurrentMachineFunction() const { 220 processOptions(); 221 222 return (renderAllMFs || 223 mfNamesToRender.find(mf->getFunction()->getName()) != 224 mfNamesToRender.end()); 225 } 226 227 const MFRenderingOptions::RegClassSet& MFRenderingOptions::regClasses() const{ 228 translateRegClassNamesToCurrentFunction(); 229 return regClassSet; 230 } 231 232 const MFRenderingOptions::IntervalSet& MFRenderingOptions::intervals() const { 233 translateIntervalNumbersToCurrentFunction(); 234 return intervalSet; 235 } 236 237 bool MFRenderingOptions::renderEmptyIndexes() const { 238 return showEmptyIndexes; 239 } 240 241 bool MFRenderingOptions::fancyVerticals() const { 242 return useFancyVerticals; 243 } 244 245 void MFRenderingOptions::translateRegClassNamesToCurrentFunction() const { 246 if (!regClassesTranslatedToCurrentFunction) { 247 processOptions(); 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); 256 } 257 } 258 regClassesTranslatedToCurrentFunction = true; 259 } 260 } 261 262 void MFRenderingOptions::translateIntervalNumbersToCurrentFunction() const { 263 if (!intervalsTranslatedToCurrentFunction) { 264 processOptions(); 265 266 // If we're not just doing explicit then do a copy over all matching 267 // types. 268 if (intervalTypesToRender != ExplicitOnly) { 269 for (LiveIntervals::iterator liItr = lis->begin(), liEnd = lis->end(); 270 liItr != liEnd; ++liItr) { 271 LiveInterval *li = liItr->second; 272 273 if (filterEmpty && li->empty()) 274 continue; 275 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); 283 } 284 } 285 } 286 } 287 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)); 298 } 299 } 300 } 301 } 302 303 intervalsTranslatedToCurrentFunction = true; 304 } 305 } 306 307 // ---------- TargetRegisterExtraInformation implementation ---------- 308 309 TargetRegisterExtraInfo::TargetRegisterExtraInfo() 310 : mapsPopulated(false) { 311 } 312 313 void TargetRegisterExtraInfo::setup(MachineFunction *mf, 314 MachineRegisterInfo *mri, 315 const TargetRegisterInfo *tri, 316 LiveIntervals *lis) { 317 this->mf = mf; 318 this->mri = mri; 319 this->tri = tri; 320 this->lis = lis; 321 } 322 323 void TargetRegisterExtraInfo::reset() { 324 if (!mapsPopulated) { 325 initWorst(); 326 //initBounds(); 327 initCapacity(); 328 mapsPopulated = true; 329 } 330 331 resetPressureAndLiveStates(); 332 } 333 334 void TargetRegisterExtraInfo::clear() { 335 prWorst.clear(); 336 vrWorst.clear(); 337 capacityMap.clear(); 338 pressureMap.clear(); 339 //liveStatesMap.clear(); 340 mapsPopulated = false; 341 } 342 343 void TargetRegisterExtraInfo::initWorst() { 344 assert(!mapsPopulated && prWorst.empty() && vrWorst.empty() && 345 "Worst map already initialised?"); 346 347 // Start with the physical registers. 348 for (unsigned preg = 1; preg < tri->getNumRegs(); ++preg) { 349 WorstMapLine &pregLine = prWorst[preg]; 350 351 for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), 352 rcEnd = tri->regclass_end(); 353 rcItr != rcEnd; ++rcItr) { 354 const TargetRegisterClass *trc = *rcItr; 355 356 unsigned numOverlaps = 0; 357 for (TargetRegisterClass::iterator rItr = trc->begin(), 358 rEnd = trc->end(); 359 rItr != rEnd; ++rItr) { 360 unsigned trcPReg = *rItr; 361 if (tri->regsOverlap(preg, trcPReg)) 362 ++numOverlaps; 363 } 364 365 pregLine[trc] = numOverlaps; 366 } 367 } 368 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]; 375 376 for (TargetRegisterInfo::regclass_iterator rc2Itr = tri->regclass_begin(); 377 rc2Itr != rcEnd; ++rc2Itr) { 378 const TargetRegisterClass *trc2 = *rc2Itr; 379 380 unsigned worst = 0; 381 382 for (TargetRegisterClass::iterator trc1Itr = trc1->begin(), 383 trc1End = trc1->end(); 384 trc1Itr != trc1End; ++trc1Itr) { 385 unsigned trc1Reg = *trc1Itr; 386 unsigned trc1RegWorst = 0; 387 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)) 393 ++trc1RegWorst; 394 } 395 if (trc1RegWorst > worst) { 396 worst = trc1RegWorst; 397 } 398 } 399 400 if (worst != 0) { 401 classLine[trc2] = worst; 402 } 403 } 404 } 405 } 406 407 unsigned TargetRegisterExtraInfo::getWorst( 408 unsigned reg, 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; 415 } else { 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; 420 } 421 422 WorstMapLine::const_iterator wmlItr = wml->find(trc); 423 if (wmlItr == wml->end()) 424 return 0; 425 426 return wmlItr->second; 427 } 428 429 void TargetRegisterExtraInfo::initCapacity() { 430 assert(!mapsPopulated && capacityMap.empty() && 431 "Capacity map already initialised?"); 432 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(); 438 439 if (capacity != 0) 440 capacityMap[trc] = capacity; 441 } 442 } 443 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; 450 } 451 452 void TargetRegisterExtraInfo::resetPressureAndLiveStates() { 453 pressureMap.clear(); 454 //liveStatesMap.clear(); 455 456 // Iterate over all slots. 457 458 459 // Iterate over all live intervals. 460 for (LiveIntervals::iterator liItr = lis->begin(), 461 liEnd = lis->end(); 462 liItr != liEnd; ++liItr) { 463 LiveInterval *li = liItr->second; 464 465 if (TargetRegisterInfo::isPhysicalRegister(li->reg)) 466 continue; 467 468 // For all ranges in the current interal. 469 for (LiveInterval::iterator lrItr = li->begin(), 470 lrEnd = li->end(); 471 lrItr != lrEnd; ++lrItr) { 472 LiveRange *lr = &*lrItr; 473 474 // For all slots in the current range. 475 for (SlotIndex i = lr->start; i != lr->end; i = i.getNextSlot()) { 476 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; 483 484 if (trc->getRawAllocationOrder(*mf).empty()) 485 continue; 486 487 unsigned worstAtI = getWorst(li->reg, trc); 488 489 if (worstAtI != 0) { 490 pressureMap[i][trc] += worstAtI; 491 } 492 } 493 } 494 } 495 } 496 } 497 498 unsigned TargetRegisterExtraInfo::getPressureAtSlot( 499 const TargetRegisterClass *trc, 500 SlotIndex i) const { 501 PressureMap::const_iterator pmItr = pressureMap.find(i); 502 if (pmItr == pressureMap.end()) 503 return 0; 504 const PressureMapLine &pmLine = pmItr->second; 505 PressureMapLine::const_iterator pmlItr = pmLine.find(trc); 506 if (pmlItr == pmLine.end()) 507 return 0; 508 return pmlItr->second; 509 } 510 511 bool TargetRegisterExtraInfo::classOverCapacityAtSlot( 512 const TargetRegisterClass *trc, 513 SlotIndex i) const { 514 return (getPressureAtSlot(trc, i) > getCapacity(trc)); 515 } 516 517 // ---------- MachineFunctionRenderer implementation ---------- 518 519 void RenderMachineFunction::Spacer::print(raw_ostream &os) const { 520 if (!prettyHTML) 521 return; 522 for (unsigned i = 0; i < ns; ++i) { 523 os << " "; 524 } 525 } 526 527 RenderMachineFunction::Spacer RenderMachineFunction::s(unsigned ns) const { 528 return Spacer(ns); 529 } 530 531 raw_ostream& operator<<(raw_ostream &os, const RenderMachineFunction::Spacer &s) { 532 s.print(os); 533 return os; 534 } 535 536 template <typename Iterator> 537 std::string RenderMachineFunction::escapeChars(Iterator sBegin, Iterator sEnd) const { 538 std::string r; 539 540 for (Iterator sItr = sBegin; sItr != sEnd; ++sItr) { 541 char c = *sItr; 542 543 switch (c) { 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; 550 } 551 } 552 553 return r; 554 } 555 556 RenderMachineFunction::LiveState 557 RenderMachineFunction::getLiveStateAt(const LiveInterval *li, 558 SlotIndex i) const { 559 const MachineInstr *mi = sis->getInstructionFromIndex(i); 560 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)) { 568 if (i.isUse()) { 569 return Used; 570 } 571 // else 572 return Defined; 573 } 574 } 575 } 576 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. 579 if (li->liveAt(i)) { 580 581 if (mi == 0) { 582 if (vrm == 0 || 583 (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { 584 return AliveReg; 585 } else { 586 return AliveStack; 587 } 588 } else { 589 if (i.isDef() && mi->definesRegister(li->reg, tri)) { 590 return Defined; 591 } else if (i.isUse() && mi->readsRegister(li->reg)) { 592 return Used; 593 } else { 594 if (vrm == 0 || 595 (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { 596 return AliveReg; 597 } else { 598 return AliveStack; 599 } 600 } 601 } 602 } 603 return Dead; 604 } 605 606 RenderMachineFunction::PressureState 607 RenderMachineFunction::getPressureStateAt(const TargetRegisterClass *trc, 608 SlotIndex i) const { 609 if (trei.getPressureAtSlot(trc, i) == 0) { 610 return Zero; 611 } else if (trei.classOverCapacityAtSlot(trc, i)){ 612 return High; 613 } 614 return Low; 615 } 616 617 /// \brief Render a machine instruction. 618 void RenderMachineFunction::renderMachineInstr(raw_ostream &os, 619 const MachineInstr *mi) const { 620 std::string s; 621 raw_string_ostream oss(s); 622 oss << *mi; 623 624 os << escapeChars(oss.str()); 625 } 626 627 template <typename T> 628 void RenderMachineFunction::renderVertical(const Spacer &indent, 629 raw_ostream &os, 630 const T &t) const { 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"; 646 } else { 647 std::ostringstream oss; 648 oss << t; 649 std::string tStr(oss.str()); 650 651 os << indent; 652 for (std::string::iterator tStrItr = tStr.begin(), tStrEnd = tStr.end(); 653 tStrItr != tStrEnd; ++tStrItr) { 654 os << *tStrItr << "<br/>"; 655 } 656 os << "\n"; 657 } 658 } 659 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"; 678 } 679 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() 684 << "</h1>\n" 685 << indent << "<h2>Rendering context: " << renderContextStr << "</h2>\n"; 686 } 687 688 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"; 714 } 715 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 { 721 722 if (rleAccumulator.second == 0) 723 return; 724 725 typename std::map<CellType, std::string>::const_iterator ctsItr = 726 cellTypeStrs.find(rleAccumulator.first); 727 728 assert(ctsItr != cellTypeStrs.end() && "No string for given cell type."); 729 730 os << indent + s(4) << "<td class=\"" << ctsItr->second << "\""; 731 if (rleAccumulator.second > 1) 732 os << " colspan=" << rleAccumulator.second; 733 os << "></td>\n"; 734 } 735 736 737 void RenderMachineFunction::renderCodeTablePlusPI(const Spacer &indent, 738 raw_ostream &os) const { 739 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"; 746 747 std::map<PressureState, std::string> psStrs; 748 psStrs[Zero] = "p-z"; 749 psStrs[Low] = "p-l"; 750 psStrs[High] = "p-h"; 751 752 // Open the table... 753 754 os << indent << "<table cellpadding=0 cellspacing=0 class=\"code\">\n" 755 << indent + s(2) << "<tr>\n"; 756 757 // Render the header row... 758 759 os << indent + s(4) << "<th>index</th>\n" 760 << indent + s(4) << "<th>instr</th>\n"; 761 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"; 772 } 773 } 774 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"; 778 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) { 785 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"; 790 } 791 } 792 793 os << indent + s(2) << "</tr>\n"; 794 795 // End header row, start with the data rows... 796 797 MachineInstr *mi = 0; 798 799 // Data rows: 800 for (SlotIndex i = sis->getZeroIndex(); i != sis->getLastIndex(); 801 i = i.getNextSlot()) { 802 803 // Render the slot column. 804 os << indent + s(2) << "<tr height=6ex>\n"; 805 806 // Render the code column. 807 if (i.isLoad()) { 808 MachineBasicBlock *mbb = sis->getMBBFromIndex(i); 809 mi = sis->getInstructionFromIndex(i); 810 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"; 815 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); 821 } else { 822 // Empty interval - leave blank. 823 } 824 os << indent + s(4) << "</td>\n"; 825 } else { 826 i = i.getStoreIndex(); // <- Will be incremented to the next index. 827 continue; 828 } 829 } 830 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); 840 841 if (newPressure == psRLEAccumulator.first) { 842 ++psRLEAccumulator.second; 843 } else { 844 renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); 845 psRLEAccumulator.first = newPressure; 846 psRLEAccumulator.second = 1; 847 } 848 } 849 renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); 850 } 851 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"; 855 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); 864 865 if (newLiveness == lsRLEAccumulator.first) { 866 ++lsRLEAccumulator.second; 867 } else { 868 renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); 869 lsRLEAccumulator.first = newLiveness; 870 lsRLEAccumulator.second = 1; 871 } 872 } 873 renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); 874 } 875 os << indent + s(2) << "</tr>\n"; 876 } 877 878 os << indent << "</table>\n"; 879 880 if (!ro.regClasses().empty()) 881 renderPressureTableLegend(indent, os); 882 } 883 884 void RenderMachineFunction::renderFunctionPage( 885 raw_ostream &os, 886 const char * const renderContextStr) const { 887 os << "<html>\n" 888 << s(2) << "<head>\n" 889 << s(4) << "<title>" << fqn << "</title>\n"; 890 891 insertCSS(s(4), os); 892 893 os << s(2) << "<head>\n" 894 << s(2) << "<body >\n"; 895 896 renderFunctionSummary(s(4), os, renderContextStr); 897 898 os << s(4) << "<br/><br/><br/>\n"; 899 900 //renderLiveIntervalInfoTable(" ", os); 901 902 os << s(4) << "<br/><br/><br/>\n"; 903 904 renderCodeTablePlusPI(s(4), os); 905 906 os << s(2) << "</body>\n" 907 << "</html>\n"; 908 } 909 910 void RenderMachineFunction::getAnalysisUsage(AnalysisUsage &au) const { 911 au.addRequired<SlotIndexes>(); 912 au.addRequired<LiveIntervals>(); 913 au.setPreservesAll(); 914 MachineFunctionPass::getAnalysisUsage(au); 915 } 916 917 bool RenderMachineFunction::runOnMachineFunction(MachineFunction &fn) { 918 919 mf = &fn; 920 mri = &mf->getRegInfo(); 921 tri = mf->getTarget().getRegisterInfo(); 922 lis = &getAnalysis<LiveIntervals>(); 923 sis = &getAnalysis<SlotIndexes>(); 924 925 trei.setup(mf, mri, tri, lis); 926 ro.setup(mf, tri, lis, this); 927 spillIntervals.clear(); 928 spillFor.clear(); 929 useDefs.clear(); 930 931 fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." + 932 mf->getFunction()->getName().str(); 933 934 return false; 935 } 936 937 void RenderMachineFunction::releaseMemory() { 938 trei.clear(); 939 ro.clear(); 940 spillIntervals.clear(); 941 spillFor.clear(); 942 useDefs.clear(); 943 } 944 945 void RenderMachineFunction::rememberUseDefs(const LiveInterval *li) { 946 947 if (!ro.shouldRenderCurrentMachineFunction()) 948 return; 949 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()); 956 } 957 if (mi->definesRegister(li->reg)) { 958 useDefs[li].insert(lis->getInstructionIndex(mi).getDefIndex()); 959 } 960 } 961 } 962 963 void RenderMachineFunction::rememberSpills( 964 const LiveInterval *li, 965 const std::vector<LiveInterval*> &spills) { 966 967 if (!ro.shouldRenderCurrentMachineFunction()) 968 return; 969 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; 976 } 977 } 978 979 bool RenderMachineFunction::isSpill(const LiveInterval *li) const { 980 SpillForMap::const_iterator sfItr = spillFor.find(li); 981 if (sfItr == spillFor.end()) 982 return false; 983 return true; 984 } 985 986 void RenderMachineFunction::renderMachineFunction( 987 const char *renderContextStr, 988 const VirtRegMap *vrm, 989 const char *renderSuffix) { 990 if (!ro.shouldRenderCurrentMachineFunction()) 991 return; 992 993 this->vrm = vrm; 994 trei.reset(); 995 996 std::string rpFileName(mf->getFunction()->getName().str() + 997 (renderSuffix ? renderSuffix : "") + 998 outputFileSuffix); 999 1000 std::string errMsg; 1001 raw_fd_ostream outFile(rpFileName.c_str(), errMsg, raw_fd_ostream::F_Binary); 1002 1003 renderFunctionPage(outFile, renderContextStr); 1004 1005 ro.resetRenderSpecificOptions(); 1006 } 1007 1008 std::string RenderMachineFunction::escapeChars(const std::string &s) const { 1009 return escapeChars(s.begin(), s.end()); 1010 } 1011 1012 } 1013