2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/trans-cfg.h"
20 #include <folly/MapUtil.h>
22 #include "hphp/runtime/vm/jit/prof-data.h"
23 #include "hphp/runtime/vm/jit/region-selection.h"
25 namespace HPHP
{ namespace jit
{
29 static TransIDSet
findPredTrans(TransID dstID
,
30 const ProfData
* profData
,
32 const TCATransIDMap
& jmpToTransID
) {
33 auto const dstRec
= profData
->transRec(dstID
);
34 auto const dstSK
= dstRec
->srcKey();
35 const SrcRec
* dstSR
= srcDB
.find(dstSK
);
39 for (auto& inBr
: dstSR
->incomingBranches()) {
40 auto src
= jmpToTransID
.find(inBr
.toSmash());
41 if (src
== jmpToTransID
.end()) continue;
43 auto const srcID
= src
->second
;
44 auto const srcRec
= profData
->transRec(srcID
);
45 if (!srcRec
|| !srcRec
->isProfile()) continue;
47 FTRACE(5, "findPredTrans: toSmash = {} srcID = {}\n",
48 inBr
.toSmash(), srcID
);
49 auto srcSuccOffsets
= srcRec
->lastSrcKey().succOffsets();
50 if (srcSuccOffsets
.count(dstSK
.offset())) {
51 predSet
.insert(srcID
);
53 FTRACE(5, "findPredTrans: WARNING: incoming branch with impossible "
54 "control flow between translations: {} -> {}"
55 "(probably due to side exit)\n", srcID
, dstID
);
63 * This function tries to infer the weight of any arc in the arcVec given the
64 * weights of other arcs in the list and totalWeight, which is the
65 * known sum of all their weights.
66 * Returns whether or not the weight of any arc was inferred and, in case of
67 * success, the weight of such arc is updated.
69 static bool inferredArcWeight(const TransCFG::ArcPtrVec
& arcVec
,
70 int64_t totalWeight
) {
71 int64_t arcWeight
= totalWeight
;
72 TransCFG::Arc
* unknownArc
= nullptr;
73 for (auto arc
: arcVec
) {
74 if (arc
->weight() == TransCFG::Arc::kUnknownWeight
) {
75 if (unknownArc
!= nullptr) {
76 // More than one arc with unknown weight, so can't infer
81 arcWeight
-= arc
->weight();
84 if (unknownArc
== nullptr) return false;
85 // Avoid creating negative-weight arcs. Node weights are not required to be
86 // accurate and, since arc weights are derived from nodes' weights, they
87 // aren't accurate either. This can result in arcWeight to be negative here.
88 if (arcWeight
< 0) arcWeight
= 0;
89 unknownArc
->setWeight(arcWeight
);
93 TransCFG::TransCFG(FuncId funcId
,
94 const ProfData
* profData
,
96 const TCATransIDMap
& jmpToTransID
,
97 bool inlining
/* = false */) {
101 for (auto const tid
: profData
->funcProfTransIDs(funcId
)) {
102 auto const rec
= profData
->transRec(tid
);
103 assertx(rec
->region() != nullptr);
104 // This will skip DV Funclets if they were already
105 // retranslated w/ the prologues:
106 if (inlining
|| !profData
->optimized(rec
->srcKey())) {
107 int64_t weight
= profData
->transCounter(tid
);
108 addNode(tid
, weight
);
113 for (auto const dstId
: nodes()) {
114 auto const rec
= profData
->transRec(dstId
);
115 auto const dstSK
= rec
->srcKey();
116 auto const dstBlock
= rec
->region()->entry();
117 FTRACE(5, "TransCFG: adding incoming arcs in dstId = {}\n", dstId
);
118 TransIDSet predIDs
= findPredTrans(dstId
, profData
, srcDB
, jmpToTransID
);
119 for (auto predId
: predIDs
) {
120 if (hasNode(predId
)) {
121 auto const predRec
= profData
->transRec(predId
);
122 auto const predBlock
= predRec
->region()->blocks().back();
123 auto const& postConds
= predBlock
->postConds();
124 auto predPostConds
= postConds
.changed
;
125 predPostConds
.insert(predPostConds
.end(), postConds
.refined
.begin(),
126 postConds
.refined
.end());
127 auto const predSK
= predRec
->srcKey();
128 if (preCondsAreSatisfied(dstBlock
, predPostConds
) &&
129 predSK
.resumed() == dstSK
.resumed()) {
130 FTRACE(5, "TransCFG: adding arc {} -> {} ({} -> {})\n",
131 predId
, dstId
, showShort(predSK
), showShort(dstSK
));
132 addArc(predId
, dstId
, TransCFG::Arc::kUnknownWeight
);
142 for (auto const tid
: nodes()) {
143 auto const nodeWeight
= weight(tid
);
144 if (inferredArcWeight(inArcs(tid
), nodeWeight
)) changed
= true;
145 if (inferredArcWeight(outArcs(tid
), nodeWeight
)) changed
= true;
149 // guess weight for non-inferred arcs
150 for (auto const tid
: nodes()) {
151 for (auto arc
: outArcs(tid
)) {
152 if (arc
->weight() == Arc::kUnknownWeight
) {
154 auto arcWgt
= std::min(weight(arc
->src()), weight(arc
->dst())) / 2;
155 arc
->setWeight(arcWgt
);
161 int64_t TransCFG::weight(TransID id
) const {
162 assertx(hasNode(id
));
163 auto const idx
= folly::get_default(m_idToIdx
, id
);
164 return m_nodeInfo
[idx
].weight();
167 const TransCFG::ArcPtrVec
& TransCFG::inArcs(TransID id
) const {
168 assertx(hasNode(id
));
169 auto const idx
= folly::get_default(m_idToIdx
, id
);
170 return m_nodeInfo
[idx
].inArcs();
173 const TransCFG::ArcPtrVec
& TransCFG::outArcs(TransID id
) const {
174 assertx(hasNode(id
));
175 auto const idx
= folly::get_default(m_idToIdx
, id
);
176 return m_nodeInfo
[idx
].outArcs();
179 TransCFG::Node::~Node() {
180 for (auto arc
: m_outArcs
) {
185 void TransCFG::addNode(TransID id
, int64_t weight
) {
186 auto const idx
= m_transIds
.size();
187 m_transIds
.push_back(id
);
189 m_nodeInfo
.push_back(Node(id
, weight
));
192 bool TransCFG::hasNode(TransID id
) const {
193 return m_idToIdx
.find(id
) != m_idToIdx
.end();
196 TransCFG::ArcPtrVec
TransCFG::arcs() const {
198 for (auto node
: nodes()) {
199 const ArcPtrVec
& nodeOutArcs
= outArcs(node
);
200 arcs
.insert(arcs
.end(), nodeOutArcs
.begin(), nodeOutArcs
.end());
205 void TransCFG::addArc(TransID srcId
, TransID dstId
, int64_t weight
) {
206 assertx(hasNode(srcId
));
207 assertx(hasNode(dstId
));
208 auto const srcIdx
= m_idToIdx
[srcId
];
209 auto const dstIdx
= m_idToIdx
[dstId
];
210 Arc
* arc
= new Arc(srcId
, dstId
, weight
);
211 m_nodeInfo
[srcIdx
].addOutArc(arc
);
212 m_nodeInfo
[dstIdx
].addInArc(arc
);
215 bool TransCFG::hasArc(TransID srcId
, TransID dstId
) const {
216 assertx(hasNode(srcId
));
217 assertx(hasNode(dstId
));
218 for (auto arc
: outArcs(srcId
)) {
219 if (arc
->dst() == dstId
) return true;
224 void TransCFG::print(std::string fileName
, FuncId funcId
,
225 const ProfData
* profData
,
226 const TransIDSet
* selected
) const {
227 FILE* file
= fopen(fileName
.c_str(), "wt");
230 fprintf(file
, "digraph CFG {\n");
232 fprintf(file
, "# function: %s\n",
233 Func::fromFuncId(funcId
)->fullName()->data());
235 // find max node weight
236 int64_t maxWeight
= 1; // 1 to avoid div by 0
237 for (auto tid
: nodes()) {
238 auto w
= weight(tid
);
239 if (w
> maxWeight
) maxWeight
= w
;
243 for (auto const tid
: nodes()) {
244 auto const w
= weight(tid
);
245 uint32_t coldness
= 255 - (255 * w
/ maxWeight
);
246 auto const rec
= profData
->transRec(tid
);
247 auto const bcStart
= rec
->startBcOff();
248 auto const bcStop
= rec
->lastBcOff();
249 auto const shape
= selected
&& selected
->count(tid
) ? "oval" : "box";
251 "t%u [shape=%s,label=\"T: %u\\np: %" PRId64
"\\n"
252 "bc: [%" PRIu32
"-%" PRIu32
")\","
253 "style=filled,fillcolor=\"#ff%02x%02x\"];\n", tid
, shape
, tid
, w
,
254 bcStart
, bcStop
, coldness
, coldness
);
258 for (auto srcId
: nodes()) {
259 for (auto arc
: outArcs(srcId
)) {
260 auto const w
= arc
->weight();
261 fprintf(file
, "t%u -> t%u [color=\"%s\",label=\"%" PRId64
"\"] ;\n",
264 arc
->guessed() ? "red" : "green4",
269 fprintf(file
, "}\n");