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 auto const dstRec
= profData
->transRec(dstID
);
33 auto const dstSK
= dstRec
->srcKey();
34 const SrcRec
* dstSR
= srcDB
.find(dstSK
);
38 for (auto& inBr
: dstSR
->incomingBranches()) {
39 auto const srcID
= profData
->jmpTransID(inBr
.toSmash());
40 if (srcID
== kInvalidTransID
) continue;
42 auto const srcRec
= profData
->transRec(srcID
);
43 if (!srcRec
|| !srcRec
->isProfile()) continue;
45 FTRACE(5, "findPredTrans: toSmash = {} srcID = {}\n",
46 inBr
.toSmash(), srcID
);
47 auto srcSuccOffsets
= srcRec
->lastSrcKey().succOffsets();
48 if (srcSuccOffsets
.count(dstSK
.offset())) {
49 predSet
.insert(srcID
);
51 FTRACE(5, "findPredTrans: WARNING: incoming branch with impossible "
52 "control flow between translations: {} -> {}"
53 "(probably due to side exit)\n", srcID
, dstID
);
61 * This function tries to infer the weight of any arc in the arcVec given the
62 * weights of other arcs in the list and totalWeight, which is the
63 * known sum of all their weights.
64 * Returns whether or not the weight of any arc was inferred and, in case of
65 * success, the weight of such arc is updated.
67 static bool inferredArcWeight(const TransCFG::ArcPtrVec
& arcVec
,
68 int64_t totalWeight
) {
69 int64_t arcWeight
= totalWeight
;
70 TransCFG::Arc
* unknownArc
= nullptr;
71 for (auto arc
: arcVec
) {
72 if (arc
->weight() == TransCFG::Arc::kUnknownWeight
) {
73 if (unknownArc
!= nullptr) {
74 // More than one arc with unknown weight, so can't infer
79 arcWeight
-= arc
->weight();
82 if (unknownArc
== nullptr) return false;
83 // Avoid creating negative-weight arcs. Node weights are not required to be
84 // accurate and, since arc weights are derived from nodes' weights, they
85 // aren't accurate either. This can result in arcWeight to be negative here.
86 if (arcWeight
< 0) arcWeight
= 0;
87 unknownArc
->setWeight(arcWeight
);
91 TransCFG::TransCFG(FuncId funcId
,
92 const ProfData
* profData
,
94 bool inlining
/* = false */) {
98 for (auto const tid
: profData
->funcProfTransIDs(funcId
)) {
99 auto const rec
= profData
->transRec(tid
);
100 assertx(rec
->region() != nullptr);
101 // This will skip DV Funclets if they were already
102 // retranslated w/ the prologues:
103 if (inlining
|| !profData
->optimized(rec
->srcKey())) {
104 int64_t weight
= profData
->transCounter(tid
);
105 addNode(tid
, weight
);
110 for (auto const dstId
: nodes()) {
111 auto const rec
= profData
->transRec(dstId
);
112 auto const dstSK
= rec
->srcKey();
113 auto const dstBlock
= rec
->region()->entry();
114 FTRACE(5, "TransCFG: adding incoming arcs in dstId = {}\n", dstId
);
115 TransIDSet predIDs
= findPredTrans(dstId
, profData
, srcDB
);
116 for (auto predId
: predIDs
) {
117 if (hasNode(predId
)) {
118 auto const predRec
= profData
->transRec(predId
);
119 auto const predBlock
= predRec
->region()->blocks().back();
120 auto const& postConds
= predBlock
->postConds();
121 auto predPostConds
= postConds
.changed
;
122 predPostConds
.insert(predPostConds
.end(), postConds
.refined
.begin(),
123 postConds
.refined
.end());
124 auto const predSK
= predRec
->srcKey();
125 if (preCondsAreSatisfied(dstBlock
, predPostConds
) &&
126 predSK
.resumed() == dstSK
.resumed()) {
127 FTRACE(5, "TransCFG: adding arc {} -> {} ({} -> {})\n",
128 predId
, dstId
, showShort(predSK
), showShort(dstSK
));
129 addArc(predId
, dstId
, TransCFG::Arc::kUnknownWeight
);
139 for (auto const tid
: nodes()) {
140 auto const nodeWeight
= weight(tid
);
141 if (inferredArcWeight(inArcs(tid
), nodeWeight
)) changed
= true;
142 if (inferredArcWeight(outArcs(tid
), nodeWeight
)) changed
= true;
146 // guess weight for non-inferred arcs
147 for (auto const tid
: nodes()) {
148 for (auto arc
: outArcs(tid
)) {
149 if (arc
->weight() == Arc::kUnknownWeight
) {
151 auto arcWgt
= std::min(weight(arc
->src()), weight(arc
->dst())) / 2;
152 arc
->setWeight(arcWgt
);
158 int64_t TransCFG::weight(TransID id
) const {
159 assertx(hasNode(id
));
160 auto const idx
= folly::get_default(m_idToIdx
, id
);
161 return m_nodeInfo
[idx
].weight();
164 const TransCFG::ArcPtrVec
& TransCFG::inArcs(TransID id
) const {
165 assertx(hasNode(id
));
166 auto const idx
= folly::get_default(m_idToIdx
, id
);
167 return m_nodeInfo
[idx
].inArcs();
170 const TransCFG::ArcPtrVec
& TransCFG::outArcs(TransID id
) const {
171 assertx(hasNode(id
));
172 auto const idx
= folly::get_default(m_idToIdx
, id
);
173 return m_nodeInfo
[idx
].outArcs();
176 TransCFG::Node::~Node() {
177 for (auto arc
: m_outArcs
) {
182 void TransCFG::addNode(TransID id
, int64_t weight
) {
183 auto const idx
= m_transIds
.size();
184 m_transIds
.push_back(id
);
186 m_nodeInfo
.push_back(Node(id
, weight
));
189 bool TransCFG::hasNode(TransID id
) const {
190 return m_idToIdx
.find(id
) != m_idToIdx
.end();
193 TransCFG::ArcPtrVec
TransCFG::arcs() const {
195 for (auto node
: nodes()) {
196 const ArcPtrVec
& nodeOutArcs
= outArcs(node
);
197 arcs
.insert(arcs
.end(), nodeOutArcs
.begin(), nodeOutArcs
.end());
202 void TransCFG::addArc(TransID srcId
, TransID dstId
, int64_t weight
) {
203 assertx(hasNode(srcId
));
204 assertx(hasNode(dstId
));
205 auto const srcIdx
= m_idToIdx
[srcId
];
206 auto const dstIdx
= m_idToIdx
[dstId
];
207 Arc
* arc
= new Arc(srcId
, dstId
, weight
);
208 m_nodeInfo
[srcIdx
].addOutArc(arc
);
209 m_nodeInfo
[dstIdx
].addInArc(arc
);
212 bool TransCFG::hasArc(TransID srcId
, TransID dstId
) const {
213 assertx(hasNode(srcId
));
214 assertx(hasNode(dstId
));
215 for (auto arc
: outArcs(srcId
)) {
216 if (arc
->dst() == dstId
) return true;
221 void TransCFG::print(std::ostream
& out
, FuncId funcId
,
222 const ProfData
* profData
) const {
223 out
<< "digraph TransCFG { // function: "
224 << Func::fromFuncId(funcId
)->fullName()->data() << "\n";
226 // find max node weight
227 int64_t maxWeight
= 1; // 1 to avoid div by 0
228 for (auto tid
: nodes()) {
229 auto w
= weight(tid
);
230 if (w
> maxWeight
) maxWeight
= w
;
234 for (auto const tid
: nodes()) {
235 auto const w
= weight(tid
);
236 uint32_t coldness
= 255 - (255 * w
/ maxWeight
);
237 auto const rec
= profData
->transRec(tid
);
238 auto const bcStart
= rec
->startBcOff();
239 auto const bcStop
= rec
->lastBcOff();
240 auto const shape
= "box";
241 out
<< folly::sformat(
242 "t{} [shape={},label=\"T: {}\\np: {}\\n"
243 "bc: [{}-{})\",style=filled,fillcolor=\"#ff{:02x}{:02x}\"];\n",
244 tid
, shape
, tid
, w
, bcStart
, bcStop
, coldness
, coldness
);
248 for (auto srcId
: nodes()) {
249 for (auto arc
: outArcs(srcId
)) {
250 auto const w
= arc
->weight();
251 out
<< folly::sformat("t{} -> t{} [color=\"{}\",label=\"{}\"] ;\n",
254 arc
->guessed() ? "red" : "green4",