2 +----------------------------------------------------------------------+
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/reg-alloc.h"
19 #include "hphp/runtime/vm/jit/abi.h"
20 #include "hphp/runtime/vm/jit/abi-arm.h"
21 #include "hphp/runtime/vm/jit/irlower.h"
22 #include "hphp/runtime/vm/jit/minstr-effects.h"
23 #include "hphp/runtime/vm/jit/native-calls.h"
24 #include "hphp/runtime/vm/jit/vasm-instr.h"
25 #include "hphp/runtime/vm/jit/vasm-print.h"
26 #include "hphp/runtime/vm/jit/vasm-unit.h"
27 #include "hphp/runtime/vm/jit/vasm-util.h"
29 #include "hphp/runtime/base/packed-array.h"
31 #include "hphp/util/arch.h"
33 #include <boost/dynamic_bitset.hpp>
35 namespace HPHP
{ namespace jit
{
40 //////////////////////////////////////////////////////////////////////
45 * Return true if this instruction can load a TypedValue using a 16-byte load
46 * into a SIMD register.
48 bool loadsCell(const IRInstruction
& inst
) {
49 auto const arch_allows
= [] {
51 case Arch::X64
: return true;
52 case Arch::ARM
: return true;
53 case Arch::PPC64
: return true;
60 return arch_allows
&& (!wide_tv_val
|| inst
.src(0)->isA(TPtrToCell
));
64 static_assert(PackedArray::stores_typed_values
, "");
84 case MemoGetStaticValue
:
85 case MemoGetStaticCache
:
88 case MemoGetInstanceValue
:
89 case MemoGetInstanceCache
:
98 * Returns true if the instruction can store source operand srcIdx to
99 * memory as a cell using a 16-byte store. (implying its okay to
100 * clobber TypedValue.m_aux)
102 bool storesCell(const IRInstruction
& inst
, uint32_t srcIdx
) {
104 case Arch::X64
: break;
105 case Arch::ARM
: break;
106 case Arch::PPC64
: return false;
109 // If this function returns true for an operand, then the register allocator
110 // may give it an XMM register, and the instruction will store the whole 16
111 // bytes into memory. Therefore it's important *not* to return true if the
112 // TypedValue.m_aux field in memory has important data. This is the case for
113 // MixedArray elements, and Map elements.
121 case InitPackedLayoutArray
:
124 return srcIdx
== 1 && (!wide_tv_val
|| inst
.src(0)->isA(TPtrToCell
));
132 //////////////////////////////////////////////////////////////////////
134 PhysReg
forceAlloc(const SSATmp
& tmp
) {
135 if (tmp
.type() <= TBottom
) return InvalidReg
;
137 auto inst
= tmp
.inst();
138 auto opc
= inst
->op();
140 // LdContActRec and LdAFWHActRec, loading a generator's AR, is the only time
141 // we have a pointer to an AR that is not in rvmfp().
142 if (opc
!= LdContActRec
&& opc
!= LdAFWHActRec
&& tmp
.isA(TFramePtr
)) {
149 // Assign virtual registers to all SSATmps used or defined in reachable
150 // blocks. This assigns a value register to constants defined by DefConst,
151 // because some HHIR instructions require them. Ordinary Gen values with
152 // a known DataType only get one register. Assign "wide" locations when
153 // possible (when all uses and defs can be wide). These will be assigned
154 // SIMD registers later.
155 void assignRegs(const IRUnit
& unit
, Vunit
& vunit
, irlower::IRLS
& state
,
156 const BlockList
& blocks
) {
157 // visit instructions to find tmps eligible to use SIMD registers
158 auto const try_wide
= RuntimeOption::EvalHHIRAllocSIMDRegs
;
159 boost::dynamic_bitset
<> not_wide(unit
.numTmps());
160 StateVector
<SSATmp
,SSATmp
*> tmps(unit
, nullptr);
161 for (auto block
: blocks
) {
162 for (auto& inst
: *block
) {
163 for (uint32_t i
= 0, n
= inst
.numSrcs(); i
< n
; i
++) {
164 auto s
= inst
.src(i
);
166 if (!try_wide
|| !storesCell(inst
, i
)) {
167 not_wide
.set(s
->id());
170 for (auto& d
: inst
.dsts()) {
172 if (!try_wide
|| inst
.isControlFlow() || !loadsCell(inst
)) {
173 not_wide
.set(d
->id());
178 // visit each tmp, assign 1 or 2 registers to each.
179 for (auto tmp
: tmps
) {
181 auto forced
= forceAlloc(*tmp
);
182 if (forced
!= InvalidReg
) {
183 state
.locs
[tmp
] = Vloc
{forced
};
184 UNUSED Reg64 r
= forced
;
185 FTRACE(kVasmRegAllocDetailLevel
,
186 "force t{} in {}\n", tmp
->id(), reg::regname(r
));
189 if (tmp
->inst()->is(DefConst
)) {
190 auto const loc
= make_const(vunit
, tmp
->type());
191 state
.locs
[tmp
] = loc
;
192 FTRACE(kVasmRegAllocDetailLevel
, "const t{} in %{}\n", tmp
->id(),
193 size_t(loc
.reg(0)), size_t(loc
.reg(1)));
195 if (tmp
->numWords() == 2) {
196 if (!not_wide
.test(tmp
->id())) {
197 auto r
= vunit
.makeReg();
198 state
.locs
[tmp
] = Vloc
{Vloc::kWide
, r
};
199 FTRACE(kVasmRegAllocDetailLevel
,
200 "def t{} in wide %{}\n", tmp
->id(), size_t(r
));
202 auto data
= vunit
.makeReg();
203 auto type
= vunit
.makeReg();
204 state
.locs
[tmp
] = Vloc
{data
, type
};
205 FTRACE(kVasmRegAllocDetailLevel
,
206 "def t{} in %{},%{}\n", tmp
->id(),
207 size_t(data
), size_t(type
));
210 auto data
= vunit
.makeReg();
211 state
.locs
[tmp
] = Vloc
{data
};
212 FTRACE(kVasmRegAllocDetailLevel
,
213 "def t{} in %{}\n", tmp
->id(), size_t(data
));
219 void getEffects(const Abi
& abi
, const Vinstr
& i
,
220 RegSet
& uses
, RegSet
& across
, RegSet
& defs
) {
221 uses
= defs
= across
= RegSet();
227 defs
= abi
.all() - (abi
.calleeSaved
| rvmfp());
230 case Vinstr::callstub
:
232 (abi
.all() - (abi
.calleeSaved
| rvmfp()))
233 | jit::abi(CodeKind::CrossTrace
).unreserved();
236 case Vinstr::callfaststub
:
237 defs
= abi
.all() - abi
.calleeSaved
- abi
.gpUnreserved
;
240 case Vinstr::callphp
:
241 defs
= abi
.all() - RegSet(rvmtl());
244 case Vinstr::callunpack
:
245 case Vinstr::contenter
:
246 defs
= abi
.all() - (rvmfp() | rvmtl());
250 uses
= RegSet(reg::rax
);
251 defs
= reg::rax
| reg::rdx
;
254 uses
= defs
= reg::rax
| reg::rdx
;
258 across
= RegSet(reg::rcx
);
262 case Vinstr::vinvoke
:
263 case Vinstr::vcallunpack
:
264 always_assert(false && "Unsupported instruction in vxls");
271 //////////////////////////////////////////////////////////////////////