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/vasm-instr.h"
20 #include "hphp/runtime/vm/jit/vasm-print.h"
21 #include "hphp/runtime/vm/jit/vasm-reg.h"
22 #include "hphp/runtime/vm/jit/vasm-unit.h"
23 #include "hphp/runtime/vm/jit/vasm-visit.h"
27 namespace HPHP
{ namespace jit
{
31 // if inst is testb{r,r,d}, return true,d
32 bool match_testb(Vinstr
& inst
, Vreg r
) {
33 return inst
.op
== Vinstr::testb
&&
34 inst
.testb_
.s0
== r
&&
38 bool match_jcc(Vinstr
& inst
, Vreg flags
) {
39 return inst
.op
== Vinstr::jcc
&& inst
.jcc_
.sf
== flags
&&
40 (inst
.jcc_
.cc
== CC_E
|| inst
.jcc_
.cc
== CC_NE
);
43 #define CMOV_MATCH(type) \
44 bool match_##type(Vinstr& inst, Vreg flags) { \
45 return inst.op == Vinstr::type && inst.type##_.sf == flags && \
46 (inst.type##_.cc == CC_E || inst.type##_.cc == CC_NE); \
54 bool sets_flags(const Vunit
& unit
, const Vinstr
& inst
) {
55 // Some special cases that also clobber flags:
63 case Vinstr::callstub
:
64 case Vinstr::callfaststub
:
66 case Vinstr::callarray
:
67 case Vinstr::contenter
:
74 visitDefs(unit
, inst
, [&] (Vreg r
, Width w
) {
75 if (w
== Width::Flags
) flags
= r
;
77 return flags
.isValid();
83 * Analyze blocks one at a time, looking for the sequence:
89 * jcc E|NE, f2 (OR cmov E|NE, f, t, d)
91 * If found, and f2 is only used by the jcc, then change the code to:
97 * jcc !cc|cc, f1 (OR cmov !cc|cc, f, t, d)
99 * Later, vasm-dead will clean up the nop, and the setcc if b became dead.
101 * During the search, any other instruction that has a status flag result
102 * will reset the pattern matcher. No instruction can "kill" flags,
103 * since flags are SSA variables. However the transformation we want to
104 * make extends the setcc flags lifetime, and we don't want it to overlap
105 * another flag's lifetime.
107 void fuseBranches(Vunit
& unit
) {
108 auto blocks
= sortBlocks(unit
);
109 jit::vector
<unsigned> uses(unit
.next_vr
);
110 for (auto b
: blocks
) {
111 for (auto& inst
: unit
.blocks
[b
].code
) {
112 visitUses(unit
, inst
, [&] (Vreg r
) { uses
[r
]++; });
115 bool should_print
= false;
116 for (auto b
: blocks
) {
117 auto& code
= unit
.blocks
[b
].code
;
119 Vreg setcc_flags
, setcc_dest
, testb_flags
;
120 unsigned testb_index
;
121 for (unsigned i
= 0, n
= code
.size(); i
< n
; ++i
) {
122 if (code
[i
].op
== Vinstr::setcc
) {
123 cc
= code
[i
].setcc_
.cc
;
124 setcc_flags
= code
[i
].setcc_
.sf
;
125 setcc_dest
= code
[i
].setcc_
.d
;
128 if (setcc_flags
.isValid() &&
129 match_testb(code
[i
], setcc_dest
) &&
130 uses
[code
[i
].testb_
.sf
] == 1) {
131 testb_flags
= code
[i
].testb_
.sf
;
135 if (match_jcc(code
[i
], testb_flags
)) {
136 code
[testb_index
] = nop
{}; // erase the testb
137 auto& jcc
= code
[i
].jcc_
;
138 jcc
.cc
= jcc
.cc
== CC_NE
? cc
: ccNegate(cc
);
139 jcc
.sf
= setcc_flags
;
144 // Check for different cmov flavors
145 #define CMOV_IMPL(type) \
146 if (match_##type(code[i], testb_flags)) { \
147 code[testb_index] = nop{}; \
148 auto& cmov = code[i].type##_; \
149 cmov.cc = cmov.cc == CC_NE ? cc : ccNegate(cc); \
150 cmov.sf = setcc_flags; \
151 should_print = true; \
160 if (setcc_flags
.isValid() && sets_flags(unit
, code
[i
])) {
161 setcc_flags
= testb_flags
= Vreg
{};
166 printUnit(kVasmFusionLevel
, "after vasm-fusion", unit
);