Coverage Report

Created: 2025-12-31 07:28

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