emit file/line with ud2
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-type.cpp
bloba7462ff9d671bb6934a4d7421e57d4b242062001
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/datatype.h"
20 #include "hphp/runtime/base/ref-data.h"
22 #include "hphp/runtime/vm/jit/abi.h"
23 #include "hphp/runtime/vm/jit/code-gen-cf.h"
24 #include "hphp/runtime/vm/jit/extra-data.h"
25 #include "hphp/runtime/vm/jit/ir-instruction.h"
26 #include "hphp/runtime/vm/jit/ssa-tmp.h"
27 #include "hphp/runtime/vm/jit/translator-inline.h"
28 #include "hphp/runtime/vm/jit/type.h"
29 #include "hphp/runtime/vm/jit/types.h"
30 #include "hphp/runtime/vm/jit/type-profile.h"
31 #include "hphp/runtime/vm/jit/vasm-gen.h"
32 #include "hphp/runtime/vm/jit/vasm-instr.h"
33 #include "hphp/runtime/vm/jit/vasm-reg.h"
35 #include "hphp/util/asm-x64.h"
36 #include "hphp/util/trace.h"
38 namespace HPHP { namespace jit { namespace irlower {
40 TRACE_SET_MOD(irlower);
42 ///////////////////////////////////////////////////////////////////////////////
44 void cgCheckType(IRLS& env, const IRInstruction* inst) {
45 // Note: If you add new supported type checks, you should update
46 // negativeCheckType() to indicate whether it is precise or not.
47 auto const src = inst->src(0);
48 auto const dst = inst->dst();
49 auto const srcData = srcLoc(env, inst, 0).reg(0);
50 auto const srcType = srcLoc(env, inst, 0).reg(1);
52 auto& v = vmain(env);
54 auto const doJcc = [&] (ConditionCode cc, Vreg sf) {
55 fwdJcc(v, env, ccNegate(cc), sf, inst->taken());
58 auto const doMov = [&] {
59 auto const dstData = dstLoc(env, inst, 0).reg(0);
60 auto const dstType = dstLoc(env, inst, 0).reg(1);
62 if (dst->isA(TBool) && !src->isA(TBool)) {
63 v << movtqb{srcData, dstData};
64 } else {
65 v << copy{srcData, dstData};
67 if (dstType == InvalidReg) return;
68 if (srcType != InvalidReg) {
69 v << copy{srcType, dstType};
70 } else {
71 v << ldimmq{src->type().toDataType(), dstType};
75 auto const typeParam = inst->typeParam();
77 if (src->isA(typeParam)) {
78 // src is the target type or better. Just define our dst.
79 doMov();
80 return;
82 if (!src->type().maybe(typeParam)) {
83 // src is definitely not the target type. Always jump.
84 v << jmp{label(env, inst->taken())};
85 return;
88 if (srcType != InvalidReg) {
89 emitTypeTest(v, env, typeParam, srcType, srcData, v.makeReg(), doJcc);
90 doMov();
91 return;
94 if (src->type() <= TBoxedCell && typeParam <= TBoxedCell) {
95 // We should never have specific known Boxed types; those should only be
96 // used for hints and predictions.
97 always_assert(!(typeParam < TBoxedInitCell));
98 doMov();
99 return;
103 * See if we're just checking the array kind or object class of a value with
104 * a mostly-known type.
106 * Important: We don't support typeParam being something like
107 * StaticArr=kPackedKind unless the src->type() also already knows its
108 * staticness. We do allow things like CheckType<Arr=Packed> t1:StaticArr,
109 * though. This is why we have to check that the unspecialized type is at
110 * least as big as the src->type().
112 if (typeParam.isSpecialized() &&
113 typeParam.unspecialize() >= src->type()) {
114 detail::emitSpecializedTypeTest(v, env, typeParam, srcData,
115 v.makeReg(), doJcc);
116 doMov();
117 return;
121 * Since not all of our unions carry a type register, there are some
122 * situations with strings and arrays that are neither constantly-foldable
123 * nor in the emitTypeTest() code path.
125 * We currently actually check their persistent bit here, which will let
126 * both static and uncounted strings through. Also note that
127 * CheckType<Uncounted> t1:{Null|Str} doesn't get this treatment currently---
128 * the emitTypeTest() path above will only check the type register.
130 if (!typeParam.isSpecialized() &&
131 typeParam <= TUncounted &&
132 src->type().subtypeOfAny(TStr, TArrLike) &&
133 src->type().maybe(typeParam)) {
134 assertx(src->type().maybe(TPersistent));
136 auto const sf = emitCmpRefCount(v, 0, srcData);
137 doJcc(CC_L, sf);
138 doMov();
139 return;
142 always_assert_flog(
143 false,
144 "Bad src: {} and dst: {} types in '{}'",
145 src->type(), typeParam, *inst
149 void cgCheckTypeMem(IRLS& env, const IRInstruction* inst) {
150 auto const src = srcLoc(env, inst, 0).reg();
151 emitTypeCheck(vmain(env), env, inst->typeParam(),
152 src[TVOFF(m_type)], src[TVOFF(m_data)], inst->taken());
155 void cgCheckLoc(IRLS& env, const IRInstruction* inst) {
156 auto const baseOff = localOffset(inst->extra<CheckLoc>()->locId);
157 auto const base = srcLoc(env, inst, 0).reg()[baseOff];
159 emitTypeCheck(vmain(env), env, inst->typeParam(),
160 base + TVOFF(m_type), base + TVOFF(m_data), inst->taken());
163 void cgCheckStk(IRLS& env, const IRInstruction* inst) {
164 auto const baseOff = cellsToBytes(inst->extra<CheckStk>()->offset.offset);
165 auto const base = srcLoc(env, inst, 0).reg()[baseOff];
167 emitTypeCheck(vmain(env), env, inst->typeParam(),
168 base + TVOFF(m_type), base + TVOFF(m_data), inst->taken());
171 void cgCheckRefInner(IRLS& env, const IRInstruction* inst) {
172 if (inst->typeParam() >= TInitCell) return;
173 auto const base = srcLoc(env, inst, 0).reg()[RefData::tvOffset()];
175 emitTypeCheck(vmain(env), env, inst->typeParam(),
176 base + TVOFF(m_type), base + TVOFF(m_data), inst->taken());
179 void cgCheckMBase(IRLS& env, const IRInstruction* inst) {
180 cgCheckTypeMem(env, inst);
183 ///////////////////////////////////////////////////////////////////////////////
185 namespace {
187 void implIsType(IRLS& env, const IRInstruction* inst, bool negate) {
188 auto const src = inst->src(0);
189 auto const loc = srcLoc(env, inst, 0);
190 auto& v = vmain(env);
192 auto const doJcc = [&] (ConditionCode cc, Vreg sf) {
193 auto const dst = dstLoc(env, inst, 0).reg();
194 v << setcc{negate ? ccNegate(cc) : cc, sf, dst};
197 if (src->isA(TPtrToGen)) {
198 auto const base = loc.reg();
199 emitTypeTest(v, env, inst->typeParam(), base[TVOFF(m_type)],
200 base[TVOFF(m_data)], v.makeReg(), doJcc);
201 return;
203 assertx(src->isA(TGen));
205 auto const data = loc.reg(0);
206 auto const type = loc.reg(1) != InvalidReg
207 ? loc.reg(1)
208 : v.cns(src->type().toDataType());
210 emitTypeTest(v, env, inst->typeParam(), type, data, v.makeReg(), doJcc);
215 ///////////////////////////////////////////////////////////////////////////////
217 void cgIsType(IRLS& env, const IRInstruction* inst) {
218 implIsType(env, inst, false);
220 void cgIsNType(IRLS& env, const IRInstruction* inst) {
221 implIsType(env, inst, true);
223 void cgIsTypeMem(IRLS& env, const IRInstruction* inst) {
224 implIsType(env, inst, false);
226 void cgIsNTypeMem(IRLS& env, const IRInstruction* inst) {
227 implIsType(env, inst, true);
230 void cgIsScalarType(IRLS& env, const IRInstruction* inst) {
231 auto rtype = srcLoc(env, inst, 0).reg(1);
232 auto dst = dstLoc(env, inst, 0).reg(0);
234 static_assert(KindOfInt64 < KindOfPersistentString,
235 "fix checks for IsScalar");
236 static_assert(KindOfBoolean < KindOfPersistentString,
237 "fix checks for IsScalar");
239 static_assert(KindOfDouble > KindOfPersistentString,
240 "fix checks for IsScalar");
241 static_assert(KindOfString > KindOfPersistentString,
242 "fix checks for IsScalar");
244 static_assert(sizeof(DataType) == 1, "");
246 auto& v = vmain(env);
248 if (rtype == InvalidReg) {
249 auto const type = inst->src(0)->type();
250 auto const imm = type <= (TBool | TInt | TDbl | TStr);
251 v << copy{v.cns(imm), dst};
252 return;
255 auto const sf = v.makeReg();
256 v << cmpbi{KindOfPersistentString, rtype, sf};
257 cond(
258 v, CC_L, sf, dst,
259 [&](Vout& v) {
260 auto const sf = v.makeReg();
261 auto const dst = v.makeReg();
262 v << cmpbi{KindOfInt64, rtype, sf};
263 cond(
264 v, CC_E, sf, dst,
265 [&](Vout& v) { return v.cns(true); },
266 [&](Vout& v) {
267 auto const sf = v.makeReg();
268 auto const dst = v.makeReg();
269 v << cmpbi{KindOfBoolean, rtype, sf};
270 v << setcc{CC_E, sf, dst};
271 return dst;
274 return dst;
276 [&](Vout& v) {
277 auto const sf = v.makeReg();
278 auto const dst = v.makeReg();
279 emitTestTVType(v, sf, KindOfStringBit, rtype);
280 cond(
281 v, CC_NZ, sf, dst,
282 [&](Vout& v) { return v.cns(true); },
283 [&](Vout& v) {
284 auto const sf = v.makeReg();
285 auto const dst = v.makeReg();
286 v << cmpbi{KindOfDouble, rtype, sf};
287 v << setcc{CC_E, sf, dst};
288 return dst;
291 return dst;
296 ///////////////////////////////////////////////////////////////////////////////
298 void cgCheckVArray(IRLS& env, const IRInstruction* inst) {
299 auto const src = srcLoc(env, inst, 0).reg();
300 auto const dst = dstLoc(env, inst, 0).reg();
301 auto& v = vmain(env);
302 auto const sf = v.makeReg();
303 v << cmpbim{ArrayData::kVArray, src + ArrayData::offsetofDVArray(), sf};
304 fwdJcc(v, env, CC_NZ, sf, inst->taken());
305 v << copy{src, dst};
308 void cgCheckDArray(IRLS& env, const IRInstruction* inst) {
309 auto const src = srcLoc(env, inst, 0).reg();
310 auto const dst = dstLoc(env, inst, 0).reg();
311 auto& v = vmain(env);
312 auto const sf = v.makeReg();
313 v << cmpbim{ArrayData::kDArray, src + ArrayData::offsetofDVArray(), sf};
314 fwdJcc(v, env, CC_NZ, sf, inst->taken());
315 v << copy{src, dst};
318 void cgIsDVArray(IRLS& env, const IRInstruction* inst) {
319 auto const src = srcLoc(env, inst, 0).reg();
320 auto const dst = dstLoc(env, inst, 0).reg();
321 auto& v = vmain(env);
322 auto const sf = v.makeReg();
323 v << cmpbim{ArrayData::kNotDVArray, src + ArrayData::offsetofDVArray(), sf};
324 v << setcc{CC_NZ, sf, dst};
327 ///////////////////////////////////////////////////////////////////////////////
329 void cgAssertType(IRLS& env, const IRInstruction* inst) {
330 auto& v = vmain(env);
331 auto const& dtype = inst->dst()->type();
332 if (dtype == TBottom) {
333 v << trap{TRAP_REASON};
334 v = v.makeBlock();
335 return;
338 auto const dst = dstLoc(env, inst, 0);
339 auto const src = srcLoc(env, inst, 0);
340 copyTV(v, src, dst, dtype);
343 void cgAssertLoc(IRLS&, const IRInstruction*) {}
344 void cgAssertStk(IRLS&, const IRInstruction*) {}
345 void cgAssertMBase(IRLS&, const IRInstruction*) {}
346 void cgHintLocInner(IRLS&, const IRInstruction*) {}
347 void cgHintStkInner(IRLS&, const IRInstruction*) {}
348 void cgHintMBaseInner(IRLS&, const IRInstruction*) {}
350 void cgProfileType(IRLS& env, const IRInstruction* inst) {
351 auto const extra = inst->extra<RDSHandleData>();
353 auto const args = argGroup(env, inst)
354 .addr(rvmtl(), safe_cast<int32_t>(extra->handle))
355 .typedValue(0);
357 cgCallHelper(vmain(env), env, CallSpec::method(&TypeProfile::report),
358 kVoidDest, SyncOptions::None, args);
361 ///////////////////////////////////////////////////////////////////////////////