/src/php-src/ext/opcache/jit/ir/ir.h
Line | Count | Source |
1 | | /* |
2 | | * IR - Lightweight JIT Compilation Framework |
3 | | * (Public API) |
4 | | * This file is part of the IR Project distributed under the MIT-style LICENSE. |
5 | | * Authors: Dmitry Stogov <dmitry@php.net> |
6 | | */ |
7 | | |
8 | | #ifndef IR_H |
9 | | #define IR_H |
10 | | |
11 | | #ifdef __cplusplus |
12 | | extern "C" { |
13 | | #endif |
14 | | |
15 | | #include <inttypes.h> |
16 | | #include <stdint.h> |
17 | | #include <stdbool.h> |
18 | | #include <stdio.h> |
19 | | #include <stdlib.h> |
20 | | |
21 | | #define IR_VERSION "0.0.1" |
22 | | |
23 | | #ifdef _WIN32 |
24 | | /* TODO Handle ARM, too. */ |
25 | | # if defined(_M_X64) || defined(_M_ARM64) |
26 | | # define __SIZEOF_SIZE_T__ 8 |
27 | | # elif defined(_M_IX86) |
28 | | # define __SIZEOF_SIZE_T__ 4 |
29 | | # endif |
30 | | /* Only supported is little endian for any arch on Windows, |
31 | | so just fake the same for all. */ |
32 | | # ifndef __ORDER_LITTLE_ENDIAN__ |
33 | | # define __ORDER_LITTLE_ENDIAN__ 1 |
34 | | # endif |
35 | | # define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
36 | | # ifndef __has_builtin |
37 | | # define __has_builtin(arg) (0) |
38 | | # endif |
39 | | #endif |
40 | | |
41 | | /* target auto detection */ |
42 | | #if !defined(IR_TARGET_X86) && !defined(IR_TARGET_X64) && !defined(IR_TARGET_AARCH64) |
43 | | # if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) |
44 | | # define IR_TARGET_X64 |
45 | | # elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86) |
46 | | # define IR_TARGET_X86 |
47 | | # elif defined(__aarch64__) || defined(_M_ARM64) |
48 | | # define IR_TARGET_AARCH64 |
49 | | # elif defined (_WIN64) |
50 | | # define IR_TARGET_X64 |
51 | | # elif defined (_WIN32) |
52 | | # define IR_TARGET_X86 |
53 | | # endif |
54 | | #endif |
55 | | |
56 | | #ifndef IR_TARGET_TRIPLET |
57 | | # if defined(IR_TARGET_X64) |
58 | | # if defined(_WIN32) |
59 | | # define IR_TARGET_TRIPLET "x86-windows-msvc" |
60 | | # elif defined(__APPLE__) |
61 | | # define IR_TARGET_TRIPLET "x86-darwin" |
62 | | # elif defined(__linux__) |
63 | | # define IR_TARGET_TRIPLET "x86-linux-sysv" |
64 | | # elif defined(__FreeBSD__) |
65 | | # define IR_TARGET_TRIPLET "x86-freebsd-sysv" |
66 | | # elif defined(__NetBSD__) |
67 | | # define IR_TARGET_TRIPLET "x86-netbsd-sysv" |
68 | | # elif defined(__OpenBSD__) |
69 | | # define IR_TARGET_TRIPLET "x86-openbsd-sysv" |
70 | | # else |
71 | | # define IR_TARGET_TRIPLET "x86-unknown-sysv" |
72 | | # endif |
73 | | # elif defined(IR_TARGET_X86) |
74 | | # if defined(_WIN32) |
75 | | # define IR_TARGET_TRIPLET "x86_64-windows-msvc" |
76 | | # elif defined(__APPLE__) |
77 | | # define IR_TARGET_TRIPLET "x86_64-darwin" |
78 | | # elif defined(__linux__) |
79 | | # define IR_TARGET_TRIPLET "x86_64-linux-sysv" |
80 | | # elif defined(__FreeBSD__) |
81 | | # define IR_TARGET_TRIPLET "x86_64-freebsd-sysv" |
82 | | # elif defined(__NetBSD__) |
83 | | # define IR_TARGET_TRIPLET "x86_64-netbsd-sysv" |
84 | | # elif defined(__OpenBSD__) |
85 | | # define IR_TARGET_TRIPLET "x86_64-openbsd-sysv" |
86 | | # else |
87 | | # define IR_TARGET_TRIPLET "x86_64-unknown-sysv" |
88 | | # endif |
89 | | # elif defined(IR_TARGET_AARCH64) |
90 | | # if defined(_WIN32) |
91 | | # define IR_TARGET_TRIPLET "aarch64-windows" |
92 | | # elif defined(__APPLE__) |
93 | | # define IR_TARGET_TRIPLET "aarch64-darwin" |
94 | | # elif defined(__linux__) |
95 | | # define IR_TARGET_TRIPLET "aarch64-linux-sysv" |
96 | | # elif defined(__FreeBSD__) |
97 | | # define IR_TARGET_TRIPLET "aarch64-freebsd-sysv" |
98 | | # elif defined(__NetBSD__) |
99 | | # define IR_TARGET_TRIPLET "aarch64-netbsd-sysv" |
100 | | # elif defined(__OpenBSD__) |
101 | | # define IR_TARGET_TRIPLET "aarch64-openbsd-sysv" |
102 | | # else |
103 | | # define IR_TARGET_TRIPLET "aarch64-unknown-sysv" |
104 | | # endif |
105 | | # else |
106 | | # error "Unknown IR_TARGET" |
107 | | # endif |
108 | | #endif |
109 | | |
110 | | #if defined(__SIZEOF_SIZE_T__) |
111 | | # if __SIZEOF_SIZE_T__ == 8 |
112 | | # define IR_64 1 |
113 | | # elif __SIZEOF_SIZE_T__ != 4 |
114 | | # error "Unknown addr size" |
115 | | # endif |
116 | | #else |
117 | | # error "Unknown addr size" |
118 | | #endif |
119 | | |
120 | | #if defined(__BYTE_ORDER__) |
121 | | # if defined(__ORDER_LITTLE_ENDIAN__) |
122 | | # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
123 | | # define IR_STRUCT_LOHI(lo, hi) struct {lo; hi;} |
124 | | # endif |
125 | | # endif |
126 | | # if defined(__ORDER_BIG_ENDIAN__) |
127 | | # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
128 | | # define IR_STRUCT_LOHI(lo, hi) struct {hi; lo;} |
129 | | # endif |
130 | | # endif |
131 | | #endif |
132 | | #ifndef IR_STRUCT_LOHI |
133 | | # error "Unknown byte order" |
134 | | #endif |
135 | | |
136 | | #ifdef __has_attribute |
137 | | # if __has_attribute(always_inline) |
138 | | # define IR_ALWAYS_INLINE static inline __attribute__((always_inline)) |
139 | | # endif |
140 | | # if __has_attribute(noinline) |
141 | | # define IR_NEVER_INLINE __attribute__((noinline)) |
142 | | # endif |
143 | | #else |
144 | | # define __has_attribute(x) 0 |
145 | | #endif |
146 | | |
147 | | #ifndef IR_ALWAYS_INLINE |
148 | | # define IR_ALWAYS_INLINE static inline |
149 | | #endif |
150 | | #ifndef IR_NEVER_INLINE |
151 | | # define IR_NEVER_INLINE |
152 | | #endif |
153 | | |
154 | | #ifdef IR_PHP |
155 | | # include "ir_php.h" |
156 | | #endif |
157 | | |
158 | | #ifdef IR_TARGET_X86 |
159 | | # ifndef IR_X86_I64 |
160 | | # define IR_X86_I64 1 |
161 | | # endif |
162 | | #else |
163 | | # define IR_X86_I64 0 |
164 | | #endif |
165 | | |
166 | | #ifndef IR_SIMD |
167 | | # define IR_SIMD 1 |
168 | | #endif |
169 | | |
170 | | /* IR Type flags */ |
171 | | #define IR_TYPE_SIGNED (1<<0) |
172 | | #define IR_TYPE_UNSIGNED (1<<1) |
173 | | #define IR_TYPE_FP (1<<2) |
174 | | #define IR_TYPE_SPECIAL (1<<3) |
175 | | #define IR_TYPE_BOOL (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED) |
176 | | #define IR_TYPE_ADDR (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED) |
177 | | #define IR_TYPE_CHAR (IR_TYPE_SPECIAL|IR_TYPE_SIGNED) |
178 | | |
179 | | /* List of IR types */ |
180 | | #define IR_TYPES(_) \ |
181 | | _(BOOL, bool, b, IR_TYPE_BOOL) \ |
182 | | _(U8, uint8_t, u8, IR_TYPE_UNSIGNED) \ |
183 | | _(U16, uint16_t, u16, IR_TYPE_UNSIGNED) \ |
184 | | _(U32, uint32_t, u32, IR_TYPE_UNSIGNED) \ |
185 | | _(U64, uint64_t, u64, IR_TYPE_UNSIGNED) \ |
186 | | _(ADDR, uintptr_t, addr, IR_TYPE_ADDR) \ |
187 | | _(CHAR, char, c, IR_TYPE_CHAR) \ |
188 | | _(I8, int8_t, i8, IR_TYPE_SIGNED) \ |
189 | | _(I16, int16_t, i16, IR_TYPE_SIGNED) \ |
190 | | _(I32, int32_t, i32, IR_TYPE_SIGNED) \ |
191 | | _(I64, int64_t, i64, IR_TYPE_SIGNED) \ |
192 | | _(DOUBLE, double, d, IR_TYPE_FP) \ |
193 | | _(FLOAT, float, f, IR_TYPE_FP) \ |
194 | | |
195 | 3.26k | #define IR_IS_TYPE_UNSIGNED(t) ((t) < IR_CHAR) |
196 | 119k | #define IR_IS_TYPE_SIGNED(t) ((t) >= IR_CHAR && (t) < IR_DOUBLE) |
197 | 3.04M | #define IR_IS_TYPE_INT(t) ((t) < IR_DOUBLE) |
198 | 476k | #define IR_IS_TYPE_FP(t) ((t) >= IR_DOUBLE && (t) <= IR_FLOAT) |
199 | | |
200 | | #define IR_TYPE_ENUM(name, type, field, flags) IR_ ## name, |
201 | | |
202 | | typedef enum _ir_type { |
203 | | IR_VOID, |
204 | | IR_TYPES(IR_TYPE_ENUM) |
205 | | IR_LAST_TYPE, |
206 | | |
207 | | IR_BASE_TYPE_MASK = 0x0f, |
208 | | IR_VECTOR_MASK = 0x70, |
209 | | |
210 | | IR_VECTOR_1 = 0x10, |
211 | | IR_VECTOR_2 = 0x20, |
212 | | IR_VECTOR_4 = 0x30, |
213 | | IR_VECTOR_8 = 0x40, |
214 | | IR_VECTOR_16 = 0x50, |
215 | | IR_VECTOR_32 = 0x60, |
216 | | IR_VECTOR_64 = 0x70, |
217 | | } ir_type; |
218 | | |
219 | 16.1k | #define IR_IS_TYPE_SCALAR(t) (((t) & IR_VECTOR_MASK) == 0) |
220 | 554k | #define IR_IS_TYPE_VECTOR(t) (((t) & IR_VECTOR_MASK) != 0) |
221 | | |
222 | 0 | #define IR_VECTOR_BASE_TYPE(t) ((t) & IR_BASE_TYPE_MASK) |
223 | 0 | #define IR_VECTOR_LENGTH(t) (1U << ((((t) & IR_VECTOR_MASK) >> 4) - 1)) |
224 | | |
225 | | #ifdef IR_64 |
226 | | # define IR_SIZE_T IR_U64 |
227 | | # define IR_SSIZE_T IR_I64 |
228 | 60 | # define IR_UINTPTR_T IR_U64 |
229 | 30 | # define IR_INTPTR_T IR_I64 |
230 | | # define IR_C_UINTPTR IR_U64 |
231 | | # define IR_C_INTPTR IR_I64 |
232 | | # define ir_const_size_t ir_const_u64 |
233 | | # define ir_const_ssize_t ir_const_i64 |
234 | | # define ir_const_uintptr_t ir_const_u64 |
235 | | # define ir_const_intptr_t ir_const_i64 |
236 | | #else |
237 | | # define IR_SIZE_T IR_U32 |
238 | | # define IR_SSIZE_T IR_I32 |
239 | | # define IR_UINTPTR_T IR_U32 |
240 | | # define IR_INTPTR_T IR_I32 |
241 | | # define IR_C_UINTPTR IR_U32 |
242 | | # define IR_C_INTPTR IR_I32 |
243 | | # define ir_const_size_t ir_const_u32 |
244 | | # define ir_const_ssize_t ir_const_i32 |
245 | | # define ir_const_uintptr_t ir_const_u32 |
246 | | # define ir_const_intptr_t ir_const_i32 |
247 | | #endif |
248 | | |
249 | | /* List of IR opcodes |
250 | | * ================== |
251 | | * |
252 | | * Each instruction is described by a type (opcode, flags, op1_type, op2_type, op3_type) |
253 | | * |
254 | | * flags |
255 | | * ----- |
256 | | * v - void |
257 | | * d - data IR_OP_FLAG_DATA |
258 | | * r - ref IR_OP_FLAG_DATA alias |
259 | | * p - pinned IR_OP_FLAG_DATA + IR_OP_FLAG_PINNED |
260 | | * c - control IR_OP_FLAG_CONTROL |
261 | | * S - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_START |
262 | | * E - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END |
263 | | * T - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END + IR_OP_FLAG_TERMINATOR |
264 | | * l - load IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_LOAD |
265 | | * s - store IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_STORE |
266 | | * x - call IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_CALL |
267 | | * a - alloc IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_ALLOC |
268 | | * 0-3 - number of input edges |
269 | | * N - number of arguments is defined in the insn->inputs_count (MERGE, PHI, CALL) |
270 | | * X1-X3 - number of extra data ops |
271 | | * C - commutative operation ("d2C" => IR_OP_FLAG_DATA + IR_OP_FLAG_COMMUTATIVE) |
272 | | * |
273 | | * operand types |
274 | | * ------------- |
275 | | * ___ - unused |
276 | | * def - reference to a definition op (data-flow use-def dependency edge) |
277 | | * ref - memory reference (data-flow use-def dependency edge) |
278 | | * var - variable reference (data-flow use-def dependency edge) |
279 | | * arg - argument reference CALL/TAILCALL/CARG->CARG |
280 | | * src - reference to a previous control region (IF, IF_TRUE, IF_FALSE, MERGE, LOOP_BEGIN, LOOP_END, RETURN) |
281 | | * reg - data-control dependency on region (PHI, VAR, PARAM) |
282 | | * grd - optional data-control dependency guard (DIV, MOD) |
283 | | * ret - reference to a previous RETURN instruction (RETURN) |
284 | | * str - string: variable/argument name (VAR, PARAM, CALL, TAILCALL) |
285 | | * num - number: argument number (PARAM) |
286 | | * prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT) |
287 | | * opt - optional number |
288 | | * alg - optional alignment |
289 | | * pro - function prototype |
290 | | * lbl - label used as value (a reference to constant): (BEGIN) |
291 | | * |
292 | | * The order of IR opcodes is carefully selected for efficient folding. |
293 | | * - foldable instruction go first |
294 | | * - NOP is never used (code 0 is used as ANY pattern) |
295 | | * - CONST is the most often used instruction (encode with 1 bit) |
296 | | * - equality inversion: EQ <-> NE => op =^ 1 |
297 | | * - comparison inversion: [U]LT <-> [U]GT, [U]LE <-> [U]GE => op =^ 3 |
298 | | */ |
299 | | |
300 | | #define IR_OPS(_) \ |
301 | | /* special op (must be the first !!!) */ \ |
302 | | _(NOP, v, ___, ___, ___) /* empty instruction */ \ |
303 | | \ |
304 | | /* constants reference */ \ |
305 | | _(C_BOOL, r0, ___, ___, ___) /* constant */ \ |
306 | | _(C_U8, r0, ___, ___, ___) /* constant */ \ |
307 | | _(C_U16, r0, ___, ___, ___) /* constant */ \ |
308 | | _(C_U32, r0, ___, ___, ___) /* constant */ \ |
309 | | _(C_U64, r0, ___, ___, ___) /* constant */ \ |
310 | | _(C_ADDR, r0, ___, ___, ___) /* constant */ \ |
311 | | _(C_CHAR, r0, ___, ___, ___) /* constant */ \ |
312 | | _(C_I8, r0, ___, ___, ___) /* constant */ \ |
313 | | _(C_I16, r0, ___, ___, ___) /* constant */ \ |
314 | | _(C_I32, r0, ___, ___, ___) /* constant */ \ |
315 | | _(C_I64, r0, ___, ___, ___) /* constant */ \ |
316 | | _(C_DOUBLE, r0, ___, ___, ___) /* constant */ \ |
317 | | _(C_FLOAT, r0, ___, ___, ___) /* constant */ \ |
318 | | \ |
319 | | /* equality ops */ \ |
320 | | _(EQ, d2C, def, def, ___) /* equal */ \ |
321 | | _(NE, d2C, def, def, ___) /* not equal */ \ |
322 | | \ |
323 | | /* comparison ops (order matters, LT must be a modulo of 4 !!!) */ \ |
324 | | _(LT, d2, def, def, ___) /* less (signed) */ \ |
325 | | _(GE, d2, def, def, ___) /* greater or equal (signed) */ \ |
326 | | _(LE, d2, def, def, ___) /* less or equal (signed) */ \ |
327 | | _(GT, d2, def, def, ___) /* greater (signed) */ \ |
328 | | _(ULT, d2, def, def, ___) /* unsigned less */ \ |
329 | | _(UGE, d2, def, def, ___) /* unsigned greater or equal */ \ |
330 | | _(ULE, d2, def, def, ___) /* unsigned less or equal */ \ |
331 | | _(UGT, d2, def, def, ___) /* unsigned greater */ \ |
332 | | _(ORDERED, d2, def, def, ___) /* both operands are not NAN */ \ |
333 | | _(UNORDERED, d2, def, def, ___) /* one of operands is NAN */ \ |
334 | | \ |
335 | | /* arithmetic ops */ \ |
336 | | _(ADD, d2C, def, def, ___) /* addition */ \ |
337 | | _(SUB, d2, def, def, ___) /* subtraction (must be ADD+1) */ \ |
338 | | _(MUL, d2C, def, def, ___) /* multiplication */ \ |
339 | | _(DIV, d3, def, def, grd) /* division */ \ |
340 | | _(MOD, d3, def, def, grd) /* modulo */ \ |
341 | | _(NEG, d1, def, ___, ___) /* change sign */ \ |
342 | | _(ABS, d1, def, ___, ___) /* absolute value */ \ |
343 | | /* (LDEXP, MIN, MAX, FPMATH) */ \ |
344 | | \ |
345 | | /* type conversion ops */ \ |
346 | | _(SEXT, d1, def, ___, ___) /* sign extension */ \ |
347 | | _(ZEXT, d1, def, ___, ___) /* zero extension */ \ |
348 | | _(TRUNC, d1, def, ___, ___) /* truncates to int type */ \ |
349 | | _(BITCAST, d1, def, ___, ___) /* binary representation */ \ |
350 | | _(INT2FP, d1, def, ___, ___) /* int to float conversion */ \ |
351 | | _(FP2INT, d1, def, ___, ___) /* float to int conversion */ \ |
352 | | _(FP2FP, d1, def, ___, ___) /* float to float conversion */ \ |
353 | | _(PROTO, d1X1, def, pro, ___) /* apply function prototype */ \ |
354 | | \ |
355 | | /* overflow-check */ \ |
356 | | _(ADD_OV, d2C, def, def, ___) /* addition */ \ |
357 | | _(SUB_OV, d2, def, def, ___) /* subtraction */ \ |
358 | | _(MUL_OV, d2C, def, def, ___) /* multiplication */ \ |
359 | | _(OVERFLOW, d1, def, ___, ___) /* overflow check add/sub/mul */ \ |
360 | | \ |
361 | | /* bitwise and shift ops */ \ |
362 | | _(NOT, d1, def, ___, ___) /* bitwise NOT */ \ |
363 | | _(OR, d2C, def, def, ___) /* bitwise OR */ \ |
364 | | _(AND, d2C, def, def, ___) /* bitwise AND */ \ |
365 | | _(XOR, d2C, def, def, ___) /* bitwise XOR */ \ |
366 | | _(SHL, d2, def, def, ___) /* logic shift left */ \ |
367 | | _(SHR, d2, def, def, ___) /* logic shift right */ \ |
368 | | _(SAR, d2, def, def, ___) /* arithmetic shift right */ \ |
369 | | _(ROL, d2, def, def, ___) /* rotate left */ \ |
370 | | _(ROR, d2, def, def, ___) /* rotate right */ \ |
371 | | _(BSWAP, d1, def, ___, ___) /* byte swap */ \ |
372 | | _(CTPOP, d1, def, ___, ___) /* count population */ \ |
373 | | _(CTLZ, d1, def, ___, ___) /* count leading zeros */ \ |
374 | | _(CTTZ, d1, def, ___, ___) /* count trailing zeros */ \ |
375 | | \ |
376 | | /* branch-less conditional ops */ \ |
377 | | _(MIN, d2C, def, def, ___) /* min(op1, op2) */ \ |
378 | | _(MAX, d2C, def, def, ___) /* max(op1, op2) */ \ |
379 | | _(COND, d3, def, def, def) /* op1 ? op2 : op3 */ \ |
380 | | \ |
381 | | /* SIMD vector ops */ \ |
382 | | _(EXTRACT, d2, def, def, ___) /* get element of vector */ \ |
383 | | _(REPLACE, d3, def, def, def) /* set element of vector */ \ |
384 | | _(SPLAT, d1, def, ___, ___) /* set all elements of vector */ \ |
385 | | _(SHUFFLE, d3, def, def, def) /* shuffle elements of vectors */ \ |
386 | | \ |
387 | | /* data-flow and miscellaneous ops */ \ |
388 | | _(VADDR, d1, var, ___, ___) /* load address of local var */ \ |
389 | | _(FRAME_ADDR, d0, ___, ___, ___) /* function frame address */ \ |
390 | | _(PHI, pN, reg, def, def) /* SSA Phi function */ \ |
391 | | _(COPY, d1X1, def, opt, ___) /* COPY (last foldable op) */ \ |
392 | | _(PI, p2, reg, def, ___) /* e-SSA Pi constraint ??? */ \ |
393 | | _(ARGVAL, d1X2, def, num, num) /* pass struct arg by value */ \ |
394 | | /* (op2 - size, op3 - align) */ \ |
395 | | /* (USE, RENAME) */ \ |
396 | | \ |
397 | | /* data ops */ \ |
398 | | _(PARAM, p1X2, reg, str, num) /* incoming parameter proj. */ \ |
399 | | _(VAR, p1X2, reg, str, alg) /* local variable */ \ |
400 | | _(FUNC_ADDR, r0, ___, ___, ___) /* constant func ref */ \ |
401 | | _(FUNC, r0, ___, ___, ___) /* constant func ref */ \ |
402 | | _(SYM, r0, ___, ___, ___) /* constant symbol ref */ \ |
403 | | _(LABEL, r0, ___, ___, ___) /* label address ref */ \ |
404 | | _(STR, r0, ___, ___, ___) /* constant str ref */ \ |
405 | | _(LONG_CONST, r0, ___, ___, ___) /* long constant (vector) */ \ |
406 | | \ |
407 | | /* call ops */ \ |
408 | | _(CALL, xN, src, def, def) /* CALL(src, func, args...) */ \ |
409 | | _(TAILCALL, xN, src, def, def) /* CALL+RETURN */ \ |
410 | | \ |
411 | | /* memory reference and load/store ops */ \ |
412 | | _(ALLOCA, a2X1, src, def, alg) /* alloca(def) */ \ |
413 | | _(AFREE, s2, src, def, ___) /* revert alloca(def) */ \ |
414 | | _(BLOCK_BEGIN, a1, src, ___, ___) /* stacksave */ \ |
415 | | _(BLOCK_END, s2, src, def, ___) /* stackrestore */ \ |
416 | | _(VLOAD, l2, src, var, ___) /* load value of local var */ \ |
417 | | _(VLOAD_v, l2, src, var, ___) /* volatile variant of VLOAD */ \ |
418 | | _(VSTORE, s3, src, var, def) /* store value to local var */ \ |
419 | | _(VSTORE_v, s3, src, var, def) /* volatile variant of VSTORE */ \ |
420 | | _(RLOAD, l1X2, src, num, opt) /* load value from register */ \ |
421 | | _(RSTORE, s2X1, src, def, num) /* store value into register */ \ |
422 | | _(LOAD, l2, src, ref, ___) /* load from memory */ \ |
423 | | _(LOAD_v, l2, src, ref, ___) /* volatile variant of VLOAD */ \ |
424 | | _(STORE, s3, src, ref, def) /* store to memory */ \ |
425 | | _(STORE_v, s3, src, ref, def) /* volatile variant of VSTORE */ \ |
426 | | _(TLS_ADDR, l1X2, src, num, num) /* TLS_ADDR(_, module, offset) */ \ |
427 | | /* for static TLS module is -1 */ \ |
428 | | _(TRAP, x1, src, ___, ___) /* DebugBreak */ \ |
429 | | /* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \ |
430 | | \ |
431 | | /* va_args */ \ |
432 | | _(VA_START, x2, src, def, ___) /* va_start(va_list) */ \ |
433 | | _(VA_END, x2, src, def, ___) /* va_end(va_list) */ \ |
434 | | _(VA_COPY, x3, src, def, def) /* va_copy(dst, stc) */ \ |
435 | | _(VA_ARG, x2X1, src, def, opt) /* va_arg(va_list) */ \ |
436 | | /* op3 - (size<<3)+log2(align) */ \ |
437 | | \ |
438 | | /* guards */ \ |
439 | | _(GUARD, c3, src, def, def) /* IF without second successor */ \ |
440 | | _(GUARD_NOT , c3, src, def, def) /* IF without second successor */ \ |
441 | | \ |
442 | | /* deoptimization */ \ |
443 | | _(SNAPSHOT, xN, src, def, def) /* SNAPSHOT(src, args...) */ \ |
444 | | \ |
445 | | /* control-flow nodes */ \ |
446 | | _(START, S0X1, ret, ___, ___) /* function start */ \ |
447 | | _(ENTRY, S1X1, src, num, ___) /* entry with a fake src edge */ \ |
448 | | _(BEGIN, S1X1, src, lbl, ___) /* block start, optional &&lbl */ \ |
449 | | _(IF_TRUE, S1X1, src, prb, ___) /* IF TRUE proj. */ \ |
450 | | _(IF_FALSE, S1X1, src, prb, ___) /* IF FALSE proj. */ \ |
451 | | _(CASE_VAL, S2X1, src, def, prb) /* switch proj. */ \ |
452 | | _(CASE_RANGE, S3, src, def, def) /* switch proj. */ \ |
453 | | _(CASE_DEFAULT, S1X1, src, prb, ___) /* switch proj. */ \ |
454 | | _(MERGE, SN, src, src, src) /* control merge */ \ |
455 | | _(LOOP_BEGIN, SN, src, src, src) /* loop start */ \ |
456 | | _(END, E1, src, ___, ___) /* block end */ \ |
457 | | _(LOOP_END, E1, src, ___, ___) /* loop end */ \ |
458 | | _(IF, E2, src, def, ___) /* conditional control split */ \ |
459 | | _(SWITCH, E2, src, def, ___) /* multi-way control split */ \ |
460 | | _(IGOTO, E2, src, def, ___) /* computed goto (internal) */ \ |
461 | | _(IJMP, T2X1, src, def, ret) /* computed goto (terminating) */ \ |
462 | | _(RETURN, T2X1, src, def, ret) /* function return */ \ |
463 | | _(UNREACHABLE, T1X2, src, ___, ret) /* unreachable (tailcall, etc) */ \ |
464 | | \ |
465 | | /* inline assembler */ \ |
466 | | _(ASM, xN, src, def, def) /* GCC inline assembler */ \ |
467 | | /* op2 - asm template string */ \ |
468 | | /* op3 - asm constraint string */ \ |
469 | | /* opN - asm input argument */ \ |
470 | | _(ASM_OUT, x1, src, ___, ___) /* ASM data output projection */ \ |
471 | | _(ASM_GOTO, E1, src, ___, ___) /* ASM goto (bb end after ASM) */ \ |
472 | | \ |
473 | | /* deoptimization helper */ \ |
474 | | _(EXITCALL, x2, src, def, ___) /* save CPU regs and call op2 */ \ |
475 | | |
476 | | |
477 | | #define IR_OP_ENUM(name, flags, op1, op2, op3) IR_ ## name, |
478 | | |
479 | | typedef enum _ir_op { |
480 | | IR_OPS(IR_OP_ENUM) |
481 | | #ifdef IR_PHP |
482 | | IR_PHP_OPS(IR_OP_ENUM) |
483 | | #endif |
484 | | IR_LAST_OP |
485 | | } ir_op; |
486 | | |
487 | | /* IR Opcode and Type Union */ |
488 | 1.07M | #define IR_OPT_OP_MASK 0x00ff |
489 | 14.0k | #define IR_OPT_TYPE_MASK 0xff00 |
490 | 1.58M | #define IR_OPT_TYPE_SHIFT 8 |
491 | 282k | #define IR_OPT_INPUTS_SHIFT 16 |
492 | | |
493 | 1.35M | #define IR_OPT(op, type) ((uint16_t)(op) | ((uint16_t)(type) << IR_OPT_TYPE_SHIFT)) |
494 | 216k | #define IR_OPTX(op, type, n) ((uint32_t)(op) | ((uint32_t)(type) << IR_OPT_TYPE_SHIFT) | ((uint32_t)(n) << IR_OPT_INPUTS_SHIFT)) |
495 | 13.9k | #define IR_OPT_TYPE(opt) (((opt) & IR_OPT_TYPE_MASK) >> IR_OPT_TYPE_SHIFT) |
496 | | |
497 | | /* "opt" modifiers */ |
498 | 7.36k | #define IR_COPY_HARD (1<<0) |
499 | | |
500 | 0 | #define IR_VA_ARG_SIZE(op3) (((uint32_t)(op3) >> 3)) |
501 | 0 | #define IR_VA_ARG_ALIGN(op3) (1U << ((uint32_t)(op3) & 0x7)) |
502 | 0 | #define IR_VA_ARG_OP3(s, a) (((s) << 3) | ir_ntzl(a)) |
503 | | |
504 | | /* IR Reference: index of ir_insn in ir_ctx.ir_base[], positive - instructions, negaive - constants */ |
505 | | typedef int32_t ir_ref; |
506 | | |
507 | 15.2M | #define IR_IS_CONST_REF(ref) ((ref) < 0) |
508 | | |
509 | | /* IR String: string index; positive - index in ir_strtab, negative - resolved through loader.get_str() */ |
510 | | typedef int32_t ir_str; |
511 | | |
512 | 44 | #define IR_IS_EXT_STR(str) ((str) < 0) |
513 | | #define IR_EXT_STR(str) (-(str)) |
514 | | |
515 | | /* IR Constant Value */ |
516 | 17.3M | #define IR_UNUSED 0 |
517 | 68.7k | #define IR_NULL (-1) |
518 | 74.5k | #define IR_FALSE (-2) |
519 | 877k | #define IR_TRUE (-3) |
520 | 191k | #define IR_LAST_FOLDABLE_OP IR_COPY |
521 | | |
522 | | #define IR_CONSTS_LIMIT_MIN (-(IR_TRUE - 1)) |
523 | | #define IR_INSNS_LIMIT_MIN (IR_UNUSED + 1) |
524 | | |
525 | | /* ADDR_MEMBER is neccessary to workaround MSVC C preprocessor bug */ |
526 | | #ifndef IR_64 |
527 | | # define ADDR_MEMBER uintptr_t addr; \ |
528 | | void *ptr; |
529 | | #else |
530 | | # define ADDR_MEMBER |
531 | | #endif |
532 | | typedef union _ir_val { |
533 | | double d; |
534 | | uint64_t u64; |
535 | | int64_t i64; |
536 | | #ifdef IR_64 |
537 | | uintptr_t addr; |
538 | | void *ptr; |
539 | | #endif |
540 | | IR_STRUCT_LOHI( |
541 | | union { |
542 | | uint32_t u32; |
543 | | int32_t i32; |
544 | | float f; |
545 | | ADDR_MEMBER |
546 | | ir_str name; |
547 | | ir_str str; |
548 | | IR_STRUCT_LOHI( |
549 | | union { |
550 | | uint16_t u16; |
551 | | int16_t i16; |
552 | | IR_STRUCT_LOHI( |
553 | | union { |
554 | | uint8_t u8; |
555 | | int8_t i8; |
556 | | bool b; |
557 | | char c; |
558 | | }, |
559 | | uint8_t u8_hi |
560 | | ); |
561 | | }, |
562 | | uint16_t u16_hi |
563 | | ); |
564 | | }, |
565 | | uint32_t u32_hi |
566 | | ); |
567 | | } ir_val; |
568 | | #undef ADDR_MEMBER |
569 | | |
570 | | /* IR Instruction */ |
571 | | typedef struct _ir_insn { |
572 | | IR_STRUCT_LOHI( |
573 | | union { |
574 | | IR_STRUCT_LOHI( |
575 | | union { |
576 | | IR_STRUCT_LOHI( |
577 | | uint8_t op, |
578 | | uint8_t type |
579 | | ); |
580 | | uint16_t opt; |
581 | | }, |
582 | | union { |
583 | | uint16_t inputs_count; /* number of input control edges for MERGE, PHI, CALL, TAILCALL */ |
584 | | uint16_t prev_insn_offset; /* 16-bit backward offset from current instruction for CSE */ |
585 | | uint16_t proto; |
586 | | uint16_t long_const_size; |
587 | | } |
588 | | ); |
589 | | uint32_t optx; |
590 | | ir_ref ops[1]; |
591 | | }, |
592 | | union { |
593 | | ir_ref op1; |
594 | | ir_ref ref; |
595 | | ir_ref prev_const; |
596 | | } |
597 | | ); |
598 | | union { |
599 | | IR_STRUCT_LOHI( |
600 | | ir_ref op2, |
601 | | ir_ref op3 |
602 | | ); |
603 | | ir_val val; |
604 | | }; |
605 | | } ir_insn; |
606 | | |
607 | | /* IR Hash Tables API (private) */ |
608 | | typedef struct _ir_hashtab ir_hashtab; |
609 | | |
610 | | /* IR String Tables API (implementation in ir_strtab.c) */ |
611 | | typedef struct _ir_strtab { |
612 | | void *data; |
613 | | uint32_t mask; |
614 | | uint32_t size; |
615 | | uint32_t count; |
616 | | uint32_t pos; |
617 | | char *buf; |
618 | | uint32_t buf_size; |
619 | | uint32_t buf_top; |
620 | | } ir_strtab; |
621 | | |
622 | 64 | #define ir_strtab_count(strtab) (strtab)->count |
623 | | |
624 | | typedef void (*ir_strtab_apply_t)(const char *str, uint32_t len, ir_str val); |
625 | | |
626 | | void ir_strtab_init(ir_strtab *strtab, uint32_t count, uint32_t buf_size); |
627 | | ir_str ir_strtab_lookup(ir_strtab *strtab, const char *str, uint32_t len, ir_str val); |
628 | | ir_str ir_strtab_find(const ir_strtab *strtab, const char *str, uint32_t len); |
629 | | ir_str ir_strtab_update(ir_strtab *strtab, const char *str, uint32_t len, ir_str val); |
630 | | void ir_strtab_set(ir_strtab *strtab, const char *str, uint32_t len, ir_str val); |
631 | | const char *ir_strtab_str(const ir_strtab *strtab, ir_str idx); |
632 | | const char *ir_strtab_strl(const ir_strtab *strtab, ir_str idx, size_t *len); |
633 | | void ir_strtab_apply(const ir_strtab *strtab, ir_strtab_apply_t func); |
634 | | void ir_strtab_free(ir_strtab *strtab); |
635 | | |
636 | | /* IR Context Flags */ |
637 | | #define IR_PROTO_MASK 0xff |
638 | 207k | #define IR_CALL_CONV_MASK 0x0f |
639 | | |
640 | 22.9k | #define IR_VARARG_FUNC (1<<4) |
641 | 0 | #define IR_CONST_FUNC (1<<5) |
642 | 0 | #define IR_PURE_FUNC (1<<6) |
643 | | |
644 | | #define IR_CONST (1<<5) |
645 | | #define IR_INITIALIZED (1<<6) /* sym data flag: constant or an initialized variable */ |
646 | | #define IR_CONST_STRING (1<<7) /* sym data flag: constant string */ |
647 | | |
648 | 39.3k | #define IR_FUNCTION (1<<8) /* Generate a function. */ |
649 | 0 | #define IR_STATIC (1<<9) |
650 | | #define IR_EXTERN (1<<10) |
651 | | |
652 | 307k | #define IR_USE_FRAME_POINTER (1<<11) |
653 | 19.4k | #define IR_NO_STACK_COMBINE (1<<12) |
654 | 13.1k | #define IR_GEN_ENDBR (1<<13) |
655 | 12.4k | #define IR_GEN_CACHE_DEMOTE (1<<14) /* Demote the generated code from closest CPU caches */ |
656 | | |
657 | 9.95k | #define IR_SKIP_PROLOGUE (1<<15) /* Don't generate function prologue. */ |
658 | 2.51k | #define IR_START_BR_TARGET (1<<16) |
659 | 0 | #define IR_ENTRY_BR_TARGET (1<<17) |
660 | 9.92k | #define IR_MERGE_EMPTY_ENTRIES (1<<18) |
661 | | |
662 | | #define IR_OPT_INLINE (1<<19) |
663 | 9.96k | #define IR_OPT_FOLDING (1<<20) |
664 | 86.9k | #define IR_OPT_CFG (1<<21) /* merge BBs, by remove END->BEGIN nodes during CFG construction */ |
665 | | #define IR_OPT_MEM2SSA (1<<22) |
666 | 10.5k | #define IR_OPT_CODEGEN (1<<23) |
667 | 9.93k | #define IR_OPT_TAILCALL (1<<24) |
668 | | |
669 | | /* debug related */ |
670 | | #ifdef IR_DEBUG |
671 | 9.93k | # define IR_DEBUG_SCCP (1<<26) |
672 | 13.9k | # define IR_DEBUG_GCM (1<<27) |
673 | 2.07k | # define IR_DEBUG_GCM_SPLIT (1<<28) |
674 | 651k | # define IR_DEBUG_SCHEDULE (1<<29) |
675 | 496k | # define IR_DEBUG_RA (1<<30) |
676 | 27.3k | # define IR_DEBUG_BB_SCHEDULE (1U<<31) |
677 | | #endif |
678 | | |
679 | | /* Calling Conventions */ |
680 | 563k | #define IR_CC_DEFAULT 0x00 |
681 | 0 | #define IR_CC_BUILTIN 0x01 |
682 | 42.4k | #define IR_CC_FASTCALL 0x02 |
683 | 0 | #define IR_CC_PRESERVE_NONE 0x03 |
684 | | |
685 | | #if defined(IR_TARGET_X64) |
686 | 0 | # define IR_CC_X86_64_SYSV 0x08 |
687 | 0 | # define IR_CC_X86_64_MS 0x09 |
688 | | #elif defined(IR_TARGET_AARCH64) |
689 | | # define IR_CC_AARCH64_SYSV 0x08 |
690 | | # define IR_CC_AARCH64_DARWIN 0x09 |
691 | | #endif |
692 | | |
693 | | /* Deprecated constants */ |
694 | | #define IR_BUILTIN_FUNC IR_CC_BUILTIN |
695 | 22.6k | #define IR_FASTCALL_FUNC IR_CC_FASTCALL |
696 | | |
697 | | typedef struct _ir_ctx ir_ctx; |
698 | | typedef struct _ir_use_list ir_use_list; |
699 | | typedef struct _ir_block ir_block; |
700 | | typedef struct _ir_arena ir_arena; |
701 | | typedef struct _ir_live_interval ir_live_interval; |
702 | | typedef struct _ir_live_range ir_live_range; |
703 | | typedef struct _ir_loader ir_loader; |
704 | | typedef int8_t ir_regs[4]; |
705 | | |
706 | | typedef void (*ir_snapshot_create_t)(ir_ctx *ctx, ir_ref addr); |
707 | | |
708 | | #if defined(IR_TARGET_AARCH64) |
709 | | typedef const void *(*ir_get_exit_addr_t)(uint32_t exit_num); |
710 | | typedef const void *(*ir_get_veneer_t)(ir_ctx *ctx, const void *addr); |
711 | | typedef bool (*ir_set_veneer_t)(ir_ctx *ctx, const void *addr, const void *veneer); |
712 | | #endif |
713 | | |
714 | | typedef struct _ir_code_buffer { |
715 | | void *start; |
716 | | void *end; |
717 | | void *pos; |
718 | | } ir_code_buffer; |
719 | | |
720 | | typedef struct { |
721 | | int size; |
722 | | int align; |
723 | | } ir_value_param; |
724 | | |
725 | | typedef struct _ir_bitqueue ir_bitqueue; |
726 | | |
727 | 20.3k | #define IR_CONST_HASH_SIZE 64 |
728 | | |
729 | | struct _ir_ctx { |
730 | | ir_insn *ir_base; /* two directional array - instructions grow down, constants grow up */ |
731 | | ir_ref insns_count; /* number of instructions stored in instructions buffer */ |
732 | | ir_ref insns_limit; /* size of allocated instructions buffer (it's extended when overflow) */ |
733 | | ir_ref consts_count; /* number of constants stored in constants buffer */ |
734 | | ir_ref consts_limit; /* size of allocated constants buffer (it's extended when overflow) */ |
735 | | uintptr_t const_hash_mask; |
736 | | ir_ref *const_hash; |
737 | | uint32_t flags; /* IR context flags (see IR_* defines above) */ |
738 | | uint32_t flags2; /* IR context private flags (see IR_* defines in ir_private.h) */ |
739 | | ir_type ret_type; /* Function return type */ |
740 | | uint32_t mflags; /* CPU specific flags (see IR_X86_... macros below) */ |
741 | | int32_t status; /* non-zero error code (see IR_ERROR_... macros), app may use negative codes */ |
742 | | ir_ref fold_cse_limit; /* CSE finds identical insns backward from "insn_count" to "fold_cse_limit" */ |
743 | | ir_insn fold_insn; /* temporary storage for folding engine */ |
744 | | ir_bitqueue *iter_worklist; |
745 | | ir_value_param *value_params; /* information about "by-val" struct parameters */ |
746 | | ir_hashtab *binding; |
747 | | ir_use_list *use_lists; /* def->use lists for each instruction */ |
748 | | ir_ref *use_edges; /* the actual uses: use = ctx->use_edges[ctx->use_lists[def].refs + n] */ |
749 | | ir_ref use_edges_count; /* number of elements in use_edges[] array */ |
750 | | uint32_t cfg_blocks_count; /* number of elements in cfg_blocks[] array */ |
751 | | uint32_t cfg_edges_count; /* number of elements in cfg_edges[] array */ |
752 | | ir_block *cfg_blocks; /* list of basic blocks (starts from 1) */ |
753 | | uint32_t *cfg_edges; /* the actual basic blocks predecessors and successors edges */ |
754 | | uint32_t *cfg_map; /* map of instructions to basic block number */ |
755 | | uint32_t *cfg_schedule; /* BB order for code generation */ |
756 | | uint32_t *rules; /* array of target specific code-generation rules (for each instruction) */ |
757 | | int32_t *vregs; /* map of insns to virtual regs (positive) or stack slots (negative) */ |
758 | | int32_t vregs_count; |
759 | | ir_str func_name; /* Function name (should be set through ir_string()/ir_stringl()) */ |
760 | | int32_t spill_base; /* base register for special spill area (e.g. PHP VM frame pointer) */ |
761 | | uint64_t fixed_regset; /* fixed registers, excluded for regular register allocation */ |
762 | | int32_t fixed_stack_red_zone; /* reusable stack allocated by caller (default 0) */ |
763 | | int32_t fixed_stack_frame_size; /* fixed stack allocated by generated code for spills and registers save/restore */ |
764 | | int32_t fixed_call_stack_size; /* fixed preallocated stack for parameter passing (default 0) */ |
765 | | uint64_t fixed_save_regset; /* registers that always saved/restored in prologue/epilogue */ |
766 | | uint32_t locals_area_size; |
767 | | uint32_t gp_reg_params; |
768 | | uint32_t fp_reg_params; |
769 | | int32_t param_stack_size; |
770 | | ir_live_interval **live_intervals; |
771 | | ir_arena *arena; |
772 | | ir_live_range *unused_ranges; |
773 | | ir_regs *regs; |
774 | | int8_t *tmp_regs; /* additional tmp registers, used for COND(I64, _, _) and SIMD */ |
775 | | ir_strtab *fused_regs; |
776 | | ir_ref *prev_ref; |
777 | | union { |
778 | | void *data; |
779 | | ir_ref control; /* used by IR construction API (see ir_builder.h) */ |
780 | | ir_ref bb_start; /* used by target CPU instruction matcher */ |
781 | | ir_ref vars; /* list of VARs (used by register allocator) */ |
782 | | }; |
783 | | ir_snapshot_create_t snapshot_create; |
784 | | int32_t stack_frame_size; /* spill stack frame size (used by register allocator and code generator) */ |
785 | | int32_t call_stack_size; /* stack for parameter passing (used by register allocator and code generator) */ |
786 | | uint64_t used_preserved_regs; |
787 | | #ifdef IR_TARGET_X86 |
788 | | int32_t ret_slot; |
789 | | #endif |
790 | | uint32_t rodata_offset; |
791 | | uint32_t jmp_table_offset; |
792 | | uint32_t entries_count; |
793 | | uint32_t *entries; /* array of ENTRY blocks */ |
794 | | void *osr_entry_loads; |
795 | | ir_code_buffer *code_buffer; |
796 | | #if defined(IR_TARGET_AARCH64) |
797 | | int32_t deoptimization_exits; |
798 | | const void *deoptimization_exits_base; |
799 | | ir_get_exit_addr_t get_exit_addr; |
800 | | ir_get_veneer_t get_veneer; |
801 | | ir_set_veneer_t set_veneer; |
802 | | #endif |
803 | | ir_loader *loader; |
804 | | ir_strtab strtab; |
805 | | ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP + 1]; |
806 | | ir_ref _const_hash[IR_CONST_HASH_SIZE]; |
807 | | }; |
808 | | |
809 | | /* Basic IR Construction API (implementation in ir.c) */ |
810 | | void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit); |
811 | | void ir_free(ir_ctx *ctx); |
812 | | void ir_truncate(ir_ctx *ctx); |
813 | | |
814 | | ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type); |
815 | | ir_ref ir_const_i8(ir_ctx *ctx, int8_t c); |
816 | | ir_ref ir_const_i16(ir_ctx *ctx, int16_t c); |
817 | | ir_ref ir_const_i32(ir_ctx *ctx, int32_t c); |
818 | | ir_ref ir_const_i64(ir_ctx *ctx, int64_t c); |
819 | | ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c); |
820 | | ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c); |
821 | | ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c); |
822 | | ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c); |
823 | | ir_ref ir_const_bool(ir_ctx *ctx, bool c); |
824 | | ir_ref ir_const_char(ir_ctx *ctx, char c); |
825 | | ir_ref ir_const_float(ir_ctx *ctx, float c); |
826 | | ir_ref ir_const_double(ir_ctx *ctx, double c); |
827 | | ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c); |
828 | | |
829 | | ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_str proto); |
830 | | ir_ref ir_const_func(ir_ctx *ctx, ir_str str, ir_str proto); |
831 | | ir_ref ir_const_sym(ir_ctx *ctx, ir_str str); |
832 | | ir_ref ir_const_str(ir_ctx *ctx, ir_str str); |
833 | | ir_ref ir_const_label(ir_ctx *ctx, ir_str str); |
834 | | |
835 | | ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c); |
836 | | |
837 | | ir_ref ir_long_const(ir_ctx *ctx, ir_type type, size_t size); |
838 | | void *ir_long_const_ptr(ir_ctx *ctx, ir_ref ref); |
839 | | ir_ref ir_long_const_commit(ir_ctx *ctx, ir_ref ref); |
840 | | |
841 | | ir_ref ir_const_vector(ir_ctx *ctx, ir_type type); |
842 | | |
843 | | void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted); |
844 | | |
845 | | ir_str ir_string(ir_ctx *ctx, const char *s); |
846 | | ir_str ir_stringl(ir_ctx *ctx, const char *s, size_t len); |
847 | | const char *ir_get_str(const ir_ctx *ctx, ir_str idx); |
848 | | const char *ir_get_strl(const ir_ctx *ctx, ir_str idx, size_t *len); |
849 | | |
850 | | #define IR_MAX_PROTO_PARAMS 255 |
851 | | |
852 | | typedef struct _ir_proto_t { |
853 | | uint8_t flags; /* first 8 bits of ir_ctx.flags */ |
854 | | uint8_t ret_type; |
855 | | uint8_t params_count; |
856 | | uint8_t param_types[5]; |
857 | | } ir_proto_t; |
858 | | |
859 | | ir_str ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type); |
860 | | ir_str ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1); |
861 | | ir_str ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2); |
862 | | ir_str ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3); |
863 | | ir_str ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3, |
864 | | ir_type t4); |
865 | | ir_str ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3, |
866 | | ir_type t4, ir_type t5); |
867 | | ir_str ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_counts, uint8_t *param_types); |
868 | | |
869 | | ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3); |
870 | | |
871 | | ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt); |
872 | | ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1); |
873 | | ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2); |
874 | | ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3); |
875 | | |
876 | | ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count); |
877 | | void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val); |
878 | | ir_ref ir_get_op(const ir_ctx *ctx, ir_ref ref, int32_t n); |
879 | | |
880 | | IR_ALWAYS_INLINE void ir_set_op1(ir_ctx *ctx, ir_ref ref, ir_ref val) |
881 | 0 | { |
882 | 0 | ctx->ir_base[ref].op1 = val; |
883 | 0 | } Unexecuted instantiation: ir_cfg.c:ir_set_op1 Unexecuted instantiation: ir_check.c:ir_set_op1 Unexecuted instantiation: ir_dump.c:ir_set_op1 Unexecuted instantiation: ir_emit.c:ir_set_op1 Unexecuted instantiation: ir_gcm.c:ir_set_op1 Unexecuted instantiation: ir_gdb.c:ir_set_op1 Unexecuted instantiation: ir_patch.c:ir_set_op1 Unexecuted instantiation: ir_perf.c:ir_set_op1 Unexecuted instantiation: ir_ra.c:ir_set_op1 Unexecuted instantiation: ir_ra_simple.c:ir_set_op1 Unexecuted instantiation: ir_save.c:ir_set_op1 Unexecuted instantiation: ir_sccp.c:ir_set_op1 Unexecuted instantiation: ir_strtab.c:ir_set_op1 Unexecuted instantiation: ir.c:ir_set_op1 Unexecuted instantiation: zend_jit.c:ir_set_op1 |
884 | | |
885 | | IR_ALWAYS_INLINE void ir_set_op2(ir_ctx *ctx, ir_ref ref, ir_ref val) |
886 | 0 | { |
887 | 0 | ctx->ir_base[ref].op2 = val; |
888 | 0 | } Unexecuted instantiation: ir_cfg.c:ir_set_op2 Unexecuted instantiation: ir_check.c:ir_set_op2 Unexecuted instantiation: ir_dump.c:ir_set_op2 Unexecuted instantiation: ir_emit.c:ir_set_op2 Unexecuted instantiation: ir_gcm.c:ir_set_op2 Unexecuted instantiation: ir_gdb.c:ir_set_op2 Unexecuted instantiation: ir_patch.c:ir_set_op2 Unexecuted instantiation: ir_perf.c:ir_set_op2 Unexecuted instantiation: ir_ra.c:ir_set_op2 Unexecuted instantiation: ir_ra_simple.c:ir_set_op2 Unexecuted instantiation: ir_save.c:ir_set_op2 Unexecuted instantiation: ir_sccp.c:ir_set_op2 Unexecuted instantiation: ir_strtab.c:ir_set_op2 Unexecuted instantiation: ir.c:ir_set_op2 Unexecuted instantiation: zend_jit.c:ir_set_op2 |
889 | | |
890 | | IR_ALWAYS_INLINE void ir_set_op3(ir_ctx *ctx, ir_ref ref, ir_ref val) |
891 | 0 | { |
892 | 0 | ctx->ir_base[ref].op3 = val; |
893 | 0 | } Unexecuted instantiation: ir_cfg.c:ir_set_op3 Unexecuted instantiation: ir_check.c:ir_set_op3 Unexecuted instantiation: ir_dump.c:ir_set_op3 Unexecuted instantiation: ir_emit.c:ir_set_op3 Unexecuted instantiation: ir_gcm.c:ir_set_op3 Unexecuted instantiation: ir_gdb.c:ir_set_op3 Unexecuted instantiation: ir_patch.c:ir_set_op3 Unexecuted instantiation: ir_perf.c:ir_set_op3 Unexecuted instantiation: ir_ra.c:ir_set_op3 Unexecuted instantiation: ir_ra_simple.c:ir_set_op3 Unexecuted instantiation: ir_save.c:ir_set_op3 Unexecuted instantiation: ir_sccp.c:ir_set_op3 Unexecuted instantiation: ir_strtab.c:ir_set_op3 Unexecuted instantiation: ir.c:ir_set_op3 Unexecuted instantiation: zend_jit.c:ir_set_op3 |
894 | | |
895 | | IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n) |
896 | 507k | { |
897 | 507k | const ir_ref *p = insn->ops + n; |
898 | 507k | return *p; |
899 | 507k | } Line | Count | Source | 896 | 90 | { | 897 | 90 | const ir_ref *p = insn->ops + n; | 898 | 90 | return *p; | 899 | 90 | } |
Unexecuted instantiation: ir_check.c:ir_insn_op Unexecuted instantiation: ir_dump.c:ir_insn_op Line | Count | Source | 896 | 405k | { | 897 | 405k | const ir_ref *p = insn->ops + n; | 898 | 405k | return *p; | 899 | 405k | } |
Line | Count | Source | 896 | 2 | { | 897 | 2 | const ir_ref *p = insn->ops + n; | 898 | 2 | return *p; | 899 | 2 | } |
Unexecuted instantiation: ir_gdb.c:ir_insn_op Unexecuted instantiation: ir_patch.c:ir_insn_op Unexecuted instantiation: ir_perf.c:ir_insn_op Line | Count | Source | 896 | 101k | { | 897 | 101k | const ir_ref *p = insn->ops + n; | 898 | 101k | return *p; | 899 | 101k | } |
Unexecuted instantiation: ir_ra_simple.c:ir_insn_op Unexecuted instantiation: ir_save.c:ir_insn_op Line | Count | Source | 896 | 259 | { | 897 | 259 | const ir_ref *p = insn->ops + n; | 898 | 259 | return *p; | 899 | 259 | } |
Unexecuted instantiation: ir_strtab.c:ir_insn_op Unexecuted instantiation: ir.c:ir_insn_op Line | Count | Source | 896 | 591 | { | 897 | 591 | const ir_ref *p = insn->ops + n; | 898 | 591 | return *p; | 899 | 591 | } |
|
900 | | |
901 | | IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val) |
902 | 241k | { |
903 | 241k | ir_ref *p = insn->ops + n; |
904 | 241k | *p = val; |
905 | 241k | } Line | Count | Source | 902 | 81 | { | 903 | 81 | ir_ref *p = insn->ops + n; | 904 | 81 | *p = val; | 905 | 81 | } |
Unexecuted instantiation: ir_check.c:ir_insn_set_op Unexecuted instantiation: ir_dump.c:ir_insn_set_op Unexecuted instantiation: ir_emit.c:ir_insn_set_op Line | Count | Source | 902 | 1 | { | 903 | 1 | ir_ref *p = insn->ops + n; | 904 | 1 | *p = val; | 905 | 1 | } |
Unexecuted instantiation: ir_gdb.c:ir_insn_set_op Unexecuted instantiation: ir_patch.c:ir_insn_set_op Unexecuted instantiation: ir_perf.c:ir_insn_set_op Unexecuted instantiation: ir_ra.c:ir_insn_set_op Unexecuted instantiation: ir_ra_simple.c:ir_insn_set_op Unexecuted instantiation: ir_save.c:ir_insn_set_op Line | Count | Source | 902 | 184 | { | 903 | 184 | ir_ref *p = insn->ops + n; | 904 | 184 | *p = val; | 905 | 184 | } |
Unexecuted instantiation: ir_strtab.c:ir_insn_set_op Line | Count | Source | 902 | 241k | { | 903 | 241k | ir_ref *p = insn->ops + n; | 904 | 241k | *p = val; | 905 | 241k | } |
Unexecuted instantiation: zend_jit.c:ir_insn_set_op |
906 | | |
907 | | IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val) |
908 | 93 | { |
909 | 93 | int i, n = insn->inputs_count; |
910 | | |
911 | 151 | for (i = 1; i <= n; i++) { |
912 | 151 | if (ir_insn_op(insn, i) == val) { |
913 | 93 | return i; |
914 | 93 | } |
915 | 151 | } |
916 | 0 | return 0; |
917 | 93 | } Unexecuted instantiation: ir_cfg.c:ir_insn_find_op Unexecuted instantiation: ir_check.c:ir_insn_find_op Unexecuted instantiation: ir_dump.c:ir_insn_find_op Unexecuted instantiation: ir_emit.c:ir_insn_find_op Unexecuted instantiation: ir_gcm.c:ir_insn_find_op Unexecuted instantiation: ir_gdb.c:ir_insn_find_op Unexecuted instantiation: ir_patch.c:ir_insn_find_op Unexecuted instantiation: ir_perf.c:ir_insn_find_op Unexecuted instantiation: ir_ra.c:ir_insn_find_op Unexecuted instantiation: ir_ra_simple.c:ir_insn_find_op Unexecuted instantiation: ir_save.c:ir_insn_find_op ir_sccp.c:ir_insn_find_op Line | Count | Source | 908 | 93 | { | 909 | 93 | int i, n = insn->inputs_count; | 910 | | | 911 | 151 | for (i = 1; i <= n; i++) { | 912 | 151 | if (ir_insn_op(insn, i) == val) { | 913 | 93 | return i; | 914 | 93 | } | 915 | 151 | } | 916 | 0 | return 0; | 917 | 93 | } |
Unexecuted instantiation: ir_strtab.c:ir_insn_find_op Unexecuted instantiation: ir.c:ir_insn_find_op Unexecuted instantiation: zend_jit.c:ir_insn_find_op |
918 | | |
919 | | ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3); |
920 | | |
921 | | ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt); |
922 | | ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1); |
923 | | ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2); |
924 | | ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3); |
925 | | |
926 | | ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos); |
927 | | ir_ref ir_param_ex(ir_ctx *ctx, ir_type type, ir_ref region, ir_str name, int pos); |
928 | | ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name); |
929 | | ir_ref ir_var_ex(ir_ctx *ctx, ir_type type, ir_ref region, ir_str name); |
930 | | |
931 | | /* IR Binding */ |
932 | | ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def); |
933 | | ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref); |
934 | | |
935 | | /* Def -> Use lists */ |
936 | | void ir_build_def_use_lists(ir_ctx *ctx); |
937 | | |
938 | | /* SSA Construction */ |
939 | | int ir_mem2ssa(ir_ctx *ctx); |
940 | | |
941 | | /* CFG - Control Flow Graph (implementation in ir_cfg.c) */ |
942 | | int ir_build_cfg(ir_ctx *ctx); |
943 | | int ir_build_dominators_tree(ir_ctx *ctx); |
944 | | int ir_find_loops(ir_ctx *ctx); |
945 | | int ir_schedule_blocks(ir_ctx *ctx); |
946 | | void ir_reset_cfg(ir_ctx *ctx); |
947 | | |
948 | | /* SCCP - Sparse Conditional Constant Propagation (implementation in ir_sccp.c) */ |
949 | | int ir_sccp(ir_ctx *ctx); |
950 | | |
951 | | /* GCM - Global Code Motion and scheduling (implementation in ir_gcm.c) */ |
952 | | int ir_gcm(ir_ctx *ctx); |
953 | | int ir_schedule(ir_ctx *ctx); |
954 | | |
955 | | /* Liveness & Register Allocation (implementation in ir_ra.c) */ |
956 | 8.39M | #define IR_REG_NONE -1 |
957 | 1.31M | #define IR_REG_SPILL_LOAD (1<<6) |
958 | 1.22M | #define IR_REG_SPILL_STORE (1<<6) |
959 | 1.22M | #define IR_REG_SPILL_SPECIAL (1<<7) |
960 | | #define IR_REG_SPILLED(r) \ |
961 | 1.18M | ((r) & (IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) |
962 | | #define IR_REG_NUM(r) \ |
963 | 253k | ((int8_t)((r) == IR_REG_NONE ? IR_REG_NONE : ((r) & ~(IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)))) |
964 | | |
965 | | int ir_assign_virtual_registers(ir_ctx *ctx); |
966 | | int ir_compute_live_ranges(ir_ctx *ctx); |
967 | | int ir_coalesce(ir_ctx *ctx); |
968 | | int ir_compute_dessa_moves(ir_ctx *ctx); |
969 | | int ir_reg_alloc(ir_ctx *ctx); |
970 | | int ir_reg_alloc_simple(ir_ctx *ctx); |
971 | | |
972 | | #define ir_reg_alloc_O0(_ctx) ir_reg_alloc_simple(_ctx) |
973 | | |
974 | | int ir_regs_number(void); |
975 | | bool ir_reg_is_int(int32_t reg); |
976 | | const char *ir_reg_name(int8_t reg, ir_type type); |
977 | | int32_t ir_get_spill_slot_offset(const ir_ctx *ctx, ir_ref ref); |
978 | | |
979 | | /* Target CPU instruction selection and code generation (see ir_x86.c) */ |
980 | | int ir_match(ir_ctx *ctx); |
981 | | void *ir_emit_code(ir_ctx *ctx, size_t *size); |
982 | | |
983 | | bool ir_needs_thunk(const ir_code_buffer *code_buffer, void *addr); |
984 | | void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr); |
985 | | void ir_fix_thunk(void *thunk_entry, void *addr); |
986 | | |
987 | | #if defined(_MSC_VER) && defined(IR_TARGET_X86) |
988 | | /* MSVC doesn't enforce 16-byte stack alignment */ |
989 | | int ir_call_with_aligned_stack(int (*func)(int, const char**), int argc, const char **argv); |
990 | | #endif |
991 | | |
992 | | /* Target address resolution (implementation in ir_emit.c) */ |
993 | | void *ir_resolve_sym_name(const char *name); |
994 | | |
995 | | /* Target CPU disassembler (implementation in ir_disasm.c) */ |
996 | | int ir_disasm_init(void); |
997 | | void ir_disasm_free(void); |
998 | | void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size); |
999 | | const char* ir_disasm_find_symbol(uint64_t addr, int64_t *offset); |
1000 | | int ir_disasm(const char *name, |
1001 | | const void *start, |
1002 | | size_t size, |
1003 | | bool asm_addr, |
1004 | | ir_ctx *ctx, |
1005 | | FILE *f); |
1006 | | |
1007 | | /* Linux perf interface (implementation in ir_perf.c) */ |
1008 | | int ir_perf_jitdump_open(void); |
1009 | | int ir_perf_jitdump_close(void); |
1010 | | int ir_perf_jitdump_register(const char *name, const void *start, size_t size); |
1011 | | void ir_perf_map_register(const char *name, const void *start, size_t size); |
1012 | | |
1013 | | /* GDB JIT interface (implementation in ir_gdb.c) */ |
1014 | | int ir_gdb_register(const char *name, |
1015 | | const void *start, |
1016 | | size_t size, |
1017 | | uint32_t sp_offset, |
1018 | | uint32_t sp_adjustment); |
1019 | | void ir_gdb_unregister_all(void); |
1020 | | bool ir_gdb_present(void); |
1021 | | |
1022 | | /* IR load API (implementation in ir_load.c) */ |
1023 | 0 | #define IR_RESOLVE_SYM_ADD_THUNK (1<<0) |
1024 | 0 | #define IR_RESOLVE_SYM_SILENT (1<<1) |
1025 | | |
1026 | | struct _ir_loader { |
1027 | | uint32_t default_func_flags; |
1028 | | bool (*init_module) (ir_loader *loader, const char *name, const char *filename, const char *target); |
1029 | | bool (*external_sym_dcl) (ir_loader *loader, const char *name, uint32_t flags); |
1030 | | bool (*external_func_dcl) (ir_loader *loader, const char *name, |
1031 | | uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types); |
1032 | | bool (*forward_func_dcl) (ir_loader *loader, const char *name, |
1033 | | uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types); |
1034 | | bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size); |
1035 | | bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data); |
1036 | | bool (*sym_data_str) (ir_loader *loader, const char *str, size_t len); |
1037 | | bool (*sym_data_pad) (ir_loader *loader, size_t offset); |
1038 | | bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref, uintptr_t offset); |
1039 | | bool (*sym_data_end) (ir_loader *loader, uint32_t flags); |
1040 | | bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name); |
1041 | | bool (*func_process) (ir_loader *loader, ir_ctx *ctx, const char *name); |
1042 | | void*(*resolve_sym_name) (ir_loader *loader, ir_ctx *ctx, ir_str name, uint32_t flags); |
1043 | | bool (*has_sym) (ir_loader *loader, const char *name); |
1044 | | bool (*add_sym) (ir_loader *loader, const char *name, void *addr); |
1045 | | bool (*add_label) (ir_loader *loader, const char *name, void *addr); |
1046 | | const char * (*get_str) (ir_loader *loader, ir_str idx); |
1047 | | const char * (*get_strl) (ir_loader *loader, ir_str idx, size_t *len); |
1048 | | }; |
1049 | | |
1050 | | void ir_loader_init(void); |
1051 | | void ir_loader_free(void); |
1052 | | int ir_load(ir_loader *loader, FILE *f); |
1053 | | |
1054 | | /* IR LLVM load API (implementation in ir_load_llvm.c) */ |
1055 | | int ir_load_llvm_bitcode(ir_loader *loader, const char *filename); |
1056 | | int ir_load_llvm_asm(ir_loader *loader, const char *filename); |
1057 | | |
1058 | | /* IR save API (implementation in ir_save.c) */ |
1059 | 0 | #define IR_SAVE_CFG (1<<0) /* add info about CFG */ |
1060 | 0 | #define IR_SAVE_CFG_MAP (1<<1) /* add info about CFG block assignment */ |
1061 | 0 | #define IR_SAVE_USE_LISTS (1<<2) /* add info about def->use lists */ |
1062 | 0 | #define IR_SAVE_RULES (1<<3) /* add info about selected code-generation rules */ |
1063 | 0 | #define IR_SAVE_REGS (1<<4) /* add info about selected registers */ |
1064 | 0 | #define IR_SAVE_SAFE_NAMES (1<<5) /* add '@' prefix to symbol names */ |
1065 | | |
1066 | | void ir_print_func_proto(const ir_ctx *ctx, const char *name, bool prefix, FILE *f); |
1067 | | void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f); |
1068 | | void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); |
1069 | | void ir_print_type_cname(ir_type type, FILE *f); |
1070 | | void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f); |
1071 | | |
1072 | | /* IR debug dump API (implementation in ir_dump.c) */ |
1073 | | void ir_dump(const ir_ctx *ctx, FILE *f); |
1074 | | void ir_dump_dot(const ir_ctx *ctx, const char *name, const char *comments, FILE *f); |
1075 | | void ir_dump_use_lists(const ir_ctx *ctx, FILE *f); |
1076 | | void ir_dump_cfg(ir_ctx *ctx, FILE *f); |
1077 | | void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f); |
1078 | | void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f); |
1079 | | void ir_dump_codegen(const ir_ctx *ctx, FILE *f); |
1080 | | |
1081 | | /* IR to C conversion (implementation in ir_emit_c.c) */ |
1082 | | int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f); |
1083 | | void ir_emit_c_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); |
1084 | | void ir_emit_c_sym_decl(const char *name, uint32_t flags, FILE *f); |
1085 | | |
1086 | | /* IR to LLVM conversion (implementation in ir_emit_llvm.c) */ |
1087 | | int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f); |
1088 | | void ir_emit_llvm_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); |
1089 | | void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, FILE *f); |
1090 | | |
1091 | | /* IR verification API (implementation in ir_check.c) */ |
1092 | | bool ir_check(const ir_ctx *ctx); |
1093 | | bool ir_check_prototype(const ir_ctx *ctx, uint32_t flags, uint8_t ret_type, uint32_t params_count, uint8_t *param_types); |
1094 | | void ir_consistency_check(void); |
1095 | | |
1096 | | /* Code patching (implementation in ir_patch.c) */ |
1097 | | int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr); |
1098 | | |
1099 | | /* CPU information (implementation in ir_cpuinfo.c) */ |
1100 | | #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) |
1101 | | # define IR_X86_SSE2 (1<<0) |
1102 | 0 | # define IR_X86_SSE3 (1<<1) |
1103 | 0 | # define IR_X86_SSSE3 (1<<2) |
1104 | 0 | # define IR_X86_SSE41 (1<<3) |
1105 | 0 | # define IR_X86_SSE42 (1<<4) |
1106 | 14.6k | # define IR_X86_AVX (1<<5) |
1107 | 0 | # define IR_X86_AVX2 (1<<6) |
1108 | 0 | # define IR_X86_BMI1 (1<<7) |
1109 | | # define IR_X86_BMI2 (1<<8) |
1110 | 2.50k | # define IR_X86_CLDEMOTE (1<<9) |
1111 | | #endif |
1112 | | |
1113 | | uint32_t ir_cpuinfo(void); |
1114 | | |
1115 | | /* Deoptimization helpers */ |
1116 | | const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_per_group, const void *exit_addr, ir_code_buffer *code_buffer, size_t *size_ptr); |
1117 | | |
1118 | | /* A reference IR JIT compiler */ |
1119 | | IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size) |
1120 | 0 | { |
1121 | 0 | if (opt_level == 0) { |
1122 | 0 | if (ctx->flags & IR_OPT_FOLDING) { |
1123 | 0 | // IR_ASSERT(0 && "IR_OPT_FOLDING is incompatible with -O0"); |
1124 | 0 | return NULL; |
1125 | 0 | } |
1126 | 0 | ctx->flags &= ~(IR_OPT_CFG | IR_OPT_CODEGEN | IR_OPT_TAILCALL); |
1127 | 0 |
|
1128 | 0 | ir_build_def_use_lists(ctx); |
1129 | 0 |
|
1130 | 0 | if (!ir_build_cfg(ctx) |
1131 | 0 | || !ir_match(ctx) |
1132 | 0 | || !ir_assign_virtual_registers(ctx) |
1133 | 0 | || !ir_compute_dessa_moves(ctx) |
1134 | 0 | || !ir_reg_alloc_O0(ctx)) { |
1135 | 0 | return NULL; |
1136 | 0 | } |
1137 | 0 |
|
1138 | 0 | return ir_emit_code(ctx, size); |
1139 | 0 | } else if (opt_level > 0) { |
1140 | 0 | if (!(ctx->flags & IR_OPT_FOLDING)) { |
1141 | 0 | // IR_ASSERT(0 && "IR_OPT_FOLDING must be set in ir_init() for -O1 and -O2"); |
1142 | 0 | return NULL; |
1143 | 0 | } |
1144 | 0 | ctx->flags |= IR_OPT_CFG | IR_OPT_CODEGEN | IR_OPT_TAILCALL; |
1145 | 0 |
|
1146 | 0 | ir_build_def_use_lists(ctx); |
1147 | 0 |
|
1148 | 0 | if (ctx->flags & IR_OPT_MEM2SSA) { |
1149 | 0 | if (!ir_build_cfg(ctx) |
1150 | 0 | || !ir_build_dominators_tree(ctx) |
1151 | 0 | || !ir_mem2ssa(ctx)) { |
1152 | 0 | return NULL; |
1153 | 0 | } |
1154 | 0 | ir_reset_cfg(ctx); |
1155 | 0 | } |
1156 | 0 |
|
1157 | 0 | if (opt_level > 1) { |
1158 | 0 | if (!ir_sccp(ctx)) { |
1159 | 0 | return NULL; |
1160 | 0 | } |
1161 | 0 | } |
1162 | 0 |
|
1163 | 0 | if (!ctx->cfg_blocks) { |
1164 | 0 | if (!ir_build_cfg(ctx) |
1165 | 0 | || !ir_build_dominators_tree(ctx)) { |
1166 | 0 | return NULL; |
1167 | 0 | } |
1168 | 0 | } |
1169 | 0 |
|
1170 | 0 | if (!ir_find_loops(ctx) |
1171 | 0 | || !ir_gcm(ctx) |
1172 | 0 | || !ir_schedule(ctx) |
1173 | 0 | || !ir_match(ctx) |
1174 | 0 | || !ir_assign_virtual_registers(ctx) |
1175 | 0 | || !ir_compute_live_ranges(ctx) |
1176 | 0 | || !ir_coalesce(ctx) |
1177 | 0 | || !ir_reg_alloc(ctx) |
1178 | 0 | || !ir_schedule_blocks(ctx)) { |
1179 | 0 | return NULL; |
1180 | 0 | } |
1181 | 0 |
|
1182 | 0 | return ir_emit_code(ctx, size); |
1183 | 0 | } else { |
1184 | 0 | // IR_ASSERT(0 && "wrong optimization level"); |
1185 | 0 | return NULL; |
1186 | 0 | } |
1187 | 0 | } Unexecuted instantiation: ir_cfg.c:ir_jit_compile Unexecuted instantiation: ir_check.c:ir_jit_compile Unexecuted instantiation: ir_dump.c:ir_jit_compile Unexecuted instantiation: ir_emit.c:ir_jit_compile Unexecuted instantiation: ir_gcm.c:ir_jit_compile Unexecuted instantiation: ir_gdb.c:ir_jit_compile Unexecuted instantiation: ir_patch.c:ir_jit_compile Unexecuted instantiation: ir_perf.c:ir_jit_compile Unexecuted instantiation: ir_ra.c:ir_jit_compile Unexecuted instantiation: ir_ra_simple.c:ir_jit_compile Unexecuted instantiation: ir_save.c:ir_jit_compile Unexecuted instantiation: ir_sccp.c:ir_jit_compile Unexecuted instantiation: ir_strtab.c:ir_jit_compile Unexecuted instantiation: ir.c:ir_jit_compile Unexecuted instantiation: zend_jit.c:ir_jit_compile |
1188 | | |
1189 | 0 | #define IR_ERROR_CODE_MEM_OVERFLOW 1 |
1190 | 0 | #define IR_ERROR_FIXED_STACK_FRAME_OVERFLOW 2 |
1191 | 0 | #define IR_ERROR_UNSUPPORTED_CODE_RULE 3 |
1192 | 0 | #define IR_ERROR_LINK 4 |
1193 | 0 | #define IR_ERROR_ENCODE 5 |
1194 | 0 | #define IR_ERROR_TOO_LARGE 6 |
1195 | | |
1196 | | /* IR Memmory Allocation */ |
1197 | | #ifndef ir_mem_malloc |
1198 | | # define ir_mem_malloc malloc |
1199 | | #endif |
1200 | | #ifndef ir_mem_calloc |
1201 | | # define ir_mem_calloc calloc |
1202 | | #endif |
1203 | | #ifndef ir_mem_realloc |
1204 | | # define ir_mem_realloc realloc |
1205 | | #endif |
1206 | | #ifndef ir_mem_free |
1207 | | # define ir_mem_free free |
1208 | | #endif |
1209 | | |
1210 | | #ifndef ir_mem_pmalloc |
1211 | | # define ir_mem_pmalloc malloc |
1212 | | #endif |
1213 | | #ifndef ir_mem_pcalloc |
1214 | | # define ir_mem_pcalloc calloc |
1215 | | #endif |
1216 | | #ifndef ir_mem_prealloc |
1217 | | # define ir_mem_prealloc realloc |
1218 | | #endif |
1219 | | #ifndef ir_mem_pfree |
1220 | | # define ir_mem_pfree free |
1221 | | #endif |
1222 | | |
1223 | | void *ir_mem_mmap(size_t size); |
1224 | | int ir_mem_unmap(void *ptr, size_t size); |
1225 | | int ir_mem_protect(void *ptr, size_t size); |
1226 | | int ir_mem_unprotect(void *ptr, size_t size); |
1227 | | int ir_mem_flush(void *ptr, size_t size); |
1228 | | |
1229 | | #ifdef __cplusplus |
1230 | | } /* extern "C" */ |
1231 | | #endif |
1232 | | |
1233 | | #endif /* IR_H */ |