forked from facebook/hhvm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcode-gen-x64.h
291 lines (243 loc) · 11.1 KB
/
code-gen-x64.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_VM_CG_X64_H_
#define incl_HPHP_VM_CG_X64_H_
#include "hphp/runtime/vm/jit/code-gen.h"
#include "hphp/runtime/vm/jit/arg-group.h"
#include "hphp/runtime/vm/jit/code-gen-helpers.h"
#include "hphp/runtime/vm/jit/target-profile.h"
#include "hphp/runtime/vm/jit/vasm-x64.h"
namespace HPHP { namespace jit {
namespace NativeCalls { struct CallInfo; }
namespace arm { struct CodeGenerator; }
namespace x64 {
// Cache alignment is required for mutable instructions to make sure
// mutations don't "tear" on remote cpus.
constexpr size_t kCacheLineSize = 64;
constexpr size_t kCacheLineMask = kCacheLineSize - 1;
struct CodeGenerator {
friend struct arm::CodeGenerator;
CodeGenerator(CodegenState& state, Vout& main, Vout& cold)
: m_state(state)
, m_vmain(main)
, m_vcold(cold)
{}
void cgInst(IRInstruction* inst);
private:
Vloc srcLoc(const IRInstruction* inst, unsigned i) const;
Vloc dstLoc(const IRInstruction* inst, unsigned i) const;
ArgGroup argGroup(const IRInstruction* inst) const;
// Autogenerate function declarations for each IR instruction in ir-opcode.h
#define O(name, dsts, srcs, flags) void cg##name(IRInstruction* inst);
IR_OPCODES
#undef O
void cgCallNative(Vout& v, IRInstruction* inst);
CallDest callDest(Vreg reg0) const;
CallDest callDest(Vreg reg0, Vreg reg1) const;
CallDest callDest(const IRInstruction*) const;
CallDest callDestTV(const IRInstruction*) const;
CallDest callDestDbl(const IRInstruction*) const;
template<class Arg>
CppCall arrayCallIfLowMem(const IRInstruction* inst, Arg vtable) const;
// Main call helper:
void cgCallHelper(Vout& v, CppCall call, const CallDest& dstInfo,
SyncOptions sync, ArgGroup& args);
void cgInterpOneCommon(IRInstruction* inst);
enum class Width { Value, Full };
void emitStore(Vptr dst, SSATmp* src, Vloc src_loc, Width);
void emitStoreTypedValue(Vptr dst, SSATmp* src, Vloc src_loc);
void emitLoad(SSATmp* dst, Vloc dstLoc, Vptr base);
void emitLoadTypedValue(SSATmp* dst, Vloc dstLoc, Vptr ref);
template <class JmpFn>
void emitReffinessTest(IRInstruction* inst, Vreg sf, JmpFn doJcc);
template<class Loc1, class Loc2, class JmpFn>
void emitTypeTest(Type type, Loc1 typeSrc, Loc2 dataSrc, Vreg sf,
JmpFn doJcc);
template<class DataLoc, class JmpFn>
void emitSpecializedTypeTest(Type type, DataLoc data, Vreg sf, JmpFn doJcc);
template<class Loc>
void emitTypeCheck(Type type, Loc typeSrc,
Loc dataSrc, Block* taken);
template<class Loc>
void emitTypeGuard(const BCMarker& marker, Type type, Loc typeLoc,
Loc dataLoc);
void cgIncRefWork(Type type, SSATmp* src, Vloc srcLoc);
void cgDecRefWork(IRInstruction* inst, bool genZeroCheck);
template<class Emit> void cgBinaryDblOp(IRInstruction*, Emit);
template<class Op, class Opi> void cgShiftCommon(IRInstruction*);
void emitVerifyCls(IRInstruction* inst);
void emitGetCtxFwdCallWithThis(Vreg srcCtx, Vreg dstCtx, bool staticCallee);
Vreg emitGetCtxFwdCallWithThisDyn(Vreg destCtxReg, Vreg thisReg,
RDS::Handle ch);
void cgJcc(IRInstruction* inst); // helper
void cgReqBindJcc(IRInstruction* inst); // helper
void cgExitJcc(IRInstruction* inst); // helper
void cgJccInt(IRInstruction* inst); // helper
void cgReqBindJccInt(IRInstruction* inst); // helper
void cgExitJccInt(IRInstruction* inst); // helper
void emitCmpInt(IRInstruction* inst, ConditionCode cc);
void emitCmpEqDbl(IRInstruction* inst, ComparisonPred pred);
void emitCmpRelDbl(IRInstruction* inst, ConditionCode cc, bool flipOperands);
void cgCmpHelper(IRInstruction* inst, ConditionCode cc,
int64_t (*str_cmp_str)(StringData*, StringData*),
int64_t (*str_cmp_int)(StringData*, int64_t),
int64_t (*str_cmp_obj)(StringData*, ObjectData*),
int64_t (*obj_cmp_obj)(ObjectData*, ObjectData*),
int64_t (*obj_cmp_int)(ObjectData*, int64_t),
int64_t (*arr_cmp_arr)(ArrayData*, ArrayData*));
void emitReqBindJcc(Vout& v, ConditionCode cc, Vreg sf,
const ReqBindJccData*);
Vreg emitCompare(Vout& v, IRInstruction* inst);
Vreg emitCompareInt(Vout& v, IRInstruction* inst);
Vreg emitTestZero(Vout& v, SSATmp* src, Vloc srcLoc);
template<class Inst>
bool emitIncDec(Vout& v, Vloc dst, SSATmp* src0, Vloc loc0,
SSATmp* src1, Vloc loc1, Vreg& sf);
Vreg emitAddInt(Vout& v, IRInstruction* inst);
Vreg emitSubInt(Vout& v, IRInstruction* inst);
Vreg emitMulInt(Vout& v, IRInstruction* inst);
private:
Vreg selectScratchReg(IRInstruction* inst);
RegSet findFreeRegs(IRInstruction* inst);
void emitSetCc(IRInstruction*, ConditionCode cc, Vreg sf);
template<class JmpFn>
void emitIsTypeTest(IRInstruction* inst, Vreg sf, JmpFn doJcc);
void cgIsTypeCommon(IRInstruction* inst, bool negate);
void cgIsTypeMemCommon(IRInstruction*, bool negate);
Vreg emitInstanceBitmaskCheck(Vout& v, IRInstruction* inst);
void emitInitObjProps(const IRInstruction* inst, Vreg dstReg,
const Class* cls, size_t nProps);
bool decRefDestroyIsUnlikely(const IRInstruction* inst,
OptDecRefProfile& profile, Type type);
template <typename F>
void cgCheckStaticBitAndDecRef(Vout& v, const IRInstruction* inst,
Vlabel done, Type type,
Vreg dataReg, F destroyImpl);
void cgCheckStaticBitAndDecRef(Vout& v, const IRInstruction* inst,
Vlabel done, Type type,
Vreg dataReg);
void cgCheckRefCountedType(Vreg typeReg, Vlabel done);
void cgCheckRefCountedType(Vreg baseReg, int64_t offset, Vlabel done);
void cgDecRefStaticType(Vout&, const IRInstruction* inst, Type type,
Vreg dataReg, bool genZeroCheck);
void cgDecRefDynamicType(const IRInstruction* inst, Vreg typeReg,
Vreg dataReg, bool genZeroCheck);
void cgDecRefDynamicTypeMem(const IRInstruction* inst, Vreg baseReg,
int64_t offset);
void cgDecRefMem(const IRInstruction* inst, Type type, Vreg baseReg,
int64_t offset);
void cgIterNextCommon(IRInstruction* inst);
void cgIterInitCommon(IRInstruction* inst);
void cgMIterNextCommon(IRInstruction* inst);
void cgMIterInitCommon(IRInstruction* inst);
Vreg cgLdFuncCachedCommon(IRInstruction* inst, Vreg dst);
void cgLookupCnsCommon(IRInstruction* inst);
RDS::Handle cgLdClsCachedCommon(Vout& v, IRInstruction* inst, Vreg dst,
Vreg sf);
void cgDefineModifiedStkPtr(IRInstruction*);
void cgPropImpl(IRInstruction*);
void cgVGetPropImpl(IRInstruction*);
void cgBindPropImpl(IRInstruction*);
void cgSetPropImpl(IRInstruction*);
void cgSetOpPropImpl(IRInstruction*);
void cgIncDecPropImpl(IRInstruction*);
void cgIssetEmptyPropImpl(IRInstruction*);
void cgElemImpl(IRInstruction*);
void cgElemArrayImpl(IRInstruction*);
void cgVGetElemImpl(IRInstruction*);
void cgArraySetImpl(IRInstruction*);
void cgSetElemImpl(IRInstruction*);
void cgUnsetElemImpl(IRInstruction*);
void cgIssetEmptyElemImpl(IRInstruction*);
Vlabel label(Block*);
void emitFwdJcc(Vout& v, ConditionCode cc, Vreg sf, Block* target);
static const Func* getFunc(const BCMarker& marker) {
return marker.func();
};
static const Class* getClass(const BCMarker& marker) {
return getFunc(marker)->cls();
}
static const Unit* getUnit(const BCMarker& marker) {
return getFunc(marker)->unit();
}
static bool resumed(const BCMarker& marker) {
return marker.resumed();
};
Fixup makeFixup(const BCMarker& marker,
SyncOptions sync = SyncOptions::kSyncPoint);
int iterOffset(const BCMarker& marker, uint32_t id);
void emitConvBoolOrIntToDbl(IRInstruction* inst);
void cgLdClsMethodCacheCommon(IRInstruction* inst, Offset offset);
void emitLdRaw(IRInstruction* inst, size_t extraOff);
void emitStRaw(IRInstruction* inst, size_t offset, int size);
void resumableStResumeImpl(IRInstruction*, ptrdiff_t, ptrdiff_t);
void emitStoreTypedValue(Vout& v, Vreg base, ptrdiff_t offset,
Vloc src, Type srcType);
/*
* Execute the code emitted by 'taken' only if the given condition code is
* true.
*/
template <class Block>
void ifBlock(Vout& v, Vout& vcold, ConditionCode cc, Vreg sf, Block taken,
bool unlikely = false);
/*
* Generate an if-block that branches around some unlikely code, handling
* the cases when a == acold and a != acold. cc is the branch condition
* to run the unlikely block.
*
* Passes the proper assembler to use to the unlikely function.
*/
template <class Then>
void unlikelyIfBlock(Vout& v, Vout& vcold, ConditionCode cc, Vreg sf,
Then then);
// Generate an if-then-else block
template <class Then, class Else>
void ifThenElse(Vout& v, ConditionCode cc, Vreg sf, Then thenBlock,
Else elseBlock);
// Generate an if-then-else block into m_as.
template <class Then, class Else>
void ifThenElse(Vout& v, Vout& vcold, ConditionCode cc, Vreg sf,
Then thenBlock, Else elseBlock, bool unlikely = false);
/*
* Same as ifThenElse except the first block is off in acold
*/
template <class Then, class Else>
void unlikelyIfThenElse(Vout& v, Vout& vcold, ConditionCode cc, Vreg sf,
Then unlikelyBlock, Else elseBlock);
// This is for printing partially-generated traces when debugging
void print() const;
Vout& vmain() { return m_vmain; }
Vout& vcold() { return m_vcold; }
private:
CodegenState& m_state;
Vout& m_vmain;
Vout& m_vcold;
};
// Helpers to compute a reference to a TypedValue type and data
inline Vptr refTVType(Vreg reg) {
return reg[TVOFF(m_type)];
}
inline Vptr refTVData(Vreg reg) {
return reg[TVOFF(m_data)];
}
inline Vptr refTVType(Vptr ref) {
return ref + TVOFF(m_type);
}
inline Vptr refTVData(Vptr ref) {
return ref + TVOFF(m_data);
}
}}}
#endif