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