xref: /php-src/ext/opcache/jit/ir/ir.h (revision 71194ea7)
1 /*
2  * IR - Lightweight JIT Compilation Framework
3  * (Public API)
4  * Copyright (C) 2022 Zend by Perforce.
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)
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 # define __ORDER_LITTLE_ENDIAN__ 1
33 # define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
34 # ifndef __has_builtin
35 #  define __has_builtin(arg) (0)
36 # endif
37 #endif
38 
39 /* target auto detection */
40 #if !defined(IR_TARGET_X86) && !defined(IR_TARGET_X64) && !defined(IR_TARGET_AARCH64)
41 # if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
42 #  define IR_TARGET_X64
43 # elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
44 #  define IR_TARGET_X86
45 # elif defined(__aarch64__) || defined(_M_ARM64)
46 #  define IR_TARGET_AARCH64
47 # elif defined (_WIN64)
48 #  define IR_TARGET_X64
49 # elif defined (_WIN32)
50 #  define IR_TARGET_X86
51 # endif
52 #endif
53 
54 #if defined(IR_TARGET_X86)
55 # define IR_TARGET "x86"
56 #elif defined(IR_TARGET_X64)
57 # ifdef _WIN64
58 #  define IR_TARGET "Windows-x86_64" /* 64-bit Windows use different ABI and calling convention */
59 # else
60 #  define IR_TARGET "x86_64"
61 # endif
62 #elif defined(IR_TARGET_AARCH64)
63 # define IR_TARGET "aarch64"
64 #else
65 # error "Unknown IR target"
66 #endif
67 
68 #if defined(__SIZEOF_SIZE_T__)
69 # if __SIZEOF_SIZE_T__ == 8
70 #  define IR_64 1
71 # elif __SIZEOF_SIZE_T__ != 4
72 #  error "Unknown addr size"
73 # endif
74 #else
75 # error "Unknown addr size"
76 #endif
77 
78 #if defined(__BYTE_ORDER__)
79 # if defined(__ORDER_LITTLE_ENDIAN__)
80 #  if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
81 #   define IR_STRUCT_LOHI(lo, hi) struct {lo; hi;}
82 #  endif
83 # endif
84 # if defined(__ORDER_BIG_ENDIAN__)
85 #  if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
86 #   define IR_STRUCT_LOHI(lo, hi) struct {hi; lo;}
87 #  endif
88 # endif
89 #endif
90 #ifndef IR_STRUCT_LOHI
91 # error "Unknown byte order"
92 #endif
93 
94 #ifdef __has_attribute
95 # if __has_attribute(always_inline)
96 #  define IR_ALWAYS_INLINE static inline __attribute__((always_inline))
97 # endif
98 # if __has_attribute(noinline)
99 #  define IR_NEVER_INLINE __attribute__((noinline))
100 # endif
101 #else
102 # define __has_attribute(x) 0
103 #endif
104 
105 #ifndef IR_ALWAYS_INLINE
106 # define IR_ALWAYS_INLINE static inline
107 #endif
108 #ifndef IR_NEVER_INLINE
109 # define IR_NEVER_INLINE
110 #endif
111 
112 #ifdef IR_PHP
113 # include "ir_php.h"
114 #endif
115 
116 /* IR Type flags (low 4 bits are used for type size) */
117 #define IR_TYPE_SIGNED     (1<<4)
118 #define IR_TYPE_UNSIGNED   (1<<5)
119 #define IR_TYPE_FP         (1<<6)
120 #define IR_TYPE_SPECIAL    (1<<7)
121 #define IR_TYPE_BOOL       (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED)
122 #define IR_TYPE_ADDR       (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED)
123 #define IR_TYPE_CHAR       (IR_TYPE_SPECIAL|IR_TYPE_SIGNED)
124 
125 /* List of IR types */
126 #define IR_TYPES(_) \
127 	_(BOOL,   bool,      b,    IR_TYPE_BOOL)     \
128 	_(U8,     uint8_t,   u8,   IR_TYPE_UNSIGNED) \
129 	_(U16,    uint16_t,  u16,  IR_TYPE_UNSIGNED) \
130 	_(U32,    uint32_t,  u32,  IR_TYPE_UNSIGNED) \
131 	_(U64,    uint64_t,  u64,  IR_TYPE_UNSIGNED) \
132 	_(ADDR,   uintptr_t, addr, IR_TYPE_ADDR)     \
133 	_(CHAR,   char,      c,    IR_TYPE_CHAR)     \
134 	_(I8,     int8_t,    i8,   IR_TYPE_SIGNED)   \
135 	_(I16,    int16_t,   i16,  IR_TYPE_SIGNED)   \
136 	_(I32,    int32_t,   i32,  IR_TYPE_SIGNED)   \
137 	_(I64,    int64_t,   i64,  IR_TYPE_SIGNED)   \
138 	_(DOUBLE, double,    d,    IR_TYPE_FP)       \
139 	_(FLOAT,  float,     f,    IR_TYPE_FP)       \
140 
141 #define IR_IS_TYPE_UNSIGNED(t) ((t) < IR_CHAR)
142 #define IR_IS_TYPE_SIGNED(t)   ((t) >= IR_CHAR && (t) < IR_DOUBLE)
143 #define IR_IS_TYPE_INT(t)      ((t) < IR_DOUBLE)
144 #define IR_IS_TYPE_FP(t)       ((t) >= IR_DOUBLE)
145 
146 #define IR_TYPE_ENUM(name, type, field, flags) IR_ ## name,
147 
148 typedef enum _ir_type {
149 	IR_VOID,
150 	IR_TYPES(IR_TYPE_ENUM)
151 	IR_LAST_TYPE
152 } ir_type;
153 
154 #ifdef IR_64
155 # define IR_SIZE_T     IR_U64
156 # define IR_SSIZE_T    IR_I64
157 # define IR_UINTPTR_T  IR_U64
158 # define IR_INTPTR_T   IR_I64
159 # define IR_C_UINTPTR  IR_U64
160 # define IR_C_INTPTR   IR_I64
161 #else
162 # define IR_SIZE_T     IR_U32
163 # define IR_SSIZE_T    IR_I32
164 # define IR_UINTPTR_T  IR_U32
165 # define IR_INTPTR_T   IR_I32
166 # define IR_C_UINTPTR  IR_U32
167 # define IR_C_INTPTR   IR_I32
168 #endif
169 
170 /* List of IR opcodes
171  * ==================
172  *
173  * Each instruction is described by a type (opcode, flags, op1_type, op2_type, op3_type)
174  *
175  * flags
176  * -----
177  * v     - void
178  * d     - data      IR_OP_FLAG_DATA
179  * r     - ref       IR_OP_FLAG_DATA alias
180  * p     - pinned    IR_OP_FLAG_DATA + IR_OP_FLAG_PINNED
181  * c     - control   IR_OP_FLAG_CONTROL
182  * S     - control   IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_START
183  * E     - control   IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END
184  * T     - control   IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END + IR_OP_FLAG_TERMINATOR
185  * l     - load      IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_LOAD
186  * s     - store     IR_OP_FLAG_MEM + IR_OP_FLAG_STORE
187  * x     - call      IR_OP_FLAG_MEM + IR_OP_FLAG_CALL
188  * a     - alloc     IR_OP_FLAG_MEM + IR_OP_FLAG_ALLOC
189  * 0-3   - number of input edges
190  * N     - number of arguments is defined in the insn->inputs_count (MERGE, PHI, CALL)
191  * X1-X3 - number of extra data ops
192  * C     - commutative operation ("d2C" => IR_OP_FLAG_DATA + IR_OP_FLAG_COMMUTATIVE)
193  *
194  * operand types
195  * -------------
196  * ___ - unused
197  * def - reference to a definition op (data-flow use-def dependency edge)
198  * ref - memory reference (data-flow use-def dependency edge)
199  * var - variable reference (data-flow use-def dependency edge)
200  * arg - argument reference CALL/TAILCALL/CARG->CARG
201  * src - reference to a previous control region (IF, IF_TRUE, IF_FALSE, MERGE, LOOP_BEGIN, LOOP_END, RETURN)
202  * reg - data-control dependency on region (PHI, VAR, PARAM)
203  * ret - reference to a previous RETURN instruction (RETURN)
204  * str - string: variable/argument name (VAR, PARAM, CALL, TAILCALL)
205  * num - number: argument number (PARAM)
206  * prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT)
207  * opt - optional number
208  * pro - function prototype
209  *
210  * The order of IR opcodes is carefully selected for efficient folding.
211  * - foldable instruction go first
212  * - NOP is never used (code 0 is used as ANY pattern)
213  * - CONST is the most often used instruction (encode with 1 bit)
214  * - equality inversion:  EQ <-> NE                         => op =^ 1
215  * - comparison inversion: [U]LT <-> [U]GT, [U]LE <-> [U]GE  => op =^ 3
216  */
217 
218 #define IR_OPS(_) \
219 	/* special op (must be the first !!!)                               */ \
220 	_(NOP,          v,    ___, ___, ___) /* empty instruction           */ \
221 	\
222 	/* constants reference                                              */ \
223 	_(C_BOOL,       r0,   ___, ___, ___) /* constant                    */ \
224 	_(C_U8,         r0,   ___, ___, ___) /* constant                    */ \
225 	_(C_U16,        r0,   ___, ___, ___) /* constant                    */ \
226 	_(C_U32,        r0,   ___, ___, ___) /* constant                    */ \
227 	_(C_U64,        r0,   ___, ___, ___) /* constant                    */ \
228 	_(C_ADDR,       r0,   ___, ___, ___) /* constant                    */ \
229 	_(C_CHAR,       r0,   ___, ___, ___) /* constant                    */ \
230 	_(C_I8,         r0,   ___, ___, ___) /* constant                    */ \
231 	_(C_I16,        r0,   ___, ___, ___) /* constant                    */ \
232 	_(C_I32,        r0,   ___, ___, ___) /* constant                    */ \
233 	_(C_I64,        r0,   ___, ___, ___) /* constant                    */ \
234 	_(C_DOUBLE,     r0,   ___, ___, ___) /* constant                    */ \
235 	_(C_FLOAT,      r0,   ___, ___, ___) /* constant                    */ \
236 	\
237 	/* equality ops  */                                                    \
238 	_(EQ,           d2C,  def, def, ___) /* equal                       */ \
239 	_(NE,           d2C,  def, def, ___) /* not equal                   */ \
240 	\
241 	/* comparison ops (order matters, LT must be a modulo of 4 !!!)     */ \
242 	_(LT,           d2,   def, def, ___) /* less                        */ \
243 	_(GE,           d2,   def, def, ___) /* greater or equal            */ \
244 	_(LE,           d2,   def, def, ___) /* less or equal               */ \
245 	_(GT,           d2,   def, def, ___) /* greater                     */ \
246 	_(ULT,          d2,   def, def, ___) /* unsigned less               */ \
247 	_(UGE,          d2,   def, def, ___) /* unsigned greater or equal   */ \
248 	_(ULE,          d2,   def, def, ___) /* unsigned less or equal      */ \
249 	_(UGT,          d2,   def, def, ___) /* unsigned greater            */ \
250 	\
251 	/* arithmetic ops                                                   */ \
252 	_(ADD,          d2C,  def, def, ___) /* addition                    */ \
253 	_(SUB,          d2,   def, def, ___) /* subtraction (must be ADD+1) */ \
254 	_(MUL,          d2C,  def, def, ___) /* multiplication              */ \
255 	_(DIV,          d2,   def, def, ___) /* division                    */ \
256 	_(MOD,          d2,   def, def, ___) /* modulo                      */ \
257 	_(NEG,          d1,   def, ___, ___) /* change sign                 */ \
258 	_(ABS,          d1,   def, ___, ___) /* absolute value              */ \
259 	/* (LDEXP, MIN, MAX, FPMATH)                                        */ \
260 	\
261 	/* type conversion ops                                              */ \
262 	_(SEXT,         d1,   def, ___, ___) /* sign extension              */ \
263 	_(ZEXT,         d1,   def, ___, ___) /* zero extension              */ \
264 	_(TRUNC,        d1,   def, ___, ___) /* truncates to int type       */ \
265 	_(BITCAST,      d1,   def, ___, ___) /* binary representation       */ \
266 	_(INT2FP,       d1,   def, ___, ___) /* int to float conversion     */ \
267 	_(FP2INT,       d1,   def, ___, ___) /* float to int conversion     */ \
268 	_(FP2FP,        d1,   def, ___, ___) /* float to float conversion   */ \
269 	_(PROTO,        d1X1, def, pro, ___) /* apply function prototype    */ \
270 	\
271 	/* overflow-check                                                   */ \
272 	_(ADD_OV,       d2C,  def, def, ___) /* addition                    */ \
273 	_(SUB_OV,       d2,   def, def, ___) /* subtraction                 */ \
274 	_(MUL_OV,       d2C,  def, def, ___) /* multiplication              */ \
275 	_(OVERFLOW,     d1,   def, ___, ___) /* overflow check add/sub/mul  */ \
276 	\
277 	/* bitwise and shift ops                                            */ \
278 	_(NOT,          d1,   def, ___, ___) /* bitwise NOT                 */ \
279 	_(OR,           d2C,  def, def, ___) /* bitwise OR                  */ \
280 	_(AND,          d2C,  def, def, ___) /* bitwise AND                 */ \
281 	_(XOR,          d2C,  def, def, ___) /* bitwise XOR                 */ \
282 	_(SHL,	        d2,   def, def, ___) /* logic shift left            */ \
283 	_(SHR,	        d2,   def, def, ___) /* logic shift right           */ \
284 	_(SAR,	        d2,   def, def, ___) /* arithmetic shift right      */ \
285 	_(ROL,	        d2,   def, def, ___) /* rotate left                 */ \
286 	_(ROR,	        d2,   def, def, ___) /* rotate right                */ \
287 	_(BSWAP,        d1,   def, ___, ___) /* byte swap                   */ \
288 	_(CTPOP,        d1,   def, ___, ___) /* count population            */ \
289 	_(CTLZ,         d1,   def, ___, ___) /* count leading zeros         */ \
290 	_(CTTZ,         d1,   def, ___, ___) /* count trailing zeros        */ \
291 	\
292 	/* branch-less conditional ops                                      */ \
293 	_(MIN,	        d2C,  def, def, ___) /* min(op1, op2)               */ \
294 	_(MAX,	        d2C,  def, def, ___) /* max(op1, op2)               */ \
295 	_(COND,	        d3,   def, def, def) /* op1 ? op2 : op3             */ \
296 	\
297 	/* data-flow and miscellaneous ops                                  */ \
298 	_(PHI,          pN,   reg, def, def) /* SSA Phi function            */ \
299 	_(COPY,         d1X1, def, opt, ___) /* COPY (last foldable op)     */ \
300 	_(PI,           p2,   reg, def, ___) /* e-SSA Pi constraint ???     */ \
301 	_(FRAME_ADDR,   d0,   ___, ___, ___) /* function frame address      */ \
302 	/* (USE, RENAME)                                                    */ \
303 	\
304 	/* data ops                                                         */ \
305 	_(PARAM,        p1X2, reg, str, num) /* incoming parameter proj.    */ \
306 	_(VAR,	        p1X1, reg, str, ___) /* local variable              */ \
307 	_(FUNC_ADDR,    r0,   ___, ___, ___) /* constant func ref           */ \
308 	_(FUNC,         r0,   ___, ___, ___) /* constant func ref           */ \
309 	_(SYM,          r0,   ___, ___, ___) /* constant symbol ref         */ \
310 	_(STR,          r0,   ___, ___, ___) /* constant str ref            */ \
311 	\
312 	/* call ops                                                         */ \
313 	_(CALL,         xN,   src, def, def) /* CALL(src, func, args...)    */ \
314 	_(TAILCALL,     xN,   src, def, def) /* CALL+RETURN                 */ \
315 	\
316 	/* memory reference and load/store ops                              */ \
317 	_(ALLOCA,       a2,   src, def, ___) /* alloca(def)                 */ \
318 	_(AFREE,        a2,   src, def, ___) /* revert alloca(def)          */ \
319 	_(BLOCK_BEGIN,  a1,   src, ___, ___) /* stacksave                   */ \
320 	_(BLOCK_END,    a2,   src, def, ___) /* stackrestore                */ \
321 	_(VADDR,        d1,   var, ___, ___) /* load address of local var   */ \
322 	_(VLOAD,        l2,   src, var, ___) /* load value of local var     */ \
323 	_(VSTORE,       s3,   src, var, def) /* store value to local var    */ \
324 	_(RLOAD,        l1X2, src, num, opt) /* load value from register    */ \
325 	_(RSTORE,       s2X1, src, def, num) /* store value into register   */ \
326 	_(LOAD,         l2,   src, ref, ___) /* load from memory            */ \
327 	_(STORE,        s3,   src, ref, def) /* store to memory             */ \
328 	_(TLS,          l1X2, src, num, num) /* thread local variable       */ \
329 	_(TRAP,         x1,   src, ___, ___) /* DebugBreak                  */ \
330 	/* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ???       */ \
331 	\
332 	/* va_args                                                          */ \
333 	_(VA_START,     x2,   src, def, ___) /* va_start(va_list)           */ \
334 	_(VA_END,       x2,   src, def, ___) /* va_end(va_list)             */ \
335 	_(VA_COPY,      x3,   src, def, def) /* va_copy(dst, stc)           */ \
336 	_(VA_ARG,       x2,   src, def, ___) /* va_arg(va_list)             */ \
337 	\
338 	/* guards                                                           */ \
339 	_(GUARD,        c3,   src, def, def) /* IF without second successor */ \
340 	_(GUARD_NOT  ,  c3,   src, def, def) /* IF without second successor */ \
341 	\
342 	/* deoptimization                                                   */ \
343 	_(SNAPSHOT,     xN,   src, def, def) /* SNAPSHOT(src, args...)      */ \
344 	\
345 	/* control-flow nodes                                               */ \
346 	_(START,        S0X1, ret, ___, ___) /* function start              */ \
347 	_(ENTRY,        S1X1, src, num, ___) /* entry with a fake src edge  */ \
348 	_(BEGIN,        S1,   src, ___, ___) /* block start                 */ \
349 	_(IF_TRUE,      S1X1, src, prb, ___) /* IF TRUE proj.               */ \
350 	_(IF_FALSE,     S1X1, src, prb, ___) /* IF FALSE proj.              */ \
351 	_(CASE_VAL,     S2X1, src, def, prb) /* switch proj.                */ \
352 	_(CASE_DEFAULT, S1X1, src, prb, ___) /* switch proj.                */ \
353 	_(MERGE,        SN,   src, src, src) /* control merge               */ \
354 	_(LOOP_BEGIN,   SN,   src, src, src) /* loop start                  */ \
355 	_(END,          E1,   src, ___, ___) /* block end                   */ \
356 	_(LOOP_END,     E1,   src, ___, ___) /* loop end                    */ \
357 	_(IF,           E2,   src, def, ___) /* conditional control split   */ \
358 	_(SWITCH,       E2,   src, def, ___) /* multi-way control split     */ \
359 	_(RETURN,       T2X1, src, def, ret) /* function return             */ \
360 	_(IJMP,         T2X1, src, def, ret) /* computed goto               */ \
361 	_(UNREACHABLE,  T1X2, src, ___, ret) /* unreachable (tailcall, etc) */ \
362 	\
363 	/* deoptimization helper                                            */ \
364 	_(EXITCALL,     x2,   src, def, ___) /* save CPU regs and call op2  */ \
365 
366 
367 #define IR_OP_ENUM(name, flags, op1, op2, op3) IR_ ## name,
368 
369 typedef enum _ir_op {
370 	IR_OPS(IR_OP_ENUM)
371 #ifdef IR_PHP
372 	IR_PHP_OPS(IR_OP_ENUM)
373 #endif
374 	IR_LAST_OP
375 } ir_op;
376 
377 /* IR Opcode and Type Union */
378 #define IR_OPT_OP_MASK       0x00ff
379 #define IR_OPT_TYPE_MASK     0xff00
380 #define IR_OPT_TYPE_SHIFT    8
381 #define IR_OPT_INPUTS_SHIFT  16
382 
383 #define IR_OPT(op, type)     ((uint16_t)(op) | ((uint16_t)(type) << IR_OPT_TYPE_SHIFT))
384 #define IR_OPTX(op, type, n) ((uint32_t)(op) | ((uint32_t)(type) << IR_OPT_TYPE_SHIFT) | ((uint32_t)(n) << IR_OPT_INPUTS_SHIFT))
385 #define IR_OPT_TYPE(opt)     (((opt) & IR_OPT_TYPE_MASK) >> IR_OPT_TYPE_SHIFT)
386 
387 /* IR References */
388 typedef int32_t ir_ref;
389 
390 #define IR_IS_CONST_REF(ref) ((ref) < 0)
391 
392 /* IR Constant Value */
393 #define IR_UNUSED            0
394 #define IR_NULL              (-1)
395 #define IR_FALSE             (-2)
396 #define IR_TRUE              (-3)
397 #define IR_LAST_FOLDABLE_OP  IR_COPY
398 
399 #define IR_CONSTS_LIMIT_MIN (-(IR_TRUE - 1))
400 #define IR_INSNS_LIMIT_MIN (IR_UNUSED + 1)
401 
402 #ifndef IR_64
403 # define ADDR_MEMBER            uintptr_t                  addr;
404 #else
405 # define ADDR_MEMBER
406 #endif
407 typedef union _ir_val {
408 	double                             d;
409 	uint64_t                           u64;
410 	int64_t                            i64;
411 #ifdef IR_64
412 	uintptr_t                          addr;
413 #endif
414 	IR_STRUCT_LOHI(
415 		union {
416 			uint32_t                   u32;
417 			int32_t                    i32;
418 			float                      f;
419 			ADDR_MEMBER
420 			ir_ref                     name;
421 			ir_ref                     str;
422 			IR_STRUCT_LOHI(
423 				union {
424 					uint16_t           u16;
425 					int16_t            i16;
426 					IR_STRUCT_LOHI(
427 						union {
428 							uint8_t    u8;
429 							int8_t     i8;
430 							bool       b;
431 							char       c;
432 						},
433 						uint8_t        u8_hi
434 					);
435 				},
436 				uint16_t               u16_hi
437 			);
438 		},
439 		uint32_t                       u32_hi
440 	);
441 } ir_val;
442 #undef ADDR_MEMBER
443 
444 /* IR Instruction */
445 typedef struct _ir_insn {
446 	IR_STRUCT_LOHI(
447 		union {
448 			IR_STRUCT_LOHI(
449 				union {
450 					IR_STRUCT_LOHI(
451 						uint8_t        op,
452 						uint8_t        type
453 					);
454 					uint16_t           opt;
455 				},
456 				union {
457 					uint16_t           inputs_count;       /* number of input control edges for MERGE, PHI, CALL, TAILCALL */
458 					uint16_t           prev_insn_offset;   /* 16-bit backward offset from current instruction for CSE */
459 					uint16_t           proto;
460 				}
461 			);
462 			uint32_t                   optx;
463 			ir_ref                     ops[1];
464 		},
465 		union {
466 			ir_ref                     op1;
467 			ir_ref                     prev_const;
468 		}
469 	);
470 	union {
471 		IR_STRUCT_LOHI(
472 			ir_ref                     op2,
473 			ir_ref                     op3
474 		);
475 		ir_val                         val;
476 	};
477 } ir_insn;
478 
479 /* IR Hash Tables API (private) */
480 typedef struct _ir_hashtab ir_hashtab;
481 
482 /* IR String Tables API (implementation in ir_strtab.c) */
483 typedef struct _ir_strtab {
484 	void       *data;
485 	uint32_t    mask;
486 	uint32_t    size;
487 	uint32_t    count;
488 	uint32_t    pos;
489 	char       *buf;
490 	uint32_t    buf_size;
491 	uint32_t    buf_top;
492 } ir_strtab;
493 
494 #define ir_strtab_count(strtab) (strtab)->count
495 
496 typedef void (*ir_strtab_apply_t)(const char *str, uint32_t len, ir_ref val);
497 
498 void ir_strtab_init(ir_strtab *strtab, uint32_t count, uint32_t buf_size);
499 ir_ref ir_strtab_lookup(ir_strtab *strtab, const char *str, uint32_t len, ir_ref val);
500 ir_ref ir_strtab_find(const ir_strtab *strtab, const char *str, uint32_t len);
501 ir_ref ir_strtab_update(ir_strtab *strtab, const char *str, uint32_t len, ir_ref val);
502 const char *ir_strtab_str(const ir_strtab *strtab, ir_ref idx);
503 const char *ir_strtab_strl(const ir_strtab *strtab, ir_ref idx, size_t *len);
504 void ir_strtab_apply(const ir_strtab *strtab, ir_strtab_apply_t func);
505 void ir_strtab_free(ir_strtab *strtab);
506 
507 /* IR Context Flags */
508 #define IR_FUNCTION            (1<<0) /* Generate a function. */
509 #define IR_FASTCALL_FUNC       (1<<1) /* Generate a function with fastcall calling convention, x86 32-bit only. */
510 #define IR_VARARG_FUNC         (1<<2)
511 #define IR_BUILTIN_FUNC        (1<<3)
512 #define IR_STATIC              (1<<4)
513 #define IR_EXTERN              (1<<5)
514 #define IR_CONST               (1<<6)
515 
516 #define IR_INITIALIZED         (1<<7) /* sym data flag: constant or an initialized variable */
517 #define IR_CONST_STRING        (1<<8) /* sym data flag: constant string */
518 
519 #define IR_SKIP_PROLOGUE       (1<<8) /* Don't generate function prologue. */
520 #define IR_USE_FRAME_POINTER   (1<<9)
521 #define IR_PREALLOCATED_STACK  (1<<10)
522 #define IR_NO_STACK_COMBINE    (1<<11)
523 #define IR_START_BR_TARGET     (1<<12)
524 #define IR_ENTRY_BR_TARGET     (1<<13)
525 #define IR_GEN_ENDBR           (1<<14)
526 #define IR_MERGE_EMPTY_ENTRIES (1<<15)
527 
528 #define IR_OPT_INLINE          (1<<16)
529 #define IR_OPT_FOLDING         (1<<17)
530 #define IR_OPT_CFG             (1<<18) /* merge BBs, by remove END->BEGIN nodes during CFG construction */
531 #define IR_OPT_CODEGEN         (1<<19)
532 #define IR_GEN_NATIVE          (1<<20)
533 #define IR_GEN_CODE            (1<<21) /* C or LLVM */
534 
535 #define IR_GEN_CACHE_DEMOTE    (1<<22) /* Demote the generated code from closest CPU caches */
536 
537 /* debug related */
538 #ifdef IR_DEBUG
539 # define IR_DEBUG_SCCP         (1<<26)
540 # define IR_DEBUG_GCM          (1<<27)
541 # define IR_DEBUG_GCM_SPLIT    (1<<28)
542 # define IR_DEBUG_SCHEDULE     (1<<29)
543 # define IR_DEBUG_RA           (1<<30)
544 #endif
545 
546 typedef struct _ir_ctx           ir_ctx;
547 typedef struct _ir_use_list      ir_use_list;
548 typedef struct _ir_block         ir_block;
549 typedef struct _ir_arena         ir_arena;
550 typedef struct _ir_live_interval ir_live_interval;
551 typedef struct _ir_live_range    ir_live_range;
552 typedef struct _ir_loader        ir_loader;
553 typedef int8_t ir_regs[4];
554 
555 typedef void (*ir_snapshot_create_t)(ir_ctx *ctx, ir_ref addr);
556 
557 #if defined(IR_TARGET_AARCH64)
558 typedef const void *(*ir_get_exit_addr_t)(uint32_t exit_num);
559 typedef const void *(*ir_get_veneer_t)(ir_ctx *ctx, const void *addr);
560 typedef bool (*ir_set_veneer_t)(ir_ctx *ctx, const void *addr, const void *veneer);
561 #endif
562 
563 typedef struct _ir_code_buffer {
564 	void *start;
565 	void *end;
566 	void *pos;
567 } ir_code_buffer;
568 
569 struct _ir_ctx {
570 	ir_insn           *ir_base;                 /* two directional array - instructions grow down, constants grow up */
571 	ir_ref             insns_count;             /* number of instructions stored in instructions buffer */
572 	ir_ref             insns_limit;             /* size of allocated instructions buffer (it's extended when overflow) */
573 	ir_ref             consts_count;            /* number of constants stored in constants buffer */
574 	ir_ref             consts_limit;            /* size of allocated constants buffer (it's extended when overflow) */
575 	uint32_t           flags;                   /* IR context flags (see IR_* defines above) */
576 	uint32_t           flags2;                  /* IR context private flags (see IR_* defines in ir_private.h) */
577 	ir_type            ret_type;                /* Function return type */
578 	uint32_t           mflags;                  /* CPU specific flags (see IR_X86_... macros below) */
579 	int32_t            status;                  /* non-zero error code (see IR_ERROR_... macros), app may use negative codes */
580 	ir_ref             fold_cse_limit;          /* CSE finds identical insns backward from "insn_count" to "fold_cse_limit" */
581 	ir_insn            fold_insn;               /* temporary storage for folding engine */
582 	ir_hashtab        *binding;
583 	ir_use_list       *use_lists;               /* def->use lists for each instruction */
584 	ir_ref            *use_edges;               /* the actual uses: use = ctx->use_edges[ctx->use_lists[def].refs + n] */
585 	ir_ref             use_edges_count;         /* number of elements in use_edges[] array */
586 	uint32_t           cfg_blocks_count;        /* number of elements in cfg_blocks[] array */
587 	uint32_t           cfg_edges_count;         /* number of elements in cfg_edges[] array */
588 	ir_block          *cfg_blocks;              /* list of basic blocks (starts from 1) */
589 	uint32_t          *cfg_edges;               /* the actual basic blocks predecessors and successors edges */
590 	uint32_t          *cfg_map;                 /* map of instructions to basic block number */
591 	uint32_t          *cfg_schedule;            /* BB order for code generation */
592 	uint32_t          *rules;                   /* array of target specific code-generation rules (for each instruction) */
593 	uint32_t          *vregs;
594 	ir_ref             vregs_count;
595 	int32_t            spill_base;              /* base register for special spill area (e.g. PHP VM frame pointer) */
596 	uint64_t           fixed_regset;            /* fixed registers, excluded for regular register allocation */
597 	int32_t            fixed_stack_red_zone;    /* reusable stack allocated by caller (default 0) */
598 	int32_t            fixed_stack_frame_size;  /* fixed stack allocated by generated code for spills and registers save/restore */
599 	int32_t            fixed_call_stack_size;   /* fixed preallocated stack for parameter passing (default 0) */
600 	uint64_t           fixed_save_regset;       /* registers that always saved/restored in prologue/epilogue */
601 	uint32_t           locals_area_size;
602 	uint32_t           gp_reg_params;
603 	uint32_t           fp_reg_params;
604 	int32_t            param_stack_size;
605 	ir_live_interval **live_intervals;
606 	ir_arena          *arena;
607 	ir_live_range     *unused_ranges;
608 	ir_regs           *regs;
609 	ir_strtab         *fused_regs;
610 	ir_ref            *prev_ref;
611 	union {
612 		void          *data;
613 		ir_ref         control;                 /* used by IR construction API (see ir_builder.h) */
614 		ir_ref         bb_start;                /* used by target CPU instruction matcher */
615 		ir_ref         vars;                    /* list of VARs (used by register allocator) */
616 	};
617 	ir_snapshot_create_t   snapshot_create;
618 	int32_t            stack_frame_alignment;
619 	int32_t            stack_frame_size;        /* spill stack frame size (used by register allocator and code generator) */
620 	int32_t            call_stack_size;         /* stack for parameter passing (used by register allocator and code generator) */
621 	uint64_t           used_preserved_regs;
622 #ifdef IR_TARGET_X86
623 	int32_t            ret_slot;
624 #endif
625 	uint32_t           rodata_offset;
626 	uint32_t           jmp_table_offset;
627 	uint32_t           entries_count;
628 	uint32_t          *entries;                /* array of ENTRY blocks */
629 	void              *osr_entry_loads;
630 	ir_code_buffer    *code_buffer;
631 #if defined(IR_TARGET_AARCH64)
632 	int32_t            deoptimization_exits;
633 	const void        *deoptimization_exits_base;
634 	ir_get_exit_addr_t get_exit_addr;
635 	ir_get_veneer_t    get_veneer;
636 	ir_set_veneer_t    set_veneer;
637 #endif
638 	ir_loader         *loader;
639 	ir_strtab          strtab;
640 	ir_ref             prev_insn_chain[IR_LAST_FOLDABLE_OP + 1];
641 	ir_ref             prev_const_chain[IR_LAST_TYPE];
642 };
643 
644 /* Basic IR Construction API (implementation in ir.c) */
645 void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit);
646 void ir_free(ir_ctx *ctx);
647 void ir_truncate(ir_ctx *ctx);
648 
649 ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type);
650 ir_ref ir_const_i8(ir_ctx *ctx, int8_t c);
651 ir_ref ir_const_i16(ir_ctx *ctx, int16_t c);
652 ir_ref ir_const_i32(ir_ctx *ctx, int32_t c);
653 ir_ref ir_const_i64(ir_ctx *ctx, int64_t c);
654 ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c);
655 ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c);
656 ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c);
657 ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c);
658 ir_ref ir_const_bool(ir_ctx *ctx, bool c);
659 ir_ref ir_const_char(ir_ctx *ctx, char c);
660 ir_ref ir_const_float(ir_ctx *ctx, float c);
661 ir_ref ir_const_double(ir_ctx *ctx, double c);
662 ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c);
663 
664 ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto);
665 ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto);
666 ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str);
667 ir_ref ir_const_str(ir_ctx *ctx, ir_ref str);
668 
669 ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c);
670 
671 void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted);
672 
673 ir_ref ir_str(ir_ctx *ctx, const char *s);
674 ir_ref ir_strl(ir_ctx *ctx, const char *s, size_t len);
675 const char *ir_get_str(const ir_ctx *ctx, ir_ref idx);
676 const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len);
677 
678 #define IR_MAX_PROTO_PARAMS 255
679 
680 typedef struct _ir_proto_t {
681 	uint8_t flags;
682 	uint8_t ret_type;
683 	uint8_t params_count;
684 	uint8_t param_types[5];
685 } ir_proto_t;
686 
687 ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type);
688 ir_ref ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1);
689 ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2);
690 ir_ref ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3);
691 ir_ref ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
692                                                                 ir_type t4);
693 ir_ref ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
694                                                                 ir_type t4, ir_type t5);
695 ir_ref ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_counts, uint8_t *param_types);
696 
697 ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
698 
699 ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt);
700 ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
701 ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
702 ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
703 
704 ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count);
705 void   ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val);
706 
ir_set_op1(ir_ctx * ctx,ir_ref ref,ir_ref val)707 IR_ALWAYS_INLINE void ir_set_op1(ir_ctx *ctx, ir_ref ref, ir_ref val)
708 {
709 	ctx->ir_base[ref].op1 = val;
710 }
711 
ir_set_op2(ir_ctx * ctx,ir_ref ref,ir_ref val)712 IR_ALWAYS_INLINE void ir_set_op2(ir_ctx *ctx, ir_ref ref, ir_ref val)
713 {
714 	ctx->ir_base[ref].op2 = val;
715 }
716 
ir_set_op3(ir_ctx * ctx,ir_ref ref,ir_ref val)717 IR_ALWAYS_INLINE void ir_set_op3(ir_ctx *ctx, ir_ref ref, ir_ref val)
718 {
719 	ctx->ir_base[ref].op3 = val;
720 }
721 
ir_insn_op(const ir_insn * insn,int32_t n)722 IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
723 {
724 	const ir_ref *p = insn->ops + n;
725 	return *p;
726 }
727 
ir_insn_set_op(ir_insn * insn,int32_t n,ir_ref val)728 IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
729 {
730 	ir_ref *p = insn->ops + n;
731 	*p = val;
732 }
733 
734 ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
735 
736 ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt);
737 ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
738 ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
739 ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
740 
741 ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos);
742 ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name);
743 ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def);
744 
745 /* Def -> Use lists */
746 void ir_build_def_use_lists(ir_ctx *ctx);
747 
748 /* CFG - Control Flow Graph (implementation in ir_cfg.c) */
749 int ir_build_cfg(ir_ctx *ctx);
750 int ir_remove_unreachable_blocks(ir_ctx *ctx);
751 int ir_build_dominators_tree(ir_ctx *ctx);
752 int ir_find_loops(ir_ctx *ctx);
753 int ir_schedule_blocks(ir_ctx *ctx);
754 void ir_build_prev_refs(ir_ctx *ctx);
755 
756 /* SCCP - Sparse Conditional Constant Propagation (implementation in ir_sccp.c) */
757 int ir_sccp(ir_ctx *ctx);
758 
759 /* GCM - Global Code Motion and scheduling (implementation in ir_gcm.c) */
760 int ir_gcm(ir_ctx *ctx);
761 int ir_schedule(ir_ctx *ctx);
762 
763 /* Liveness & Register Allocation (implementation in ir_ra.c) */
764 #define IR_REG_NONE          -1
765 #define IR_REG_SPILL_LOAD    (1<<6)
766 #define IR_REG_SPILL_STORE   (1<<6)
767 #define IR_REG_SPILL_SPECIAL (1<<7)
768 #define IR_REG_SPILLED(r) \
769 	((r) & (IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))
770 #define IR_REG_NUM(r) \
771 	((int8_t)((r) == IR_REG_NONE ? IR_REG_NONE : ((r) & ~(IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))))
772 
773 int ir_assign_virtual_registers(ir_ctx *ctx);
774 int ir_compute_live_ranges(ir_ctx *ctx);
775 int ir_coalesce(ir_ctx *ctx);
776 int ir_compute_dessa_moves(ir_ctx *ctx);
777 int ir_reg_alloc(ir_ctx *ctx);
778 
779 int ir_regs_number(void);
780 bool ir_reg_is_int(int32_t reg);
781 const char *ir_reg_name(int8_t reg, ir_type type);
782 int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref);
783 
784 /* Target CPU instruction selection and code generation (see ir_x86.c) */
785 int ir_match(ir_ctx *ctx);
786 void *ir_emit_code(ir_ctx *ctx, size_t *size);
787 
788 bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr);
789 void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr);
790 void ir_fix_thunk(void *thunk_entry, void *addr);
791 
792 /* Target address resolution (implementation in ir_emit.c) */
793 void *ir_resolve_sym_name(const char *name);
794 
795 /* Target CPU disassembler (implementation in ir_disasm.c) */
796 int  ir_disasm_init(void);
797 void ir_disasm_free(void);
798 void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size);
799 const char* ir_disasm_find_symbol(uint64_t addr, int64_t *offset);
800 int  ir_disasm(const char *name,
801                const void *start,
802                size_t      size,
803                bool        asm_addr,
804                ir_ctx     *ctx,
805                FILE       *f);
806 
807 /* Linux perf interface (implementation in ir_perf.c) */
808 int ir_perf_jitdump_open(void);
809 int ir_perf_jitdump_close(void);
810 int ir_perf_jitdump_register(const char *name, const void *start, size_t size);
811 void ir_perf_map_register(const char *name, const void *start, size_t size);
812 
813 /* GDB JIT interface (implementation in ir_gdb.c) */
814 int ir_gdb_register(const char    *name,
815                     const void    *start,
816                     size_t         size,
817                     uint32_t       sp_offset,
818                     uint32_t       sp_adjustment);
819 void ir_gdb_unregister_all(void);
820 bool ir_gdb_present(void);
821 
822 /* IR load API (implementation in ir_load.c) */
823 struct _ir_loader {
824 	uint32_t default_func_flags;
825 	bool (*init_module)       (ir_loader *loader, const char *name, const char *filename, const char *target);
826 	bool (*external_sym_dcl)  (ir_loader *loader, const char *name, uint32_t flags);
827 	bool (*external_func_dcl) (ir_loader *loader, const char *name,
828                                uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
829 	bool (*forward_func_dcl)  (ir_loader *loader, const char *name,
830                                uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
831 	bool (*sym_dcl)           (ir_loader *loader, const char *name, uint32_t flags, size_t size);
832 	bool (*sym_data)          (ir_loader *loader, ir_type type, uint32_t count, const void *data);
833 	bool (*sym_data_str)      (ir_loader *loader, const char *str, size_t len);
834 	bool (*sym_data_pad)      (ir_loader *loader, size_t offset);
835 	bool (*sym_data_ref)      (ir_loader *loader, ir_op op, const char *ref, uintptr_t offset);
836 	bool (*sym_data_end)      (ir_loader *loader, uint32_t flags);
837 	bool (*func_init)         (ir_loader *loader, ir_ctx *ctx, const char *name);
838 	bool (*func_process)      (ir_loader *loader, ir_ctx *ctx, const char *name);
839 	void*(*resolve_sym_name)  (ir_loader *loader, const char *name, bool add_thunk);
840 	bool (*has_sym)           (ir_loader *loader, const char *name);
841 	bool (*add_sym)           (ir_loader *loader, const char *name, void *addr);
842 };
843 
844 void ir_loader_init(void);
845 void ir_loader_free(void);
846 int ir_load(ir_loader *loader, FILE *f);
847 
848 /* IR LLVM load API (implementation in ir_load_llvm.c) */
849 int ir_load_llvm_bitcode(ir_loader *loader, const char *filename);
850 int ir_load_llvm_asm(ir_loader *loader, const char *filename);
851 
852 /* IR save API (implementation in ir_save.c) */
853 #define IR_SAVE_CFG       (1<<0) /* add info about CFG */
854 #define IR_SAVE_CFG_MAP   (1<<1) /* add info about CFG block assignment */
855 #define IR_SAVE_USE_LISTS (1<<2) /* add info about def->use lists */
856 #define IR_SAVE_RULES     (1<<3) /* add info about selected code-generation rules */
857 #define IR_SAVE_REGS      (1<<4) /* add info about selected registers */
858 
859 void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f);
860 void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f);
861 
862 /* IR debug dump API (implementation in ir_dump.c) */
863 void ir_dump(const ir_ctx *ctx, FILE *f);
864 void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f);
865 void ir_dump_use_lists(const ir_ctx *ctx, FILE *f);
866 void ir_dump_cfg(ir_ctx *ctx, FILE *f);
867 void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f);
868 void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f);
869 void ir_dump_codegen(const ir_ctx *ctx, FILE *f);
870 
871 /* IR to C conversion (implementation in ir_emit_c.c) */
872 int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f);
873 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);
874 void ir_emit_c_sym_decl(const char *name, uint32_t flags, FILE *f);
875 
876 /* IR to LLVM conversion (implementation in ir_emit_llvm.c) */
877 int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f);
878 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);
879 void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, FILE *f);
880 
881 /* IR verification API (implementation in ir_check.c) */
882 bool ir_check(const ir_ctx *ctx);
883 void ir_consistency_check(void);
884 
885 /* Code patching (implementation in ir_patch.c) */
886 int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr);
887 
888 /* CPU information (implementation in ir_cpuinfo.c) */
889 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
890 # define IR_X86_SSE2     (1<<0)
891 # define IR_X86_SSE3     (1<<1)
892 # define IR_X86_SSSE3    (1<<2)
893 # define IR_X86_SSE41    (1<<3)
894 # define IR_X86_SSE42    (1<<4)
895 # define IR_X86_AVX      (1<<5)
896 # define IR_X86_AVX2     (1<<6)
897 # define IR_X86_BMI1     (1<<7)
898 # define IR_X86_CLDEMOTE (1<<8)
899 #endif
900 
901 uint32_t ir_cpuinfo(void);
902 
903 /* Deoptimization helpers */
904 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);
905 
906 /* A reference IR JIT compiler */
ir_jit_compile(ir_ctx * ctx,int opt_level,size_t * size)907 IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size)
908 {
909 	if (opt_level == 0) {
910 		if (ctx->flags & IR_OPT_FOLDING) {
911 			// IR_ASSERT(0 && "IR_OPT_FOLDING is incompatible with -O0");
912 			return NULL;
913 		}
914 		ctx->flags &= ~(IR_OPT_CFG | IR_OPT_CODEGEN);
915 
916 		ir_build_def_use_lists(ctx);
917 
918 		if (!ir_build_cfg(ctx)
919 		 || !ir_match(ctx)
920 		 || !ir_assign_virtual_registers(ctx)
921 		 || !ir_compute_dessa_moves(ctx)) {
922 			return NULL;
923 		}
924 
925 		return ir_emit_code(ctx, size);
926 	} else if (opt_level == 1 || opt_level == 2) {
927 		if (!(ctx->flags & IR_OPT_FOLDING)) {
928 			// IR_ASSERT(0 && "IR_OPT_FOLDING must be set in ir_init() for -O1 and -O2");
929 			return NULL;
930 		}
931 		ctx->flags |= IR_OPT_CFG | IR_OPT_CODEGEN;
932 
933 		ir_build_def_use_lists(ctx);
934 
935 		if (opt_level == 2
936 		 && !ir_sccp(ctx)) {
937 			return NULL;
938 		}
939 
940 		if (!ir_build_cfg(ctx)
941 		 || !ir_build_dominators_tree(ctx)
942 		 || !ir_find_loops(ctx)
943 		 || !ir_gcm(ctx)
944 		 || !ir_schedule(ctx)
945 		 || !ir_match(ctx)
946 		 || !ir_assign_virtual_registers(ctx)
947 		 || !ir_compute_live_ranges(ctx)
948 		 || !ir_coalesce(ctx)
949 		 || !ir_reg_alloc(ctx)
950 		 || !ir_schedule_blocks(ctx)) {
951 			return NULL;
952 		}
953 
954 		return ir_emit_code(ctx, size);
955 	} else {
956 		// IR_ASSERT(0 && "wrong optimization level");
957 		return NULL;
958 	}
959 }
960 
961 #define IR_ERROR_CODE_MEM_OVERFLOW               1
962 #define IR_ERROR_FIXED_STACK_FRAME_OVERFLOW      2
963 #define IR_ERROR_UNSUPPORTED_CODE_RULE           3
964 #define IR_ERROR_LINK                            4
965 #define IR_ERROR_ENCODE                          5
966 
967 /* IR Memmory Allocation */
968 #ifndef ir_mem_malloc
969 # define ir_mem_malloc   malloc
970 #endif
971 #ifndef ir_mem_calloc
972 # define ir_mem_calloc   calloc
973 #endif
974 #ifndef ir_mem_realloc
975 # define ir_mem_realloc  realloc
976 #endif
977 #ifndef ir_mem_free
978 # define ir_mem_free     free
979 #endif
980 
981 #ifndef ir_mem_pmalloc
982 # define ir_mem_pmalloc  malloc
983 #endif
984 #ifndef ir_mem_pcalloc
985 # define ir_mem_pcalloc  calloc
986 #endif
987 #ifndef ir_mem_prealloc
988 # define ir_mem_prealloc realloc
989 #endif
990 #ifndef ir_mem_pfree
991 # define ir_mem_pfree    free
992 #endif
993 
994 void *ir_mem_mmap(size_t size);
995 int ir_mem_unmap(void *ptr, size_t size);
996 int ir_mem_protect(void *ptr, size_t size);
997 int ir_mem_unprotect(void *ptr, size_t size);
998 int ir_mem_flush(void *ptr, size_t size);
999 
1000 #ifdef __cplusplus
1001 } /* extern "C" */
1002 #endif
1003 
1004 #endif /* IR_H */
1005