Move pretty-printing code into its own file

Pretty-printing the IR is a kind of pass, and definitely a separate
concern, just like rendering IR as machine code.  Put it in its own file.
Esse commit está contido em:
Edwin Smith
2013-05-07 06:17:22 -07:00
commit de Sara Golemon
commit 4fdec8b2a1
9 arquivos alterados com 513 adições e 427 exclusões
+2 -1
Ver Arquivo
@@ -44,6 +44,7 @@
#include "runtime/vm/translator/hopt/ir.h"
#include "runtime/vm/translator/hopt/linearscan.h"
#include "runtime/vm/translator/hopt/nativecalls.h"
#include "runtime/vm/translator/hopt/print.h"
using HPHP::VM::Transl::TCA;
using namespace HPHP::VM::Transl::TargetCache;
@@ -5142,7 +5143,7 @@ void cgTrace(Trace* trace, Asm& amain, Asm& astubs, Transl::TranslatorX64* tx64,
}
void CodeGenerator::print() const {
m_curTrace->print(std::cout, m_state.asmInfo);
JIT::print(std::cout, m_curTrace, m_state.asmInfo);
}
// select instructions for the trace and its exits
+12 -389
Ver Arquivo
@@ -26,9 +26,7 @@
#include "folly/Format.h"
#include "folly/Traits.h"
#include "util/disasm.h"
#include "util/trace.h"
#include "util/text_color.h"
#include "runtime/base/string_data.h"
#include "runtime/vm/runtime.h"
#include "runtime/base/stats.h"
@@ -36,6 +34,8 @@
#include "runtime/vm/translator/hopt/linearscan.h"
#include "runtime/vm/translator/hopt/cse.h"
#include "runtime/vm/translator/hopt/simplifier.h"
#include "runtime/vm/translator/hopt/print.h"
#include "runtime/vm/translator/hopt/codegen.h"
// Include last to localize effects to this file
#include "util/assert_throw.h"
@@ -262,7 +262,7 @@ typename std::enable_if<
has_show<T,std::string () const>::value,
std::string
>::type showExtraImpl(T* t) { return t->show(); }
std::string showExtraImpl(IRExtraData*) { return "..."; }
std::string showExtraImpl(const IRExtraData*) { return "..."; }
MAKE_DISPATCHER(HashDispatcher, size_t, cseHashExtraImpl);
size_t cseHashExtra(Opcode opc, IRExtraData* data) {
@@ -280,22 +280,16 @@ IRExtraData* cloneExtra(Opcode opc, IRExtraData* data, Arena& a) {
}
MAKE_DISPATCHER(ShowDispatcher, std::string, showExtraImpl);
std::string showExtra(Opcode opc, IRExtraData* data) {
return dispatchExtra<std::string,ShowDispatcher>(opc, data);
} // namespace
std::string showExtra(Opcode opc, const IRExtraData* data) {
return dispatchExtra<std::string,ShowDispatcher>(opc,
const_cast<IRExtraData*>(data));
}
//////////////////////////////////////////////////////////////////////
// Helper for pretty-printing punctuation.
std::string punc(const char* str) {
return folly::format("{}{}{}",
color(ANSI_COLOR_DARK_GRAY), str, color(ANSI_COLOR_END)).str();
}
//////////////////////////////////////////////////////////////////////
}
IRInstruction::IRInstruction(Arena& arena, const IRInstruction* inst, IId iid)
: m_op(inst->m_op)
, m_typeParam(inst->m_typeParam)
@@ -732,198 +726,12 @@ size_t IRInstruction::cseHash() const {
return CSEHash::hashCombine(srcHash, m_op, m_typeParam);
}
void IRInstruction::printOpcode(std::ostream& os) const {
os << color(ANSI_COLOR_CYAN)
<< opcodeName(m_op)
<< color(ANSI_COLOR_END)
;
if (m_typeParam == Type::None && !hasExtra()) {
return;
}
os << color(ANSI_COLOR_LIGHT_BLUE) << '<' << color(ANSI_COLOR_END);
if (m_typeParam != Type::None) {
os << color(ANSI_COLOR_GREEN)
<< m_typeParam.toString()
<< color(ANSI_COLOR_END)
;
if (hasExtra()) {
os << punc(",");
}
}
if (hasExtra()) {
os << color(ANSI_COLOR_GREEN)
<< showExtra(op(), m_extra)
<< color(ANSI_COLOR_END);
}
os << color(ANSI_COLOR_LIGHT_BLUE)
<< '>'
<< color(ANSI_COLOR_END);
}
void IRInstruction::printDst(std::ostream& os) const {
if (getNumDsts() == 0) return;
const char* sep = "";
for (const SSATmp& dst : getDsts()) {
os << punc(sep);
dst.print(os, true);
sep = ", ";
}
os << punc(" = ");
}
void IRInstruction::printSrc(std::ostream& ostream, uint32_t i) const {
SSATmp* src = getSrc(i);
if (src != nullptr) {
if (m_id != 0 && !src->isConst() && src->getLastUseId() == m_id) {
ostream << "~";
}
src->print(ostream);
} else {
ostream << color(ANSI_COLOR_RED)
<< "!!!NULL @ " << i
<< color(ANSI_COLOR_END)
;
}
}
void IRInstruction::printSrcs(std::ostream& os) const {
bool first = true;
if (op() == IncStat) {
os << " " << Stats::g_counterNames[getSrc(0)->getValInt()]
<< ", " << getSrc(1)->getValInt();
return;
}
for (uint32_t i = 0; i < m_numSrcs; i++) {
if (!first) {
os << punc(", ");
} else {
os << " ";
first = false;
}
printSrc(os, i);
}
}
void IRInstruction::print(std::ostream& ostream) const {
if (op() == Marker) {
auto* marker = getExtra<Marker>();
ostream << color(ANSI_COLOR_BLUE)
<< folly::format("--- bc {}, spOff {} ({})",
marker->bcOff,
marker->stackOff,
marker->func->fullName()->data())
<< color(ANSI_COLOR_END);
return;
}
if (!isTransient()) {
ostream << color(ANSI_COLOR_YELLOW);
if (!m_id) ostream << folly::format("({:02d}) ", getIId());
else ostream << folly::format("({:02d}@{:02d}) ", getIId(), m_id);
ostream << color(ANSI_COLOR_END);
}
printDst(ostream);
printOpcode(ostream);
printSrcs(ostream);
if (m_taken) {
ostream << punc(" -> ");
m_taken->printLabel(ostream);
}
if (m_tca) {
ostream << punc(", ");
if (m_tca == kIRDirectJccJmpActive) {
ostream << "JccJmp_Exit ";
}
else
if (m_tca == kIRDirectJccActive) {
ostream << "Jcc_Exit ";
}
else
if (m_tca == kIRDirectGuardActive) {
ostream << "Guard_Exit ";
}
else {
ostream << (void*)m_tca;
}
}
}
void IRInstruction::print() const {
print(std::cerr);
std::cerr << std::endl;
}
std::string IRInstruction::toString() const {
std::ostringstream str;
print(str);
print(str, this);
return str.str();
}
static void printConst(std::ostream& os, IRInstruction* inst) {
os << color(ANSI_COLOR_LIGHT_BLUE);
SCOPE_EXIT { os << color(ANSI_COLOR_END); };
auto t = inst->getTypeParam();
auto c = inst->getExtra<DefConst>();
if (t == Type::Int) {
os << c->as<int64_t>();
} else if (t == Type::Dbl) {
os << c->as<double>();
} else if (t == Type::Bool) {
os << (c->as<bool>() ? "true" : "false");
} else if (t.isString()) {
auto str = c->as<const StringData*>();
os << "\""
<< Util::escapeStringForCPP(str->data(), str->size())
<< "\"";
} else if (t.isArray()) {
auto arr = inst->getExtra<DefConst>()->as<const ArrayData*>();
if (arr->empty()) {
os << "array()";
} else {
os << "Array(" << arr << ")";
}
} else if (t.isNull()) {
os << t.toString();
} else if (t.subtypeOf(Type::Func)) {
auto func = c->as<const Func*>();
os << "Func(" << (func ? func->fullName()->data() : "0") << ")";
} else if (t.subtypeOf(Type::Cls)) {
auto cls = c->as<const Class*>();
os << "Cls(" << (cls ? cls->name()->data() : "0") << ")";
} else if (t.subtypeOf(Type::NamedEntity)) {
auto ne = c->as<const NamedEntity*>();
os << "NamedEntity(" << ne << ")";
} else if (t.subtypeOf(Type::TCA)) {
TCA tca = c->as<TCA>();
auto name = Util::getNativeFunctionName(tca);
SCOPE_EXIT { free(name); };
os << folly::format("TCA: {}({})", tca,
boost::trim_copy(std::string(name)));
} else if (t.subtypeOf(Type::None)) {
os << "None:" << c->as<int64_t>();
} else if (t.isPtr()) {
os << folly::format("{}({:#x})", t.toString(), c->as<uint64_t>());
} else if (t.subtypeOf(Type::CacheHandle)) {
os << folly::format("CacheHandle({:#x})", c->as<int64_t>());
} else {
not_reached();
}
}
void Block::printLabel(std::ostream& os) const {
os << color(ANSI_COLOR_MAGENTA);
os << "L" << m_id;
if (getHint() == Unlikely) {
os << "<Unlikely>";
}
os << color(ANSI_COLOR_END);
}
int SSATmp::numNeededRegs() const {
auto t = type();
if (t.subtypeOfAny(Type::None, Type::Null, Type::ActRec, Type::RetAddr)) {
@@ -1074,176 +882,16 @@ std::string ExitData::show() const {
std::string SSATmp::toString() const {
std::ostringstream out;
print(out);
print(out, this);
return out.str();
}
void SSATmp::print(std::ostream& os, bool printLastUse) const {
if (m_inst->op() == DefConst) {
printConst(os, m_inst);
return;
}
os << color(ANSI_COLOR_WHITE);
os << "t" << m_id;
os << color(ANSI_COLOR_END);
if (printLastUse && m_lastUseId != 0) {
os << color(ANSI_COLOR_GRAY)
<< "@" << m_lastUseId << "#" << m_useCount
<< color(ANSI_COLOR_END);
}
if (m_isSpilled || numAllocatedRegs() > 0) {
os << color(ANSI_COLOR_BROWN) << '(';
if (!m_isSpilled) {
for (int i = 0, sz = numAllocatedRegs(); i < sz; ++i) {
if (i != 0) os << ",";
os << reg::regname(Reg64(int(m_regs[i])));
}
} else {
for (int i = 0, sz = numNeededRegs(); i < sz; ++i) {
if (i != 0) os << ",";
os << m_spillInfo[i];
}
}
os << ')' << color(ANSI_COLOR_END);
}
os << punc(":")
<< color(ANSI_COLOR_GREEN)
<< type().toString()
<< color(ANSI_COLOR_END)
;
}
void SSATmp::print() const {
print(std::cerr);
std::cerr << std::endl;
}
std::string Trace::toString() const {
std::ostringstream out;
print(out, nullptr);
print(out, this, nullptr);
return out.str();
}
void Trace::print() const {
print(std::cout, nullptr);
}
void Trace::print(std::ostream& os, const AsmInfo* asmInfo) const {
static const int kIndent = 4;
Disasm disasm(Disasm::Options().indent(kIndent + 4)
.printEncoding(dumpIREnabled(6))
.color(color(ANSI_COLOR_BROWN)));
// Print unlikely blocks at the end
BlockList blocks, unlikely;
for (Block* block : m_blocks) {
if (block->getHint() == Block::Unlikely) {
unlikely.push_back(block);
} else {
blocks.push_back(block);
}
}
blocks.splice(blocks.end(), unlikely);
for (Block* block : blocks) {
TcaRange blockRange = asmInfo ? asmInfo->asmRanges[block] :
TcaRange(nullptr, nullptr);
for (auto it = block->begin(); it != block->end();) {
auto& inst = *it; ++it;
if (inst.op() == Marker) {
os << std::string(kIndent, ' ');
inst.print(os);
os << '\n';
// Don't print bytecode in a non-main trace.
if (!isMain()) continue;
auto* marker = inst.getExtra<Marker>();
uint32_t bcOffset = marker->bcOff;
if (const auto* func = marker->func) {
std::ostringstream uStr;
func->unit()->prettyPrint(
uStr, Unit::PrintOpts()
.range(bcOffset, bcOffset+1)
.noLineNumbers()
.indent(0));
std::vector<std::string> vec;
folly::split('\n', uStr.str(), vec);
for (auto& s : vec) {
os << color(ANSI_COLOR_BLUE) << s << color(ANSI_COLOR_END) << '\n';
}
continue;
}
}
if (inst.op() == DefLabel) {
os << std::string(kIndent - 2, ' ');
inst.getBlock()->printLabel(os);
os << punc(":") << "\n";
// print phi pseudo-instructions
for (unsigned i = 0, n = inst.getNumDsts(); i < n; ++i) {
os << std::string(kIndent +
folly::format("({}) ", inst.getIId()).str().size(),
' ');
inst.getDst(i)->print(os, false);
os << punc(" = ") << color(ANSI_COLOR_CYAN) << "phi "
<< color(ANSI_COLOR_END);
bool first = true;
inst.getBlock()->forEachSrc(i, [&](IRInstruction* jmp, SSATmp*) {
if (!first) os << punc(", ");
first = false;
jmp->printSrc(os, i);
os << punc("@");
jmp->getBlock()->printLabel(os);
});
os << '\n';
}
}
os << std::string(kIndent, ' ');
inst.print(os);
os << '\n';
if (asmInfo) {
TcaRange instRange = asmInfo->instRanges[inst];
if (!instRange.empty()) {
disasm.disasm(os, instRange.begin(), instRange.end());
os << '\n';
assert(instRange.end() >= blockRange.start() &&
instRange.end() <= blockRange.end());
blockRange = TcaRange(instRange.end(), blockRange.end());
}
}
}
if (asmInfo) {
// print code associated with this block that isn't tied to any
// instruction. This includes code after the last isntruction (e.g.
// jmp to next block), and AStubs code.
if (!blockRange.empty()) {
os << std::string(kIndent, ' ') << punc("A:") << "\n";
disasm.disasm(os, blockRange.start(), blockRange.end());
}
auto astubRange = asmInfo->astubRanges[block];
if (!astubRange.empty()) {
os << std::string(kIndent, ' ') << punc("AStubs:") << "\n";
disasm.disasm(os, astubRange.start(), astubRange.end());
}
if (!blockRange.empty() || !astubRange.empty()) {
os << '\n';
}
}
}
for (auto* exitTrace : m_exitTraces) {
os << "\n" << color(ANSI_COLOR_GREEN)
<< " ------- Exit Trace -------"
<< color(ANSI_COLOR_END) << '\n';
exitTrace->print(os, asmInfo);
}
}
int32_t spillValueCells(IRInstruction* spillStack) {
assert(spillStack->op() == SpillStack);
int32_t numSrcs = spillStack->getNumSrcs();
@@ -1417,30 +1065,5 @@ bool hasInternalFlow(Trace* trace) {
return false;
}
void dumpTraceImpl(const Trace* trace, std::ostream& out,
const AsmInfo* asmInfo) {
trace->print(out, asmInfo);
}
// Suggested captions: "before jiffy removal", "after goat saturation",
// etc.
void dumpTrace(int level, const Trace* trace, const char* caption,
AsmInfo* ai) {
if (dumpIREnabled(level)) {
std::ostringstream str;
auto bannerFmt = "{:-^40}\n";
str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
<< folly::format(bannerFmt, caption)
<< color(ANSI_COLOR_END)
;
dumpTraceImpl(trace, str, ai);
str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
<< folly::format(bannerFmt, "")
<< color(ANSI_COLOR_END)
;
HPHP::Trace::traceRelease("%s", str.str().c_str());
}
}
}}}
+10 -27
Ver Arquivo
@@ -886,6 +886,8 @@ template<class T> void assert_opcode_extra(Opcode opc) {
#undef O
}
std::string showExtra(Opcode opc, const IRExtraData* data);
//////////////////////////////////////////////////////////////////////
inline bool isCmpOp(Opcode opc) {
@@ -1730,6 +1732,11 @@ struct IRInstruction {
*/
void setExtra(IRExtraData* data) { assert(!m_extra); m_extra = data; }
/*
* Return the raw extradata pointer, for pretty-printing.
*/
const IRExtraData* rawExtra() const { return m_extra; }
/*
* Clear the extra data pointer in a IRInstruction. Used during
* IRFactory::gen to avoid having dangling IRExtraData*'s into stack
@@ -1867,8 +1874,6 @@ struct IRInstruction {
bool cseEquals(IRInstruction* inst) const;
size_t cseHash() const;
void print(std::ostream& ostream) const;
void print() const;
std::string toString() const;
/*
@@ -1903,11 +1908,6 @@ struct IRInstruction {
// ModifiesStack set.
bool hasMainDst() const;
void printDst(std::ostream& ostream) const;
void printSrc(std::ostream& ostream, uint32_t srcIndex) const;
void printOpcode(std::ostream& ostream) const;
void printSrcs(std::ostream& ostream) const;
private:
bool mayReenterHelper() const;
@@ -1986,13 +1986,11 @@ public:
void setUseCount(uint32_t count) { m_useCount = count; }
void incUseCount() { m_useCount++; }
uint32_t decUseCount() { return --m_useCount; }
bool isSpilled() const { return m_isSpilled; }
bool isBoxed() const { return type().isBoxed(); }
bool isString() const { return isA(Type::Str); }
bool isArray() const { return isA(Type::Arr); }
std::string toString() const;
void print(std::ostream& ostream,
bool printLastUse = false) const;
void print() const;
// XXX: false for Null, etc. Would rather it returns whether we
// have a compile-time constant value.
@@ -2277,8 +2275,6 @@ struct Block : boost::noncopyable {
unsigned postId() const { return m_postid; }
void setPostId(unsigned id) { m_postid = id; }
void printLabel(std::ostream& ostream) const;
// insert inst after this block's label, return an iterator to the
// newly inserted instruction.
iterator prepend(IRInstruction* inst) {
@@ -2385,6 +2381,7 @@ public:
}
std::list<Block*>& getBlocks() { return m_blocks; }
const std::list<Block*>& getBlocks() const { return m_blocks; }
Block* front() { return *m_blocks.begin(); }
Block* back() { auto it = m_blocks.end(); return *(--it); }
const Block* front() const { return *m_blocks.begin(); }
@@ -2423,9 +2420,8 @@ public:
typedef std::list<Trace*>::iterator ExitIterator;
ExitList& getExitTraces() { return m_exitTraces; }
const ExitList& getExitTraces() const { return m_exitTraces; }
std::string toString() const;
void print(std::ostream& ostream, const AsmInfo* asmInfo = nullptr) const;
void print() const;
private:
// offset of the first bytecode in this trace; 0 if this trace doesn't
@@ -2607,19 +2603,6 @@ void forEachTraceInst(Trace* main, Body body) {
});
}
/*
* Some utilities related to dumping. Rather than file-by-file control, we control
* most IR logging via the hhir trace module.
*/
static inline bool dumpIREnabled(int level = 1) {
return HPHP::Trace::moduleEnabledRelease(HPHP::Trace::hhir, level);
}
void dumpTraceImpl(const Trace* trace, std::ostream& out,
const AsmInfo* asmInfo = nullptr);
void dumpTrace(int level, const Trace* trace, const char* caption,
AsmInfo* ai = nullptr);
}}}
namespace std {
@@ -37,6 +37,7 @@
#include "runtime/vm/translator/hopt/linearscan.h"
#include "runtime/vm/translator/hopt/codegen.h"
#include "runtime/vm/translator/hopt/hhbctranslator.h"
#include "runtime/vm/translator/hopt/print.h"
// Include last to localize effects to this file
#include "util/assert_throw.h"
+9 -1
Ver Arquivo
@@ -18,6 +18,14 @@
#include "runtime/vm/translator/hopt/irfactory.h"
#include "runtime/vm/translator/hopt/nativecalls.h"
#include "runtime/vm/translator/hopt/print.h"
#include "runtime/vm/translator/hopt/ir.h"
#include "runtime/vm/translator/hopt/tracebuilder.h"
#include "runtime/vm/translator/hopt/codegen.h"
#include "runtime/vm/translator/hopt/state_vector.h"
#include "runtime/vm/translator/physreg.h"
#include "runtime/vm/translator/abi-x64.h"
#include <boost/noncopyable.hpp>
namespace HPHP {
namespace VM {
@@ -278,7 +286,7 @@ template<typename Inner, int DumpVal=4>
static inline void dumpIR(const Inner* in, const char* msg) {
if (dumpIREnabled(DumpVal)) {
std::ostringstream str;
in->print(str);
print(str, in);
HPHP::Trace::traceRelease("--- %s: %s\n", msg, str.str().c_str());
}
}
+3 -9
Ver Arquivo
@@ -17,17 +17,11 @@
#ifndef incl_HPHP_VM_LINEAR_SCAN_H_
#define incl_HPHP_VM_LINEAR_SCAN_H_
#include <boost/noncopyable.hpp>
#include "runtime/vm/translator/physreg.h"
#include "runtime/vm/translator/abi-x64.h"
#include "runtime/vm/translator/hopt/ir.h"
#include "runtime/vm/translator/hopt/tracebuilder.h"
#include "runtime/vm/translator/hopt/codegen.h"
#include "runtime/vm/translator/hopt/state_vector.h"
namespace HPHP { namespace VM { namespace JIT {
class Trace;
class IRFactory;
/*
* The main entry point for register allocation. Called prior to code
* generation.
+1
Ver Arquivo
@@ -17,6 +17,7 @@
#include "runtime/vm/translator/hopt/tracebuilder.h"
#include "util/trace.h"
#include "runtime/vm/translator/hopt/irfactory.h"
#include "runtime/vm/translator/hopt/print.h"
namespace HPHP {
namespace VM {
+412
Ver Arquivo
@@ -0,0 +1,412 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "runtime/vm/translator/hopt/print.h"
#include "runtime/vm/translator/hopt/ir.h"
#include "runtime/vm/translator/hopt/linearscan.h"
#include "runtime/vm/translator/hopt/codegen.h"
#include "runtime/base/stats.h"
#include "util/disasm.h"
#include "util/text_color.h"
namespace HPHP { namespace VM { namespace JIT {
//////////////////////////////////////////////////////////////////////
// Helper for pretty-printing punctuation.
static std::string punc(const char* str) {
return folly::format("{}{}{}",
color(ANSI_COLOR_DARK_GRAY), str, color(ANSI_COLOR_END)).str();
}
//////////////////////////////////////////////////////////////////////
void printOpcode(std::ostream& os, const IRInstruction* inst) {
os << color(ANSI_COLOR_CYAN)
<< opcodeName(inst->op())
<< color(ANSI_COLOR_END)
;
auto type_param = inst->getTypeParam();
if (type_param == Type::None && !inst->hasExtra()) {
return;
}
os << color(ANSI_COLOR_LIGHT_BLUE) << '<' << color(ANSI_COLOR_END);
if (type_param != Type::None) {
os << color(ANSI_COLOR_GREEN)
<< type_param.toString()
<< color(ANSI_COLOR_END)
;
if (inst->hasExtra()) {
os << punc(",");
}
}
if (inst->hasExtra()) {
os << color(ANSI_COLOR_GREEN)
<< showExtra(inst->op(), inst->rawExtra())
<< color(ANSI_COLOR_END);
}
os << color(ANSI_COLOR_LIGHT_BLUE)
<< '>'
<< color(ANSI_COLOR_END);
}
void printDst(std::ostream& os, const IRInstruction* inst) {
if (inst->getNumDsts() == 0) return;
const char* sep = "";
for (const SSATmp& dst : inst->getDsts()) {
os << punc(sep);
print(os, &dst, true);
sep = ", ";
}
os << punc(" = ");
}
void printSrc(std::ostream& ostream, const IRInstruction* inst, uint32_t i) {
SSATmp* src = inst->getSrc(i);
if (src != nullptr) {
if (inst->getId() != 0 && !src->isConst() &&
src->getLastUseId() == inst->getId()) {
ostream << "~";
}
print(ostream, src);
} else {
ostream << color(ANSI_COLOR_RED)
<< "!!!NULL @ " << i
<< color(ANSI_COLOR_END)
;
}
}
void printSrcs(std::ostream& os, const IRInstruction* inst) {
bool first = true;
if (inst->op() == IncStat) {
os << " " << Stats::g_counterNames[inst->getSrc(0)->getValInt()]
<< ", " << inst->getSrc(1)->getValInt();
return;
}
for (uint32_t i = 0, n = inst->getNumSrcs(); i < n; i++) {
if (!first) {
os << punc(", ");
} else {
os << " ";
first = false;
}
printSrc(os, inst, i);
}
}
void printLabel(std::ostream& os, const Block* block) {
os << color(ANSI_COLOR_MAGENTA);
os << "L" << block->getId();
if (block->getHint() == Block::Unlikely) os << "<Unlikely>";
os << color(ANSI_COLOR_END);
}
void print(std::ostream& ostream, const IRInstruction* inst) {
if (inst->op() == Marker) {
auto* marker = inst->getExtra<Marker>();
ostream << color(ANSI_COLOR_BLUE)
<< folly::format("--- bc {}, spOff {} ({})",
marker->bcOff,
marker->stackOff,
marker->func->fullName()->data())
<< color(ANSI_COLOR_END);
return;
}
if (!inst->isTransient()) {
ostream << color(ANSI_COLOR_YELLOW);
if (!inst->getId()) {
ostream << folly::format("({:02d}) ", inst->getIId());
} else {
ostream << folly::format("({:02d}@{:02d}) ", inst->getIId(),
inst->getId());
}
ostream << color(ANSI_COLOR_END);
}
printDst(ostream, inst);
printOpcode(ostream, inst);
printSrcs(ostream, inst);
if (Block* taken = inst->getTaken()) {
ostream << punc(" -> ");
printLabel(ostream, taken);
}
if (TCA tca = inst->getTCA()) {
ostream << punc(", ");
if (tca == kIRDirectJccJmpActive) {
ostream << "JccJmp_Exit ";
}
else if (tca == kIRDirectJccActive) {
ostream << "Jcc_Exit ";
}
else if (tca == kIRDirectGuardActive) {
ostream << "Guard_Exit ";
}
else {
ostream << (void*)tca;
}
}
}
void print(const IRInstruction* inst) {
print(std::cerr, inst);
std::cerr << std::endl;
}
static void printConst(std::ostream& os, IRInstruction* inst) {
os << color(ANSI_COLOR_LIGHT_BLUE);
SCOPE_EXIT { os << color(ANSI_COLOR_END); };
auto t = inst->getTypeParam();
auto c = inst->getExtra<DefConst>();
if (t == Type::Int) {
os << c->as<int64_t>();
} else if (t == Type::Dbl) {
os << c->as<double>();
} else if (t == Type::Bool) {
os << (c->as<bool>() ? "true" : "false");
} else if (t.isString()) {
auto str = c->as<const StringData*>();
os << "\""
<< Util::escapeStringForCPP(str->data(), str->size())
<< "\"";
} else if (t.isArray()) {
auto arr = inst->getExtra<DefConst>()->as<const ArrayData*>();
if (arr->empty()) {
os << "array()";
} else {
os << "Array(" << arr << ")";
}
} else if (t.isNull()) {
os << t.toString();
} else if (t.subtypeOf(Type::Func)) {
auto func = c->as<const Func*>();
os << "Func(" << (func ? func->fullName()->data() : "0") << ")";
} else if (t.subtypeOf(Type::Cls)) {
auto cls = c->as<const Class*>();
os << "Cls(" << (cls ? cls->name()->data() : "0") << ")";
} else if (t.subtypeOf(Type::NamedEntity)) {
auto ne = c->as<const NamedEntity*>();
os << "NamedEntity(" << ne << ")";
} else if (t.subtypeOf(Type::TCA)) {
TCA tca = c->as<TCA>();
auto name = Util::getNativeFunctionName(tca);
SCOPE_EXIT { free(name); };
os << folly::format("TCA: {}({})", tca,
boost::trim_copy(std::string(name)));
} else if (t.subtypeOf(Type::None)) {
os << "None:" << c->as<int64_t>();
} else if (t.isPtr()) {
os << folly::format("{}({:#x})", t.toString(), c->as<uint64_t>());
} else if (t.subtypeOf(Type::CacheHandle)) {
os << folly::format("CacheHandle({:#x})", c->as<int64_t>());
} else {
not_reached();
}
}
void print(std::ostream& os, const SSATmp* tmp, bool printLastUse) {
if (tmp->inst()->op() == DefConst) {
printConst(os, tmp->inst());
return;
}
os << color(ANSI_COLOR_WHITE);
os << "t" << tmp->getId();
os << color(ANSI_COLOR_END);
if (printLastUse && tmp->getLastUseId() != 0) {
os << color(ANSI_COLOR_GRAY)
<< "@" << tmp->getLastUseId() << "#" << tmp->getUseCount()
<< color(ANSI_COLOR_END);
}
if (tmp->isSpilled() || tmp->numAllocatedRegs() > 0) {
os << color(ANSI_COLOR_BROWN) << '(';
if (!tmp->isSpilled()) {
for (int i = 0, sz = tmp->numAllocatedRegs(); i < sz; ++i) {
if (i != 0) os << ",";
os << reg::regname(Reg64(tmp->getReg(i)));
}
} else {
for (int i = 0, sz = tmp->numNeededRegs(); i < sz; ++i) {
if (i != 0) os << ",";
os << tmp->getSpillInfo(i);
}
}
os << ')' << color(ANSI_COLOR_END);
}
os << punc(":")
<< color(ANSI_COLOR_GREEN)
<< tmp->type().toString()
<< color(ANSI_COLOR_END)
;
}
void print(const SSATmp* tmp) {
print(std::cerr, tmp);
std::cerr << std::endl;
}
void print(const Trace* trace) {
print(std::cout, trace, nullptr);
}
void print(std::ostream& os, const Trace* trace, const AsmInfo* asmInfo) {
static const int kIndent = 4;
Disasm disasm(Disasm::Options().indent(kIndent + 4)
.printEncoding(dumpIREnabled(6))
.color(color(ANSI_COLOR_BROWN)));
// Print unlikely blocks at the end
BlockList blocks, unlikely;
for (Block* block : trace->getBlocks()) {
if (block->getHint() == Block::Unlikely) {
unlikely.push_back(block);
} else {
blocks.push_back(block);
}
}
blocks.splice(blocks.end(), unlikely);
for (Block* block : blocks) {
TcaRange blockRange = asmInfo ? asmInfo->asmRanges[block] :
TcaRange(nullptr, nullptr);
for (auto it = block->begin(); it != block->end();) {
auto& inst = *it; ++it;
if (inst.op() == Marker) {
os << std::string(kIndent, ' ');
JIT::print(os, &inst);
os << '\n';
// Don't print bytecode in a non-main trace.
if (!trace->isMain()) continue;
auto* marker = inst.getExtra<Marker>();
uint32_t bcOffset = marker->bcOff;
if (const auto* func = marker->func) {
std::ostringstream uStr;
func->unit()->prettyPrint(
uStr, Unit::PrintOpts()
.range(bcOffset, bcOffset+1)
.noLineNumbers()
.indent(0));
std::vector<std::string> vec;
folly::split('\n', uStr.str(), vec);
for (auto& s : vec) {
os << color(ANSI_COLOR_BLUE) << s << color(ANSI_COLOR_END) << '\n';
}
continue;
}
}
if (inst.op() == DefLabel) {
os << std::string(kIndent - 2, ' ');
printLabel(os, inst.getBlock());
os << punc(":") << "\n";
// print phi pseudo-instructions
for (unsigned i = 0, n = inst.getNumDsts(); i < n; ++i) {
os << std::string(kIndent +
folly::format("({}) ", inst.getIId()).str().size(),
' ');
JIT::print(os, inst.getDst(i), false);
os << punc(" = ") << color(ANSI_COLOR_CYAN) << "phi "
<< color(ANSI_COLOR_END);
bool first = true;
inst.getBlock()->forEachSrc(i, [&](IRInstruction* jmp, SSATmp*) {
if (!first) os << punc(", ");
first = false;
printSrc(os, jmp, i);
os << punc("@");
printLabel(os, jmp->getBlock());
});
os << '\n';
}
}
os << std::string(kIndent, ' ');
JIT::print(os, &inst);
os << '\n';
if (asmInfo) {
TcaRange instRange = asmInfo->instRanges[inst];
if (!instRange.empty()) {
disasm.disasm(os, instRange.begin(), instRange.end());
os << '\n';
assert(instRange.end() >= blockRange.start() &&
instRange.end() <= blockRange.end());
blockRange = TcaRange(instRange.end(), blockRange.end());
}
}
}
if (asmInfo) {
// print code associated with this block that isn't tied to any
// instruction. This includes code after the last isntruction (e.g.
// jmp to next block), and AStubs code.
if (!blockRange.empty()) {
os << std::string(kIndent, ' ') << punc("A:") << "\n";
disasm.disasm(os, blockRange.start(), blockRange.end());
}
auto astubRange = asmInfo->astubRanges[block];
if (!astubRange.empty()) {
os << std::string(kIndent, ' ') << punc("AStubs:") << "\n";
disasm.disasm(os, astubRange.start(), astubRange.end());
}
if (!blockRange.empty() || !astubRange.empty()) {
os << '\n';
}
}
}
for (auto* exitTrace : trace->getExitTraces()) {
os << "\n" << color(ANSI_COLOR_GREEN)
<< " ------- Exit Trace -------"
<< color(ANSI_COLOR_END) << '\n';
print(os, exitTrace, asmInfo);
}
}
void dumpTraceImpl(const Trace* trace, std::ostream& out,
const AsmInfo* asmInfo) {
print(out, trace, asmInfo);
}
// Suggested captions: "before jiffy removal", "after goat saturation",
// etc.
void dumpTrace(int level, const Trace* trace, const char* caption,
AsmInfo* ai) {
if (dumpIREnabled(level)) {
std::ostringstream str;
auto bannerFmt = "{:-^40}\n";
str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
<< folly::format(bannerFmt, caption)
<< color(ANSI_COLOR_END)
;
dumpTraceImpl(trace, str, ai);
str << color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN)
<< folly::format(bannerFmt, "")
<< color(ANSI_COLOR_END)
;
HPHP::Trace::traceRelease("%s", str.str().c_str());
}
}
}}}
+63
Ver Arquivo
@@ -0,0 +1,63 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_VM_PRINT_H_
#define incl_HPHP_VM_PRINT_H_
#include <iosfwd>
#include "util/trace.h"
namespace HPHP {
namespace VM {
namespace JIT {
struct IRInstruction;
class SSATmp;
struct Block;
struct AsmInfo;
class Trace;
// IRInstruction
void print(std::ostream& ostream, const IRInstruction*);
void print(const IRInstruction*);
void printSrc(std::ostream& ostream, const IRInstruction*, uint32_t srcIndex);
// SSATmp
void print(std::ostream& ostream, const SSATmp*,
bool printLastUse = false);
void print(const SSATmp*);
// Trace
void print(std::ostream& ostream, const Trace*,
const AsmInfo* asmInfo = nullptr);
void print(const Trace*);
/*
* Some utilities related to dumping. Rather than file-by-file control, we
* control most IR logging via the hhir trace module.
*/
static inline bool dumpIREnabled(int level = 1) {
return HPHP::Trace::moduleEnabledRelease(HPHP::Trace::hhir, level);
}
void dumpTraceImpl(const Trace* trace, std::ostream& out,
const AsmInfo* asmInfo = nullptr);
void dumpTrace(int level, const Trace* trace, const char* caption,
AsmInfo* ai = nullptr);
}}}
#endif