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/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);
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
};
65 v
<< copy
{srcData
, dstData
};
67 if (dstType
== InvalidReg
) return;
68 if (srcType
!= InvalidReg
) {
69 v
<< copy
{srcType
, dstType
};
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.
82 if (!src
->type().maybe(typeParam
)) {
83 // src is definitely not the target type. Always jump.
84 v
<< jmp
{label(env
, inst
->taken())};
88 if (srcType
!= InvalidReg
) {
89 emitTypeTest(v
, env
, typeParam
, srcType
, srcData
, v
.makeReg(), doJcc
);
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
));
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
,
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
);
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 ///////////////////////////////////////////////////////////////////////////////
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
);
203 assertx(src
->isA(TGen
));
205 auto const data
= loc
.reg(0);
206 auto const type
= loc
.reg(1) != InvalidReg
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
};
255 auto const sf
= v
.makeReg();
256 v
<< cmpbi
{KindOfPersistentString
, rtype
, sf
};
260 auto const sf
= v
.makeReg();
261 auto const dst
= v
.makeReg();
262 v
<< cmpbi
{KindOfInt64
, rtype
, sf
};
265 [&](Vout
& v
) { return v
.cns(true); },
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
};
277 auto const sf
= v
.makeReg();
278 auto const dst
= v
.makeReg();
279 emitTestTVType(v
, sf
, KindOfStringBit
, rtype
);
282 [&](Vout
& v
) { return v
.cns(true); },
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
};
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());
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());
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
};
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
))
357 cgCallHelper(vmain(env
), env
, CallSpec::method(&TypeProfile::report
),
358 kVoidDest
, SyncOptions::None
, args
);
361 ///////////////////////////////////////////////////////////////////////////////