1 //===-- llvm/CodeGen/RenderMachineFunction.cpp - MF->HTML -----------------===// 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 // FIXME: This is all wrong, uses and defs share the same slots. 564 if (i.isEarlyClobber() || i.isRegister()) { 565 UseDefs::const_iterator udItr = useDefs.find(li); 566 if (udItr != useDefs.end()) { 567 const SlotSet &slotSet = udItr->second; 568 if (slotSet.count(i)) { 569 if (i.isEarlyClobber()) { 570 return Used; 571 } 572 // else 573 return Defined; 574 } 575 } 576 } 577 578 // If the slot is a load/store, or there's no info in the use/def set then 579 // use liveness and instruction operand info. 580 if (li->liveAt(i)) { 581 582 if (mi == 0) { 583 if (vrm == 0 || 584 (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { 585 return AliveReg; 586 } else { 587 return AliveStack; 588 } 589 } else { 590 if (i.isRegister() && mi->definesRegister(li->reg, tri)) { 591 return Defined; 592 } else if (i.isEarlyClobber() && mi->readsRegister(li->reg)) { 593 return Used; 594 } else { 595 if (vrm == 0 || 596 (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { 597 return AliveReg; 598 } else { 599 return AliveStack; 600 } 601 } 602 } 603 } 604 return Dead; 605 } 606 607 RenderMachineFunction::PressureState 608 RenderMachineFunction::getPressureStateAt(const TargetRegisterClass *trc, 609 SlotIndex i) const { 610 if (trei.getPressureAtSlot(trc, i) == 0) { 611 return Zero; 612 } else if (trei.classOverCapacityAtSlot(trc, i)){ 613 return High; 614 } 615 return Low; 616 } 617 618 /// \brief Render a machine instruction. 619 void RenderMachineFunction::renderMachineInstr(raw_ostream &os, 620 const MachineInstr *mi) const { 621 std::string s; 622 raw_string_ostream oss(s); 623 oss << *mi; 624 625 os << escapeChars(oss.str()); 626 } 627 628 template <typename T> 629 void RenderMachineFunction::renderVertical(const Spacer &indent, 630 raw_ostream &os, 631 const T &t) const { 632 if (ro.fancyVerticals()) { 633 os << indent << "<object\n" 634 << indent + s(2) << "class=\"obj\"\n" 635 << indent + s(2) << "type=\"image/svg+xml\"\n" 636 << indent + s(2) << "width=\"14px\"\n" 637 << indent + s(2) << "height=\"55px\"\n" 638 << indent + s(2) << "data=\"data:image/svg+xml,\n" 639 << indent + s(4) << "<svg xmlns='http://www.w3.org/2000/svg'>\n" 640 << indent + s(6) << "<text x='-55' y='10' " 641 "font-family='Courier' font-size='12' " 642 "transform='rotate(-90)' " 643 "text-rendering='optimizeSpeed' " 644 "fill='#000'>" << t << "</text>\n" 645 << indent + s(4) << "</svg>\">\n" 646 << indent << "</object>\n"; 647 } else { 648 std::ostringstream oss; 649 oss << t; 650 std::string tStr(oss.str()); 651 652 os << indent; 653 for (std::string::iterator tStrItr = tStr.begin(), tStrEnd = tStr.end(); 654 tStrItr != tStrEnd; ++tStrItr) { 655 os << *tStrItr << "<br/>"; 656 } 657 os << "\n"; 658 } 659 } 660 661 void RenderMachineFunction::insertCSS(const Spacer &indent, 662 raw_ostream &os) const { 663 os << indent << "<style type=\"text/css\">\n" 664 << indent + s(2) << "body { font-color: black; }\n" 665 << indent + s(2) << "table.code td { font-family: monospace; " 666 "border-width: 0px; border-style: solid; " 667 "border-bottom: 1px solid #dddddd; white-space: nowrap; }\n" 668 << indent + s(2) << "table.code td.p-z { background-color: #000000; }\n" 669 << indent + s(2) << "table.code td.p-l { background-color: #00ff00; }\n" 670 << indent + s(2) << "table.code td.p-h { background-color: #ff0000; }\n" 671 << indent + s(2) << "table.code td.l-n { background-color: #ffffff; }\n" 672 << indent + s(2) << "table.code td.l-d { background-color: #ff0000; }\n" 673 << indent + s(2) << "table.code td.l-u { background-color: #ffff00; }\n" 674 << indent + s(2) << "table.code td.l-r { background-color: #000000; }\n" 675 << indent + s(2) << "table.code td.l-s { background-color: #770000; }\n" 676 << indent + s(2) << "table.code th { border-width: 0px; " 677 "border-style: solid; }\n" 678 << indent << "</style>\n"; 679 } 680 681 void RenderMachineFunction::renderFunctionSummary( 682 const Spacer &indent, raw_ostream &os, 683 const char * const renderContextStr) const { 684 os << indent << "<h1>Function: " << mf->getFunction()->getName() 685 << "</h1>\n" 686 << indent << "<h2>Rendering context: " << renderContextStr << "</h2>\n"; 687 } 688 689 690 void RenderMachineFunction::renderPressureTableLegend( 691 const Spacer &indent, 692 raw_ostream &os) const { 693 os << indent << "<h2>Rendering Pressure Legend:</h2>\n" 694 << indent << "<table class=\"code\">\n" 695 << indent + s(2) << "<tr>\n" 696 << indent + s(4) << "<th>Pressure</th><th>Description</th>" 697 "<th>Appearance</th>\n" 698 << indent + s(2) << "</tr>\n" 699 << indent + s(2) << "<tr>\n" 700 << indent + s(4) << "<td>No Pressure</td>" 701 "<td>No physical registers of this class requested.</td>" 702 "<td class=\"p-z\"> </td>\n" 703 << indent + s(2) << "</tr>\n" 704 << indent + s(2) << "<tr>\n" 705 << indent + s(4) << "<td>Low Pressure</td>" 706 "<td>Sufficient physical registers to meet demand.</td>" 707 "<td class=\"p-l\"> </td>\n" 708 << indent + s(2) << "</tr>\n" 709 << indent + s(2) << "<tr>\n" 710 << indent + s(4) << "<td>High Pressure</td>" 711 "<td>Potentially insufficient physical registers to meet demand.</td>" 712 "<td class=\"p-h\"> </td>\n" 713 << indent + s(2) << "</tr>\n" 714 << indent << "</table>\n"; 715 } 716 717 template <typename CellType> 718 void RenderMachineFunction::renderCellsWithRLE( 719 const Spacer &indent, raw_ostream &os, 720 const std::pair<CellType, unsigned> &rleAccumulator, 721 const std::map<CellType, std::string> &cellTypeStrs) const { 722 723 if (rleAccumulator.second == 0) 724 return; 725 726 typename std::map<CellType, std::string>::const_iterator ctsItr = 727 cellTypeStrs.find(rleAccumulator.first); 728 729 assert(ctsItr != cellTypeStrs.end() && "No string for given cell type."); 730 731 os << indent + s(4) << "<td class=\"" << ctsItr->second << "\""; 732 if (rleAccumulator.second > 1) 733 os << " colspan=" << rleAccumulator.second; 734 os << "></td>\n"; 735 } 736 737 738 void RenderMachineFunction::renderCodeTablePlusPI(const Spacer &indent, 739 raw_ostream &os) const { 740 741 std::map<LiveState, std::string> lsStrs; 742 lsStrs[Dead] = "l-n"; 743 lsStrs[Defined] = "l-d"; 744 lsStrs[Used] = "l-u"; 745 lsStrs[AliveReg] = "l-r"; 746 lsStrs[AliveStack] = "l-s"; 747 748 std::map<PressureState, std::string> psStrs; 749 psStrs[Zero] = "p-z"; 750 psStrs[Low] = "p-l"; 751 psStrs[High] = "p-h"; 752 753 // Open the table... 754 755 os << indent << "<table cellpadding=0 cellspacing=0 class=\"code\">\n" 756 << indent + s(2) << "<tr>\n"; 757 758 // Render the header row... 759 760 os << indent + s(4) << "<th>index</th>\n" 761 << indent + s(4) << "<th>instr</th>\n"; 762 763 // Render class names if necessary... 764 if (!ro.regClasses().empty()) { 765 for (MFRenderingOptions::RegClassSet::const_iterator 766 rcItr = ro.regClasses().begin(), 767 rcEnd = ro.regClasses().end(); 768 rcItr != rcEnd; ++rcItr) { 769 const TargetRegisterClass *trc = *rcItr; 770 os << indent + s(4) << "<th>\n"; 771 renderVertical(indent + s(6), os, trc->getName()); 772 os << indent + s(4) << "</th>\n"; 773 } 774 } 775 776 // FIXME: Is there a nicer way to insert space between columns in HTML? 777 if (!ro.regClasses().empty() && !ro.intervals().empty()) 778 os << indent + s(4) << "<th> </th>\n"; 779 780 // Render interval numbers if necessary... 781 if (!ro.intervals().empty()) { 782 for (MFRenderingOptions::IntervalSet::const_iterator 783 liItr = ro.intervals().begin(), 784 liEnd = ro.intervals().end(); 785 liItr != liEnd; ++liItr) { 786 787 const LiveInterval *li = *liItr; 788 os << indent + s(4) << "<th>\n"; 789 renderVertical(indent + s(6), os, li->reg); 790 os << indent + s(4) << "</th>\n"; 791 } 792 } 793 794 os << indent + s(2) << "</tr>\n"; 795 796 // End header row, start with the data rows... 797 798 MachineInstr *mi = 0; 799 800 // Data rows: 801 for (SlotIndex i = sis->getZeroIndex(); i != sis->getLastIndex(); 802 i = i.getNextSlot()) { 803 804 // Render the slot column. 805 os << indent + s(2) << "<tr height=6ex>\n"; 806 807 // Render the code column. 808 if (i.isBlock()) { 809 MachineBasicBlock *mbb = sis->getMBBFromIndex(i); 810 mi = sis->getInstructionFromIndex(i); 811 812 if (i == sis->getMBBStartIdx(mbb) || mi != 0 || 813 ro.renderEmptyIndexes()) { 814 os << indent + s(4) << "<td rowspan=4>" << i << " </td>\n" 815 << indent + s(4) << "<td rowspan=4>\n"; 816 817 if (i == sis->getMBBStartIdx(mbb)) { 818 os << indent + s(6) << "BB#" << mbb->getNumber() << ": \n"; 819 } else if (mi != 0) { 820 os << indent + s(6) << " "; 821 renderMachineInstr(os, mi); 822 } else { 823 // Empty interval - leave blank. 824 } 825 os << indent + s(4) << "</td>\n"; 826 } else { 827 i = i.getDeadSlot(); // <- Will be incremented to the next index. 828 continue; 829 } 830 } 831 832 // Render the class columns. 833 if (!ro.regClasses().empty()) { 834 std::pair<PressureState, unsigned> psRLEAccumulator(Zero, 0); 835 for (MFRenderingOptions::RegClassSet::const_iterator 836 rcItr = ro.regClasses().begin(), 837 rcEnd = ro.regClasses().end(); 838 rcItr != rcEnd; ++rcItr) { 839 const TargetRegisterClass *trc = *rcItr; 840 PressureState newPressure = getPressureStateAt(trc, i); 841 842 if (newPressure == psRLEAccumulator.first) { 843 ++psRLEAccumulator.second; 844 } else { 845 renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); 846 psRLEAccumulator.first = newPressure; 847 psRLEAccumulator.second = 1; 848 } 849 } 850 renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); 851 } 852 853 // FIXME: Is there a nicer way to insert space between columns in HTML? 854 if (!ro.regClasses().empty() && !ro.intervals().empty()) 855 os << indent + s(4) << "<td width=2em></td>\n"; 856 857 if (!ro.intervals().empty()) { 858 std::pair<LiveState, unsigned> lsRLEAccumulator(Dead, 0); 859 for (MFRenderingOptions::IntervalSet::const_iterator 860 liItr = ro.intervals().begin(), 861 liEnd = ro.intervals().end(); 862 liItr != liEnd; ++liItr) { 863 const LiveInterval *li = *liItr; 864 LiveState newLiveness = getLiveStateAt(li, i); 865 866 if (newLiveness == lsRLEAccumulator.first) { 867 ++lsRLEAccumulator.second; 868 } else { 869 renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); 870 lsRLEAccumulator.first = newLiveness; 871 lsRLEAccumulator.second = 1; 872 } 873 } 874 renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); 875 } 876 os << indent + s(2) << "</tr>\n"; 877 } 878 879 os << indent << "</table>\n"; 880 881 if (!ro.regClasses().empty()) 882 renderPressureTableLegend(indent, os); 883 } 884 885 void RenderMachineFunction::renderFunctionPage( 886 raw_ostream &os, 887 const char * const renderContextStr) const { 888 os << "<html>\n" 889 << s(2) << "<head>\n" 890 << s(4) << "<title>" << fqn << "</title>\n"; 891 892 insertCSS(s(4), os); 893 894 os << s(2) << "<head>\n" 895 << s(2) << "<body >\n"; 896 897 renderFunctionSummary(s(4), os, renderContextStr); 898 899 os << s(4) << "<br/><br/><br/>\n"; 900 901 //renderLiveIntervalInfoTable(" ", os); 902 903 os << s(4) << "<br/><br/><br/>\n"; 904 905 renderCodeTablePlusPI(s(4), os); 906 907 os << s(2) << "</body>\n" 908 << "</html>\n"; 909 } 910 911 void RenderMachineFunction::getAnalysisUsage(AnalysisUsage &au) const { 912 au.addRequired<SlotIndexes>(); 913 au.addRequired<LiveIntervals>(); 914 au.setPreservesAll(); 915 MachineFunctionPass::getAnalysisUsage(au); 916 } 917 918 bool RenderMachineFunction::runOnMachineFunction(MachineFunction &fn) { 919 920 mf = &fn; 921 mri = &mf->getRegInfo(); 922 tri = mf->getTarget().getRegisterInfo(); 923 lis = &getAnalysis<LiveIntervals>(); 924 sis = &getAnalysis<SlotIndexes>(); 925 926 trei.setup(mf, mri, tri, lis); 927 ro.setup(mf, tri, lis, this); 928 spillIntervals.clear(); 929 spillFor.clear(); 930 useDefs.clear(); 931 932 fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." + 933 mf->getFunction()->getName().str(); 934 935 return false; 936 } 937 938 void RenderMachineFunction::releaseMemory() { 939 trei.clear(); 940 ro.clear(); 941 spillIntervals.clear(); 942 spillFor.clear(); 943 useDefs.clear(); 944 } 945 946 void RenderMachineFunction::rememberUseDefs(const LiveInterval *li) { 947 948 if (!ro.shouldRenderCurrentMachineFunction()) 949 return; 950 951 for (MachineRegisterInfo::reg_iterator rItr = mri->reg_begin(li->reg), 952 rEnd = mri->reg_end(); 953 rItr != rEnd; ++rItr) { 954 const MachineInstr *mi = &*rItr; 955 if (mi->readsRegister(li->reg)) { 956 useDefs[li].insert(lis->getInstructionIndex(mi).getRegSlot(true)); 957 } 958 if (mi->definesRegister(li->reg)) { 959 useDefs[li].insert(lis->getInstructionIndex(mi).getRegSlot()); 960 } 961 } 962 } 963 964 void RenderMachineFunction::rememberSpills( 965 const LiveInterval *li, 966 const std::vector<LiveInterval*> &spills) { 967 968 if (!ro.shouldRenderCurrentMachineFunction()) 969 return; 970 971 for (std::vector<LiveInterval*>::const_iterator siItr = spills.begin(), 972 siEnd = spills.end(); 973 siItr != siEnd; ++siItr) { 974 const LiveInterval *spill = *siItr; 975 spillIntervals[li].insert(spill); 976 spillFor[spill] = li; 977 } 978 } 979 980 bool RenderMachineFunction::isSpill(const LiveInterval *li) const { 981 SpillForMap::const_iterator sfItr = spillFor.find(li); 982 if (sfItr == spillFor.end()) 983 return false; 984 return true; 985 } 986 987 void RenderMachineFunction::renderMachineFunction( 988 const char *renderContextStr, 989 const VirtRegMap *vrm, 990 const char *renderSuffix) { 991 if (!ro.shouldRenderCurrentMachineFunction()) 992 return; 993 994 this->vrm = vrm; 995 trei.reset(); 996 997 std::string rpFileName(mf->getFunction()->getName().str() + 998 (renderSuffix ? renderSuffix : "") + 999 outputFileSuffix); 1000 1001 std::string errMsg; 1002 raw_fd_ostream outFile(rpFileName.c_str(), errMsg, raw_fd_ostream::F_Binary); 1003 1004 renderFunctionPage(outFile, renderContextStr); 1005 1006 ro.resetRenderSpecificOptions(); 1007 } 1008 1009 std::string RenderMachineFunction::escapeChars(const std::string &s) const { 1010 return escapeChars(s.begin(), s.end()); 1011 } 1012 1013 } 1014