xref: /PHP-8.0/ext/opcache/jit/zend_jit_x86.h (revision a167e042)
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