Coverage Report

Created: 2025-09-27 06:26

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