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/irlower-internal.h"
19 #include "hphp/runtime/base/memory-manager.h"
20 #include "hphp/runtime/base/ref-data.h"
22 #include "hphp/runtime/vm/runtime.h"
23 #include "hphp/runtime/vm/jit/abi.h"
24 #include "hphp/runtime/vm/jit/analysis.h"
25 #include "hphp/runtime/vm/jit/arg-group.h"
26 #include "hphp/runtime/vm/jit/call-spec.h"
27 #include "hphp/runtime/vm/jit/code-gen-cf.h"
28 #include "hphp/runtime/vm/jit/code-gen-helpers.h"
29 #include "hphp/runtime/vm/jit/dce.h"
30 #include "hphp/runtime/vm/jit/extra-data.h"
31 #include "hphp/runtime/vm/jit/ir-instruction.h"
32 #include "hphp/runtime/vm/jit/ir-opcode.h"
33 #include "hphp/runtime/vm/jit/ssa-tmp.h"
34 #include "hphp/runtime/vm/jit/translator-inline.h"
35 #include "hphp/runtime/vm/jit/types.h"
36 #include "hphp/runtime/vm/jit/vasm-gen.h"
37 #include "hphp/runtime/vm/jit/vasm-instr.h"
38 #include "hphp/runtime/vm/jit/vasm-reg.h"
40 #include "hphp/util/asm-x64.h"
41 #include "hphp/util/trace.h"
43 namespace HPHP
{ namespace jit
{ namespace irlower
{
45 TRACE_SET_MOD(irlower
);
47 ///////////////////////////////////////////////////////////////////////////////
49 void cgLdLoc(IRLS
& env
, const IRInstruction
* inst
) {
50 auto const fp
= srcLoc(env
, inst
, 0).reg();
51 auto const off
= localOffset(inst
->extra
<LdLoc
>()->locId
);
52 loadTV(vmain(env
), inst
->dst(), dstLoc(env
, inst
, 0), fp
[off
]);
55 void cgLdLocAddr(IRLS
& env
, const IRInstruction
* inst
) {
56 auto const fp
= srcLoc(env
, inst
, 0).reg();
57 auto const off
= localOffset(inst
->extra
<LdLocAddr
>()->locId
);
58 if (dstLoc(env
, inst
, 0).hasReg()) {
59 vmain(env
) << lea
{fp
[off
], dstLoc(env
, inst
, 0).reg()};
63 void cgStLoc(IRLS
& env
, const IRInstruction
* inst
) {
64 auto const fp
= srcLoc(env
, inst
, 0).reg();
65 auto const off
= localOffset(inst
->extra
<StLoc
>()->locId
);
66 storeTV(vmain(env
), fp
[off
], srcLoc(env
, inst
, 1), inst
->src(1));
69 void cgStLocRange(IRLS
& env
, const IRInstruction
* inst
) {
70 auto const range
= inst
->extra
<StLocRange
>();
72 if (range
->start
>= range
->end
) return;
74 auto const fp
= srcLoc(env
, inst
, 0).reg();
75 auto const loc
= srcLoc(env
, inst
, 1);
76 auto const val
= inst
->src(1);
79 auto ireg
= v
.makeReg();
80 auto nreg
= v
.makeReg();
82 v
<< lea
{fp
[localOffset(range
->start
)], ireg
};
83 v
<< lea
{fp
[localOffset(range
->end
)], nreg
};
85 doWhile(v
, CC_NE
, {ireg
},
86 [&] (const VregList
& in
, const VregList
& out
) {
88 auto const res
= out
[0];
89 auto const sf
= v
.makeReg();
91 storeTV(v
, i
[0], loc
, val
);
92 v
<< subqi
{int32_t{sizeof(Cell
)}, i
, res
, v
.makeReg()};
93 v
<< cmpq
{res
, nreg
, sf
};
99 void cgDbgTrashFrame(IRLS
& env
, const IRInstruction
* inst
) {
100 auto const fp
= srcLoc(env
, inst
, 0).reg();
101 auto const off
= cellsToBytes(inst
->extra
<DbgTrashFrame
>()->offset
.offset
);
102 for (auto i
= 0; i
< kNumActRecCells
; ++i
) {
103 trashTV(vmain(env
), fp
, off
+ cellsToBytes(i
), kTVTrashJITFrame
);
107 ///////////////////////////////////////////////////////////////////////////////
109 void cgLdLocPseudoMain(IRLS
& env
, const IRInstruction
* inst
) {
110 auto const fp
= srcLoc(env
, inst
, 0).reg();
111 auto const off
= localOffset(inst
->extra
<LdLocPseudoMain
>()->locId
);
112 auto& v
= vmain(env
);
114 irlower::emitTypeCheck(v
, env
, inst
->typeParam(), fp
[off
+ TVOFF(m_type
)],
115 fp
[off
+ TVOFF(m_data
)], inst
->taken());
116 loadTV(v
, inst
->dst(), dstLoc(env
, inst
, 0), fp
[off
]);
119 void cgStLocPseudoMain(IRLS
& env
, const IRInstruction
* inst
) {
120 auto const fp
= srcLoc(env
, inst
, 0).reg();
121 auto const off
= localOffset(inst
->extra
<StLocPseudoMain
>()->locId
);
122 storeTV(vmain(env
), fp
[off
], srcLoc(env
, inst
, 1), inst
->src(1));
125 ///////////////////////////////////////////////////////////////////////////////
127 void cgLdStk(IRLS
& env
, const IRInstruction
* inst
) {
128 auto const sp
= srcLoc(env
, inst
, 0).reg();
129 auto const off
= cellsToBytes(inst
->extra
<LdStk
>()->offset
.offset
);
130 loadTV(vmain(env
), inst
->dst(), dstLoc(env
, inst
, 0), sp
[off
]);
133 void cgLdStkAddr(IRLS
& env
, const IRInstruction
* inst
) {
134 auto const sp
= srcLoc(env
, inst
, 0).reg();
135 auto const off
= cellsToBytes(inst
->extra
<LdStkAddr
>()->offset
.offset
);
136 vmain(env
) << lea
{sp
[off
], dstLoc(env
, inst
, 0).reg()};
139 void cgStStk(IRLS
& env
, const IRInstruction
* inst
) {
140 auto const sp
= srcLoc(env
, inst
, 0).reg();
141 auto const off
= cellsToBytes(inst
->extra
<StStk
>()->offset
.offset
);
142 storeTV(vmain(env
), sp
[off
], srcLoc(env
, inst
, 1), inst
->src(1));
145 void cgDbgTrashStk(IRLS
& env
, const IRInstruction
* inst
) {
146 auto const sp
= srcLoc(env
, inst
, 0).reg();
147 auto const off
= cellsToBytes(inst
->extra
<DbgTrashStk
>()->offset
.offset
);
148 trashTV(vmain(env
), sp
, off
, kTVTrashJITStk
);
151 ///////////////////////////////////////////////////////////////////////////////
155 const Func
* funcFromFp(const SSATmp
* fp
) {
157 auto inst
= fp
->inst();
158 if (UNLIKELY(inst
->is(DefLabel
))) {
159 inst
= resolveFpDefLabel(fp
);
162 assertx(inst
->is(DefFP
, DefInlineFP
));
163 if (inst
->is(DefFP
)) return inst
->marker().func();
164 if (inst
->is(DefInlineFP
)) return inst
->extra
<DefInlineFP
>()->target
;
165 always_assert(false);
170 void cgLdClsRef(IRLS
& env
, const IRInstruction
* inst
) {
171 auto const fp
= srcLoc(env
, inst
, 0).reg();
172 auto const dst
= dstLoc(env
, inst
, 0).reg();
173 auto const off
= frame_clsref_offset(
174 funcFromFp(inst
->src(0)),
175 inst
->extra
<ClsRefSlotData
>()->slot
177 emitLdLowPtr(vmain(env
), fp
[off
], dst
, sizeof(LowPtr
<Class
>));
180 void cgStClsRef(IRLS
& env
, const IRInstruction
* inst
) {
181 auto const fp
= srcLoc(env
, inst
, 0).reg();
182 auto const src
= srcLoc(env
, inst
, 1).reg();
183 auto const off
= frame_clsref_offset(
184 funcFromFp(inst
->src(0)),
185 inst
->extra
<ClsRefSlotData
>()->slot
187 emitStLowPtr(vmain(env
), src
, fp
[off
], sizeof(LowPtr
<Class
>));
190 void cgKillClsRef(IRLS
& env
, const IRInstruction
* inst
) {
193 auto& v
= vmain(env
);
194 auto const fp
= srcLoc(env
, inst
, 0).reg();
195 auto const off
= frame_clsref_offset(
196 funcFromFp(inst
->src(0)),
197 inst
->extra
<ClsRefSlotData
>()->slot
201 memset(&trash
, kTrashClsRef
, sizeof(trash
));
202 Immed64
immed(trash
.get());
204 if (sizeof(trash
) == 4) {
205 v
<< storeli
{immed
.l(), fp
[off
]};
206 } else if (sizeof(trash
) == 8) {
207 if (immed
.fits(sz::dword
)) {
208 v
<< storeqi
{immed
.l(), fp
[off
]};
210 v
<< store
{v
.cns(immed
.q()), fp
[off
]};
217 ///////////////////////////////////////////////////////////////////////////////
219 void cgLdMem(IRLS
& env
, const IRInstruction
* inst
) {
220 auto const ptr
= srcLoc(env
, inst
, 0).reg();
221 loadTV(vmain(env
), inst
->dst(), dstLoc(env
, inst
, 0), *ptr
);
224 void cgStMem(IRLS
& env
, const IRInstruction
* inst
) {
225 auto const ptr
= srcLoc(env
, inst
, 0).reg();
226 storeTV(vmain(env
), *ptr
, srcLoc(env
, inst
, 1), inst
->src(1));
229 void cgDbgTrashMem(IRLS
& env
, const IRInstruction
* inst
) {
230 auto const ptr
= srcLoc(env
, inst
, 0).reg();
231 trashTV(vmain(env
), ptr
, 0, kTVTrashJITHeap
);
234 ///////////////////////////////////////////////////////////////////////////////
236 void cgLdRef(IRLS
& env
, const IRInstruction
* inst
) {
237 auto const ptr
= srcLoc(env
, inst
, 0).reg();
238 loadTV(vmain(env
), inst
->dst(), dstLoc(env
, inst
, 0),
239 ptr
[RefData::tvOffset()]);
242 void cgStRef(IRLS
& env
, const IRInstruction
* inst
) {
243 auto const ptr
= srcLoc(env
, inst
, 0).reg();
244 auto const valLoc
= srcLoc(env
, inst
, 1);
245 always_assert(!srcLoc(env
, inst
, 1).isFullSIMD());
247 storeTV(vmain(env
), ptr
[RefData::tvOffset()], valLoc
, inst
->src(1));
250 ///////////////////////////////////////////////////////////////////////////////
252 void cgLdElem(IRLS
& env
, const IRInstruction
* inst
) {
253 auto const rbase
= srcLoc(env
, inst
, 0).reg();
254 auto const ridx
= srcLoc(env
, inst
, 1).reg();
255 auto const idx
= inst
->src(1);
256 auto& v
= vmain(env
);
258 if (idx
->hasConstVal() && deltaFits(idx
->intVal(), sz::dword
)) {
259 loadTV(v
, inst
->dst(), dstLoc(env
, inst
, 0), rbase
[idx
->intVal()]);
261 loadTV(v
, inst
->dst(), dstLoc(env
, inst
, 0), rbase
[ridx
]);
265 void cgStElem(IRLS
& env
, const IRInstruction
* inst
) {
266 auto const rbase
= srcLoc(env
, inst
, 0).reg();
267 auto const ridx
= srcLoc(env
, inst
, 1).reg();
268 auto const idx
= inst
->src(1);
269 auto& v
= vmain(env
);
271 if (idx
->hasConstVal() && deltaFits(idx
->intVal(), sz::dword
)) {
272 storeTV(v
, rbase
[idx
->intVal()], srcLoc(env
, inst
, 2), inst
->src(2));
274 storeTV(v
, rbase
[ridx
], srcLoc(env
, inst
, 2), inst
->src(2));
278 ///////////////////////////////////////////////////////////////////////////////
280 void cgLdMIStateAddr(IRLS
& env
, const IRInstruction
* inst
) {
281 auto const off
= rds::kVmMInstrStateOff
+ inst
->src(0)->intVal();
282 vmain(env
) << lea
{rvmtl()[off
], dstLoc(env
, inst
, 0).reg()};
285 void cgLdMBase(IRLS
& env
, const IRInstruction
* inst
) {
286 auto const off
= rds::kVmMInstrStateOff
+ offsetof(MInstrState
, base
);
287 vmain(env
) << load
{rvmtl()[off
], dstLoc(env
, inst
, 0).reg()};
290 void cgStMBase(IRLS
& env
, const IRInstruction
* inst
) {
291 auto const off
= rds::kVmMInstrStateOff
+ offsetof(MInstrState
, base
);
292 vmain(env
) << store
{srcLoc(env
, inst
, 0).reg(), rvmtl()[off
]};
295 ///////////////////////////////////////////////////////////////////////////////
297 static TypedValue
* ldGblAddrHelper(const StringData
* name
) {
298 return g_context
->m_globalVarEnv
->lookup(name
);
301 void cgLdGblAddr(IRLS
& env
, const IRInstruction
* inst
) {
302 auto const dst
= dstLoc(env
, inst
, 0).reg();
303 auto& v
= vmain(env
);
305 cgCallHelper(v
, env
, CallSpec::direct(ldGblAddrHelper
), callDest(dst
),
306 SyncOptions::None
, argGroup(env
, inst
).ssa(0));
308 auto const sf
= v
.makeReg();
309 v
<< testq
{dst
, dst
, sf
};
310 v
<< jcc
{CC_Z
, sf
, {label(env
, inst
->next()), label(env
, inst
->taken())}};
313 IMPL_OPCODE_CALL(LdGblAddrDef
)
315 void cgLdPropAddr(IRLS
& env
, const IRInstruction
* inst
) {
316 auto const dst
= dstLoc(env
, inst
, 0).reg();
317 auto const obj
= srcLoc(env
, inst
, 0).reg();
318 vmain(env
) << lea
{obj
[inst
->extra
<LdPropAddr
>()->offsetBytes
], dst
};
321 IMPL_OPCODE_CALL(LdClsPropAddrOrNull
)
322 IMPL_OPCODE_CALL(LdClsPropAddrOrRaise
)
324 ///////////////////////////////////////////////////////////////////////////////
326 void cgLdRDSAddr(IRLS
& env
, const IRInstruction
* inst
) {
327 auto const handle
= inst
->extra
<LdRDSAddr
>()->handle
;
328 vmain(env
) << lea
{rvmtl()[handle
], dstLoc(env
, inst
, 0).reg()};
331 void cgLdTVAux(IRLS
& env
, const IRInstruction
* inst
) {
332 auto const dst
= dstLoc(env
, inst
, 0).reg();
334 auto const tv
= srcLoc(env
, inst
, 0);
335 assertx(tv
.hasReg(1));
336 auto const type
= tv
.reg(1);
338 auto& v
= vmain(env
);
339 v
<< shrqi
{32, type
, dst
, v
.makeReg()};
341 if (RuntimeOption::EvalHHIRGenerateAsserts
) {
342 auto const extra
= inst
->extra
<LdTVAux
>();
343 auto const mask
= -extra
->valid
- 1;
346 auto const sf
= v
.makeReg();
347 v
<< testqi
{mask
, dst
, sf
};
348 ifThen(v
, CC_NZ
, sf
, [](Vout
& v
) {
349 v
<< trap
{TRAP_REASON
};
355 ///////////////////////////////////////////////////////////////////////////////