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/base/array-data.h"
18 #include "hphp/runtime/base/attr.h"
19 #include "hphp/runtime/base/datatype.h"
20 #include "hphp/runtime/base/header-kind.h"
21 #include "hphp/runtime/base/object-data.h"
23 #include "hphp/runtime/vm/jit/arg-group.h"
24 #include "hphp/runtime/vm/jit/code-gen-helpers.h"
25 #include "hphp/runtime/vm/jit/ir-instruction.h"
26 #include "hphp/runtime/vm/jit/ir-opcode.h"
27 #include "hphp/runtime/vm/jit/irlower.h"
28 #include "hphp/runtime/vm/jit/type.h"
29 #include "hphp/runtime/vm/jit/type-specialization.h"
30 #include "hphp/runtime/vm/jit/vasm.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"
37 namespace HPHP
{ namespace jit
{ namespace irlower
{
39 ///////////////////////////////////////////////////////////////////////////////
41 inline Vout
& vmain(IRLS
& env
) { assertx(env
.vmain
); return *env
.vmain
; }
42 inline Vout
& vcold(IRLS
& env
) { assertx(env
.vcold
); return *env
.vcold
; }
44 inline Vlabel
label(IRLS
& env
, Block
* b
) { return env
.labels
[b
]; }
46 inline Vloc
srcLoc(IRLS
& env
, const IRInstruction
* inst
, unsigned i
) {
47 return env
.locs
[inst
->src(i
)];
50 inline Vloc
dstLoc(IRLS
& env
, const IRInstruction
* inst
, unsigned i
) {
51 return env
.locs
[inst
->dst(i
)];
54 inline ArgGroup
argGroup(IRLS
& env
, const IRInstruction
* inst
) {
55 return ArgGroup(inst
, env
.locs
);
58 inline CallDest
callDest(Vreg reg0
) {
59 return { DestType::SSA
, reg0
};
62 inline CallDest
callDest(Vreg reg0
, Vreg reg1
) {
63 return { DestType::TV
, reg0
, reg1
};
66 inline CallDest
callDest(IRLS
& env
, const IRInstruction
* inst
) {
67 if (!inst
->numDsts()) return kVoidDest
;
69 auto const loc
= dstLoc(env
, inst
, 0);
70 if (loc
.numAllocated() == 0) return kVoidDest
;
71 assertx(loc
.numAllocated() == 1);
74 inst
->dst(0)->isA(TBool
) ? DestType::Byte
: DestType::SSA
,
79 inline CallDest
callDestTV(IRLS
& env
, const IRInstruction
* inst
) {
80 if (!inst
->numDsts()) return kVoidDest
;
82 auto const loc
= dstLoc(env
, inst
, 0);
83 if (loc
.numAllocated() == 0) return kVoidDest
;
85 if (loc
.isFullSIMD()) {
86 assertx(loc
.numAllocated() == 1);
87 return { DestType::SIMD
, loc
.reg(0) };
89 if (loc
.numAllocated() == 2) {
90 return { DestType::TV
, loc
.reg(0), loc
.reg(1) };
92 assertx(loc
.numAllocated() == 1);
94 // Sometimes we statically know the type and only need the value.
95 return { DestType::TV
, loc
.reg(0), InvalidReg
};
98 inline CallDest
callDestDbl(IRLS
& env
, const IRInstruction
* inst
) {
99 if (!inst
->numDsts()) return kVoidDest
;
100 auto const loc
= dstLoc(env
, inst
, 0);
101 return { DestType::Dbl
, loc
.reg(0) };
104 ///////////////////////////////////////////////////////////////////////////////
106 inline void fwdJcc(Vout
& v
, IRLS
& env
, ConditionCode cc
,
107 Vreg sf
, Block
* target
) {
108 auto const next
= v
.makeBlock();
109 v
<< jcc
{cc
, sf
, {next
, label(env
, target
)}};
113 ///////////////////////////////////////////////////////////////////////////////
117 ///////////////////////////////////////////////////////////////////////////////
120 * Materialize `data' into a Vreg and return it.
122 inline Vreg
materialize(Vout
& v
, Vptr data
) {
123 auto const t
= v
.makeReg();
127 inline Vreg
materialize(Vout
&, Vreg data
) { return data
; }
130 * Test whether the value given by `dataSrc' has the same type specialization
133 * Assumes that the DataType corresponding to `dataSrc' already matches `type'.
135 template <class Loc
, class JmpFn
>
136 void emitSpecializedTypeTest(Vout
& v
, IRLS
& /*env*/, Type type
, Loc dataSrc
,
137 Vreg sf
, JmpFn doJcc
) {
139 // No cls field in Resource.
140 always_assert(false && "unexpected guard on specialized Resource");
143 if (type
< TObj
|| type
< TCls
) {
144 // Emit the specific class test.
145 assertx(type
.clsSpec());
146 assertx(type
.clsSpec().exact() ||
147 type
.clsSpec().cls()->attrs() & AttrNoOverride
);
149 auto const data
= materialize(v
, dataSrc
);
151 emitCmpLowPtr(v
, sf
, type
.clsSpec().cls(),
152 data
[ObjectData::getVMClassOffset()]);
154 v
<< cmpq
{v
.cns(type
.clsSpec().cls()), data
, sf
};
158 assertx(type
< TArr
&& type
.arrSpec() && type
.arrSpec().kind());
159 assertx(type
.arrSpec().type() == nullptr);
161 auto const arrSpec
= type
.arrSpec();
162 auto const data
= materialize(v
, dataSrc
);
164 static_assert(sizeof(HeaderKind
) == 1, "");
165 v
<< cmpbim
{*arrSpec
.kind(), data
[HeaderKindOffset
], sf
};
170 ///////////////////////////////////////////////////////////////////////////////
174 ///////////////////////////////////////////////////////////////////////////////
176 template<class Loc
, class JmpFn
>
177 void emitTypeTest(Vout
& v
, IRLS
& env
, Type type
,
178 Loc typeSrc
, Loc dataSrc
, Vreg sf
, JmpFn doJcc
) {
179 // Note: If you add new supported type tests, you should update
180 // negativeCheckType() to indicate whether it is precise or not.
181 always_assert(!type
.hasConstVal());
183 !type
.subtypeOfAny(TCls
, TCountedStr
, TPersistentArrLike
),
184 "Unsupported type in emitTypeTest(): {}", type
188 if (type
== TGen
) return;
190 auto const cc
= [&] {
192 auto const mask_cmp
= [&] (int mask
, int bits
, ConditionCode cc
) {
193 auto const masked
= emitMaskTVType(v
, mask
, typeSrc
);
194 emitCmpTVType(v
, sf
, bits
, masked
);
198 auto const cmp
= [&] (DataType kind
, ConditionCode cc
) {
199 emitCmpTVType(v
, sf
, kind
, typeSrc
);
203 auto const test
= [&] (int bits
, ConditionCode cc
) {
204 emitTestTVType(v
, sf
, bits
, typeSrc
);
208 if (type
<= TPersistentStr
) return cmp(KindOfPersistentString
, CC_E
);
209 if (type
<= TStr
) return test(KindOfStringBit
, CC_NZ
);
210 if (type
<= TArr
) return test(KindOfArrayBit
, CC_NZ
);
211 if (type
<= TVec
) return mask_cmp(kDataTypeEquivalentMask
,
212 KindOfHackArrayVecType
,
214 if (type
<= TDict
) return mask_cmp(kDataTypeEquivalentMask
,
215 KindOfHackArrayDictType
,
217 if (type
<= TKeyset
) return mask_cmp(kDataTypeEquivalentMask
,
218 KindOfHackArrayKeysetType
,
220 if (type
<= TArrLike
) return test(KindOfArrayLikeMask
, CC_NZ
);
222 // These are intentionally == and not <=.
223 if (type
== TNull
) return cmp(KindOfNull
, CC_LE
);
224 if (type
== TUncountedInit
) return test(KindOfUncountedInitBit
, CC_NZ
);
225 if (type
== TUncounted
) return cmp(KindOfRefCountThreshold
, CC_LE
);
226 if (type
== TCell
) return cmp(KindOfRef
, CC_NE
);
228 always_assert(type
.isKnownDataType());
229 always_assert(!(type
< TBoxedInitCell
));
231 auto const dt
= type
.toDataType();
232 return cmp(dt
, CC_E
);
237 if (type
.isSpecialized()) {
238 auto const sf2
= v
.makeReg();
239 detail::emitSpecializedTypeTest(v
, env
, type
, dataSrc
, sf2
, doJcc
);
244 void emitTypeCheck(Vout
& v
, IRLS
& env
, Type type
,
245 Loc typeSrc
, Loc dataSrc
, Block
* taken
) {
246 emitTypeTest(v
, env
, type
, typeSrc
, dataSrc
, v
.makeReg(),
247 [&] (ConditionCode cc
, Vreg sf
) {
248 fwdJcc(v
, env
, ccNegate(cc
), sf
, taken
);
253 ///////////////////////////////////////////////////////////////////////////////