Coverage Report

Created: 2025-11-16 06:23

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