codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / vm / jit / region-hot-trace.cpp
blob06b90e4e3c59158699c8e15e4c0298b7a1c41f0e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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/region-selection.h"
19 #include "hphp/runtime/vm/jit/location.h"
20 #include "hphp/runtime/vm/jit/prof-data.h"
21 #include "hphp/runtime/vm/jit/trans-cfg.h"
22 #include "hphp/runtime/vm/jit/translator-inline.h"
24 #include <limits>
26 namespace HPHP { namespace jit {
28 TRACE_SET_MOD(pgo);
30 /**
31 * Remove from pConds the elements that correspond to stack positions
32 * that have been popped given the current SP offset from FP.
34 static void discardPoppedTypes(TypedLocations& pConds,
35 FPInvOffset curSpOffset) {
36 for (auto it = pConds.begin(); it != pConds.end(); ) {
37 if (it->location.tag() == LTag::Stack &&
38 it->location.stackIdx() > curSpOffset) {
39 it = pConds.erase(it);
40 } else {
41 it++;
46 static void mergePostConds(TypedLocations& dst,
47 const PostConditions& src) {
48 for (const auto &post : src.changed) {
49 bool replace = false;
50 for (auto it = dst.begin(); it != dst.end(); ++it) {
51 if (post.location == it->location) {
52 *it = post;
53 replace = true;
56 if (!replace) {
57 dst.emplace_back(post);
62 RegionDescPtr selectHotTrace(HotTransContext& ctx) {
63 auto region = std::make_shared<RegionDesc>();
64 TransID tid = ctx.tid;
65 TransID prevId = kInvalidTransID;
66 TransIDSet selectedSet;
67 TypedLocations accumPostConds;
69 // Maps from BlockIds to accumulated post conditions for that block.
70 // Used to determine if we can add branch-over edges by checking the
71 // pre-conditions of the successor block.
72 hphp_hash_map<RegionDesc::BlockId, TypedLocations> blockPostConds;
74 auto numBCInstrs = ctx.maxBCInstrs;
75 FTRACE(1, "selectHotTrace: starting with maxBCInstrs = {}\n", numBCInstrs);
77 while (!selectedSet.count(tid)) {
78 auto rec = ctx.profData->transRec(tid);
79 auto blockRegion = rec->region();
80 if (blockRegion == nullptr) break;
82 // Break if region would be larger than the specified limit.
83 if (blockRegion->instrSize() > numBCInstrs) {
84 FTRACE(2, "selectHotTrace: breaking region at Translation {} because "
85 "size would exceed of maximum translation limit\n", tid);
86 break;
89 // If the debugger is attached, only allow single-block regions.
90 if (prevId != kInvalidTransID && isDebuggerAttachedProcess()) {
91 FTRACE(2, "selectHotTrace: breaking region at Translation {} "
92 "because of debugger is attached\n", tid);
93 break;
96 // Break if block is not the first and it corresponds to the main
97 // function body entry. This is to prevent creating multiple
98 // large regions containing the function body (starting at various
99 // DV funclets).
100 if (prevId != kInvalidTransID) {
101 auto const func = rec->func();
102 auto const bcOffset = rec->startBcOff();
103 if (func->base() == bcOffset) {
104 FTRACE(2, "selectHotTrace: breaking region because reached the main "
105 "function body entry at Translation {} (BC offset {})\n",
106 tid, bcOffset);
107 break;
111 if (prevId != kInvalidTransID) {
112 auto sk = rec->srcKey();
113 if (ctx.profData->optimized(sk)) {
114 FTRACE(2, "selectHotTrace: breaking region because next sk already "
115 "optimized, for Translation {}\n", tid);
116 break;
120 bool hasPredBlock = !region->empty();
121 RegionDesc::BlockId predBlockId = (hasPredBlock ?
122 region->blocks().back().get()->id() : 0);
123 auto const& newFirstBlock = blockRegion->entry();
124 auto newFirstBlockId = newFirstBlock->id();
126 // Add blockRegion's blocks and arcs to region.
127 region->append(*blockRegion);
128 numBCInstrs -= blockRegion->instrSize();
129 assertx(numBCInstrs >= 0);
131 if (hasPredBlock) {
132 region->addArc(predBlockId, newFirstBlockId);
134 selectedSet.insert(tid);
136 const auto lastSk = rec->lastSrcKey();
137 if (breaksRegion(lastSk)) {
138 FTRACE(2, "selectHotTrace: breaking region because of last instruction "
139 "in Translation {}: {}\n", tid, opcodeToName(lastSk.op()));
140 break;
143 auto outArcs = ctx.cfg->outArcs(tid);
144 if (outArcs.size() == 0) {
145 FTRACE(2, "selectHotTrace: breaking region because there's no successor "
146 "for Translation {}\n", tid);
147 break;
150 auto newLastBlock = blockRegion->blocks().back();
151 discardPoppedTypes(accumPostConds,
152 blockRegion->entry()->initialSpOffset());
153 mergePostConds(accumPostConds, newLastBlock->postConds());
154 blockPostConds[newLastBlock->id()] = accumPostConds;
156 TransCFG::ArcPtrVec possibleOutArcs;
157 for (auto arc : outArcs) {
158 auto dstRec = ctx.profData->transRec(arc->dst());
159 auto possibleNext = dstRec->region()->entry();
160 if (preCondsAreSatisfied(possibleNext, accumPostConds)) {
161 possibleOutArcs.emplace_back(arc);
165 if (possibleOutArcs.size() == 0) {
166 FTRACE(2, "selectHotTrace: breaking region because postcondition check "
167 "pruned all successors of Translation {}\n", tid);
168 break;
171 auto maxWeight = std::numeric_limits<int64_t>::min();
172 TransCFG::Arc* maxArc = nullptr;
173 for (auto arc : possibleOutArcs) {
174 if (arc->weight() >= maxWeight) {
175 maxWeight = arc->weight();
176 maxArc = arc;
179 assertx(maxArc != nullptr);
180 prevId = tid;
181 tid = maxArc->dst();
184 FTRACE(3, "selectHotTrace: before chainRetransBlocks:\n{}\n", show(*region));
185 region->chainRetransBlocks();
186 FTRACE(3, "selectHotTrace: after chainRetransBlocks:\n{}\n", show(*region));
188 return region;