1 /*
2 +----------------------------------------------------------------------+
3 | Zend JIT |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
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 +----------------------------------------------------------------------+
15 | Authors: Dmitry Stogov <dmitry@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifndef HAVE_JIT_X86_H
20 #define HAVE_JIT_X86_H
21
22 typedef enum _zend_reg {
23 ZREG_NONE = -1,
24
25 ZREG_R0,
26 ZREG_R1,
27 ZREG_R2,
28 ZREG_R3,
29 ZREG_R4,
30 ZREG_R5,
31 ZREG_R6,
32 ZREG_R7,
33
34 #if defined(__x86_64__) || defined(_WIN64)
35 ZREG_R8,
36 ZREG_R9,
37 ZREG_R10,
38 ZREG_R11,
39 ZREG_R12,
40 ZREG_R13,
41 ZREG_R14,
42 ZREG_R15,
43 #endif
44
45 ZREG_XMM0,
46 ZREG_XMM1,
47 ZREG_XMM2,
48 ZREG_XMM3,
49 ZREG_XMM4,
50 ZREG_XMM5,
51 ZREG_XMM6,
52 ZREG_XMM7,
53
54 #if defined(__x86_64__) || defined(_WIN64)
55 ZREG_XMM8,
56 ZREG_XMM9,
57 ZREG_XMM10,
58 ZREG_XMM11,
59 ZREG_XMM12,
60 ZREG_XMM13,
61 ZREG_XMM14,
62 ZREG_XMM15,
63 #endif
64
65 ZREG_NUM,
66
67 ZREG_THIS, /* used for delayed FETCH_THIS deoptimization */
68
69 /* pseudo constants used by deoptimizer */
70 ZREG_LONG_MIN_MINUS_1,
71 ZREG_LONG_MIN,
72 ZREG_LONG_MAX,
73 ZREG_LONG_MAX_PLUS_1,
74 ZREG_NULL,
75
76 ZREG_ZVAL_TRY_ADDREF,
77 ZREG_ZVAL_COPY_R0,
78 } zend_reg;
79
80 typedef struct _zend_jit_registers_buf {
81 #if defined(__x86_64__) || defined(_WIN64)
82 uint64_t r[16];
83 double xmm[16];
84 #else
85 uint32_t r[8];
86 double xmm[8];
87 #endif
88 } zend_jit_registers_buf;
89
90 #define ZREG_RAX ZREG_R0
91 #define ZREG_RCX ZREG_R1
92 #define ZREG_RDX ZREG_R2
93 #define ZREG_RBX ZREG_R3
94 #define ZREG_RSP ZREG_R4
95 #define ZREG_RBP ZREG_R5
96 #define ZREG_RSI ZREG_R6
97 #define ZREG_RDI ZREG_R7
98
99 #ifdef _WIN64
100 # define ZREG_FP ZREG_R14
101 # define ZREG_IP ZREG_R15
102 # define ZREG_RX ZREG_IP
103 # define ZREG_FCARG1a ZREG_RCX
104 # define ZREG_FCARG2a ZREG_RDX
105 #elif defined(__x86_64__)
106 # define ZREG_FP ZREG_R14
107 # define ZREG_IP ZREG_R15
108 # define ZREG_RX ZREG_IP
109 # define ZREG_FCARG1a ZREG_RDI
110 # define ZREG_FCARG2a ZREG_RSI
111 #else
112 # define ZREG_FP ZREG_RSI
113 # define ZREG_IP ZREG_RDI
114 # define ZREG_RX ZREG_IP
115 # define ZREG_FCARG1a ZREG_RCX
116 # define ZREG_FCARG2a ZREG_RDX
117 #endif
118
119 extern const char *zend_reg_name[];
120
121 typedef uint32_t zend_regset;
122
123 #define ZEND_REGSET_EMPTY 0
124
125 #define ZEND_REGSET_IS_EMPTY(regset) \
126 (regset == ZEND_REGSET_EMPTY)
127
128 #define ZEND_REGSET(reg) \
129 (1u << (reg))
130
131 #define ZEND_REGSET_INTERVAL(reg1, reg2) \
132 (((1u << ((reg2) - (reg1) + 1)) - 1) << (reg1))
133
134 #define ZEND_REGSET_IN(regset, reg) \
135 (((regset) & ZEND_REGSET(reg)) != 0)
136
137 #define ZEND_REGSET_INCL(regset, reg) \
138 (regset) |= ZEND_REGSET(reg)
139
140 #define ZEND_REGSET_EXCL(regset, reg) \
141 (regset) &= ~ZEND_REGSET(reg)
142
143 #define ZEND_REGSET_UNION(set1, set2) \
144 ((set1) | (set2))
145
146 #define ZEND_REGSET_INTERSECTION(set1, set2) \
147 ((set1) & (set2))
148
149 #define ZEND_REGSET_DIFFERENCE(set1, set2) \
150 ((set1) & ~(set2))
151
152 #ifdef _WIN64
153 # define ZEND_REGSET_FIXED \
154 (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
155 # define ZEND_REGSET_GP \
156 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
157 # define ZEND_REGSET_FP \
158 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
159 # define ZEND_REGSET_SCRATCH \
160 (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
161 # define ZEND_REGSET_PRESERVED \
162 (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI))
163 #elif defined(__x86_64__)
164 # define ZEND_REGSET_FIXED \
165 (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
166 # define ZEND_REGSET_GP \
167 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
168 # define ZEND_REGSET_FP \
169 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
170 # define ZEND_REGSET_SCRATCH \
171 (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
172 # define ZEND_REGSET_PRESERVED \
173 (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13))
174 #else
175 # define ZEND_REGSET_FIXED \
176 (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDI))
177 # define ZEND_REGSET_GP \
178 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R7), ZEND_REGSET_FIXED)
179 # define ZEND_REGSET_FP \
180 ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM7), ZEND_REGSET_FIXED)
181 # define ZEND_REGSET_SCRATCH \
182 (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET_FP)
183 # define ZEND_REGSET_PRESERVED \
184 (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP))
185 #endif
186
187 #ifndef _WIN32
188 #define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctz(set))
189 #define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clz(set)^31)))
190 #else
191 #include <intrin.h>
__zend_jit_ctz(uint32_t value)192 uint32_t __inline __zend_jit_ctz( uint32_t value ) {
193 DWORD trailing_zero = 0;
194 if (_BitScanForward(&trailing_zero, value)) {
195 return trailing_zero;
196 }
197 return 32;
198 }
__zend_jit_clz(uint32_t value)199 uint32_t __inline __zend_jit_clz(uint32_t value) {
200 DWORD leading_zero = 0;
201 if (_BitScanReverse(&leading_zero, value)) {
202 return 31 - leading_zero;
203 }
204 return 32;
205 }
206 #define ZEND_REGSET_FIRST(set) ((zend_reg)__zend_jit_ctz(set))
207 #define ZEND_REGSET_LAST(set) ((zend_reg)(__zend_jit_clz(set)^31)))
208 #endif
209
210 #define ZEND_REGSET_FOREACH(set, reg) \
211 do { \
212 zend_regset _tmp = (set); \
213 while (!ZEND_REGSET_IS_EMPTY(_tmp)) { \
214 zend_reg _reg = ZEND_REGSET_FIRST(_tmp); \
215 ZEND_REGSET_EXCL(_tmp, _reg); \
216 reg = _reg; \
217
218 #define ZEND_REGSET_FOREACH_END() \
219 } \
220 } while (0)
221
222 typedef uintptr_t zend_jit_addr;
223
224 #define IS_CONST_ZVAL 0
225 #define IS_MEM_ZVAL 1
226 #define IS_REG 2
227
228 #define _ZEND_ADDR_MODE_MASK 0x3
229 #define _ZEND_ADDR_REG_SHIFT 2
230 #define _ZEND_ADDR_REG_MASK 0x3f
231 #define _ZEND_ADDR_OFFSET_SHIFT 8
232 #define _ZEND_ADDR_REG_STORE_BIT 8
233 #define _ZEND_ADDR_REG_LOAD_BIT 9
234 #define _ZEND_ADDR_REG_LAST_USE_BIT 10
235
236 #define ZEND_ADDR_CONST_ZVAL(zv) \
237 (((zend_jit_addr)(uintptr_t)(zv)) | IS_CONST_ZVAL)
238 #define ZEND_ADDR_MEM_ZVAL(reg, offset) \
239 ((((zend_jit_addr)(uintptr_t)(offset)) << _ZEND_ADDR_OFFSET_SHIFT) | \
240 (((zend_jit_addr)(uintptr_t)(reg)) << _ZEND_ADDR_REG_SHIFT) | \
241 IS_MEM_ZVAL)
242 #define ZEND_ADDR_REG(reg) \
243 ((((zend_jit_addr)(uintptr_t)(reg)) << _ZEND_ADDR_REG_SHIFT) | \
244 IS_REG)
245
246 #define Z_MODE(addr) (((addr) & _ZEND_ADDR_MODE_MASK))
247 #define Z_ZV(addr) ((zval*)(addr))
248 #define Z_OFFSET(addr) ((uint32_t)((addr)>>_ZEND_ADDR_OFFSET_SHIFT))
249 #define Z_REG(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_SHIFT) & _ZEND_ADDR_REG_MASK))
250 #define Z_STORE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_STORE_BIT) & 1))
251 #define Z_LOAD(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LOAD_BIT) & 1))
252 #define Z_LAST_USE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LAST_USE_BIT) & 1))
253
254 #define OP_REG_EX(reg, store, load, last_use) \
255 ((reg) | \
256 ((store) ? (1 << (_ZEND_ADDR_REG_STORE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
257 ((load) ? (1 << (_ZEND_ADDR_REG_LOAD_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
258 ((last_use) ? (1 << (_ZEND_ADDR_REG_LAST_USE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) \
259 )
260
261 #define OP_REG(ssa_op, op) \
262 (ra && ssa_op->op >= 0 && ra[ssa_op->op] ? \
263 OP_REG_EX(ra[ssa_op->op]->reg, \
264 (ra[ssa_op->op]->flags & ZREG_STORE), \
265 (ra[ssa_op->op]->flags & ZREG_LOAD), \
266 zend_ival_is_last_use(ra[ssa_op->op], ssa_op - ssa->ops) \
267 ) : ZREG_NONE)
268
_zend_jit_decode_op(zend_uchar op_type,znode_op op,const zend_op * opline,zend_reg reg)269 static zend_always_inline zend_jit_addr _zend_jit_decode_op(zend_uchar op_type, znode_op op, const zend_op *opline, zend_reg reg)
270 {
271 if (op_type == IS_CONST) {
272 #if ZEND_USE_ABS_CONST_ADDR
273 return ZEND_ADDR_CONST_ZVAL(op.zv);
274 #else
275 return ZEND_ADDR_CONST_ZVAL(RT_CONSTANT(opline, op));
276 #endif
277 } else {
278 ZEND_ASSERT(op_type & (IS_CV|IS_TMP_VAR|IS_VAR));
279 if (reg != ZREG_NONE) {
280 return ZEND_ADDR_REG(reg);
281 } else {
282 return ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
283 }
284 }
285 }
286
287 #define OP_ADDR(opline, type, op) \
288 _zend_jit_decode_op((opline)->type, (opline)->op, opline, ZREG_NONE)
289
290 #define OP1_ADDR() \
291 OP_ADDR(opline, op1_type, op1)
292 #define OP2_ADDR() \
293 OP_ADDR(opline, op2_type, op2)
294 #define RES_ADDR() \
295 OP_ADDR(opline, result_type, result)
296 #define OP1_DATA_ADDR() \
297 OP_ADDR(opline + 1, op1_type, op1)
298
299 #define OP_REG_ADDR(opline, type, _op, _ssa_op) \
300 _zend_jit_decode_op((opline)->type, (opline)->_op, opline, \
301 OP_REG(ssa_op, _ssa_op))
302
303 #define OP1_REG_ADDR() \
304 OP_REG_ADDR(opline, op1_type, op1, op1_use)
305 #define OP2_REG_ADDR() \
306 OP_REG_ADDR(opline, op2_type, op2, op2_use)
307 #define RES_REG_ADDR() \
308 OP_REG_ADDR(opline, result_type, result, result_def)
309 #define OP1_DATA_REG_ADDR() \
310 OP_REG_ADDR(opline + 1, op1_type, op1, op1_use)
311
312 #define OP1_DEF_REG_ADDR() \
313 OP_REG_ADDR(opline, op1_type, op1, op1_def)
314 #define OP2_DEF_REG_ADDR() \
315 OP_REG_ADDR(opline, op2_type, op2, op2_def)
316 #define RES_USE_REG_ADDR() \
317 OP_REG_ADDR(opline, result_type, result, result_use)
318 #define OP1_DATA_DEF_REG_ADDR() \
319 OP_REG_ADDR(opline + 1, op1_type, op1, op1_def)
320
zend_jit_same_addr(zend_jit_addr addr1,zend_jit_addr addr2)321 static zend_always_inline zend_bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_addr addr2)
322 {
323 if (addr1 == addr2) {
324 return 1;
325 } else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) {
326 return Z_REG(addr1) == Z_REG(addr2);
327 }
328 return 0;
329 }
330
331 #endif /* ZEND_JIT_X86_H */
332