emit file/line with ud2
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-load-store.cpp
blob187544f2af01cd0c822199cf80655b72692610c0
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/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);
77 auto& v = vmain(env);
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) {
87 auto const i = in[0];
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};
94 return 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 ///////////////////////////////////////////////////////////////////////////////
153 namespace {
155 const Func* funcFromFp(const SSATmp* fp) {
156 fp = canonical(fp);
157 auto inst = fp->inst();
158 if (UNLIKELY(inst->is(DefLabel))) {
159 inst = resolveFpDefLabel(fp);
160 assertx(inst);
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) {
191 if (!debug) return;
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
200 LowPtr<Class> trash;
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]};
209 } else {
210 v << store{v.cns(immed.q()), fp[off]};
212 } else {
213 not_implemented();
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()]);
260 } else {
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));
273 } else {
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;
345 if (mask) {
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 ///////////////////////////////////////////////////////////////////////////////