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) || 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 # 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 # define IR_DEBUG_BB_SCHEDULE (1U<<31)
545 #endif
546
547 typedef struct _ir_ctx ir_ctx;
548 typedef struct _ir_use_list ir_use_list;
549 typedef struct _ir_block ir_block;
550 typedef struct _ir_arena ir_arena;
551 typedef struct _ir_live_interval ir_live_interval;
552 typedef struct _ir_live_range ir_live_range;
553 typedef struct _ir_loader ir_loader;
554 typedef int8_t ir_regs[4];
555
556 typedef void (*ir_snapshot_create_t)(ir_ctx *ctx, ir_ref addr);
557
558 #if defined(IR_TARGET_AARCH64)
559 typedef const void *(*ir_get_exit_addr_t)(uint32_t exit_num);
560 typedef const void *(*ir_get_veneer_t)(ir_ctx *ctx, const void *addr);
561 typedef bool (*ir_set_veneer_t)(ir_ctx *ctx, const void *addr, const void *veneer);
562 #endif
563
564 typedef struct _ir_code_buffer {
565 void *start;
566 void *end;
567 void *pos;
568 } ir_code_buffer;
569
570 struct _ir_ctx {
571 ir_insn *ir_base; /* two directional array - instructions grow down, constants grow up */
572 ir_ref insns_count; /* number of instructions stored in instructions buffer */
573 ir_ref insns_limit; /* size of allocated instructions buffer (it's extended when overflow) */
574 ir_ref consts_count; /* number of constants stored in constants buffer */
575 ir_ref consts_limit; /* size of allocated constants buffer (it's extended when overflow) */
576 uint32_t flags; /* IR context flags (see IR_* defines above) */
577 uint32_t flags2; /* IR context private flags (see IR_* defines in ir_private.h) */
578 ir_type ret_type; /* Function return type */
579 uint32_t mflags; /* CPU specific flags (see IR_X86_... macros below) */
580 int32_t status; /* non-zero error code (see IR_ERROR_... macros), app may use negative codes */
581 ir_ref fold_cse_limit; /* CSE finds identical insns backward from "insn_count" to "fold_cse_limit" */
582 ir_insn fold_insn; /* temporary storage for folding engine */
583 ir_hashtab *binding;
584 ir_use_list *use_lists; /* def->use lists for each instruction */
585 ir_ref *use_edges; /* the actual uses: use = ctx->use_edges[ctx->use_lists[def].refs + n] */
586 ir_ref use_edges_count; /* number of elements in use_edges[] array */
587 uint32_t cfg_blocks_count; /* number of elements in cfg_blocks[] array */
588 uint32_t cfg_edges_count; /* number of elements in cfg_edges[] array */
589 ir_block *cfg_blocks; /* list of basic blocks (starts from 1) */
590 uint32_t *cfg_edges; /* the actual basic blocks predecessors and successors edges */
591 uint32_t *cfg_map; /* map of instructions to basic block number */
592 uint32_t *cfg_schedule; /* BB order for code generation */
593 uint32_t *rules; /* array of target specific code-generation rules (for each instruction) */
594 uint32_t *vregs;
595 ir_ref vregs_count;
596 int32_t spill_base; /* base register for special spill area (e.g. PHP VM frame pointer) */
597 uint64_t fixed_regset; /* fixed registers, excluded for regular register allocation */
598 int32_t fixed_stack_red_zone; /* reusable stack allocated by caller (default 0) */
599 int32_t fixed_stack_frame_size; /* fixed stack allocated by generated code for spills and registers save/restore */
600 int32_t fixed_call_stack_size; /* fixed preallocated stack for parameter passing (default 0) */
601 uint64_t fixed_save_regset; /* registers that always saved/restored in prologue/epilogue */
602 uint32_t locals_area_size;
603 uint32_t gp_reg_params;
604 uint32_t fp_reg_params;
605 int32_t param_stack_size;
606 ir_live_interval **live_intervals;
607 ir_arena *arena;
608 ir_live_range *unused_ranges;
609 ir_regs *regs;
610 ir_strtab *fused_regs;
611 ir_ref *prev_ref;
612 union {
613 void *data;
614 ir_ref control; /* used by IR construction API (see ir_builder.h) */
615 ir_ref bb_start; /* used by target CPU instruction matcher */
616 ir_ref vars; /* list of VARs (used by register allocator) */
617 };
618 ir_snapshot_create_t snapshot_create;
619 int32_t stack_frame_alignment;
620 int32_t stack_frame_size; /* spill stack frame size (used by register allocator and code generator) */
621 int32_t call_stack_size; /* stack for parameter passing (used by register allocator and code generator) */
622 uint64_t used_preserved_regs;
623 #ifdef IR_TARGET_X86
624 int32_t ret_slot;
625 #endif
626 uint32_t rodata_offset;
627 uint32_t jmp_table_offset;
628 uint32_t entries_count;
629 uint32_t *entries; /* array of ENTRY blocks */
630 void *osr_entry_loads;
631 ir_code_buffer *code_buffer;
632 #if defined(IR_TARGET_AARCH64)
633 int32_t deoptimization_exits;
634 const void *deoptimization_exits_base;
635 ir_get_exit_addr_t get_exit_addr;
636 ir_get_veneer_t get_veneer;
637 ir_set_veneer_t set_veneer;
638 #endif
639 ir_loader *loader;
640 ir_strtab strtab;
641 ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP + 1];
642 ir_ref prev_const_chain[IR_LAST_TYPE];
643 };
644
645 /* Basic IR Construction API (implementation in ir.c) */
646 void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit);
647 void ir_free(ir_ctx *ctx);
648 void ir_truncate(ir_ctx *ctx);
649
650 ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type);
651 ir_ref ir_const_i8(ir_ctx *ctx, int8_t c);
652 ir_ref ir_const_i16(ir_ctx *ctx, int16_t c);
653 ir_ref ir_const_i32(ir_ctx *ctx, int32_t c);
654 ir_ref ir_const_i64(ir_ctx *ctx, int64_t c);
655 ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c);
656 ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c);
657 ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c);
658 ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c);
659 ir_ref ir_const_bool(ir_ctx *ctx, bool c);
660 ir_ref ir_const_char(ir_ctx *ctx, char c);
661 ir_ref ir_const_float(ir_ctx *ctx, float c);
662 ir_ref ir_const_double(ir_ctx *ctx, double c);
663 ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c);
664
665 ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto);
666 ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto);
667 ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str);
668 ir_ref ir_const_str(ir_ctx *ctx, ir_ref str);
669
670 ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c);
671
672 void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted);
673
674 ir_ref ir_str(ir_ctx *ctx, const char *s);
675 ir_ref ir_strl(ir_ctx *ctx, const char *s, size_t len);
676 const char *ir_get_str(const ir_ctx *ctx, ir_ref idx);
677 const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len);
678
679 #define IR_MAX_PROTO_PARAMS 255
680
681 typedef struct _ir_proto_t {
682 uint8_t flags;
683 uint8_t ret_type;
684 uint8_t params_count;
685 uint8_t param_types[5];
686 } ir_proto_t;
687
688 ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type);
689 ir_ref ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1);
690 ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2);
691 ir_ref ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3);
692 ir_ref ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
693 ir_type t4);
694 ir_ref ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
695 ir_type t4, ir_type t5);
696 ir_ref ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_counts, uint8_t *param_types);
697
698 ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
699
700 ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt);
701 ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
702 ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
703 ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
704
705 ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count);
706 void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val);
707
ir_set_op1(ir_ctx * ctx,ir_ref ref,ir_ref val)708 IR_ALWAYS_INLINE void ir_set_op1(ir_ctx *ctx, ir_ref ref, ir_ref val)
709 {
710 ctx->ir_base[ref].op1 = val;
711 }
712
ir_set_op2(ir_ctx * ctx,ir_ref ref,ir_ref val)713 IR_ALWAYS_INLINE void ir_set_op2(ir_ctx *ctx, ir_ref ref, ir_ref val)
714 {
715 ctx->ir_base[ref].op2 = val;
716 }
717
ir_set_op3(ir_ctx * ctx,ir_ref ref,ir_ref val)718 IR_ALWAYS_INLINE void ir_set_op3(ir_ctx *ctx, ir_ref ref, ir_ref val)
719 {
720 ctx->ir_base[ref].op3 = val;
721 }
722
ir_insn_op(const ir_insn * insn,int32_t n)723 IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
724 {
725 const ir_ref *p = insn->ops + n;
726 return *p;
727 }
728
ir_insn_set_op(ir_insn * insn,int32_t n,ir_ref val)729 IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
730 {
731 ir_ref *p = insn->ops + n;
732 *p = val;
733 }
734
735 ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
736
737 ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt);
738 ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
739 ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
740 ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
741
742 ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos);
743 ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name);
744 ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def);
745
746 /* Def -> Use lists */
747 void ir_build_def_use_lists(ir_ctx *ctx);
748
749 /* CFG - Control Flow Graph (implementation in ir_cfg.c) */
750 int ir_build_cfg(ir_ctx *ctx);
751 int ir_remove_unreachable_blocks(ir_ctx *ctx);
752 int ir_build_dominators_tree(ir_ctx *ctx);
753 int ir_find_loops(ir_ctx *ctx);
754 int ir_schedule_blocks(ir_ctx *ctx);
755 void ir_build_prev_refs(ir_ctx *ctx);
756
757 /* SCCP - Sparse Conditional Constant Propagation (implementation in ir_sccp.c) */
758 int ir_sccp(ir_ctx *ctx);
759
760 /* GCM - Global Code Motion and scheduling (implementation in ir_gcm.c) */
761 int ir_gcm(ir_ctx *ctx);
762 int ir_schedule(ir_ctx *ctx);
763
764 /* Liveness & Register Allocation (implementation in ir_ra.c) */
765 #define IR_REG_NONE -1
766 #define IR_REG_SPILL_LOAD (1<<6)
767 #define IR_REG_SPILL_STORE (1<<6)
768 #define IR_REG_SPILL_SPECIAL (1<<7)
769 #define IR_REG_SPILLED(r) \
770 ((r) & (IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))
771 #define IR_REG_NUM(r) \
772 ((int8_t)((r) == IR_REG_NONE ? IR_REG_NONE : ((r) & ~(IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))))
773
774 int ir_assign_virtual_registers(ir_ctx *ctx);
775 int ir_compute_live_ranges(ir_ctx *ctx);
776 int ir_coalesce(ir_ctx *ctx);
777 int ir_compute_dessa_moves(ir_ctx *ctx);
778 int ir_reg_alloc(ir_ctx *ctx);
779
780 int ir_regs_number(void);
781 bool ir_reg_is_int(int32_t reg);
782 const char *ir_reg_name(int8_t reg, ir_type type);
783 int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref);
784
785 /* Target CPU instruction selection and code generation (see ir_x86.c) */
786 int ir_match(ir_ctx *ctx);
787 void *ir_emit_code(ir_ctx *ctx, size_t *size);
788
789 bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr);
790 void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr);
791 void ir_fix_thunk(void *thunk_entry, void *addr);
792
793 /* Target address resolution (implementation in ir_emit.c) */
794 void *ir_resolve_sym_name(const char *name);
795
796 /* Target CPU disassembler (implementation in ir_disasm.c) */
797 int ir_disasm_init(void);
798 void ir_disasm_free(void);
799 void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size);
800 const char* ir_disasm_find_symbol(uint64_t addr, int64_t *offset);
801 int ir_disasm(const char *name,
802 const void *start,
803 size_t size,
804 bool asm_addr,
805 ir_ctx *ctx,
806 FILE *f);
807
808 /* Linux perf interface (implementation in ir_perf.c) */
809 int ir_perf_jitdump_open(void);
810 int ir_perf_jitdump_close(void);
811 int ir_perf_jitdump_register(const char *name, const void *start, size_t size);
812 void ir_perf_map_register(const char *name, const void *start, size_t size);
813
814 /* GDB JIT interface (implementation in ir_gdb.c) */
815 int ir_gdb_register(const char *name,
816 const void *start,
817 size_t size,
818 uint32_t sp_offset,
819 uint32_t sp_adjustment);
820 void ir_gdb_unregister_all(void);
821 bool ir_gdb_present(void);
822
823 /* IR load API (implementation in ir_load.c) */
824 struct _ir_loader {
825 uint32_t default_func_flags;
826 bool (*init_module) (ir_loader *loader, const char *name, const char *filename, const char *target);
827 bool (*external_sym_dcl) (ir_loader *loader, const char *name, uint32_t flags);
828 bool (*external_func_dcl) (ir_loader *loader, const char *name,
829 uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
830 bool (*forward_func_dcl) (ir_loader *loader, const char *name,
831 uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
832 bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size);
833 bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data);
834 bool (*sym_data_str) (ir_loader *loader, const char *str, size_t len);
835 bool (*sym_data_pad) (ir_loader *loader, size_t offset);
836 bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref, uintptr_t offset);
837 bool (*sym_data_end) (ir_loader *loader, uint32_t flags);
838 bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name);
839 bool (*func_process) (ir_loader *loader, ir_ctx *ctx, const char *name);
840 void*(*resolve_sym_name) (ir_loader *loader, const char *name, bool add_thunk);
841 bool (*has_sym) (ir_loader *loader, const char *name);
842 bool (*add_sym) (ir_loader *loader, const char *name, void *addr);
843 };
844
845 void ir_loader_init(void);
846 void ir_loader_free(void);
847 int ir_load(ir_loader *loader, FILE *f);
848
849 /* IR LLVM load API (implementation in ir_load_llvm.c) */
850 int ir_load_llvm_bitcode(ir_loader *loader, const char *filename);
851 int ir_load_llvm_asm(ir_loader *loader, const char *filename);
852
853 /* IR save API (implementation in ir_save.c) */
854 #define IR_SAVE_CFG (1<<0) /* add info about CFG */
855 #define IR_SAVE_CFG_MAP (1<<1) /* add info about CFG block assignment */
856 #define IR_SAVE_USE_LISTS (1<<2) /* add info about def->use lists */
857 #define IR_SAVE_RULES (1<<3) /* add info about selected code-generation rules */
858 #define IR_SAVE_REGS (1<<4) /* add info about selected registers */
859
860 void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f);
861 void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f);
862
863 /* IR debug dump API (implementation in ir_dump.c) */
864 void ir_dump(const ir_ctx *ctx, FILE *f);
865 void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f);
866 void ir_dump_use_lists(const ir_ctx *ctx, FILE *f);
867 void ir_dump_cfg(ir_ctx *ctx, FILE *f);
868 void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f);
869 void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f);
870 void ir_dump_codegen(const ir_ctx *ctx, FILE *f);
871
872 /* IR to C conversion (implementation in ir_emit_c.c) */
873 int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f);
874 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);
875 void ir_emit_c_sym_decl(const char *name, uint32_t flags, FILE *f);
876
877 /* IR to LLVM conversion (implementation in ir_emit_llvm.c) */
878 int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f);
879 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);
880 void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, FILE *f);
881
882 /* IR verification API (implementation in ir_check.c) */
883 bool ir_check(const ir_ctx *ctx);
884 void ir_consistency_check(void);
885
886 /* Code patching (implementation in ir_patch.c) */
887 int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr);
888
889 /* CPU information (implementation in ir_cpuinfo.c) */
890 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
891 # define IR_X86_SSE2 (1<<0)
892 # define IR_X86_SSE3 (1<<1)
893 # define IR_X86_SSSE3 (1<<2)
894 # define IR_X86_SSE41 (1<<3)
895 # define IR_X86_SSE42 (1<<4)
896 # define IR_X86_AVX (1<<5)
897 # define IR_X86_AVX2 (1<<6)
898 # define IR_X86_BMI1 (1<<7)
899 # define IR_X86_CLDEMOTE (1<<8)
900 #endif
901
902 uint32_t ir_cpuinfo(void);
903
904 /* Deoptimization helpers */
905 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);
906
907 /* A reference IR JIT compiler */
ir_jit_compile(ir_ctx * ctx,int opt_level,size_t * size)908 IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size)
909 {
910 if (opt_level == 0) {
911 if (ctx->flags & IR_OPT_FOLDING) {
912 // IR_ASSERT(0 && "IR_OPT_FOLDING is incompatible with -O0");
913 return NULL;
914 }
915 ctx->flags &= ~(IR_OPT_CFG | IR_OPT_CODEGEN);
916
917 ir_build_def_use_lists(ctx);
918
919 if (!ir_build_cfg(ctx)
920 || !ir_match(ctx)
921 || !ir_assign_virtual_registers(ctx)
922 || !ir_compute_dessa_moves(ctx)) {
923 return NULL;
924 }
925
926 return ir_emit_code(ctx, size);
927 } else if (opt_level == 1 || opt_level == 2) {
928 if (!(ctx->flags & IR_OPT_FOLDING)) {
929 // IR_ASSERT(0 && "IR_OPT_FOLDING must be set in ir_init() for -O1 and -O2");
930 return NULL;
931 }
932 ctx->flags |= IR_OPT_CFG | IR_OPT_CODEGEN;
933
934 ir_build_def_use_lists(ctx);
935
936 if (opt_level == 2
937 && !ir_sccp(ctx)) {
938 return NULL;
939 }
940
941 if (!ir_build_cfg(ctx)
942 || !ir_build_dominators_tree(ctx)
943 || !ir_find_loops(ctx)
944 || !ir_gcm(ctx)
945 || !ir_schedule(ctx)
946 || !ir_match(ctx)
947 || !ir_assign_virtual_registers(ctx)
948 || !ir_compute_live_ranges(ctx)
949 || !ir_coalesce(ctx)
950 || !ir_reg_alloc(ctx)
951 || !ir_schedule_blocks(ctx)) {
952 return NULL;
953 }
954
955 return ir_emit_code(ctx, size);
956 } else {
957 // IR_ASSERT(0 && "wrong optimization level");
958 return NULL;
959 }
960 }
961
962 #define IR_ERROR_CODE_MEM_OVERFLOW 1
963 #define IR_ERROR_FIXED_STACK_FRAME_OVERFLOW 2
964 #define IR_ERROR_UNSUPPORTED_CODE_RULE 3
965 #define IR_ERROR_LINK 4
966 #define IR_ERROR_ENCODE 5
967
968 /* IR Memmory Allocation */
969 #ifndef ir_mem_malloc
970 # define ir_mem_malloc malloc
971 #endif
972 #ifndef ir_mem_calloc
973 # define ir_mem_calloc calloc
974 #endif
975 #ifndef ir_mem_realloc
976 # define ir_mem_realloc realloc
977 #endif
978 #ifndef ir_mem_free
979 # define ir_mem_free free
980 #endif
981
982 #ifndef ir_mem_pmalloc
983 # define ir_mem_pmalloc malloc
984 #endif
985 #ifndef ir_mem_pcalloc
986 # define ir_mem_pcalloc calloc
987 #endif
988 #ifndef ir_mem_prealloc
989 # define ir_mem_prealloc realloc
990 #endif
991 #ifndef ir_mem_pfree
992 # define ir_mem_pfree free
993 #endif
994
995 void *ir_mem_mmap(size_t size);
996 int ir_mem_unmap(void *ptr, size_t size);
997 int ir_mem_protect(void *ptr, size_t size);
998 int ir_mem_unprotect(void *ptr, size_t size);
999 int ir_mem_flush(void *ptr, size_t size);
1000
1001 #ifdef __cplusplus
1002 } /* extern "C" */
1003 #endif
1004
1005 #endif /* IR_H */
1006