2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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/vasm.h"
19 #include "hphp/runtime/vm/jit/timer.h"
20 #include "hphp/runtime/vm/jit/vasm-instr.h"
21 #include "hphp/runtime/vm/jit/vasm-print.h"
22 #include "hphp/runtime/vm/jit/vasm-reg.h"
23 #include "hphp/runtime/vm/jit/vasm-unit.h"
24 #include "hphp/runtime/vm/jit/vasm-util.h"
25 #include "hphp/runtime/vm/jit/vasm-visit.h"
27 #include <boost/dynamic_bitset.hpp>
33 namespace HPHP
{ namespace jit
{
36 typedef boost::dynamic_bitset
<> LiveSet
;
37 bool effectful(Vinstr
& inst
) {
76 case Vinstr::copyargs
:
81 case Vinstr::cvtsi2sd
:
82 case Vinstr::cvtsi2sdm
:
83 case Vinstr::cvttsd2siq
:
86 case Vinstr::defvmretdata
:
87 case Vinstr::defvmrettype
:
112 case Vinstr::loadtqb
:
113 case Vinstr::loadtql
:
114 case Vinstr::loadups
:
116 case Vinstr::loadzbl
:
117 case Vinstr::loadzbq
:
118 case Vinstr::loadzlq
:
119 case Vinstr::loadsbq
:
148 case Vinstr::roundsd
:
168 case Vinstr::testbim
:
173 case Vinstr::testlim
:
176 case Vinstr::testqim
:
178 case Vinstr::testwim
:
179 case Vinstr::ucomisd
:
180 case Vinstr::unpcklpd
:
196 case Vinstr::bindaddr
:
197 case Vinstr::bindjcc
:
198 case Vinstr::bindjmp
:
199 case Vinstr::funcguard
:
200 case Vinstr::debugguardjmp
:
201 case Vinstr::inlinestart
:
202 case Vinstr::inlineend
:
203 case Vinstr::popframe
:
204 case Vinstr::pushframe
:
206 case Vinstr::callunpack
:
207 case Vinstr::callfaststub
:
209 case Vinstr::callphp
:
212 case Vinstr::callstub
:
214 case Vinstr::contenter
:
216 case Vinstr::debugtrap
:
219 case Vinstr::decqmlock
:
220 case Vinstr::fallback
:
221 case Vinstr::fallbackcc
:
222 case Vinstr::fallthru
:
234 case Vinstr::landingpad
:
235 case Vinstr::leavetc
:
236 case Vinstr::loadstubret
:
240 case Vinstr::nothrow
:
248 case Vinstr::phplogue
:
260 case Vinstr::resumetc
:
262 case Vinstr::retransopt
:
265 case Vinstr::storebi
:
266 case Vinstr::storeups
:
268 case Vinstr::storeli
:
269 case Vinstr::storeqi
:
270 case Vinstr::storesd
:
272 case Vinstr::storewi
:
273 case Vinstr::stublogue
:
274 case Vinstr::stubret
:
275 case Vinstr::stubtophp
:
276 case Vinstr::stubunwind
:
277 case Vinstr::syncpoint
:
278 case Vinstr::syncvmret
:
279 case Vinstr::syncvmrettype
:
280 case Vinstr::syncvmsp
:
281 case Vinstr::tailcallphp
:
282 case Vinstr::tailcallstub
:
286 case Vinstr::vcallunpack
:
287 case Vinstr::vinvoke
:
288 case Vinstr::vregrestrict
:
289 case Vinstr::vregunrestrict
:
290 case Vinstr::conjure
:
291 case Vinstr::conjureuse
:
294 always_assert(false);
298 // Remove dead instructions by doing a traditional liveness analysis.
299 // instructions that mutate memory, physical registers, or status flags
300 // are considered useful. All branches are considered useful.
302 // Given SSA, there's a faster sparse version of this algorithm that marks
303 // useful instructions in one pass, then transitively marks pure instructions
304 // that define inputs to useful instructions. However it requires a mapping
305 // from vreg numbers to the instruction that defines them, and a way to address
306 // individual instructions.
308 // We could remove useless branches by computing the post-dominator tree and
309 // RDF(b) for each block; then a branch is only useful if it controls whether
310 // or not a useful block executes, and useless branches can be forwarded to
311 // the nearest useful post-dominator.
312 void removeDeadCode(Vunit
& unit
) {
313 Timer
timer(Timer::vasm_dce
);
314 auto blocks
= sortBlocks(unit
);
315 jit::vector
<LiveSet
> livein(unit
.blocks
.size());
316 LiveSet
live(unit
.next_vr
);
318 auto pass
= [&](bool mutate
) {
319 bool changed
= false;
320 for (auto blockIt
= blocks
.end(); blockIt
!= blocks
.begin();) {
322 auto& block
= unit
.blocks
[b
];
324 for (auto s
: succs(block
)) {
325 if (!livein
[s
].empty()) {
329 for (auto i
= block
.code
.end(); i
!= block
.code
.begin();) {
331 auto useful
= effectful(inst
);
332 visitDefs(unit
, inst
, [&](Vreg r
) {
333 if (r
.isPhys() || live
.test(r
)) {
339 visitUses(unit
, inst
, [&](Vreg r
) {
348 assertx(live
== livein
[b
]);
350 if (live
!= livein
[b
]) {
359 // analyze until livein reaches a fixed point
360 while (pass(false)) {}
361 auto const changed
= pass(true);
362 removeTrivialNops(unit
);
364 printUnit(kVasmDCELevel
, "after vasm-dead", unit
);
369 * A very simple dead code elimination pass that just removes trivial nop
370 * instructions. We run this before any other passes because it allows
371 * code-gen to create things like self-copies or self-lea's without affect on
372 * optimizations downstream. (In particular early passes like optimizeExits
373 * that are looking for specific vasm sequences inside of a block.)
375 void removeTrivialNops(Vunit
& unit
) {
376 for (auto& b
: unit
.blocks
) {
379 begin(b
.code
), end(b
.code
),