PageRenderTime 30ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/vm/jit/print.cpp

https://github.com/tstarling/hiphop-php
C++ | 516 lines | 422 code | 53 blank | 41 comment | 80 complexity | 679de53742304a90c81a44fd7c6a8482 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/vm/jit/print.h"
  17. #include <vector>
  18. #include "hphp/util/disasm.h"
  19. #include "hphp/util/text-color.h"
  20. #include "hphp/util/abi-cxx.h"
  21. #include "hphp/vixl/a64/disasm-a64.h"
  22. #include "hphp/runtime/base/smart-containers.h"
  23. #include "hphp/runtime/base/stats.h"
  24. #include "hphp/runtime/vm/jit/ir.h"
  25. #include "hphp/runtime/vm/jit/layout.h"
  26. #include "hphp/runtime/vm/jit/block.h"
  27. #include "hphp/runtime/vm/jit/code-gen.h"
  28. #include "hphp/util/text-util.h"
  29. namespace HPHP { namespace JIT {
  30. //////////////////////////////////////////////////////////////////////
  31. namespace {
  32. // Helper for pretty-printing punctuation.
  33. std::string punc(const char* str) {
  34. return folly::format("{}{}{}",
  35. color(ANSI_COLOR_DARK_GRAY), str, color(ANSI_COLOR_END)).str();
  36. }
  37. std::string constToString(Type t) {
  38. std::ostringstream os;
  39. os << color(ANSI_COLOR_LIGHT_BLUE)
  40. << t.constValString()
  41. << color(ANSI_COLOR_END);
  42. return os.str();
  43. }
  44. const PhysLoc* srcLoc(const RegAllocInfo* regs,
  45. const IRInstruction* inst, unsigned i) {
  46. return regs ? &(*regs)[inst].src(i) : nullptr;
  47. }
  48. const PhysLoc* dstLoc(const RegAllocInfo* regs,
  49. const IRInstruction* inst, unsigned i) {
  50. return regs ? &(*regs)[inst].dst(i) : nullptr;
  51. }
  52. void printSrc(std::ostream& ostream, const IRInstruction* inst, uint32_t i,
  53. const RegAllocInfo* regs) {
  54. SSATmp* src = inst->src(i);
  55. if (src != nullptr) {
  56. print(ostream, src, srcLoc(regs, inst, i));
  57. } else {
  58. ostream << color(ANSI_COLOR_RED)
  59. << "!!!NULL @ " << i
  60. << color(ANSI_COLOR_END)
  61. ;
  62. }
  63. }
  64. void printLabel(std::ostream& os, const Block* block) {
  65. os << color(ANSI_COLOR_MAGENTA);
  66. os << "B" << block->id();
  67. if (block->isCatch()) {
  68. os << "<Catch>";
  69. } else {
  70. switch (block->hint()) {
  71. case Block::Hint::Unlikely: os << "<Unlikely>"; break;
  72. case Block::Hint::Likely: os << "<Likely>"; break;
  73. default:
  74. break;
  75. }
  76. }
  77. os << color(ANSI_COLOR_END);
  78. }
  79. } // namespace
  80. //////////////////////////////////////////////////////////////////////
  81. /*
  82. * IRInstruction
  83. */
  84. void printOpcode(std::ostream& os, const IRInstruction* inst,
  85. const GuardConstraints* guards) {
  86. os << color(ANSI_COLOR_CYAN)
  87. << opcodeName(inst->op())
  88. << color(ANSI_COLOR_END)
  89. ;
  90. auto const hasTypeParam = inst->hasTypeParam();
  91. auto const hasExtra = inst->hasExtra();
  92. auto const isGuard = guards && !inst->isTransient() && isGuardOp(inst->op());
  93. if (!hasTypeParam && !hasExtra && !isGuard) return;
  94. os << color(ANSI_COLOR_LIGHT_BLUE) << '<' << color(ANSI_COLOR_END);
  95. if (hasTypeParam) {
  96. os << color(ANSI_COLOR_GREEN)
  97. << inst->typeParam().toString()
  98. << color(ANSI_COLOR_END)
  99. ;
  100. if (hasExtra || isGuard) os << punc(",");
  101. }
  102. if (hasExtra) {
  103. os << color(ANSI_COLOR_GREEN)
  104. << showExtra(inst->op(), inst->rawExtra())
  105. << color(ANSI_COLOR_END);
  106. if (isGuard) os << punc(",");
  107. }
  108. if (isGuard) {
  109. auto it = guards->find(inst);
  110. os << (it == guards->end() ? "unused" : it->second.toString());
  111. }
  112. os << color(ANSI_COLOR_LIGHT_BLUE)
  113. << '>'
  114. << color(ANSI_COLOR_END);
  115. }
  116. void printSrcs(std::ostream& os, const IRInstruction* inst,
  117. const RegAllocInfo* regs) {
  118. bool first = true;
  119. if (inst->op() == IncStat) {
  120. os << " " << Stats::g_counterNames[inst->src(0)->intVal()]
  121. << ", " << inst->src(1)->intVal();
  122. return;
  123. }
  124. for (uint32_t i = 0, n = inst->numSrcs(); i < n; i++) {
  125. if (!first) {
  126. os << punc(", ");
  127. } else {
  128. os << " ";
  129. first = false;
  130. }
  131. printSrc(os, inst, i, regs);
  132. }
  133. }
  134. void printDsts(std::ostream& os, const IRInstruction* inst,
  135. const RegAllocInfo* regs) {
  136. const char* sep = "";
  137. for (unsigned i = 0, n = inst->numDsts(); i < n; i++) {
  138. os << punc(sep);
  139. print(os, inst->dst(i), dstLoc(regs, inst, i));
  140. sep = ", ";
  141. }
  142. }
  143. void printInstr(std::ostream& ostream, const IRInstruction* inst,
  144. const RegAllocInfo* regs, const GuardConstraints* guards) {
  145. printDsts(ostream, inst, regs);
  146. if (inst->numDsts()) ostream << punc(" = ");
  147. printOpcode(ostream, inst, guards);
  148. printSrcs(ostream, inst, regs);
  149. }
  150. void print(std::ostream& ostream, const IRInstruction* inst,
  151. const RegAllocInfo* regs, const GuardConstraints* guards) {
  152. if (!inst->isTransient()) {
  153. ostream << color(ANSI_COLOR_YELLOW);
  154. ostream << folly::format("({:02d}) ", inst->id());
  155. ostream << color(ANSI_COLOR_END);
  156. }
  157. printInstr(ostream, inst, regs, guards);
  158. if (Block* taken = inst->taken()) {
  159. ostream << punc(" -> ");
  160. printLabel(ostream, taken);
  161. }
  162. }
  163. void print(const IRInstruction* inst) {
  164. print(std::cerr, inst);
  165. std::cerr << std::endl;
  166. }
  167. //////////////////////////////////////////////////////////////////////
  168. /*
  169. * SSATmp
  170. */
  171. std::ostream& operator<<(std::ostream& os, const PhysLoc& loc) {
  172. auto sz = loc.numAllocated();
  173. if (!sz) return os;
  174. os << '(';
  175. auto delim = "";
  176. for (int i = 0; i < sz; ++i) {
  177. if (!loc.spilled()) {
  178. PhysReg reg = loc.reg(i);
  179. switch (arch()) {
  180. case Arch::X64: {
  181. auto name = reg.type() == PhysReg::GP ? reg::regname(Reg64(reg)) :
  182. reg::regname(RegXMM(reg));
  183. os << delim << name;
  184. break;
  185. }
  186. case Arch::ARM: {
  187. auto prefix =
  188. reg.isGP() ? (vixl::Register(reg).size() == vixl::kXRegSize
  189. ? 'x' : 'w')
  190. : (vixl::FPRegister(reg).size() == vixl::kSRegSize
  191. ? 's' : 'd');
  192. os << delim << prefix << int(RegNumber(reg));
  193. break;
  194. }
  195. }
  196. } else {
  197. os << delim << "spill[" << loc.slot(i) << "]";
  198. }
  199. delim = ",";
  200. }
  201. os << ')';
  202. return os;
  203. }
  204. void printPhysLoc(std::ostream& os, const PhysLoc& loc) {
  205. if (loc.numAllocated() > 0) {
  206. os << color(ANSI_COLOR_BROWN) << loc << color(ANSI_COLOR_END);
  207. }
  208. }
  209. std::string ShuffleData::show() const {
  210. std::ostringstream os;
  211. auto delim = "";
  212. for (unsigned i = 0; i < size; ++i) {
  213. os << delim;
  214. printPhysLoc(os, dests[i]);
  215. delim = ",";
  216. }
  217. return os.str();
  218. }
  219. void print(std::ostream& os, const SSATmp* tmp, const PhysLoc* loc) {
  220. if (tmp->inst()->is(DefConst)) {
  221. os << constToString(tmp->type());
  222. if (loc) printPhysLoc(os, *loc);
  223. return;
  224. }
  225. os << color(ANSI_COLOR_WHITE);
  226. os << "t" << tmp->id();
  227. os << color(ANSI_COLOR_END);
  228. if (loc) {
  229. printPhysLoc(os, *loc);
  230. }
  231. os << punc(":")
  232. << color(ANSI_COLOR_GREEN)
  233. << tmp->type().toString()
  234. << color(ANSI_COLOR_END)
  235. ;
  236. }
  237. void print(const SSATmp* tmp) {
  238. print(std::cerr, tmp);
  239. std::cerr << std::endl;
  240. }
  241. //////////////////////////////////////////////////////////////////////
  242. /*
  243. * Block
  244. */
  245. static constexpr auto kIndent = 4;
  246. static void disasmRange(std::ostream& os, TCA begin, TCA end) {
  247. switch (arch()) {
  248. case Arch::X64: {
  249. Disasm disasm(Disasm::Options().indent(kIndent + 4)
  250. .printEncoding(dumpIREnabled(kExtraLevel))
  251. .color(color(ANSI_COLOR_BROWN)));
  252. disasm.disasm(os, begin, end);
  253. break;
  254. }
  255. case Arch::ARM: {
  256. using namespace vixl;
  257. Decoder dec;
  258. PrintDisassembler disasm(os, kIndent + 4, dumpIREnabled(kExtraLevel),
  259. color(ANSI_COLOR_BROWN));
  260. dec.AppendVisitor(&disasm);
  261. assert(begin <= end);
  262. for (; begin < end; begin += kInstructionSize) {
  263. dec.Decode(Instruction::Cast(begin));
  264. }
  265. break;
  266. }
  267. }
  268. }
  269. void print(std::ostream& os, const Block* block,
  270. const RegAllocInfo* regs, const AsmInfo* asmInfo,
  271. const GuardConstraints* guards, BCMarker* markerPtr) {
  272. BCMarker dummy;
  273. BCMarker& curMarker = markerPtr ? *markerPtr : dummy;
  274. TcaRange blockRange = asmInfo ? asmInfo->asmRanges[block] :
  275. TcaRange(nullptr, nullptr);
  276. os << '\n' << std::string(kIndent - 3, ' ');
  277. printLabel(os, block);
  278. os << punc(":");
  279. auto& preds = block->preds();
  280. if (!preds.empty()) {
  281. os << " (preds";
  282. for (auto const& edge : preds) {
  283. os << " B" << edge.inst()->block()->id();
  284. }
  285. os << ')';
  286. }
  287. os << "\n";
  288. if (block->empty()) {
  289. os << std::string(kIndent, ' ') << "empty block\n";
  290. return;
  291. }
  292. const char* markerEndl = "";
  293. for (auto it = block->begin(); it != block->end();) {
  294. auto& inst = *it; ++it;
  295. if (inst.marker() != curMarker) {
  296. std::ostringstream mStr;
  297. auto const& newMarker = inst.marker();
  298. auto func = newMarker.func;
  299. if (!func) {
  300. os << color(ANSI_COLOR_BLUE)
  301. << std::string(kIndent, ' ')
  302. << "--- invalid marker"
  303. << color(ANSI_COLOR_END)
  304. << '\n';
  305. } else {
  306. if (func != curMarker.func) {
  307. func->prettyPrint(mStr, Func::PrintOpts().noFpi());
  308. }
  309. mStr << std::string(kIndent, ' ')
  310. << newMarker.show()
  311. << '\n';
  312. auto bcOffset = newMarker.bcOff;
  313. func->unit()->prettyPrint(
  314. mStr, Unit::PrintOpts()
  315. .range(bcOffset, bcOffset+1)
  316. .noLineNumbers()
  317. .noFuncs()
  318. .indent(0));
  319. std::vector<std::string> vec;
  320. folly::split('\n', mStr.str(), vec);
  321. os << markerEndl;
  322. markerEndl = "\n";
  323. for (auto& s : vec) {
  324. if (s.empty()) continue;
  325. os << color(ANSI_COLOR_BLUE) << s << color(ANSI_COLOR_END) << '\n';
  326. }
  327. }
  328. curMarker = newMarker;
  329. }
  330. if (inst.op() == DefLabel) {
  331. // print phi pseudo-instructions
  332. for (unsigned i = 0, n = inst.numDsts(); i < n; ++i) {
  333. os << std::string(kIndent +
  334. folly::format("({}) ", inst.id()).str().size(),
  335. ' ');
  336. auto dst = inst.dst(i);
  337. JIT::print(os, dst, dstLoc(regs, &inst, i));
  338. os << punc(" = ") << color(ANSI_COLOR_CYAN) << "phi "
  339. << color(ANSI_COLOR_END);
  340. bool first = true;
  341. inst.block()->forEachSrc(i, [&](IRInstruction* jmp, SSATmp*) {
  342. if (!first) os << punc(", ");
  343. first = false;
  344. printSrc(os, jmp, i, regs);
  345. os << punc("@");
  346. printLabel(os, jmp->block());
  347. });
  348. os << '\n';
  349. }
  350. }
  351. os << std::string(kIndent, ' ');
  352. JIT::print(os, &inst, regs, guards);
  353. os << '\n';
  354. if (asmInfo) {
  355. TcaRange instRange = asmInfo->instRanges[inst];
  356. if (!instRange.empty()) {
  357. disasmRange(os, instRange.begin(), instRange.end());
  358. os << '\n';
  359. assert(instRange.end() >= blockRange.start() &&
  360. instRange.end() <= blockRange.end());
  361. blockRange = TcaRange(instRange.end(), blockRange.end());
  362. }
  363. }
  364. }
  365. if (asmInfo) {
  366. // print code associated with this block that isn't tied to any
  367. // instruction. This includes code after the last isntruction (e.g.
  368. // jmp to next block), and AStubs code.
  369. if (!blockRange.empty()) {
  370. os << std::string(kIndent, ' ') << punc("A:") << "\n";
  371. disasmRange(os, blockRange.start(), blockRange.end());
  372. }
  373. auto astubRange = asmInfo->astubRanges[block];
  374. if (!astubRange.empty()) {
  375. os << std::string(kIndent, ' ') << punc("AStubs:") << "\n";
  376. disasmRange(os, astubRange.start(), astubRange.end());
  377. }
  378. if (!blockRange.empty() || !astubRange.empty()) {
  379. os << '\n';
  380. }
  381. }
  382. os << std::string(kIndent - 2, ' ');
  383. auto next = block->empty() ? nullptr : block->next();
  384. if (next) {
  385. os << punc("-> ");
  386. printLabel(os, next);
  387. os << '\n';
  388. } else {
  389. os << "no fallthrough\n";
  390. }
  391. }
  392. void print(const Block* block) {
  393. print(std::cerr, block);
  394. std::cerr << std::endl;
  395. }
  396. std::string Block::toString() const {
  397. std::ostringstream out;
  398. print(out, this);
  399. return out.str();
  400. }
  401. //////////////////////////////////////////////////////////////////////
  402. /*
  403. * Unit
  404. */
  405. void print(std::ostream& os, const IRUnit& unit,
  406. const RegAllocInfo* regs, const AsmInfo* asmInfo,
  407. const GuardConstraints* guards) {
  408. auto const layout = layoutBlocks(unit);
  409. auto const& blocks = layout.blocks;
  410. // Print the block CFG above the actual code.
  411. os << "digraph G {\n";
  412. for (Block* block : blocks) {
  413. if (block->empty()) continue;
  414. auto* next = block->next();
  415. auto* taken = block->taken();
  416. if (!next && !taken) continue;
  417. if (next) {
  418. os << folly::format("B{} -> B{}", block->id(), next->id());
  419. if (taken) os << "; ";
  420. }
  421. if (taken) os << folly::format("B{} -> B{}", block->id(), taken->id());
  422. os << "\n";
  423. }
  424. os << "}\n";
  425. // For nice-looking dumps, we want to remember curMarker between blocks.
  426. BCMarker curMarker;
  427. for (auto it = blocks.begin(); it != blocks.end(); ++it) {
  428. if (it == layout.astubsIt) {
  429. os << folly::format("\n{:-^60}", "unlikely blocks");
  430. }
  431. print(os, *it, regs, asmInfo, guards, &curMarker);
  432. }
  433. }
  434. void print(const IRUnit& unit) {
  435. print(std::cerr, unit);
  436. std::cerr << std::endl;
  437. }
  438. std::string IRUnit::toString() const {
  439. std::ostringstream out;
  440. print(out, *this);
  441. return out.str();
  442. }
  443. // Suggested captions: "before jiffy removal", "after goat saturation",
  444. // etc.
  445. void dumpTrace(int level, const IRUnit& unit, const char* caption,
  446. const RegAllocInfo* regs, AsmInfo* ai,
  447. const GuardConstraints* guards) {
  448. if (dumpIREnabled(level)) {
  449. std::ostringstream str;
  450. auto bannerFmt = "{:-^80}\n";
  451. str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
  452. << folly::format(bannerFmt, caption)
  453. << color(ANSI_COLOR_END)
  454. ;
  455. print(str, unit, regs, ai, guards);
  456. str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
  457. << folly::format(bannerFmt, "")
  458. << color(ANSI_COLOR_END)
  459. ;
  460. HPHP::Trace::traceRelease("%s\n", str.str().c_str());
  461. }
  462. }
  463. }}