Coverage Report

Created: 2026-06-02 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/jit/ir/ir.c
Line
Count
Source
1
/*
2
 * IR - Lightweight JIT Compilation Framework
3
 * (IR construction, folding, utilities)
4
 * Copyright (C) 2022 Zend by Perforce.
5
 * Authors: Dmitry Stogov <dmitry@php.net>
6
 *
7
 * The logical IR representation is based on Cliff Click's Sea of Nodes.
8
 * See: C. Click, M. Paleczny. "A Simple Graph-Based Intermediate
9
 * Representation" In ACM SIGPLAN Workshop on Intermediate Representations
10
 * (IR '95), pages 35-49, Jan. 1995.
11
 *
12
 * The physical IR representation is based on Mike Pall's LuaJIT IR.
13
 * See: M. Pall. "LuaJIT 2.0 intellectual property disclosure and research
14
 * opportunities" November 2009 http://lua-users.org/lists/lua-l/2009-11/msg00089.html
15
 */
16
17
#ifndef _GNU_SOURCE
18
# define _GNU_SOURCE
19
#endif
20
21
#ifndef _WIN32
22
# include <sys/mman.h>
23
# if defined(__linux__) || defined(__sun)
24
#  include <alloca.h>
25
# endif
26
# if defined(__APPLE__) && defined(__aarch64__)
27
#  include <libkern/OSCacheControl.h>
28
# endif
29
#else
30
# define WIN32_LEAN_AND_MEAN
31
# include <windows.h>
32
#endif
33
34
#include "ir.h"
35
#include "ir_private.h"
36
37
#include <stddef.h>
38
#include <stdlib.h>
39
#include <math.h>
40
41
#ifdef HAVE_VALGRIND
42
# include <valgrind/valgrind.h>
43
#endif
44
45
#define IR_TYPE_FLAGS(name, type, field, flags) ((flags)|sizeof(type)),
46
#define IR_TYPE_NAME(name, type, field, flags)  #name,
47
#define IR_TYPE_CNAME(name, type, field, flags) #type,
48
#define IR_TYPE_SIZE(name, type, field, flags)  sizeof(type),
49
#define IR_OP_NAME(name, flags, op1, op2, op3)  #name,
50
51
const uint8_t ir_type_flags[IR_LAST_TYPE] = {
52
  0,
53
  IR_TYPES(IR_TYPE_FLAGS)
54
};
55
56
const char *ir_type_name[IR_LAST_TYPE] = {
57
  "void",
58
  IR_TYPES(IR_TYPE_NAME)
59
};
60
61
const uint8_t ir_type_size[IR_LAST_TYPE] = {
62
  0,
63
  IR_TYPES(IR_TYPE_SIZE)
64
};
65
66
const char *ir_type_cname[IR_LAST_TYPE] = {
67
  "void",
68
  IR_TYPES(IR_TYPE_CNAME)
69
};
70
71
const char *ir_op_name[IR_LAST_OP] = {
72
  IR_OPS(IR_OP_NAME)
73
#ifdef IR_PHP
74
  IR_PHP_OPS(IR_OP_NAME)
75
#endif
76
};
77
78
void ir_print_escaped_str(const char *s, size_t len, FILE *f)
79
0
{
80
0
  char ch;
81
82
0
  while (len > 0) {
83
0
    ch = *s;
84
0
    switch (ch) {
85
0
      case '\\': fputs("\\\\", f); break;
86
0
      case '\'': fputs("'", f); break;
87
0
      case '\"': fputs("\\\"", f); break;
88
0
      case '\a': fputs("\\a", f); break;
89
0
      case '\b': fputs("\\b", f); break;
90
0
      case '\033': fputs("\\e", f); break;
91
0
      case '\f': fputs("\\f", f); break;
92
0
      case '\n': fputs("\\n", f); break;
93
0
      case '\r': fputs("\\r", f); break;
94
0
      case '\t': fputs("\\t", f); break;
95
0
      case '\v': fputs("\\v", f); break;
96
0
      case '\?': fputs("\\?", f); break;
97
0
      default:
98
#ifdef __aarch64__
99
        if (ch < 32) {
100
#else
101
0
        if (ch >= 0 && ch < 32) {
102
0
#endif
103
0
          fprintf(f, "\\%c%c%c",
104
0
            '0' + ((ch >> 6) % 8),
105
0
            '0' + ((ch >> 3) % 8),
106
0
            '0' + (ch % 8));
107
0
          break;
108
0
        } else {
109
0
          fputc(ch, f);
110
0
        }
111
0
    }
112
0
    s++;
113
0
    len--;
114
0
  }
115
0
}
116
117
void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted)
118
0
{
119
0
  char buf[128];
120
121
0
  if (insn->op == IR_FUNC || insn->op == IR_SYM || insn->op == IR_LABEL) {
122
0
    fprintf(f, "%s", ir_get_str(ctx, insn->val.name));
123
0
    return;
124
0
  } else if (insn->op == IR_STR) {
125
0
    size_t len;
126
0
    const char *str = ir_get_strl(ctx, insn->val.str, &len);
127
128
0
    if (quoted) {
129
0
      fprintf(f, "\"");
130
0
      ir_print_escaped_str(str, len, f);
131
0
      fprintf(f, "\"");
132
0
    } else {
133
0
      ir_print_escaped_str(str, len, f);
134
0
    }
135
0
    return;
136
0
  }
137
0
  IR_ASSERT(IR_IS_CONST_OP(insn->op) || insn->op == IR_FUNC_ADDR);
138
0
  switch (insn->type) {
139
0
    case IR_BOOL:
140
0
      fprintf(f, "%u", insn->val.b);
141
0
      break;
142
0
    case IR_U8:
143
0
      fprintf(f, "%u", insn->val.u8);
144
0
      break;
145
0
    case IR_U16:
146
0
      fprintf(f, "%u", insn->val.u16);
147
0
      break;
148
0
    case IR_U32:
149
0
      fprintf(f, "%u", insn->val.u32);
150
0
      break;
151
0
    case IR_U64:
152
0
      fprintf(f, "%" PRIu64, insn->val.u64);
153
0
      break;
154
0
    case IR_ADDR:
155
0
      if (insn->val.addr) {
156
0
        fprintf(f, "0x%" PRIxPTR, insn->val.addr);
157
0
      } else {
158
0
        fprintf(f, "0");
159
0
      }
160
0
      break;
161
0
    case IR_CHAR:
162
0
      if (insn->val.c == '\\') {
163
0
        fprintf(f, "'\\\\'");
164
0
      } else if (insn->val.c == '\'') {
165
0
        fprintf(f, "'\\\''");
166
0
      } else if (insn->val.c >= ' ') {
167
0
        fprintf(f, "'%c'", insn->val.c);
168
0
      } else if (insn->val.c == '\t') {
169
0
        fprintf(f, "'\\t'");
170
0
      } else if (insn->val.c == '\r') {
171
0
        fprintf(f, "'\\r'");
172
0
      } else if (insn->val.c == '\n') {
173
0
        fprintf(f, "'\\n'");
174
0
      } else if (insn->val.c == '\0') {
175
0
        fprintf(f, "'\\0'");
176
0
      } else {
177
0
        fprintf(f, "%u", (unsigned char)insn->val.c);
178
0
      }
179
0
      break;
180
0
    case IR_I8:
181
0
      fprintf(f, "%d", insn->val.i8);
182
0
      break;
183
0
    case IR_I16:
184
0
      fprintf(f, "%d", insn->val.i16);
185
0
      break;
186
0
    case IR_I32:
187
0
      fprintf(f, "%d", insn->val.i32);
188
0
      break;
189
0
    case IR_I64:
190
0
      fprintf(f, "%" PRIi64, insn->val.i64);
191
0
      break;
192
0
    case IR_DOUBLE:
193
0
      if (isnan(insn->val.d)) {
194
0
        fprintf(f, "nan");
195
0
      } else {
196
0
        snprintf(buf, sizeof(buf), "%g", insn->val.d);
197
0
        if (strtod(buf, NULL) != insn->val.d) {
198
0
          snprintf(buf, sizeof(buf), "%.53e", insn->val.d);
199
0
          if (strtod(buf, NULL) != insn->val.d) {
200
0
            IR_ASSERT(0 && "can't format double");
201
0
          }
202
0
        }
203
0
        fprintf(f, "%s", buf);
204
0
      }
205
0
      break;
206
0
    case IR_FLOAT:
207
0
      if (isnan(insn->val.f)) {
208
0
        fprintf(f, "nan");
209
0
      } else {
210
0
        snprintf(buf, sizeof(buf), "%g", insn->val.f);
211
0
        if (strtod(buf, NULL) != insn->val.f) {
212
0
          snprintf(buf, sizeof(buf), "%.24e", insn->val.f);
213
0
          if (strtod(buf, NULL) != insn->val.f) {
214
0
            IR_ASSERT(0 && "can't format float");
215
0
          }
216
0
        }
217
0
        fprintf(f, "%s", buf);
218
0
      }
219
0
      break;
220
0
    default:
221
0
      IR_ASSERT(0);
222
0
      break;
223
0
  }
224
0
}
225
226
#define ir_op_flag_v       0
227
#define ir_op_flag_v0X3    (0 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
228
#define ir_op_flag_d       IR_OP_FLAG_DATA
229
#define ir_op_flag_d0      ir_op_flag_d
230
#define ir_op_flag_d1      (ir_op_flag_d | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
231
#define ir_op_flag_d1X1    (ir_op_flag_d | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
232
#define ir_op_flag_d1X2    (ir_op_flag_d | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
233
#define ir_op_flag_d2      (ir_op_flag_d | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
234
#define ir_op_flag_d2C     (ir_op_flag_d | IR_OP_FLAG_COMMUTATIVE | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
235
#define ir_op_flag_d3      (ir_op_flag_d | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
236
#define ir_op_flag_r       IR_OP_FLAG_DATA                                         // "d" and "r" are the same now
237
#define ir_op_flag_r0      ir_op_flag_r
238
#define ir_op_flag_p       (IR_OP_FLAG_DATA | IR_OP_FLAG_PINNED)
239
#define ir_op_flag_p1      (ir_op_flag_p | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
240
#define ir_op_flag_p1X1    (ir_op_flag_p | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
241
#define ir_op_flag_p1X2    (ir_op_flag_p | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
242
#define ir_op_flag_p2      (ir_op_flag_p | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
243
#define ir_op_flag_pN      (ir_op_flag_p | IR_OP_FLAG_VAR_INPUTS)
244
#define ir_op_flag_c       IR_OP_FLAG_CONTROL
245
#define ir_op_flag_c1X2    (ir_op_flag_c | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
246
#define ir_op_flag_c3      (ir_op_flag_c | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
247
#define ir_op_flag_S       (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_START)
248
#define ir_op_flag_S0X1    (ir_op_flag_S | 0 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
249
#define ir_op_flag_S1      (ir_op_flag_S | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
250
#define ir_op_flag_S1X1    (ir_op_flag_S | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
251
#define ir_op_flag_S2      (ir_op_flag_S | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
252
#define ir_op_flag_S2X1    (ir_op_flag_S | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
253
#define ir_op_flag_S3      (ir_op_flag_S | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
254
#define ir_op_flag_SN      (ir_op_flag_S | IR_OP_FLAG_VAR_INPUTS)
255
#define ir_op_flag_E       (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_END)
256
#define ir_op_flag_E1      (ir_op_flag_E | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
257
#define ir_op_flag_E2      (ir_op_flag_E | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
258
#define ir_op_flag_T       (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_END|IR_OP_FLAG_TERMINATOR)
259
#define ir_op_flag_T2X1    (ir_op_flag_T | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
260
#define ir_op_flag_T1X2    (ir_op_flag_T | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
261
#define ir_op_flag_l       (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_LOAD)
262
#define ir_op_flag_l0      ir_op_flag_l
263
#define ir_op_flag_l1      (ir_op_flag_l | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
264
#define ir_op_flag_l1X1    (ir_op_flag_l | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
265
#define ir_op_flag_l1X2    (ir_op_flag_l | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
266
#define ir_op_flag_l2      (ir_op_flag_l | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
267
#define ir_op_flag_l3      (ir_op_flag_l | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
268
#define ir_op_flag_s       (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_STORE)
269
#define ir_op_flag_s0      ir_op_flag_s
270
#define ir_op_flag_s1      (ir_op_flag_s | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
271
#define ir_op_flag_s2      (ir_op_flag_s | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
272
#define ir_op_flag_s2X1    (ir_op_flag_s | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
273
#define ir_op_flag_s3      (ir_op_flag_s | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
274
#define ir_op_flag_x1      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
275
#define ir_op_flag_x2      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
276
#define ir_op_flag_x2X1    (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
277
#define ir_op_flag_x3      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
278
#define ir_op_flag_xN      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | IR_OP_FLAG_VAR_INPUTS)
279
#define ir_op_flag_a1      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
280
#define ir_op_flag_a2      (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
281
282
#define ir_op_kind____     IR_OPND_UNUSED
283
#define ir_op_kind_def     IR_OPND_DATA
284
#define ir_op_kind_ref     IR_OPND_DATA
285
#define ir_op_kind_src     IR_OPND_CONTROL
286
#define ir_op_kind_reg     IR_OPND_CONTROL_DEP
287
#define ir_op_kind_ret     IR_OPND_CONTROL_REF
288
#define ir_op_kind_grd     IR_OPND_CONTROL_GUARD
289
#define ir_op_kind_str     IR_OPND_STR
290
#define ir_op_kind_num     IR_OPND_NUM
291
#define ir_op_kind_fld     IR_OPND_STR
292
#define ir_op_kind_var     IR_OPND_DATA
293
#define ir_op_kind_prb     IR_OPND_PROB
294
#define ir_op_kind_opt     IR_OPND_PROB
295
#define ir_op_kind_pro     IR_OPND_PROTO
296
#define ir_op_kind_lbl     IR_OPND_LABEL_REF
297
298
#define _IR_OP_FLAGS(name, flags, op1, op2, op3) \
299
  IR_OP_FLAGS(ir_op_flag_ ## flags, ir_op_kind_ ## op1, ir_op_kind_ ## op2, ir_op_kind_ ## op3),
300
301
const uint32_t ir_op_flags[IR_LAST_OP] = {
302
  IR_OPS(_IR_OP_FLAGS)
303
#ifdef IR_PHP
304
  IR_PHP_OPS(_IR_OP_FLAGS)
305
#endif
306
};
307
308
static void ir_grow_bottom(ir_ctx *ctx)
309
0
{
310
0
  ir_insn *buf = ctx->ir_base - ctx->consts_limit;
311
0
  ir_ref old_consts_limit = ctx->consts_limit;
312
313
0
  if (ctx->consts_limit < 1024 * 4) {
314
0
    ctx->consts_limit *= 2;
315
0
  } else if (ctx->consts_limit < 1024 * 4 * 2) {
316
0
    ctx->consts_limit = 1024 * 4 * 2;
317
0
  } else {
318
0
    ctx->consts_limit += 1024 * 4;
319
0
  }
320
0
  buf = ir_mem_realloc(buf, (ctx->consts_limit + ctx->insns_limit) * sizeof(ir_insn));
321
0
  memmove(buf + (ctx->consts_limit - old_consts_limit),
322
0
    buf,
323
0
    (old_consts_limit + ctx->insns_count) * sizeof(ir_insn));
324
0
  ctx->ir_base = buf + ctx->consts_limit;
325
0
}
326
327
static ir_ref ir_next_const(ir_ctx *ctx)
328
0
{
329
0
  ir_ref ref = ctx->consts_count;
330
331
0
  if (UNEXPECTED(ref >= ctx->consts_limit)) {
332
0
    ir_grow_bottom(ctx);
333
0
  }
334
0
  ctx->consts_count = ref + 1;
335
0
  return -ref;
336
0
}
337
338
static void ir_grow_top(ir_ctx *ctx)
339
0
{
340
0
  ir_ref old_insns_limit = ctx->insns_limit;
341
0
  ir_insn *buf = ctx->ir_base - ctx->consts_limit;
342
343
0
  if (ctx->insns_limit < 1024 * 4) {
344
0
    ctx->insns_limit *= 2;
345
0
  } else if (ctx->insns_limit < 1024 * 4 * 2) {
346
0
    ctx->insns_limit = 1024 * 4 * 2;
347
0
  } else {
348
0
    ctx->insns_limit += 1024 * 4;
349
0
  }
350
0
  buf = ir_mem_realloc(buf, (ctx->consts_limit + ctx->insns_limit) * sizeof(ir_insn));
351
0
  ctx->ir_base = buf + ctx->consts_limit;
352
353
0
  if (ctx->use_lists) {
354
0
    ctx->use_lists = ir_mem_realloc(ctx->use_lists, ctx->insns_limit * sizeof(ir_use_list));
355
0
    memset(ctx->use_lists + old_insns_limit, 0,
356
0
      (ctx->insns_limit - old_insns_limit) * sizeof(ir_use_list));
357
0
  }
358
359
0
  if (ctx->cfg_map) {
360
0
    ctx->cfg_map = ir_mem_realloc(ctx->cfg_map, ctx->insns_limit * sizeof(uint32_t));
361
0
    memset(ctx->cfg_map + old_insns_limit, 0,
362
0
      (ctx->insns_limit - old_insns_limit) * sizeof(uint32_t));
363
0
  }
364
0
}
365
366
static ir_ref ir_next_insn(ir_ctx *ctx)
367
0
{
368
0
  ir_ref ref = ctx->insns_count;
369
370
0
  if (UNEXPECTED(ref >= ctx->insns_limit)) {
371
0
    ir_grow_top(ctx);
372
0
  }
373
0
  ctx->insns_count = ref + 1;
374
0
  return ref;
375
0
}
376
377
void ir_truncate(ir_ctx *ctx)
378
0
{
379
0
  ir_insn *buf = ir_mem_malloc((ctx->consts_count + ctx->insns_count) * sizeof(ir_insn));
380
381
0
  memcpy(buf, ctx->ir_base - ctx->consts_count, (ctx->consts_count + ctx->insns_count) * sizeof(ir_insn));
382
0
  ir_mem_free(ctx->ir_base - ctx->consts_limit);
383
0
  ctx->insns_limit = ctx->insns_count;
384
0
  ctx->consts_limit = ctx->consts_count;
385
0
  ctx->ir_base = buf + ctx->consts_limit;
386
0
}
387
388
void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit)
389
0
{
390
0
  ir_insn *buf;
391
392
0
  IR_ASSERT(consts_limit >= IR_CONSTS_LIMIT_MIN);
393
0
  IR_ASSERT(insns_limit >= IR_INSNS_LIMIT_MIN);
394
395
0
  memset(ctx, 0, sizeof(ir_ctx));
396
397
0
  ctx->insns_count = IR_UNUSED + 1;
398
0
  ctx->insns_limit = insns_limit;
399
0
  ctx->consts_count = -(IR_TRUE - 1);
400
0
  ctx->consts_limit = consts_limit;
401
0
  ctx->const_hash = ctx->_const_hash;
402
0
  ctx->const_hash_mask = IR_CONST_HASH_SIZE - 1;
403
0
  ctx->fold_cse_limit = IR_UNUSED + 1;
404
0
  ctx->flags = flags;
405
406
0
  ctx->spill_base = -1;
407
0
  ctx->fixed_stack_frame_size = -1;
408
409
0
  buf = ir_mem_malloc((consts_limit + insns_limit) * sizeof(ir_insn));
410
0
  ctx->ir_base = buf + consts_limit;
411
412
0
  MAKE_NOP(&ctx->ir_base[IR_UNUSED]);
413
0
  ctx->ir_base[IR_NULL].optx = IR_OPT(IR_C_ADDR, IR_ADDR);
414
0
  ctx->ir_base[IR_NULL].val.u64 = 0;
415
0
  ctx->ir_base[IR_FALSE].optx = IR_OPT(IR_C_BOOL, IR_BOOL);
416
0
  ctx->ir_base[IR_FALSE].val.u64 = 0;
417
0
  ctx->ir_base[IR_TRUE].optx = IR_OPT(IR_C_BOOL, IR_BOOL);
418
0
  ctx->ir_base[IR_TRUE].val.u64 = 1;
419
0
}
420
421
void ir_free(ir_ctx *ctx)
422
0
{
423
0
  ir_insn *buf = ctx->ir_base - ctx->consts_limit;
424
0
  ir_mem_free(buf);
425
0
  if (ctx->value_params) {
426
0
    ir_mem_free(ctx->value_params);
427
0
  }
428
0
  if (ctx->strtab.data) {
429
0
    ir_strtab_free(&ctx->strtab);
430
0
  }
431
0
  if (ctx->binding) {
432
0
    ir_hashtab_free(ctx->binding);
433
0
    ir_mem_free(ctx->binding);
434
0
  }
435
0
  if (ctx->use_lists) {
436
0
    ir_mem_free(ctx->use_lists);
437
0
  }
438
0
  if (ctx->use_edges) {
439
0
    ir_mem_free(ctx->use_edges);
440
0
  }
441
0
  if (ctx->cfg_blocks) {
442
0
    ir_mem_free(ctx->cfg_blocks);
443
0
  }
444
0
  if (ctx->cfg_edges) {
445
0
    ir_mem_free(ctx->cfg_edges);
446
0
  }
447
0
  if (ctx->cfg_map) {
448
0
    ir_mem_free(ctx->cfg_map);
449
0
  }
450
0
  if (ctx->cfg_schedule) {
451
0
    ir_mem_free(ctx->cfg_schedule);
452
0
  }
453
0
  if (ctx->rules) {
454
0
    ir_mem_free(ctx->rules);
455
0
  }
456
0
  if (ctx->vregs) {
457
0
    ir_mem_free(ctx->vregs);
458
0
  }
459
0
  if (ctx->live_intervals) {
460
0
    ir_mem_free(ctx->live_intervals);
461
0
  }
462
0
  if (ctx->arena) {
463
0
    ir_arena_free(ctx->arena);
464
0
  }
465
0
  if (ctx->regs) {
466
0
    ir_mem_free(ctx->regs);
467
0
    if (ctx->fused_regs) {
468
0
      ir_strtab_free(ctx->fused_regs);
469
0
      ir_mem_free(ctx->fused_regs);
470
0
    }
471
0
  }
472
0
  if (ctx->prev_ref) {
473
0
    ir_mem_free(ctx->prev_ref);
474
0
  }
475
0
  if (ctx->entries) {
476
0
    ir_mem_free(ctx->entries);
477
0
  }
478
0
  if (ctx->osr_entry_loads) {
479
0
    ir_list_free((ir_list*)ctx->osr_entry_loads);
480
0
    ir_mem_free(ctx->osr_entry_loads);
481
0
  }
482
483
0
  if (ctx->const_hash_mask != IR_CONST_HASH_SIZE - 1) {
484
0
    ir_mem_free(ctx->const_hash);
485
0
  }
486
0
}
487
488
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t addr)
489
0
{
490
0
  ir_ref ref = ir_next_const(ctx);
491
0
  ir_insn *insn = &ctx->ir_base[ref];
492
493
0
  insn->optx = IR_OPT(IR_ADDR, IR_ADDR);
494
0
  insn->val.u64 = addr;
495
  /* don't insert into constants chain */
496
0
  insn->prev_const = IR_UNUSED;
497
498
0
  return ref;
499
0
}
500
501
IR_ALWAYS_INLINE uintptr_t ir_const_hash(ir_val val, uint32_t optx)
502
0
{
503
0
  return (val.u64 ^ (val.u64 >> 32) ^ optx);
504
0
}
505
506
static IR_NEVER_INLINE void ir_const_hash_rehash(ir_ctx *ctx)
507
0
{
508
0
  ir_insn *insn;
509
0
  ir_ref ref;
510
0
  uintptr_t hash;
511
512
0
  if (ctx->const_hash_mask != IR_CONST_HASH_SIZE - 1) {
513
0
    ir_mem_free(ctx->const_hash);
514
0
  }
515
0
  ctx->const_hash_mask = (ctx->const_hash_mask + 1) * 2 - 1;
516
0
  ctx->const_hash = ir_mem_calloc(ctx->const_hash_mask + 1, sizeof(ir_ref));
517
0
  for (ref = IR_TRUE - 1; ref > -ctx->consts_count; ref--) {
518
0
    insn = &ctx->ir_base[ref];
519
0
    hash = ir_const_hash(insn->val, insn->optx) & ctx->const_hash_mask;
520
0
    insn->prev_const = ctx->const_hash[hash];
521
0
    ctx->const_hash[hash] = ref;
522
0
  }
523
0
}
524
525
ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx)
526
0
{
527
0
  ir_insn *insn;
528
0
  ir_ref ref, prev;
529
0
  uintptr_t hash;
530
531
0
  if (type == IR_BOOL) {
532
0
    return val.u64 ? IR_TRUE : IR_FALSE;
533
0
  } else if (type == IR_ADDR && val.u64 == 0) {
534
0
    return IR_NULL;
535
0
  }
536
537
0
  hash = ir_const_hash(val, optx) & ctx->const_hash_mask;
538
0
  ref = ctx->const_hash[hash];
539
0
  while (ref) {
540
0
    insn = &ctx->ir_base[ref];
541
0
    if (insn->val.u64 == val.u64 && insn->optx == optx) {
542
0
      return ref;
543
0
    }
544
0
    ref = insn->prev_const;
545
0
  }
546
547
0
  if ((uintptr_t)ctx->consts_count > ctx->const_hash_mask) {
548
0
    ir_const_hash_rehash(ctx);
549
0
    hash = ir_const_hash(val, optx) & ctx->const_hash_mask;
550
0
  }
551
552
0
  prev = ctx->const_hash[hash];
553
0
  ctx->const_hash[hash] = -ctx->consts_count;
554
555
0
  ref = ir_next_const(ctx);
556
0
  insn = &ctx->ir_base[ref];
557
0
  insn->prev_const = prev;
558
559
0
  insn->optx = optx;
560
0
  insn->val.u64 = val.u64;
561
562
0
  return ref;
563
0
}
564
565
ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type)
566
0
{
567
0
  return ir_const_ex(ctx, val, type, IR_OPT(type, type));
568
0
}
569
570
ir_ref ir_const_i8(ir_ctx *ctx, int8_t c)
571
0
{
572
0
  ir_val val;
573
0
  val.i64 = c;
574
0
  return ir_const(ctx, val, IR_I8);
575
0
}
576
577
ir_ref ir_const_i16(ir_ctx *ctx, int16_t c)
578
0
{
579
0
  ir_val val;
580
0
  val.i64 = c;
581
0
  return ir_const(ctx, val, IR_I16);
582
0
}
583
584
ir_ref ir_const_i32(ir_ctx *ctx, int32_t c)
585
0
{
586
0
  ir_val val;
587
0
  val.i64 = c;
588
0
  return ir_const(ctx, val, IR_I32);
589
0
}
590
591
ir_ref ir_const_i64(ir_ctx *ctx, int64_t c)
592
0
{
593
0
  ir_val val;
594
0
  val.i64 = c;
595
0
  return ir_const(ctx, val, IR_I64);
596
0
}
597
598
ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c)
599
0
{
600
0
  ir_val val;
601
0
  val.u64 = c;
602
0
  return ir_const(ctx, val, IR_U8);
603
0
}
604
605
ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c)
606
0
{
607
0
  ir_val val;
608
0
  val.u64 = c;
609
0
  return ir_const(ctx, val, IR_U16);
610
0
}
611
612
ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c)
613
0
{
614
0
  ir_val val;
615
0
  val.u64 = c;
616
0
  return ir_const(ctx, val, IR_U32);
617
0
}
618
619
ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c)
620
0
{
621
0
  ir_val val;
622
0
  val.u64 = c;
623
0
  return ir_const(ctx, val, IR_U64);
624
0
}
625
626
ir_ref ir_const_bool(ir_ctx *ctx, bool c)
627
0
{
628
0
  return (c) ? IR_TRUE : IR_FALSE;
629
0
}
630
631
ir_ref ir_const_char(ir_ctx *ctx, char c)
632
0
{
633
0
  ir_val val;
634
0
  val.i64 = (signed char)c;
635
0
  return ir_const(ctx, val, IR_CHAR);
636
0
}
637
638
ir_ref ir_const_float(ir_ctx *ctx, float c)
639
0
{
640
0
  ir_val val;
641
0
  val.u32_hi = 0;
642
0
  val.f = c;
643
0
  return ir_const(ctx, val, IR_FLOAT);
644
0
}
645
646
ir_ref ir_const_double(ir_ctx *ctx, double c)
647
0
{
648
0
  ir_val val;
649
0
  val.d = c;
650
0
  return ir_const(ctx, val, IR_DOUBLE);
651
0
}
652
653
ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c)
654
0
{
655
0
  if (c == 0) {
656
0
    return IR_NULL;
657
0
  }
658
0
  ir_val val;
659
0
  val.u64 = c;
660
0
  return ir_const(ctx, val, IR_ADDR);
661
0
}
662
663
ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto)
664
0
{
665
0
  if (c == 0) {
666
0
    return IR_NULL;
667
0
  }
668
0
  ir_val val;
669
0
  val.u64 = c;
670
0
  IR_ASSERT(proto >= 0 && proto < 0xffff);
671
0
  return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_FUNC_ADDR, IR_ADDR, proto));
672
0
}
673
674
ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto)
675
0
{
676
0
  ir_val val;
677
0
  val.u64 = str;
678
0
  IR_ASSERT(proto >= 0 && proto < 0xffff);
679
0
  return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_FUNC, IR_ADDR, proto));
680
0
}
681
682
ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str)
683
0
{
684
0
  ir_val val;
685
0
  val.u64 = str;
686
0
  return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_SYM, IR_ADDR, 0));
687
0
}
688
689
ir_ref ir_const_str(ir_ctx *ctx, ir_ref str)
690
0
{
691
0
  ir_val val;
692
0
  val.u64 = str;
693
0
  return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_STR, IR_ADDR, 0));
694
0
}
695
696
ir_ref ir_const_label(ir_ctx *ctx, ir_ref str)
697
0
{
698
0
  ir_val val;
699
0
  val.u64 = str;
700
0
  return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_LABEL, IR_ADDR, 0));
701
0
}
702
703
ir_ref ir_str(ir_ctx *ctx, const char *s)
704
0
{
705
0
  size_t len;
706
707
0
  if (!ctx->strtab.data) {
708
0
    ir_strtab_init(&ctx->strtab, 64, 4096);
709
0
  }
710
0
  len = strlen(s);
711
0
  IR_ASSERT(len <= 0xffffffff);
712
0
  return ir_strtab_lookup(&ctx->strtab, s, (uint32_t)len, ir_strtab_count(&ctx->strtab) + 1);
713
0
}
714
715
ir_ref ir_strl(ir_ctx *ctx, const char *s, size_t len)
716
0
{
717
0
  if (!ctx->strtab.data) {
718
0
    ir_strtab_init(&ctx->strtab, 64, 4096);
719
0
  }
720
0
  IR_ASSERT(len <= 0xffffffff);
721
0
  return ir_strtab_lookup(&ctx->strtab, s, (uint32_t)len, ir_strtab_count(&ctx->strtab) + 1);
722
0
}
723
724
const char *ir_get_str(const ir_ctx *ctx, ir_ref idx)
725
0
{
726
0
  IR_ASSERT(ctx->strtab.data);
727
0
  return ir_strtab_str(&ctx->strtab, idx - 1);
728
0
}
729
730
const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len)
731
0
{
732
0
  IR_ASSERT(ctx->strtab.data);
733
0
  return ir_strtab_strl(&ctx->strtab, idx - 1, len);
734
0
}
735
736
ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type)
737
0
{
738
0
  ir_proto_t proto;
739
740
0
  proto.flags = flags;
741
0
  proto.ret_type = ret_type;
742
0
  proto.params_count = 0;
743
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 0);
744
0
}
745
746
ir_ref ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1)
747
0
{
748
0
  ir_proto_t proto;
749
750
0
  proto.flags = flags;
751
0
  proto.ret_type = ret_type;
752
0
  proto.params_count = 1;
753
0
  proto.param_types[0] = t1;
754
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 1);
755
0
}
756
757
ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2)
758
0
{
759
0
  ir_proto_t proto;
760
761
0
  proto.flags = flags;
762
0
  proto.ret_type = ret_type;
763
0
  proto.params_count = 2;
764
0
  proto.param_types[0] = t1;
765
0
  proto.param_types[1] = t2;
766
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 2);
767
0
}
768
769
ir_ref ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3)
770
0
{
771
0
  ir_proto_t proto;
772
773
0
  proto.flags = flags;
774
0
  proto.ret_type = ret_type;
775
0
  proto.params_count = 3;
776
0
  proto.param_types[0] = t1;
777
0
  proto.param_types[1] = t2;
778
0
  proto.param_types[2] = t3;
779
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 3);
780
0
}
781
782
ir_ref ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
783
                                                                ir_type t4)
784
0
{
785
0
  ir_proto_t proto;
786
787
0
  proto.flags = flags;
788
0
  proto.ret_type = ret_type;
789
0
  proto.params_count = 4;
790
0
  proto.param_types[0] = t1;
791
0
  proto.param_types[1] = t2;
792
0
  proto.param_types[2] = t3;
793
0
  proto.param_types[3] = t4;
794
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 4);
795
0
}
796
797
ir_ref ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
798
                                                                ir_type t4, ir_type t5)
799
0
{
800
0
  ir_proto_t proto;
801
802
0
  proto.flags = flags;
803
0
  proto.ret_type = ret_type;
804
0
  proto.params_count = 5;
805
0
  proto.param_types[0] = t1;
806
0
  proto.param_types[1] = t2;
807
0
  proto.param_types[2] = t3;
808
0
  proto.param_types[3] = t4;
809
0
  proto.param_types[4] = t5;
810
0
  return ir_strl(ctx, (const char *)&proto, offsetof(ir_proto_t, param_types) + 5);
811
0
}
812
813
ir_ref ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_count, uint8_t *param_types)
814
0
{
815
0
  ir_proto_t *proto = alloca(offsetof(ir_proto_t, param_types) + params_count);
816
817
0
  IR_ASSERT(params_count <= IR_MAX_PROTO_PARAMS);
818
0
  proto->flags = flags;
819
0
  proto->ret_type = ret_type;
820
0
  proto->params_count = params_count;
821
0
  if (params_count) {
822
0
    memcpy(proto->param_types, param_types, params_count);
823
0
  }
824
0
  return ir_strl(ctx, (const char *)proto, offsetof(ir_proto_t, param_types) + params_count);
825
0
}
826
827
/* IR construction */
828
ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
829
0
{
830
0
  ir_ref   ref = ir_next_insn(ctx);
831
0
  ir_insn *insn = &ctx->ir_base[ref];
832
833
0
  insn->optx = opt;
834
0
  insn->op1 = op1;
835
0
  insn->op2 = op2;
836
0
  insn->op3 = op3;
837
838
0
  return ref;
839
0
}
840
841
ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt)
842
0
{
843
0
  return ir_emit(ctx, opt, IR_UNUSED, IR_UNUSED, IR_UNUSED);
844
0
}
845
846
ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
847
0
{
848
0
  return ir_emit(ctx, opt, op1, IR_UNUSED, IR_UNUSED);
849
0
}
850
851
ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
852
0
{
853
0
  return ir_emit(ctx, opt, op1, op2, IR_UNUSED);
854
0
}
855
856
ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
857
0
{
858
0
  return ir_emit(ctx, opt, op1, op2, op3);
859
0
}
860
861
static ir_ref _ir_fold_cse(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
862
0
{
863
0
  ir_ref ref = ctx->prev_insn_chain[opt & IR_OPT_OP_MASK];
864
0
  const ir_insn *insn;
865
866
0
  if (ref) {
867
0
    ir_ref limit = ctx->fold_cse_limit;
868
869
0
    if (op1 > limit) {
870
0
      limit = op1;
871
0
    }
872
0
    if (op2 > limit) {
873
0
      limit = op2;
874
0
    }
875
0
    if (op3 > limit) {
876
0
      limit = op3;
877
0
    }
878
0
    while (ref >= limit) {
879
0
      insn = &ctx->ir_base[ref];
880
0
      if (insn->opt == opt && insn->op1 == op1 && insn->op2 == op2 && insn->op3 == op3) {
881
0
        return ref;
882
0
      }
883
0
      if (!insn->prev_insn_offset) {
884
0
        break;
885
0
      }
886
0
      ref = ref - (ir_ref)(uint32_t)insn->prev_insn_offset;
887
0
    }
888
0
  }
889
890
0
  return IR_UNUSED;
891
0
}
892
893
IR_ALWAYS_INLINE ir_ref _ir_fold_cast(ir_ctx *ctx, ir_ref ref, ir_type type)
894
0
{
895
0
  if (ctx->ir_base[ref].type == type) {
896
0
    return ref;
897
0
  } else if (IR_IS_CONST_REF(ref) && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)) {
898
0
    return ir_const(ctx, ctx->ir_base[ref].val, type);
899
0
  } else {
900
0
    return ir_emit1(ctx, IR_OPT(IR_BITCAST, type), ref);
901
0
  }
902
0
}
903
904
0
#define IR_FOLD(X)        IR_FOLD1(X, __LINE__)
905
0
#define IR_FOLD1(X, Y)    IR_FOLD2(X, Y)
906
0
#define IR_FOLD2(X, Y)    case IR_RULE_ ## Y:
907
908
#define IR_FOLD_ERROR(msg) do { \
909
    IR_ASSERT(0 && (msg)); \
910
    goto ir_fold_emit; \
911
  } while (0)
912
913
0
#define IR_FOLD_CONST_U(_val) do { \
914
0
    val.u64 = (_val); \
915
0
    goto ir_fold_const; \
916
0
  } while (0)
917
918
0
#define IR_FOLD_CONST_I(_val) do { \
919
0
    val.i64 = (_val); \
920
0
    goto ir_fold_const; \
921
0
  } while (0)
922
923
0
#define IR_FOLD_CONST_D(_val) do { \
924
0
    val.d = (_val); \
925
0
    goto ir_fold_const; \
926
0
  } while (0)
927
928
0
#define IR_FOLD_CONST_F(_val) do { \
929
0
    val.f = (_val); \
930
0
    val.u32_hi = 0; \
931
0
    goto ir_fold_const; \
932
0
  } while (0)
933
934
0
#define IR_FOLD_COPY(op)  do { \
935
0
    ref = (op); \
936
0
    goto ir_fold_copy; \
937
0
  } while (0)
938
939
#define IR_FOLD_BOOL(cond) \
940
0
  IR_FOLD_COPY((cond) ? IR_TRUE : IR_FALSE)
941
942
0
#define IR_FOLD_NAMED(name)    ir_fold_ ## name:
943
0
#define IR_FOLD_DO_NAMED(name) goto ir_fold_ ## name
944
0
#define IR_FOLD_RESTART        goto ir_fold_restart
945
#define IR_FOLD_CSE            goto ir_fold_cse
946
0
#define IR_FOLD_EMIT           goto ir_fold_emit
947
0
#define IR_FOLD_NEXT           break
948
949
#include <ir_fold_hash.h>
950
951
0
#define IR_FOLD_RULE(x) ((x) >> 21)
952
0
#define IR_FOLD_KEY(x)  ((x) & 0x1fffff)
953
954
/*
955
 * key = insn->op | (insn->op1->op << 7) | (insn->op2->op << 14)
956
 *
957
 * ANY and UNUSED ops are represented by 0
958
 */
959
960
ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3,
961
                  const ir_insn *op1_insn, const ir_insn *op2_insn, const ir_insn *op3_insn)
962
0
{
963
0
  uint8_t op;
964
0
  ir_ref ref;
965
0
  ir_val val;
966
0
  uint32_t key, any;
967
0
  (void) op3_insn;
968
969
0
restart:
970
0
  key = (opt & IR_OPT_OP_MASK) + ((uint32_t)op1_insn->op << 7) + ((uint32_t)op2_insn->op << 14);
971
0
  any = 0x1fffff;
972
0
  do {
973
0
    uint32_t k = key & any;
974
0
    uint32_t h = _ir_fold_hashkey(k);
975
0
    uint32_t fh = _ir_fold_hash[h];
976
0
    if (IR_FOLD_KEY(fh) == k
977
0
#ifdef IR_FOLD_SEMI_PERFECT_HASH
978
0
     || (fh = _ir_fold_hash[h+1], (fh & 0x1fffff) == k)
979
0
#endif
980
0
    ) {
981
0
      switch (IR_FOLD_RULE(fh)) {
982
0
#include "ir_fold.h"
983
0
        default:
984
0
          break;
985
0
      }
986
0
    }
987
0
    if (any == 0x7f) {
988
      /* All parrerns are checked. Pass on to CSE. */
989
0
      goto ir_fold_cse;
990
0
    }
991
    /* op2/op1/op  op2/_/op    _/op1/op    _/_/op
992
     * 0x1fffff -> 0x1fc07f -> 0x003fff -> 0x00007f
993
     * from masks to bis: 11 -> 10 -> 01 -> 00
994
     *
995
     * a b  => x y
996
     * 1 1     1 0
997
     * 1 0     0 1
998
     * 0 1     0 0
999
     *
1000
     * x = a & b; y = !b
1001
     */
1002
0
    any = ((any & (any << 7)) & 0x1fc000) | (~any & 0x3f80) | 0x7f;
1003
0
  } while (1);
1004
1005
0
ir_fold_restart:
1006
0
  if (!ctx->use_lists) {
1007
0
    op1_insn = ctx->ir_base + op1;
1008
0
    op2_insn = ctx->ir_base + op2;
1009
0
    op3_insn = ctx->ir_base + op3;
1010
0
    goto restart;
1011
0
  } else {
1012
0
    ctx->fold_insn.optx = opt;
1013
0
    ctx->fold_insn.op1 = op1;
1014
0
    ctx->fold_insn.op2 = op2;
1015
0
    ctx->fold_insn.op3 = op3;
1016
0
    return IR_FOLD_DO_RESTART;
1017
0
  }
1018
0
ir_fold_cse:
1019
0
  if (!ctx->use_lists) {
1020
    /* Local CSE */
1021
0
    ref = _ir_fold_cse(ctx, opt, op1, op2, op3);
1022
0
    if (ref) {
1023
0
      return ref;
1024
0
    }
1025
1026
0
    ref = ir_emit(ctx, opt, op1, op2, op3);
1027
1028
    /* Update local CSE chain */
1029
0
    op = opt & IR_OPT_OP_MASK;
1030
0
    ir_ref prev = ctx->prev_insn_chain[op];
1031
0
    ir_insn *insn = ctx->ir_base + ref;
1032
0
    if (!prev || ref - prev > 0xffff) {
1033
      /* can't fit into 16-bit */
1034
0
      insn->prev_insn_offset = 0;
1035
0
    } else {
1036
0
      insn->prev_insn_offset = ref - prev;
1037
0
    }
1038
0
    ctx->prev_insn_chain[op] = ref;
1039
1040
0
    return ref;
1041
0
  } else {
1042
0
    ctx->fold_insn.optx = opt;
1043
0
    ctx->fold_insn.op1 = op1;
1044
0
    ctx->fold_insn.op2 = op2;
1045
0
    ctx->fold_insn.op3 = op3;
1046
0
    return IR_FOLD_DO_CSE;
1047
0
  }
1048
0
ir_fold_emit:
1049
0
  if (!ctx->use_lists) {
1050
0
    return ir_emit(ctx, opt, op1, op2, op3);
1051
0
  } else {
1052
0
    ctx->fold_insn.optx = opt;
1053
0
    ctx->fold_insn.op1 = op1;
1054
0
    ctx->fold_insn.op2 = op2;
1055
0
    ctx->fold_insn.op3 = op3;
1056
0
    return IR_FOLD_DO_EMIT;
1057
0
  }
1058
0
ir_fold_copy:
1059
0
  if (!ctx->use_lists) {
1060
0
    return ref;
1061
0
  } else {
1062
0
    ctx->fold_insn.op1 = ref;
1063
0
    return IR_FOLD_DO_COPY;
1064
0
  }
1065
0
ir_fold_const:
1066
0
  if (!ctx->use_lists) {
1067
0
    return ir_const(ctx, val, IR_OPT_TYPE(opt));
1068
0
  } else {
1069
0
    ctx->fold_insn.opt = IR_OPT(IR_OPT_TYPE(opt), IR_OPT_TYPE(opt));
1070
0
    ctx->fold_insn.val.u64 = val.u64;
1071
0
    return IR_FOLD_DO_CONST;
1072
0
  }
1073
0
}
1074
1075
ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
1076
0
{
1077
0
  if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
1078
0
    if ((opt & IR_OPT_OP_MASK) == IR_PHI) {
1079
0
      opt |= (3 << IR_OPT_INPUTS_SHIFT);
1080
0
    }
1081
0
    return ir_emit(ctx, opt, op1, op2, op3);
1082
0
  }
1083
0
  return ir_folding(ctx, opt, op1, op2, op3, ctx->ir_base + op1, ctx->ir_base + op2, ctx->ir_base + op3);
1084
0
}
1085
1086
ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt)
1087
0
{
1088
0
  return ir_fold(ctx, opt, IR_UNUSED, IR_UNUSED, IR_UNUSED);
1089
0
}
1090
1091
ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
1092
0
{
1093
0
  return ir_fold(ctx, opt, op1, IR_UNUSED, IR_UNUSED);
1094
0
}
1095
1096
ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
1097
0
{
1098
0
  return ir_fold(ctx, opt, op1, op2, IR_UNUSED);
1099
0
}
1100
1101
ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
1102
0
{
1103
0
  return ir_fold(ctx, opt, op1, op2, op3);
1104
0
}
1105
1106
ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count)
1107
0
{
1108
0
  int i;
1109
0
  ir_ref *p, ref = ctx->insns_count;
1110
0
  ir_insn *insn;
1111
1112
0
  IR_ASSERT(count >= 0 && count < 65536);
1113
0
  while (UNEXPECTED(ref + count/4 >= ctx->insns_limit)) {
1114
0
    ir_grow_top(ctx);
1115
0
  }
1116
0
  ctx->insns_count = ref + 1 + count/4;
1117
1118
0
  insn = &ctx->ir_base[ref];
1119
0
  insn->optx = opt | (count << IR_OPT_INPUTS_SHIFT);
1120
0
  for (i = 1, p = insn->ops + i; i <= (count|3); i++, p++) {
1121
0
    *p = IR_UNUSED;
1122
0
  }
1123
1124
0
  return ref;
1125
0
}
1126
1127
void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val)
1128
0
{
1129
0
  ir_insn *insn = &ctx->ir_base[ref];
1130
1131
0
#ifdef IR_DEBUG
1132
0
  if (n > 3) {
1133
0
    int32_t count;
1134
1135
0
    IR_ASSERT(IR_OP_HAS_VAR_INPUTS(ir_op_flags[insn->op]));
1136
0
    count = insn->inputs_count;
1137
0
    IR_ASSERT(n <= count);
1138
0
  }
1139
0
#endif
1140
0
  ir_insn_set_op(insn, n, val);
1141
0
}
1142
1143
ir_ref ir_get_op(const ir_ctx *ctx, ir_ref ref, int32_t n)
1144
0
{
1145
0
  const ir_insn *insn = &ctx->ir_base[ref];
1146
1147
0
#ifdef IR_DEBUG
1148
0
  if (n > 3) {
1149
0
    int32_t count;
1150
1151
0
    IR_ASSERT(IR_OP_HAS_VAR_INPUTS(ir_op_flags[insn->op]));
1152
0
    count = insn->inputs_count;
1153
0
    IR_ASSERT(n <= count);
1154
0
  }
1155
0
#endif
1156
0
  return ir_insn_op(insn, n);
1157
0
}
1158
1159
ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos)
1160
0
{
1161
0
  IR_ASSERT(ctx->ir_base[region].op == IR_START);
1162
0
  return ir_emit(ctx, IR_OPT(IR_PARAM, type), region, ir_str(ctx, name), pos);
1163
0
}
1164
1165
ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name)
1166
0
{
1167
0
  IR_ASSERT(IR_IS_BB_START(ctx->ir_base[region].op));
1168
0
  return ir_emit(ctx, IR_OPT(IR_VAR, type), region, ir_str(ctx, name), IR_UNUSED);
1169
0
}
1170
1171
ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def)
1172
0
{
1173
0
  if (IR_IS_CONST_REF(def)) {
1174
0
    return def;
1175
0
  }
1176
0
  if (!ctx->binding) {
1177
0
    ctx->binding = ir_mem_malloc(sizeof(ir_hashtab));;
1178
0
    ir_hashtab_init(ctx->binding, 16);
1179
0
  }
1180
  /* Node may be bound to some special spill slot (using negative "var") */
1181
0
  IR_ASSERT(var < 0);
1182
0
  if (!ir_hashtab_add(ctx->binding, def, var)) {
1183
    /* Add a copy with different binding */
1184
0
    def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, IR_COPY_HARD);
1185
0
    ir_hashtab_add(ctx->binding, def, var);
1186
0
  }
1187
0
  return def;
1188
0
}
1189
1190
ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref)
1191
0
{
1192
0
  ir_ref var = ir_hashtab_find(ctx->binding, ref);
1193
0
  return (var != (ir_ref)IR_INVALID_VAL) ? var : 0;
1194
0
}
1195
1196
/* Batch construction of def->use edges */
1197
#if 0
1198
void ir_build_def_use_lists(ir_ctx *ctx)
1199
{
1200
  ir_ref n, i, j, *p, def;
1201
  ir_insn *insn;
1202
  uint32_t edges_count;
1203
  ir_use_list *lists = ir_mem_calloc(ctx->insns_limit, sizeof(ir_use_list));
1204
  ir_ref *edges;
1205
  ir_use_list *use_list;
1206
1207
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1208
    uint32_t flags = ir_op_flags[insn->op];
1209
1210
    if (UNEXPECTED(IR_OP_HAS_VAR_INPUTS(flags))) {
1211
      n = insn->inputs_count;
1212
    } else {
1213
      n = insn->inputs_count = IR_INPUT_EDGES_COUNT(flags);
1214
    }
1215
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1216
      def = *p;
1217
      if (def > 0) {
1218
        lists[def].count++;
1219
      }
1220
    }
1221
    n = ir_insn_inputs_to_len(n);
1222
    i += n;
1223
    insn += n;
1224
  }
1225
1226
  edges_count = 0;
1227
  for (i = IR_UNUSED + 1, use_list = &lists[i]; i < ctx->insns_count; i++, use_list++) {
1228
    use_list->refs = edges_count;
1229
    edges_count += use_list->count;
1230
    use_list->count = 0;
1231
  }
1232
1233
  edges = ir_mem_malloc(IR_ALIGNED_SIZE(edges_count * sizeof(ir_ref), 4096));
1234
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1235
    n = insn->inputs_count;
1236
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1237
      def = *p;
1238
      if (def > 0) {
1239
        use_list = &lists[def];
1240
        edges[use_list->refs + use_list->count++] = i;
1241
      }
1242
    }
1243
    n = ir_insn_inputs_to_len(n);
1244
    i += n;
1245
    insn += n;
1246
  }
1247
1248
  ctx->use_edges = edges;
1249
  ctx->use_edges_count = edges_count;
1250
  ctx->use_lists = lists;
1251
}
1252
#else
1253
void ir_build_def_use_lists(ir_ctx *ctx)
1254
0
{
1255
0
  ir_ref n, i, j, *p, def;
1256
0
  ir_insn *insn;
1257
0
  size_t linked_lists_size, linked_lists_top = 0, edges_count = 0;
1258
0
  ir_use_list *lists = ir_mem_calloc(ctx->insns_limit, sizeof(ir_use_list));
1259
0
  ir_ref *edges;
1260
0
  ir_use_list *use_list;
1261
0
  ir_ref *linked_lists;
1262
1263
0
  linked_lists_size = IR_ALIGNED_SIZE(ctx->insns_count, 1024);
1264
0
  linked_lists = ir_mem_malloc(linked_lists_size * sizeof(ir_ref));
1265
0
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1266
0
    uint32_t flags = ir_op_flags[insn->op];
1267
1268
0
    if (UNEXPECTED(IR_OP_HAS_VAR_INPUTS(flags))) {
1269
0
      n = insn->inputs_count;
1270
0
    } else {
1271
0
      n = insn->inputs_count = IR_INPUT_EDGES_COUNT(flags);
1272
0
    }
1273
0
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1274
0
      def = *p;
1275
0
      if (def > 0) {
1276
0
        use_list = &lists[def];
1277
0
        edges_count++;
1278
0
        if (!use_list->refs) {
1279
          /* store a single "use" directly in "refs" using a positive number */
1280
0
          use_list->refs = i;
1281
0
          use_list->count = 1;
1282
0
        } else {
1283
0
          if (UNEXPECTED(linked_lists_top >= linked_lists_size)) {
1284
0
            linked_lists_size += 1024;
1285
0
            linked_lists = ir_mem_realloc(linked_lists, linked_lists_size * sizeof(ir_ref));
1286
0
          }
1287
          /* form a linked list of "uses" (like in binsort) */
1288
0
          linked_lists[linked_lists_top] = i; /* store the "use" */
1289
0
          linked_lists[linked_lists_top + 1] = use_list->refs; /* store list next */
1290
0
          use_list->refs = -(linked_lists_top + 1); /* store a head of the list using a negative number */
1291
0
          linked_lists_top += 2;
1292
0
          use_list->count++;
1293
0
        }
1294
0
      }
1295
0
    }
1296
0
    n = ir_insn_inputs_to_len(n);
1297
0
    i += n;
1298
0
    insn += n;
1299
0
  }
1300
1301
0
  ctx->use_edges_count = edges_count;
1302
0
  edges = ir_mem_malloc(IR_ALIGNED_SIZE(edges_count * sizeof(ir_ref), 4096));
1303
0
  for (use_list = lists + ctx->insns_count - 1; use_list != lists; use_list--) {
1304
0
    n = use_list->refs;
1305
0
    if (n) {
1306
      /* transform linked list to plain array */
1307
0
      while (n < 0) {
1308
0
        n = -n;
1309
0
        edges[--edges_count] = linked_lists[n - 1];
1310
0
        n = linked_lists[n];
1311
0
      }
1312
0
      IR_ASSERT(n > 0);
1313
0
      edges[--edges_count] = n;
1314
0
      use_list->refs = edges_count;
1315
0
    }
1316
0
  }
1317
1318
0
  ctx->use_edges = edges;
1319
0
  ctx->use_lists = lists;
1320
0
  ir_mem_free(linked_lists);
1321
0
}
1322
#endif
1323
1324
void ir_use_list_remove_all(ir_ctx *ctx, ir_ref from, ir_ref ref)
1325
0
{
1326
0
  ir_ref n, *p, *q, use;
1327
0
  ir_use_list *use_list;
1328
1329
0
  IR_ASSERT(from > 0);
1330
0
  use_list = &ctx->use_lists[from];
1331
0
  n = use_list->count;
1332
0
  for (p = q = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1333
0
    use = *p;
1334
0
    if (use != ref) {
1335
0
      if (p != q) {
1336
0
        *q = use;
1337
0
      }
1338
0
      q++;
1339
0
    }
1340
0
  }
1341
0
  if (p != q) {
1342
0
    use_list->count -= (p - q);
1343
0
    do {
1344
0
      *q = IR_UNUSED;
1345
0
      q++;
1346
0
    } while (q != p);
1347
0
  }
1348
0
}
1349
1350
void ir_use_list_remove_one(ir_ctx *ctx, ir_ref from, ir_ref ref)
1351
0
{
1352
0
  ir_ref n, *p;
1353
0
  ir_use_list *use_list;
1354
1355
0
  IR_ASSERT(from > 0);
1356
0
  use_list = &ctx->use_lists[from];
1357
0
  n = use_list->count;
1358
0
  p = &ctx->use_edges[use_list->refs];
1359
0
  while (n > 0) {
1360
0
    if (*p == ref) {
1361
0
      use_list->count--;
1362
0
      n--;
1363
0
      while (n > 0) {
1364
0
        *p = *(p+1);
1365
0
        p++;
1366
0
        n--;
1367
0
      }
1368
0
      *p = IR_UNUSED;
1369
0
      break;
1370
0
    }
1371
0
    p++;
1372
0
    n--;
1373
0
  }
1374
0
}
1375
1376
void ir_use_list_replace_one(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
1377
0
{
1378
0
  ir_use_list *use_list;
1379
0
  ir_ref n, *p;
1380
1381
0
  IR_ASSERT(ref > 0);
1382
0
  use_list = &ctx->use_lists[ref];
1383
0
  n = use_list->count;
1384
0
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1385
0
    if (*p == use) {
1386
0
      *p = new_use;
1387
0
      break;
1388
0
    }
1389
0
  }
1390
0
}
1391
1392
void ir_use_list_replace_all(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
1393
0
{
1394
0
  ir_use_list *use_list;
1395
0
  ir_ref n, *p;
1396
1397
0
  IR_ASSERT(ref > 0);
1398
0
  use_list = &ctx->use_lists[ref];
1399
0
  n = use_list->count;
1400
0
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1401
0
    if (*p == use) {
1402
0
      *p = new_use;
1403
0
    }
1404
0
  }
1405
0
}
1406
1407
bool ir_use_list_add(ir_ctx *ctx, ir_ref to, ir_ref ref)
1408
0
{
1409
0
  ir_use_list *use_list;
1410
0
  ir_ref n;
1411
1412
0
  IR_ASSERT(to > 0);
1413
0
  use_list = &ctx->use_lists[to];
1414
0
  n = use_list->refs + use_list->count;
1415
0
  if (n < ctx->use_edges_count && ctx->use_edges[n] == IR_UNUSED) {
1416
0
    ctx->use_edges[n] = ref;
1417
0
    use_list->count++;
1418
0
    return 0;
1419
0
  } else {
1420
0
    size_t old_size = IR_ALIGNED_SIZE(ctx->use_edges_count * sizeof(ir_ref), 4096);
1421
0
    size_t new_size = IR_ALIGNED_SIZE((ctx->use_edges_count + use_list->count + 1) * sizeof(ir_ref), 4096);
1422
1423
0
    if (old_size < new_size) {
1424
      /* Reallocate the whole edges buffer (this is inefficient) */
1425
0
      ctx->use_edges = ir_mem_realloc(ctx->use_edges, new_size);
1426
0
      if (n == ctx->use_edges_count) {
1427
0
        ctx->use_edges[n] = ref;
1428
0
        use_list->count++;
1429
0
        ctx->use_edges_count++;
1430
0
        return 1;
1431
0
      }
1432
0
    } else if (n == ctx->use_edges_count) {
1433
0
      ctx->use_edges[n] = ref;
1434
0
      use_list->count++;
1435
0
      ctx->use_edges_count++;
1436
0
      return 0;
1437
0
    }
1438
0
    if (use_list->count) {
1439
0
      memcpy(ctx->use_edges + ctx->use_edges_count, ctx->use_edges + use_list->refs, use_list->count * sizeof(ir_ref));
1440
0
    }
1441
0
    use_list->refs = ctx->use_edges_count;
1442
0
    ctx->use_edges[use_list->refs + use_list->count] = ref;
1443
0
    use_list->count++;
1444
0
    ctx->use_edges_count += use_list->count;
1445
0
    return 1;
1446
0
  }
1447
0
}
1448
1449
void ir_replace(ir_ctx *ctx, ir_ref ref, ir_ref new_ref)
1450
0
{
1451
0
  int i, j, n, *p, use;
1452
0
  ir_insn *insn;
1453
0
  ir_use_list *use_list;
1454
1455
0
  IR_ASSERT(ref != new_ref);
1456
0
  use_list = &ctx->use_lists[ref];
1457
0
  n = use_list->count;
1458
0
  p = ctx->use_edges + use_list->refs;
1459
1460
0
  if (new_ref <= 0) {
1461
    /* constant or IR_UNUSED */
1462
0
    for (; n; p++, n--) {
1463
0
      use = *p;
1464
0
      IR_ASSERT(use != ref);
1465
0
      insn = &ctx->ir_base[use];
1466
0
      j = ir_insn_find_op(insn, ref);
1467
0
      IR_ASSERT(j > 0);
1468
0
      ir_insn_set_op(insn, j, new_ref);
1469
0
    }
1470
0
  } else {
1471
0
    for (i = 0; i < n; p++, i++) {
1472
0
      use = *p;
1473
0
      IR_ASSERT(use != ref);
1474
0
      insn = &ctx->ir_base[use];
1475
0
      j = ir_insn_find_op(insn, ref);
1476
0
      IR_ASSERT(j > 0);
1477
0
      ir_insn_set_op(insn, j, new_ref);
1478
0
      if (ir_use_list_add(ctx, new_ref, use)) {
1479
        /* restore after reallocation */
1480
0
        use_list = &ctx->use_lists[ref];
1481
0
        n = use_list->count;
1482
0
        p = &ctx->use_edges[use_list->refs + i];
1483
0
      }
1484
0
    }
1485
0
  }
1486
0
}
1487
1488
void ir_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val)
1489
0
{
1490
0
  ir_insn *insn = &ctx->ir_base[ref];
1491
0
  ir_ref old_val = ir_insn_op(insn, idx);
1492
1493
0
  IR_ASSERT(old_val != new_val);
1494
0
  if (new_val > 0) {
1495
0
    ir_use_list_add(ctx, new_val, ref);
1496
0
  }
1497
0
  ir_insn_set_op(insn, idx, new_val);
1498
0
  if (old_val > 0) {
1499
0
    ir_use_list_remove_one(ctx, old_val, ref);
1500
0
  }
1501
0
}
1502
1503
/* Helper Data Types */
1504
void ir_array_grow(ir_array *a, uint32_t size)
1505
0
{
1506
0
  IR_ASSERT(size > a->size);
1507
0
  if (size >= 256) {
1508
0
    size = IR_ALIGNED_SIZE(size, 256);
1509
0
  } else {
1510
    /* Use big enough power of 2 */
1511
0
    size -= 1;
1512
0
    size |= (size >> 1);
1513
0
    size |= (size >> 2);
1514
0
    size |= (size >> 4);
1515
//    size |= (size >> 8);
1516
//    size |= (size >> 16);
1517
0
    size += 1;
1518
0
  }
1519
0
  a->refs = ir_mem_realloc(a->refs, size * sizeof(ir_ref));
1520
0
  a->size = size;
1521
0
}
1522
1523
void ir_array_insert(ir_array *a, uint32_t i, ir_ref val)
1524
0
{
1525
0
  IR_ASSERT(i < a->size);
1526
0
  if (a->refs[a->size - 1]) {
1527
0
    ir_array_grow(a, a->size + 1);
1528
0
  }
1529
0
  memmove(a->refs + i + 1, a->refs + i, (a->size - i - 1) * sizeof(ir_ref));
1530
0
  a->refs[i] = val;
1531
0
}
1532
1533
void ir_array_remove(ir_array *a, uint32_t i)
1534
0
{
1535
0
  IR_ASSERT(i < a->size);
1536
0
  memmove(a->refs + i, a->refs + i + 1, (a->size - i - 1) * sizeof(ir_ref));
1537
0
  a->refs[a->size - 1] = IR_UNUSED;
1538
0
}
1539
1540
void ir_list_insert(ir_list *l, uint32_t i, ir_ref val)
1541
0
{
1542
0
  IR_ASSERT(i < l->len);
1543
0
  if (l->len >= l->a.size) {
1544
0
    ir_array_grow(&l->a, l->a.size + 1);
1545
0
  }
1546
0
  memmove(l->a.refs + i + 1, l->a.refs + i, (l->len - i) * sizeof(ir_ref));
1547
0
  l->a.refs[i] = val;
1548
0
  l->len++;
1549
0
}
1550
1551
void ir_list_remove(ir_list *l, uint32_t i)
1552
0
{
1553
0
  IR_ASSERT(i < l->len);
1554
0
  memmove(l->a.refs + i, l->a.refs + i + 1, (l->len - i) * sizeof(ir_ref));
1555
0
  l->len--;
1556
0
}
1557
1558
uint32_t ir_list_find(const ir_list *l, ir_ref val)
1559
0
{
1560
0
  uint32_t i;
1561
1562
0
  for (i = 0; i < l->len; i++) {
1563
0
    if (ir_array_at(&l->a, i) == val) {
1564
0
      return i;
1565
0
    }
1566
0
  }
1567
0
  return (uint32_t)-1;
1568
0
}
1569
1570
static uint32_t ir_hashtab_hash_size(uint32_t size)
1571
0
{
1572
0
  size -= 1;
1573
0
  size |= (size >> 1);
1574
0
  size |= (size >> 2);
1575
0
  size |= (size >> 4);
1576
0
  size |= (size >> 8);
1577
0
  size |= (size >> 16);
1578
0
  return IR_MAX(size + 1, 4);
1579
0
}
1580
1581
static void ir_hashtab_resize(ir_hashtab *tab)
1582
0
{
1583
0
  uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->mask);
1584
0
  char *old_data = tab->data;
1585
0
  uint32_t size = tab->size * 2;
1586
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1587
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_hashtab_bucket));
1588
0
  ir_hashtab_bucket *p;
1589
0
  uint32_t pos, i;
1590
1591
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1592
0
  tab->data = data + (hash_size * sizeof(uint32_t));
1593
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1594
0
  tab->size = size;
1595
1596
0
  memcpy(tab->data, old_data, tab->count * sizeof(ir_hashtab_bucket));
1597
0
  ir_mem_free(old_data - (old_hash_size * sizeof(uint32_t)));
1598
1599
0
  i = tab->count;
1600
0
  pos = 0;
1601
0
  p = (ir_hashtab_bucket*)tab->data;
1602
0
  do {
1603
0
    uint32_t key = p->key | tab->mask;
1604
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1605
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1606
0
    pos += sizeof(ir_hashtab_bucket);
1607
0
    p++;
1608
0
  } while (--i);
1609
0
}
1610
1611
void ir_hashtab_init(ir_hashtab *tab, uint32_t size)
1612
0
{
1613
0
  IR_ASSERT(size > 0);
1614
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1615
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_hashtab_bucket));
1616
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1617
0
  tab->data = (data + (hash_size * sizeof(uint32_t)));
1618
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1619
0
  tab->size = size;
1620
0
  tab->count = 0;
1621
0
  tab->pos = 0;
1622
0
}
1623
1624
void ir_hashtab_free(ir_hashtab *tab)
1625
0
{
1626
0
  uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask);
1627
0
  char *data = (char*)tab->data - (hash_size * sizeof(uint32_t));
1628
0
  ir_mem_free(data);
1629
0
  tab->data = NULL;
1630
0
}
1631
1632
ir_ref ir_hashtab_find(const ir_hashtab *tab, uint32_t key)
1633
0
{
1634
0
  const char *data = (const char*)tab->data;
1635
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1636
0
  ir_hashtab_bucket *p;
1637
1638
0
  while (pos != IR_INVALID_IDX) {
1639
0
    p = (ir_hashtab_bucket*)(data + pos);
1640
0
    if (p->key == key) {
1641
0
      return p->val;
1642
0
    }
1643
0
    pos = p->next;
1644
0
  }
1645
0
  return IR_INVALID_VAL;
1646
0
}
1647
1648
bool ir_hashtab_add(ir_hashtab *tab, uint32_t key, ir_ref val)
1649
0
{
1650
0
  char *data = (char*)tab->data;
1651
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1652
0
  ir_hashtab_bucket *p;
1653
1654
0
  while (pos != IR_INVALID_IDX) {
1655
0
    p = (ir_hashtab_bucket*)(data + pos);
1656
0
    if (p->key == key) {
1657
0
      return p->val == val;
1658
0
    }
1659
0
    pos = p->next;
1660
0
  }
1661
1662
0
  if (UNEXPECTED(tab->count >= tab->size)) {
1663
0
    ir_hashtab_resize(tab);
1664
0
    data = tab->data;
1665
0
  }
1666
1667
0
  pos = tab->pos;
1668
0
  tab->pos += sizeof(ir_hashtab_bucket);
1669
0
  tab->count++;
1670
0
  p = (ir_hashtab_bucket*)(data + pos);
1671
0
  p->key = key;
1672
0
  p->val = val;
1673
0
  key |= tab->mask;
1674
0
  p->next = ((uint32_t*)data)[(int32_t)key];
1675
0
  ((uint32_t*)data)[(int32_t)key] = pos;
1676
0
  return 1;
1677
0
}
1678
1679
static int ir_hashtab_key_cmp(const void *b1, const void *b2)
1680
0
{
1681
0
  return ((ir_hashtab_bucket*)b1)->key - ((ir_hashtab_bucket*)b2)->key;
1682
0
}
1683
1684
void ir_hashtab_key_sort(ir_hashtab *tab)
1685
0
{
1686
0
  ir_hashtab_bucket *p;
1687
0
  uint32_t hash_size, pos, i;
1688
1689
0
  if (!tab->count) {
1690
0
    return;
1691
0
  }
1692
1693
0
  qsort(tab->data, tab->count, sizeof(ir_hashtab_bucket), ir_hashtab_key_cmp);
1694
1695
0
  hash_size = ir_hashtab_hash_size(tab->size);
1696
0
  memset((char*)tab->data - (hash_size * sizeof(uint32_t)), -1, hash_size * sizeof(uint32_t));
1697
1698
0
  i = tab->count;
1699
0
  pos = 0;
1700
0
  p = (ir_hashtab_bucket*)tab->data;
1701
0
  do {
1702
0
    uint32_t key = p->key | tab->mask;
1703
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1704
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1705
0
    pos += sizeof(ir_hashtab_bucket);
1706
0
    p++;
1707
0
  } while (--i);
1708
0
}
1709
1710
static void ir_addrtab_resize(ir_hashtab *tab)
1711
0
{
1712
0
  uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->mask);
1713
0
  char *old_data = tab->data;
1714
0
  uint32_t size = tab->size * 2;
1715
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1716
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
1717
0
  ir_addrtab_bucket *p;
1718
0
  uint32_t pos, i;
1719
1720
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1721
0
  tab->data = data + (hash_size * sizeof(uint32_t));
1722
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1723
0
  tab->size = size;
1724
1725
0
  memcpy(tab->data, old_data, tab->count * sizeof(ir_addrtab_bucket));
1726
0
  ir_mem_free(old_data - (old_hash_size * sizeof(uint32_t)));
1727
1728
0
  i = tab->count;
1729
0
  pos = 0;
1730
0
  p = (ir_addrtab_bucket*)tab->data;
1731
0
  do {
1732
0
    uint32_t key = (uint32_t)p->key | tab->mask;
1733
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1734
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1735
0
    pos += sizeof(ir_addrtab_bucket);
1736
0
    p++;
1737
0
  } while (--i);
1738
0
}
1739
1740
void ir_addrtab_init(ir_hashtab *tab, uint32_t size)
1741
0
{
1742
0
  IR_ASSERT(size > 0);
1743
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1744
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
1745
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1746
0
  tab->data = (data + (hash_size * sizeof(uint32_t)));
1747
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1748
0
  tab->size = size;
1749
0
  tab->count = 0;
1750
0
  tab->pos = 0;
1751
0
}
1752
1753
void ir_addrtab_free(ir_hashtab *tab)
1754
0
{
1755
0
  uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask);
1756
0
  char *data = (char*)tab->data - (hash_size * sizeof(uint32_t));
1757
0
  ir_mem_free(data);
1758
0
  tab->data = NULL;
1759
0
}
1760
1761
ir_ref ir_addrtab_find(const ir_hashtab *tab, uint64_t key)
1762
0
{
1763
0
  const char *data = (const char*)tab->data;
1764
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1765
0
  ir_addrtab_bucket *p;
1766
1767
0
  while (pos != IR_INVALID_IDX) {
1768
0
    p = (ir_addrtab_bucket*)(data + pos);
1769
0
    if (p->key == key) {
1770
0
      return p->val;
1771
0
    }
1772
0
    pos = p->next;
1773
0
  }
1774
0
  return IR_INVALID_VAL;
1775
0
}
1776
1777
void ir_addrtab_set(ir_hashtab *tab, uint64_t key, ir_ref val)
1778
0
{
1779
0
  char *data = (char*)tab->data;
1780
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1781
0
  ir_addrtab_bucket *p;
1782
1783
0
  while (pos != IR_INVALID_IDX) {
1784
0
    p = (ir_addrtab_bucket*)(data + pos);
1785
0
    if (p->key == key) {
1786
0
      p->val = val;
1787
0
      return;
1788
0
    }
1789
0
    pos = p->next;
1790
0
  }
1791
1792
0
  if (UNEXPECTED(tab->count >= tab->size)) {
1793
0
    ir_addrtab_resize(tab);
1794
0
    data = tab->data;
1795
0
  }
1796
1797
0
  pos = tab->pos;
1798
0
  tab->pos += sizeof(ir_addrtab_bucket);
1799
0
  tab->count++;
1800
0
  p = (ir_addrtab_bucket*)(data + pos);
1801
0
  p->key = key;
1802
0
  p->val = val;
1803
0
  key |= tab->mask;
1804
0
  p->next = ((uint32_t*)data)[(int32_t)key];
1805
0
  ((uint32_t*)data)[(int32_t)key] = pos;
1806
0
}
1807
1808
/* Memory API */
1809
#ifdef _WIN32
1810
void *ir_mem_mmap(size_t size)
1811
{
1812
  void *ret;
1813
1814
#ifdef _M_X64
1815
  DWORD size_hi = size >> 32, size_lo = size & 0xffffffff;
1816
#else
1817
  DWORD size_hi = 0, size_lo = size;
1818
#endif
1819
1820
  HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, size_hi, size_lo, NULL);
1821
1822
  ret = MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE, 0, 0, size);
1823
  if (!ret) {
1824
    CloseHandle(h);
1825
  }
1826
1827
  return ret;
1828
}
1829
1830
int ir_mem_unmap(void *ptr, size_t size)
1831
{
1832
  /* XXX file handle is leaked. */
1833
  UnmapViewOfFile(ptr);
1834
  return 1;
1835
}
1836
1837
int ir_mem_protect(void *ptr, size_t size)
1838
{
1839
  return 1;
1840
}
1841
1842
int ir_mem_unprotect(void *ptr, size_t size)
1843
{
1844
  return 1;
1845
}
1846
1847
int ir_mem_flush(void *ptr, size_t size)
1848
{
1849
  return FlushInstructionCache(GetCurrentProcess(), ptr, size) == TRUE ? 1 : 0;
1850
}
1851
#else
1852
1853
#if defined(__linux__) && defined(__x86_64__) && defined(PKEY_DISABLE_WRITE)
1854
# define HAVE_PKEY_MPROTECT 1
1855
#endif
1856
1857
#ifdef HAVE_PKEY_MPROTECT
1858
1859
#ifndef PKEY_DISABLE_EXECUTE
1860
0
# define PKEY_DISABLE_EXECUTE 0
1861
#endif
1862
1863
int pkey_mprotect(void* addr, size_t len, int prot, int pkey) __attribute__((weak));
1864
int pkey_alloc(unsigned int, unsigned int) __attribute__((weak));
1865
int pkey_free(int) __attribute__((weak));
1866
int pkey_set(int, unsigned) __attribute__((weak));
1867
1868
static int ir_pkey = 0;
1869
#endif
1870
1871
void *ir_mem_mmap(size_t size)
1872
0
{
1873
0
#ifdef HAVE_PKEY_MPROTECT
1874
0
  if (!ir_pkey && pkey_mprotect) {
1875
0
    int key = pkey_alloc(0, PKEY_DISABLE_WRITE);
1876
0
    if (key > 0) {
1877
0
      ir_pkey = key;
1878
0
    }
1879
0
  }
1880
0
  if (ir_pkey > 0) {
1881
0
    void *ret = mmap(NULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1882
0
    if (ret == MAP_FAILED) {
1883
0
      return NULL;
1884
0
    }
1885
0
    if (pkey_mprotect(ret, size, PROT_EXEC|PROT_READ|PROT_WRITE, ir_pkey) != 0) {
1886
0
#ifdef IR_DEBUG
1887
0
      fprintf(stderr, "pkey_mprotect() failed\n");
1888
0
#endif
1889
0
      munmap(ret, size);
1890
0
      return NULL;
1891
0
    }
1892
0
    return ret;
1893
0
  }
1894
0
#endif
1895
0
  int prot_flags = PROT_EXEC;
1896
#if defined(__NetBSD__)
1897
  prot_flags |= PROT_MPROTECT(PROT_READ|PROT_WRITE);
1898
#endif
1899
0
  void *ret = mmap(NULL, size, prot_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1900
0
  if (ret == MAP_FAILED) {
1901
0
    ret = NULL;
1902
0
  }
1903
0
  return ret;
1904
0
}
1905
1906
int ir_mem_unmap(void *ptr, size_t size)
1907
0
{
1908
0
  munmap(ptr, size);
1909
0
#ifdef HAVE_PKEY_MPROTECT
1910
//  if (ir_pkey > 0) {
1911
//    pkey_free(ir_pkey);
1912
//    ir_pkey = 0;
1913
//  }
1914
0
#endif
1915
0
  return 1;
1916
0
}
1917
1918
int ir_mem_protect(void *ptr, size_t size)
1919
0
{
1920
0
#ifdef HAVE_PKEY_MPROTECT
1921
0
  if (ir_pkey > 0) {
1922
0
    if (pkey_set(ir_pkey, PKEY_DISABLE_WRITE)) {
1923
0
#ifdef IR_DEBUG
1924
0
      fprintf(stderr, "mprotect() failed\n");
1925
0
#endif
1926
0
      return 0;
1927
0
    }
1928
0
    return 1;
1929
0
  }
1930
0
#endif
1931
0
  if (mprotect(ptr, size, PROT_READ | PROT_EXEC) != 0) {
1932
0
#ifdef IR_DEBUG
1933
0
    fprintf(stderr, "mprotect() failed\n");
1934
0
#endif
1935
0
    return 0;
1936
0
  }
1937
0
  return 1;
1938
0
}
1939
1940
int ir_mem_unprotect(void *ptr, size_t size)
1941
0
{
1942
0
#ifdef HAVE_PKEY_MPROTECT
1943
0
  if (ir_pkey > 0) {
1944
0
    if (pkey_set(ir_pkey, PKEY_DISABLE_EXECUTE)) {
1945
0
#ifdef IR_DEBUG
1946
0
      fprintf(stderr, "mprotect() failed\n");
1947
0
#endif
1948
0
      return 0;
1949
0
    }
1950
0
    return 1;
1951
0
  }
1952
0
#endif
1953
0
  if (mprotect(ptr, size, PROT_READ | PROT_WRITE) != 0) {
1954
0
#ifdef IR_DEBUG
1955
0
    fprintf(stderr, "mprotect() failed\n");
1956
0
#endif
1957
0
    return 0;
1958
0
  }
1959
0
  return 1;
1960
0
}
1961
1962
int ir_mem_flush(void *ptr, size_t size)
1963
0
{
1964
0
#if ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4003) || __has_builtin(__builtin___clear_cache))
1965
0
  __builtin___clear_cache((char*)(ptr), (char*)(ptr) + size);
1966
0
#endif
1967
#if defined(__APPLE__) && defined(__aarch64__)
1968
  sys_icache_invalidate(ptr, size);
1969
#endif
1970
#ifdef HAVE_VALGRIND
1971
  VALGRIND_DISCARD_TRANSLATIONS(ptr, size);
1972
#endif
1973
0
  return 1;
1974
0
}
1975
#endif
1976
1977
/* Alias Analyses */
1978
typedef enum _ir_alias {
1979
  IR_MAY_ALIAS  = -1,
1980
  IR_NO_ALIAS   =  0,
1981
  IR_MUST_ALIAS =  1,
1982
} ir_alias;
1983
1984
#if 0
1985
static ir_alias ir_check_aliasing(ir_ctx *ctx, ir_ref addr1, ir_ref addr2)
1986
{
1987
  ir_insn *insn1, *insn2;
1988
1989
  if (addr1 == addr2) {
1990
    return IR_MUST_ALIAS;
1991
  }
1992
1993
  insn1 = &ctx->ir_base[addr1];
1994
  insn2 = &ctx->ir_base[addr2];
1995
  if (insn1->op == IR_ADD && IR_IS_CONST_REF(insn1->op2)) {
1996
    if (insn1->op1 == addr2) {
1997
      uintptr_t offset1 = ctx->ir_base[insn1->op2].val.u64;
1998
      return (offset1 != 0) ? IR_MUST_ALIAS : IR_NO_ALIAS;
1999
    } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn1->op2) && insn1->op1 == insn2->op1) {
2000
      if (insn1->op2 == insn2->op2) {
2001
        return IR_MUST_ALIAS;
2002
      } else if (IR_IS_CONST_REF(insn1->op2) && IR_IS_CONST_REF(insn2->op2)) {
2003
        uintptr_t offset1 = ctx->ir_base[insn1->op2].val.u64;
2004
        uintptr_t offset2 = ctx->ir_base[insn2->op2].val.u64;
2005
2006
        return (offset1 == offset2) ? IR_MUST_ALIAS : IR_NO_ALIAS;
2007
      }
2008
    }
2009
  } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn2->op2)) {
2010
    if (insn2->op1 == addr1) {
2011
      uintptr_t offset2 = ctx->ir_base[insn2->op2].val.u64;
2012
2013
      return (offset2 != 0) ? IR_MUST_ALIAS : IR_NO_ALIAS;
2014
    }
2015
  }
2016
  return IR_MAY_ALIAS;
2017
}
2018
#endif
2019
2020
ir_alias ir_check_partial_aliasing(const ir_ctx *ctx, ir_ref addr1, ir_ref addr2, ir_type type1, ir_type type2)
2021
0
{
2022
0
  const ir_insn *insn1, *insn2;
2023
0
  ir_ref base1, base2, off1, off2;
2024
2025
  /* this must be already check */
2026
0
  IR_ASSERT(addr1 != addr2);
2027
2028
0
  insn1 = &ctx->ir_base[addr1];
2029
0
  insn2 = &ctx->ir_base[addr2];
2030
0
  if (insn1->op != IR_ADD) {
2031
0
    base1 = addr1;
2032
0
    off1 = IR_UNUSED;
2033
0
  } else if (ctx->ir_base[insn1->op2].op == IR_SYM
2034
0
      || ctx->ir_base[insn1->op2].op == IR_ALLOCA
2035
0
      || ctx->ir_base[insn1->op2].op == IR_VADDR) {
2036
0
    base1 = insn1->op2;
2037
0
    off1 = insn1->op1;
2038
0
  } else {
2039
0
    base1 = insn1->op1;
2040
0
    off1 = insn1->op2;
2041
0
  }
2042
0
  if (insn2->op != IR_ADD) {
2043
0
    base2 = addr2;
2044
0
    off2 = IR_UNUSED;
2045
0
  } else if (ctx->ir_base[insn2->op2].op == IR_SYM
2046
0
      || ctx->ir_base[insn2->op2].op == IR_ALLOCA
2047
0
      || ctx->ir_base[insn2->op2].op == IR_VADDR) {
2048
0
    base2 = insn2->op2;
2049
0
    off2 = insn2->op1;
2050
0
  } else {
2051
0
    base2 = insn2->op1;
2052
0
    off2 = insn2->op2;
2053
0
  }
2054
0
  if (base1 == base2) {
2055
0
    uintptr_t offset1, offset2;
2056
2057
0
    if (!off1) {
2058
0
      offset1 = 0;
2059
0
    } else if (IR_IS_CONST_REF(off1) && !IR_IS_SYM_CONST(ctx->ir_base[off1].op)) {
2060
0
      offset1 = ctx->ir_base[off1].val.addr;
2061
0
    } else {
2062
0
      return IR_MAY_ALIAS;
2063
0
    }
2064
0
    if (!off2) {
2065
0
      offset2 = 0;
2066
0
    } else if (IR_IS_CONST_REF(off2) && !IR_IS_SYM_CONST(ctx->ir_base[off2].op)) {
2067
0
      offset2 = ctx->ir_base[off2].val.addr;
2068
0
    } else {
2069
0
      return IR_MAY_ALIAS;
2070
0
    }
2071
0
    if (offset1 == offset2) {
2072
0
      return IR_MUST_ALIAS;
2073
0
    } else if (offset1 < offset2) {
2074
0
      return offset1 + ir_type_size[type1] <= offset2 ? IR_NO_ALIAS : IR_MUST_ALIAS;
2075
0
    } else {
2076
0
      return offset2 + ir_type_size[type2] <= offset1 ? IR_NO_ALIAS : IR_MUST_ALIAS;
2077
0
    }
2078
0
  } else {
2079
0
    insn1 = &ctx->ir_base[base1];
2080
0
    insn2 = &ctx->ir_base[base2];
2081
0
    while (insn1->op == IR_ADD) {
2082
0
      insn1 = &ctx->ir_base[insn1->op2];
2083
0
      if (insn1->op == IR_SYM
2084
0
       || insn1->op == IR_ALLOCA
2085
0
       || insn1->op == IR_VADDR) {
2086
0
        break;
2087
0
      } else {
2088
0
        insn1 = &ctx->ir_base[insn1->op1];
2089
0
      }
2090
0
    }
2091
0
    while (insn2->op == IR_ADD) {
2092
0
      insn2 = &ctx->ir_base[insn2->op2];
2093
0
      if (insn2->op == IR_SYM
2094
0
       || insn2->op == IR_ALLOCA
2095
0
       || insn2->op == IR_VADDR) {
2096
0
        break;
2097
0
      } else {
2098
0
        insn2 = &ctx->ir_base[insn2->op1];
2099
0
      }
2100
0
    }
2101
0
    if (insn1 == insn2) {
2102
0
      return IR_MAY_ALIAS;
2103
0
    }
2104
0
    if ((insn1->op == IR_ALLOCA && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2105
0
     || (insn1->op == IR_VADDR && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2106
0
     || (insn1->op == IR_SYM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM))
2107
0
     || (insn1->op == IR_PARAM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR))) {
2108
0
      return IR_NO_ALIAS;
2109
0
    }
2110
0
  }
2111
0
  return IR_MAY_ALIAS;
2112
0
}
2113
2114
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr, ir_ref limit)
2115
0
{
2116
0
  const ir_insn *insn;
2117
0
  uint32_t modified_regset = 0;
2118
2119
0
  while (ref > limit) {
2120
0
    insn = &ctx->ir_base[ref];
2121
0
    if (insn->op == IR_LOAD) {
2122
0
      if (insn->op2 == addr) {
2123
0
        if (insn->type == type) {
2124
0
          return ref; /* load forwarding (L2L) */
2125
0
        } else if (ir_type_size[insn->type] == ir_type_size[type]) {
2126
0
          return ref; /* load forwarding with bitcast (L2L) */
2127
0
        } else if (ir_type_size[insn->type] > ir_type_size[type]
2128
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(insn->type)) {
2129
0
          return ref; /* partial load forwarding (L2L) */
2130
0
        }
2131
0
      }
2132
0
    } else if (insn->op == IR_STORE) {
2133
0
      ir_type type2 = ctx->ir_base[insn->op3].type;
2134
2135
0
      if (insn->op2 == addr) {
2136
0
        if (ctx->ir_base[insn->op3].op == IR_RLOAD
2137
0
         && (modified_regset & (1 << ctx->ir_base[insn->op3].op2))) {
2138
          /* anti-dependency */
2139
0
          return IR_UNUSED;
2140
0
        } else if (type2 == type) {
2141
0
          return insn->op3; /* store forwarding (S2L) */
2142
0
        } else if (ir_type_size[type2] == ir_type_size[type]) {
2143
0
          return insn->op3; /* store forwarding with bitcast (S2L) */
2144
0
        } else if (ir_type_size[type2] > ir_type_size[type]
2145
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(type2)) {
2146
0
          return insn->op3; /* partial store forwarding (S2L) */
2147
0
        } else {
2148
0
          return IR_UNUSED;
2149
0
        }
2150
0
      } else if (ir_check_partial_aliasing(ctx, addr, insn->op2, type, type2) != IR_NO_ALIAS) {
2151
0
        return IR_UNUSED;
2152
0
      }
2153
0
    } else if (insn->op == IR_RSTORE) {
2154
0
      modified_regset |= (1 << insn->op3);
2155
0
    } else if (insn->op == IR_CALL) {
2156
0
      const ir_insn *func = &ctx->ir_base[insn->op2];
2157
0
      ir_ref func_proto;
2158
0
      const ir_proto_t *proto;
2159
2160
0
      if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2161
0
        func_proto = func->proto;
2162
0
      } else if (func->op == IR_PROTO) {
2163
0
        func_proto = func->op2;
2164
0
      } else {
2165
0
        break;
2166
0
      }
2167
0
      if (!func_proto) {
2168
0
        break;
2169
0
      }
2170
0
      proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2171
0
      if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2172
0
        break;
2173
0
      }
2174
0
    } else if (insn->op == IR_MERGE
2175
0
        || insn->op == IR_LOOP_BEGIN
2176
0
        || insn->op == IR_VSTORE
2177
0
        || (insn->op == IR_BEGIN && insn->op2)) {
2178
0
      return IR_UNUSED;
2179
0
    }
2180
0
    ref = insn->op1;
2181
0
  }
2182
2183
0
  return IR_UNUSED;
2184
0
}
2185
2186
ir_ref ir_find_aliasing_load(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr)
2187
0
{
2188
0
  return ir_find_aliasing_load_i(ctx, ref, type, addr, (addr > 0 && addr < ref) ? addr : 1);
2189
0
}
2190
2191
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
2192
0
{
2193
0
  const ir_insn *insn;
2194
2195
0
  while (ref > var) {
2196
0
    insn = &ctx->ir_base[ref];
2197
0
    if (insn->op == IR_VLOAD) {
2198
0
      if (insn->op2 == var) {
2199
0
        if (insn->type == type) {
2200
0
          return ref; /* load forwarding (L2L) */
2201
0
        } else if (ir_type_size[insn->type] == ir_type_size[type]) {
2202
0
          return ref; /* load forwarding with bitcast (L2L) */
2203
0
        } else if (ir_type_size[insn->type] > ir_type_size[type]
2204
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(insn->type)) {
2205
0
          return ref; /* partial load forwarding (L2L) */
2206
0
        }
2207
0
      }
2208
0
    } else if (insn->op == IR_VSTORE) {
2209
0
      ir_type type2 = ctx->ir_base[insn->op3].type;
2210
2211
0
      if (insn->op2 == var) {
2212
0
        if (type2 == type) {
2213
0
          return insn->op3; /* store forwarding (S2L) */
2214
0
        } else if (ir_type_size[type2] == ir_type_size[type]) {
2215
0
          return insn->op3; /* store forwarding with bitcast (S2L) */
2216
0
        } else if (ir_type_size[type2] > ir_type_size[type]
2217
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(type2)) {
2218
0
          return insn->op3; /* partial store forwarding (S2L) */
2219
0
        } else {
2220
0
          break;
2221
0
        }
2222
0
      }
2223
0
    } else if (insn->op == IR_CALL) {
2224
0
      const ir_insn *func = &ctx->ir_base[insn->op2];
2225
0
      ir_ref func_proto;
2226
0
      const ir_proto_t *proto;
2227
2228
0
      if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2229
0
        func_proto = func->proto;
2230
0
      } else if (func->op == IR_PROTO) {
2231
0
        func_proto = func->op2;
2232
0
      } else {
2233
0
        break;
2234
0
      }
2235
0
      if (!func_proto) {
2236
0
        break;
2237
0
      }
2238
0
      proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2239
0
      if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2240
0
        break;
2241
0
      }
2242
0
    } else if (insn->op == IR_MERGE
2243
0
        || insn->op == IR_LOOP_BEGIN
2244
0
        || insn->op == IR_STORE
2245
0
        || (insn->op == IR_BEGIN && insn->op2)) {
2246
0
      break;
2247
0
    }
2248
0
    ref = insn->op1;
2249
0
  }
2250
2251
0
  return IR_UNUSED;
2252
0
}
2253
2254
ir_ref ir_find_aliasing_vload(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
2255
0
{
2256
0
  return ir_find_aliasing_vload_i(ctx, ref, type, var);
2257
0
}
2258
2259
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_store_i(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val, ir_ref limit)
2260
0
{
2261
0
  ir_ref next = IR_UNUSED;
2262
0
  ir_insn *insn;
2263
0
  ir_type type = ctx->ir_base[val].type;
2264
0
  ir_type type2;
2265
0
  bool guarded = 0;
2266
2267
//  if (!IR_IS_CONST_REF(val)) {
2268
//    insn = &ctx->ir_base[val];
2269
//    if (insn->op == IR_BITCAST
2270
//     && !IR_IS_CONST_REF(insn->op1)
2271
//     && ir_type_size[insn->type] == ir_type_size[ctx->ir_base[insn->op1].type]) {
2272
//      /* skip BITCAST */
2273
//      val = insn->op1;
2274
//    }
2275
//  }
2276
2277
0
  while (ref > limit) {
2278
0
    insn = &ctx->ir_base[ref];
2279
0
    if (insn->op == IR_STORE) {
2280
0
      if (insn->op2 == addr) {
2281
0
        if (ctx->ir_base[insn->op3].type == type) {
2282
0
          if (insn->op3 == val) {
2283
            /* dead STORE (store the same value once again) */
2284
0
            return ref;
2285
0
          } else {
2286
0
            if (!guarded) {
2287
              /* the previous STORE is dead (there are no LOADs) */
2288
0
              if (!ctx->use_lists) {
2289
0
                if (next) {
2290
0
                  ctx->ir_base[next].op1 = insn->op1;
2291
0
                } else {
2292
0
                  ctx->control = insn->op1;
2293
0
                }
2294
0
              } else {
2295
0
                ir_ref prev = insn->op1;
2296
2297
0
                if (!next) {
2298
0
                  IR_ASSERT(ctx->use_lists[ref].count == 1);
2299
0
                  next = ctx->use_edges[ctx->use_lists[ref].refs];
2300
0
                }
2301
0
                ctx->ir_base[next].op1 = prev;
2302
0
                ir_use_list_remove_one(ctx, ref, next);
2303
0
                ir_use_list_replace_one(ctx, prev, ref, next);
2304
0
                if (!IR_IS_CONST_REF(insn->op2)) {
2305
0
                  ir_use_list_remove_one(ctx, insn->op2, ref);
2306
0
                }
2307
0
                if (!IR_IS_CONST_REF(insn->op3)) {
2308
0
                  ir_use_list_remove_one(ctx, insn->op3, ref);
2309
0
                }
2310
0
                insn->op1 = IR_UNUSED;
2311
0
              }
2312
0
              MAKE_NOP(insn);
2313
0
            }
2314
0
            break;
2315
0
          }
2316
0
        } else {
2317
0
          break;
2318
0
        }
2319
0
      } else {
2320
0
        type2 = ctx->ir_base[insn->op3].type;
2321
0
        goto check_aliasing;
2322
0
      }
2323
0
    } else if (insn->op == IR_LOAD) {
2324
0
      if (insn->op2 == addr) {
2325
0
        if (ref == val) {
2326
          /* dead STORE (store the value that was loaded before) */
2327
0
          return ref;
2328
0
        }
2329
0
        break;
2330
0
      }
2331
0
      type2 = insn->type;
2332
0
check_aliasing:
2333
0
      if (ir_check_partial_aliasing(ctx, addr, insn->op2, type, type2) != IR_NO_ALIAS) {
2334
0
        break;
2335
0
      }
2336
0
    } else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2337
0
      guarded = 1;
2338
0
    } else if (insn->op >= IR_START) {
2339
0
      if (insn->op == IR_BEGIN && insn->op1 && !insn->op2) {
2340
        /* skip END */
2341
0
        ref = insn->op1;
2342
0
        insn = &ctx->ir_base[ref];
2343
0
      } else {
2344
0
        break;
2345
0
      }
2346
0
    } else if (insn->op == IR_CALL) {
2347
0
      break;
2348
0
    }
2349
0
    next = ref;
2350
0
    ref = insn->op1;
2351
0
  }
2352
2353
0
  return IR_UNUSED;
2354
0
}
2355
2356
ir_ref ir_find_aliasing_store(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val)
2357
0
{
2358
0
  return ir_find_aliasing_store_i(ctx, ref, addr, val, (addr > 0 && addr < ref) ? addr : 1);
2359
0
}
2360
2361
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vstore_i(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
2362
0
{
2363
0
  ir_ref limit = var;
2364
0
  ir_ref next = IR_UNUSED;
2365
0
  ir_insn *insn;
2366
0
  bool guarded = 0;
2367
2368
//  if (!IR_IS_CONST_REF(val)) {
2369
//    insn = &ctx->ir_base[val];
2370
//    if (insn->op == IR_BITCAST
2371
//     && !IR_IS_CONST_REF(insn->op1)
2372
//     && ir_type_size[insn->type] == ir_type_size[ctx->ir_base[insn->op1].type]) {
2373
//      /* skip BITCAST */
2374
//      val = insn->op1;
2375
//    }
2376
//  }
2377
2378
0
  while (ref > limit) {
2379
0
    insn = &ctx->ir_base[ref];
2380
0
    if (insn->op == IR_VSTORE) {
2381
0
      if (insn->op2 == var) {
2382
0
        if (insn->op3 == val) {
2383
          /* dead VSTORE */
2384
0
          return ref;
2385
0
        } else {
2386
0
          if (!guarded) {
2387
            /* the previous VSTORE is dead (there are no VLOADs) */
2388
0
            if (!ctx->use_lists) {
2389
0
              if (next) {
2390
0
                ctx->ir_base[next].op1 = insn->op1;
2391
0
              } else {
2392
0
                ctx->control = insn->op1;
2393
0
              }
2394
0
            } else {
2395
0
              ir_ref prev = insn->op1;
2396
2397
0
              if (!next) {
2398
0
                IR_ASSERT(ctx->use_lists[ref].count == 1);
2399
0
                next = ctx->use_edges[ctx->use_lists[ref].refs];
2400
0
              }
2401
0
              ctx->ir_base[next].op1 = prev;
2402
0
              ir_use_list_remove_one(ctx, ref, next);
2403
0
              ir_use_list_replace_one(ctx, prev, ref, next);
2404
0
              if (!IR_IS_CONST_REF(insn->op2)) {
2405
0
                ir_use_list_remove_one(ctx, insn->op2, ref);
2406
0
              }
2407
0
              if (!IR_IS_CONST_REF(insn->op3)) {
2408
0
                ir_use_list_remove_one(ctx, insn->op3, ref);
2409
0
              }
2410
0
              insn->op1 = IR_UNUSED;
2411
0
            }
2412
0
            MAKE_NOP(insn);
2413
0
          }
2414
0
          break;
2415
0
        }
2416
0
      }
2417
0
    } else if (insn->op == IR_VLOAD) {
2418
0
      if (insn->op2 == var) {
2419
0
        if (ref == val) {
2420
          /* dead VSTORE */
2421
0
          return ref;
2422
0
        }
2423
0
        break;
2424
0
      }
2425
0
    } else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2426
0
      guarded = 1;
2427
0
    } else if (insn->op >= IR_START) {
2428
0
      if (insn->op == IR_BEGIN && insn->op1 && !insn->op2) {
2429
        /* skip END */
2430
0
        ref = insn->op1;
2431
0
        insn = &ctx->ir_base[ref];
2432
0
      } else {
2433
0
        break;
2434
0
      }
2435
0
    } else if (insn->op == IR_CALL || insn->op == IR_LOAD || insn->op == IR_STORE) {
2436
0
      break;
2437
0
    }
2438
0
    next = ref;
2439
0
    ref = insn->op1;
2440
0
  }
2441
0
  return IR_UNUSED;
2442
0
}
2443
2444
ir_ref ir_find_aliasing_vstore(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
2445
0
{
2446
0
  return ir_find_aliasing_vstore_i(ctx, ref, var, val);
2447
0
}
2448
2449
/* IR Construction API */
2450
static ir_ref ir_last_guard(ir_ctx *ctx)
2451
0
{
2452
0
  ir_ref ref;
2453
0
  ir_insn *insn;
2454
2455
0
  IR_ASSERT(ctx->control);
2456
0
  ref = ctx->control;
2457
0
  while (1) {
2458
0
    insn = &ctx->ir_base[ref];
2459
0
    if (IR_IS_BB_START(insn->op) || insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2460
0
      if (insn->op == IR_START) ref = IR_UNUSED;
2461
0
      break;
2462
0
    }
2463
0
    ref = insn->op1;
2464
0
  }
2465
0
  return ref;
2466
0
}
2467
2468
ir_ref _ir_DIV(ir_ctx *ctx, ir_type type, ir_ref op1, ir_ref op2)
2469
0
{
2470
0
  ir_ref guard = (IR_IS_TYPE_FP(type) || (IR_IS_CONST_REF(op2) && ctx->ir_base[op2].val.u64 != 0)) ?
2471
0
    IR_UNUSED : ir_last_guard(ctx);
2472
0
  return ir_fold3(ctx, IR_OPT(IR_DIV, type), op1, op2, guard);
2473
0
}
2474
2475
ir_ref _ir_MOD(ir_ctx *ctx, ir_type type, ir_ref op1, ir_ref op2)
2476
0
{
2477
0
  ir_ref guard = (IR_IS_CONST_REF(op2) && ctx->ir_base[op2].val.u64 != 0) ?
2478
0
    IR_UNUSED : ir_last_guard(ctx);
2479
0
  return ir_fold3(ctx, IR_OPT(IR_MOD, type), op1, op2, guard);
2480
0
}
2481
2482
ir_ref _ir_PARAM(ir_ctx *ctx, ir_type type, const char* name, ir_ref num)
2483
0
{
2484
0
  IR_ASSERT(ctx->control);
2485
0
  IR_ASSERT(ctx->ir_base[ctx->control].op == IR_START);
2486
0
  IR_ASSERT(ctx->insns_count == num + 1);
2487
0
  return ir_param(ctx, type, ctx->control, name, num);
2488
0
}
2489
2490
ir_ref _ir_VAR(ir_ctx *ctx, ir_type type, const char* name)
2491
0
{
2492
//  IR_ASSERT(ctx->control);
2493
//  IR_ASSERT(IR_IS_BB_START(ctx->ir_base[ctx->control].op));
2494
//  TODO: VAR may be insterted after some "memory" instruction
2495
0
  ir_ref ref = ctx->control;
2496
2497
0
  while (1) {
2498
0
    IR_ASSERT(ref);
2499
0
    if (IR_IS_BB_START(ctx->ir_base[ref].op)) {
2500
0
      break;
2501
0
    }
2502
0
    ref = ctx->ir_base[ref].op1;
2503
0
  }
2504
0
  return ir_var(ctx, type, ref, name);
2505
0
}
2506
2507
ir_ref _ir_PHI_2(ir_ctx *ctx, ir_type type, ir_ref src1, ir_ref src2)
2508
0
{
2509
0
  IR_ASSERT(ctx->control);
2510
0
  IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
2511
0
  if (src1 == src2 && src1 != IR_UNUSED) {
2512
0
    return src1;
2513
0
  }
2514
0
  return ir_emit3(ctx, IR_OPTX(IR_PHI, type, 3), ctx->control, src1, src2);
2515
0
}
2516
2517
ir_ref _ir_PHI_N(ir_ctx *ctx, ir_type type, ir_ref n, ir_ref *inputs)
2518
0
{
2519
0
  IR_ASSERT(ctx->control);
2520
0
  IR_ASSERT(n > 0);
2521
0
  if (n == 1) {
2522
0
    return inputs[0];
2523
0
  } else {
2524
0
      ir_ref i;
2525
0
    ir_ref ref;
2526
2527
0
    if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
2528
0
      IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE
2529
0
        || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
2530
0
      ref = inputs[0];
2531
0
      if (ref != IR_UNUSED) {
2532
0
        for (i = 1; i < n; i++) {
2533
0
          if (inputs[i] != ref) {
2534
0
            break;
2535
0
          }
2536
0
        }
2537
0
        if (i == n) {
2538
          /* all the same */
2539
0
          return ref;
2540
0
        }
2541
0
      }
2542
0
    }
2543
2544
0
    ref = ir_emit_N(ctx, IR_OPT(IR_PHI, type), n + 1);
2545
0
    ir_set_op(ctx, ref, 1, ctx->control);
2546
0
    for (i = 0; i < n; i++) {
2547
0
      ir_set_op(ctx, ref, i + 2, inputs[i]);
2548
0
    }
2549
0
    return ref;
2550
0
  }
2551
0
}
2552
2553
void _ir_PHI_SET_OP(ir_ctx *ctx, ir_ref phi, ir_ref pos, ir_ref src)
2554
0
{
2555
0
  ir_insn *insn = &ctx->ir_base[phi];
2556
0
  ir_ref *ops = insn->ops;
2557
2558
0
  IR_ASSERT(insn->op == IR_PHI);
2559
0
  IR_ASSERT(ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN);
2560
0
  IR_ASSERT(pos > 0 && pos < insn->inputs_count);
2561
0
  pos++; /* op1 is used for control */
2562
0
  ops[pos] = src;
2563
0
}
2564
2565
void _ir_START(ir_ctx *ctx)
2566
0
{
2567
0
  IR_ASSERT(!ctx->control);
2568
0
  IR_ASSERT(ctx->insns_count == 1);
2569
0
  ctx->control = ir_emit0(ctx, IR_START);
2570
0
}
2571
2572
void _ir_ENTRY(ir_ctx *ctx, ir_ref src, ir_ref num)
2573
0
{
2574
0
  IR_ASSERT(!ctx->control);
2575
  /* fake control edge */
2576
0
  IR_ASSERT((ir_op_flags[ctx->ir_base[src].op] & IR_OP_FLAG_TERMINATOR)
2577
0
    || ctx->ir_base[src].op == IR_END
2578
0
    || ctx->ir_base[src].op == IR_LOOP_END); /* return from a recursive call */
2579
0
  ctx->control = ir_emit2(ctx, IR_ENTRY, src, num);
2580
0
}
2581
2582
void _ir_BEGIN(ir_ctx *ctx, ir_ref src)
2583
0
{
2584
0
  IR_ASSERT(!ctx->control);
2585
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)
2586
0
   && src
2587
0
   && src + 1 == ctx->insns_count
2588
0
   && ctx->ir_base[src].op == IR_END) {
2589
    /* merge with the last END */
2590
0
    ctx->control = ctx->ir_base[src].op1;
2591
0
    ctx->insns_count--;
2592
0
  } else {
2593
0
    ctx->control = ir_emit1(ctx, IR_BEGIN, src);
2594
0
  }
2595
0
}
2596
2597
static ir_ref _ir_fold_condition(const ir_ctx *ctx, ir_ref ref)
2598
0
{
2599
0
  const ir_insn *insn = &ctx->ir_base[ref];
2600
2601
0
  if (insn->op == IR_NE && IR_IS_CONST_REF(insn->op2)) {
2602
0
    const ir_insn *op2_insn = &ctx->ir_base[insn->op2];
2603
2604
0
    if (IR_IS_TYPE_INT(op2_insn->type) && op2_insn->val.u64 == 0) {
2605
0
      ref = insn->op1;
2606
0
      insn = &ctx->ir_base[ref];
2607
0
      if (insn->op == IR_ALLOCA || insn->op == IR_VADDR) {
2608
0
        return IR_TRUE;
2609
0
      }
2610
0
    }
2611
0
  } else if (insn->op == IR_EQ && insn->op2 == IR_TRUE) {
2612
0
    ref = insn->op1;
2613
0
    insn = &ctx->ir_base[ref];
2614
0
  } else if (insn->op == IR_EQ && insn->op2 == IR_NULL) {
2615
0
    const ir_insn *op1_insn = &ctx->ir_base[insn->op1];
2616
0
    if (op1_insn->op == IR_ALLOCA || op1_insn->op == IR_VADDR) {
2617
0
      return IR_FALSE;
2618
0
    }
2619
0
  }
2620
//  while (insn->op == IR_SEXT || insn->op == IR_ZEXT || insn->op == IR_BITCAST) {
2621
//    ref = insn->op1;
2622
//    insn = &ctx->ir_base[ref];
2623
//  }
2624
0
  return ref;
2625
0
}
2626
2627
IR_ALWAYS_INLINE ir_ref ir_check_dominating_predicates_i(const ir_ctx *ctx, ir_ref ref, ir_ref condition, ir_ref limit)
2628
0
{
2629
0
  const ir_insn *prev = NULL;
2630
0
  const ir_insn *insn;
2631
2632
0
  while (ref > limit) {
2633
0
    insn = &ctx->ir_base[ref];
2634
0
    if (insn->op == IR_GUARD_NOT) {
2635
0
      if (insn->op2 == condition) {
2636
0
        return IR_FALSE;
2637
0
      }
2638
0
    } else if (insn->op == IR_GUARD) {
2639
0
      if (insn->op2 == condition) {
2640
0
        return IR_TRUE;
2641
0
      }
2642
0
    } else if (insn->op == IR_IF) {
2643
0
      if (insn->op2 == condition) {
2644
0
        if (prev->op == IR_IF_TRUE) {
2645
0
          return IR_TRUE;
2646
0
        } else if (prev->op == IR_IF_FALSE) {
2647
0
          return IR_FALSE;
2648
0
        }
2649
0
      }
2650
0
    } else if (insn->op == IR_START || insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
2651
0
      break;
2652
0
    }
2653
0
    prev = insn;
2654
0
    ref = insn->op1;
2655
0
  }
2656
2657
0
  return condition;
2658
0
}
2659
2660
ir_ref ir_check_dominating_predicates(const ir_ctx *ctx, ir_ref ref, ir_ref condition)
2661
0
{
2662
0
  IR_ASSERT(!IR_IS_CONST_REF(condition));
2663
0
  return ir_check_dominating_predicates_i(ctx, ref, condition, (condition < ref) ? condition : 1);
2664
0
}
2665
2666
ir_ref _ir_IF(ir_ctx *ctx, ir_ref condition)
2667
0
{
2668
0
  ir_ref if_ref;
2669
2670
0
  IR_ASSERT(ctx->control);
2671
0
  if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
2672
0
    if_ref = ir_emit2(ctx, IR_IF, ctx->control, condition);
2673
0
    ctx->control = IR_UNUSED;
2674
0
    return if_ref;
2675
0
  }
2676
2677
0
  condition = _ir_fold_condition(ctx, condition);
2678
0
  if (IR_IS_CONST_REF(condition)) {
2679
0
    condition = ir_ref_is_true(ctx, condition) ? IR_TRUE : IR_FALSE;
2680
0
  } else {
2681
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
2682
0
  }
2683
0
  if_ref = ir_emit2(ctx, IR_IF, ctx->control, condition);
2684
0
  ctx->control = IR_UNUSED;
2685
0
  return if_ref;
2686
0
}
2687
2688
void _ir_IF_TRUE(ir_ctx *ctx, ir_ref if_ref)
2689
0
{
2690
0
  IR_ASSERT(!ctx->control);
2691
0
  IR_ASSERT(if_ref);
2692
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2693
0
  ctx->control = ir_emit1(ctx, IR_IF_TRUE, if_ref);
2694
0
}
2695
2696
void _ir_IF_TRUE_cold(ir_ctx *ctx, ir_ref if_ref)
2697
0
{
2698
0
  IR_ASSERT(!ctx->control);
2699
0
  IR_ASSERT(if_ref);
2700
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2701
  /* op2 is used as an indicator of low-probability branch */
2702
0
  ctx->control = ir_emit2(ctx, IR_IF_TRUE, if_ref, 1);
2703
0
}
2704
2705
void _ir_IF_FALSE(ir_ctx *ctx, ir_ref if_ref)
2706
0
{
2707
0
  IR_ASSERT(!ctx->control);
2708
0
  IR_ASSERT(if_ref);
2709
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2710
0
  ctx->control = ir_emit1(ctx, IR_IF_FALSE, if_ref);
2711
0
}
2712
2713
void _ir_IF_FALSE_cold(ir_ctx *ctx, ir_ref if_ref)
2714
0
{
2715
0
  IR_ASSERT(!ctx->control);
2716
0
  IR_ASSERT(if_ref);
2717
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2718
  /* op2 is used as an indicator of low-probability branch */
2719
0
  ctx->control = ir_emit2(ctx, IR_IF_FALSE, if_ref, 1);
2720
0
}
2721
2722
ir_ref _ir_END(ir_ctx *ctx)
2723
0
{
2724
0
  ir_ref ref;
2725
2726
0
  IR_ASSERT(ctx->control);
2727
0
  ref = ir_emit1(ctx, IR_END, ctx->control);
2728
0
  ctx->control = IR_UNUSED;
2729
0
  return ref;
2730
0
}
2731
2732
void _ir_MERGE_2(ir_ctx *ctx, ir_ref src1, ir_ref src2)
2733
0
{
2734
0
  IR_ASSERT(!ctx->control);
2735
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_MERGE, IR_VOID, 2), src1, src2);
2736
0
}
2737
2738
void _ir_MERGE_N(ir_ctx *ctx, ir_ref n, ir_ref *inputs)
2739
0
{
2740
0
  IR_ASSERT(!ctx->control);
2741
0
  IR_ASSERT(n > 0);
2742
0
  if (n == 1) {
2743
0
    _ir_BEGIN(ctx, inputs[0]);
2744
0
  } else {
2745
0
    ir_ref *ops;
2746
2747
0
    ctx->control = ir_emit_N(ctx, IR_MERGE, n);
2748
0
    ops = ctx->ir_base[ctx->control].ops;
2749
0
    while (n) {
2750
0
      n--;
2751
0
      ops[n + 1] = inputs[n];
2752
0
    }
2753
0
  }
2754
0
}
2755
2756
void _ir_MERGE_SET_OP(ir_ctx *ctx, ir_ref merge, ir_ref pos, ir_ref src)
2757
0
{
2758
0
  ir_insn *insn = &ctx->ir_base[merge];
2759
0
  ir_ref *ops = insn->ops;
2760
2761
0
  IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
2762
0
  IR_ASSERT(pos > 0 && pos <= insn->inputs_count);
2763
0
  ops[pos] = src;
2764
0
}
2765
2766
ir_ref _ir_END_LIST(ir_ctx *ctx, ir_ref list)
2767
0
{
2768
0
  ir_ref ref;
2769
2770
0
  IR_ASSERT(ctx->control);
2771
0
  IR_ASSERT(!list || ctx->ir_base[list].op == IR_END);
2772
  /* create a liked list of END nodes with the same destination through END.op2 */
2773
0
  ref = ir_emit2(ctx, IR_END, ctx->control, list);
2774
0
  ctx->control = IR_UNUSED;
2775
0
  return ref;
2776
0
}
2777
2778
ir_ref _ir_END_PHI_LIST(ir_ctx *ctx, ir_ref list, ir_ref val)
2779
0
{
2780
0
  ir_ref ref;
2781
2782
0
  IR_ASSERT(ctx->control);
2783
0
  IR_ASSERT(!list || ctx->ir_base[list].op == IR_END);
2784
  /* create a liked list of END nodes with the same destination through END.op2 */
2785
0
  ref = ir_emit3(ctx, IR_END, ctx->control, list, val);
2786
0
  ctx->control = IR_UNUSED;
2787
0
  return ref;
2788
0
}
2789
2790
void _ir_MERGE_LIST(ir_ctx *ctx, ir_ref list)
2791
0
{
2792
0
  ir_ref ref = list;
2793
2794
0
  if (list != IR_UNUSED) {
2795
0
    uint32_t n = 0;
2796
2797
0
    IR_ASSERT(!ctx->control);
2798
2799
    /* count inputs count */
2800
0
    do {
2801
0
      const ir_insn *insn = &ctx->ir_base[ref];
2802
2803
0
      IR_ASSERT(insn->op == IR_END);
2804
0
      ref = insn->op2;
2805
0
      n++;
2806
0
    } while (ref != IR_UNUSED);
2807
2808
2809
    /* create MERGE node */
2810
0
    IR_ASSERT(n > 0);
2811
0
    if (n == 1) {
2812
0
      ctx->ir_base[list].op2 = IR_UNUSED;
2813
0
      _ir_BEGIN(ctx, list);
2814
0
    } else {
2815
0
      ctx->control = ir_emit_N(ctx, IR_MERGE, n);
2816
0
      ref = list;
2817
0
      while (n) {
2818
0
        ir_insn *insn = &ctx->ir_base[ref];
2819
2820
0
        ir_set_op(ctx, ctx->control, n, ref);
2821
0
        ref = insn->op2;
2822
0
        insn->op2 = IR_UNUSED;
2823
0
        n--;
2824
0
      }
2825
0
    }
2826
0
  }
2827
0
}
2828
2829
ir_ref _ir_PHI_LIST(ir_ctx *ctx, ir_ref list)
2830
0
{
2831
0
  const ir_insn *merge;
2832
0
  const ir_ref *ops;
2833
0
  ir_insn *end;
2834
0
  ir_ref phi, i;
2835
0
  ir_type type;
2836
2837
0
  if (list == IR_UNUSED) {
2838
0
    return IR_UNUSED;
2839
0
  }
2840
0
  end = &ctx->ir_base[list];
2841
0
  if (!end->op2) {
2842
0
    phi = end->op3;
2843
0
    end->op3 = IR_UNUSED;
2844
0
    _ir_BEGIN(ctx, list);
2845
0
  } else if (!end->op3) {
2846
0
    _ir_MERGE_LIST(ctx, list);
2847
0
    phi = IR_UNUSED;
2848
0
  } else {
2849
0
    type = ctx->ir_base[end->op3].type;
2850
0
    _ir_MERGE_LIST(ctx, list);
2851
0
    merge = &ctx->ir_base[ctx->control];
2852
0
    IR_ASSERT(merge->op == IR_MERGE);
2853
0
    phi = ir_emit_N(ctx, IR_OPT(IR_PHI, type), merge->inputs_count + 1);
2854
0
    merge = &ctx->ir_base[ctx->control];
2855
0
    ops = merge->ops;
2856
0
    ir_set_op(ctx, phi, 1, ctx->control);
2857
0
    for (i = 0; i < merge->inputs_count; i++) {
2858
0
      end = &ctx->ir_base[ops[i + 1]];
2859
0
      ir_set_op(ctx, phi, i + 2, end->op3);
2860
0
      end->op3 = IR_END;
2861
0
    }
2862
0
  }
2863
0
  return phi;
2864
0
}
2865
2866
ir_ref _ir_LOOP_BEGIN(ir_ctx *ctx, ir_ref src1)
2867
0
{
2868
0
  IR_ASSERT(!ctx->control);
2869
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_LOOP_BEGIN, IR_VOID, 2), src1, IR_UNUSED);
2870
0
  return ctx->control;
2871
0
}
2872
2873
ir_ref _ir_LOOP_END(ir_ctx *ctx)
2874
0
{
2875
0
  ir_ref ref;
2876
2877
0
  IR_ASSERT(ctx->control);
2878
0
  ref = ir_emit1(ctx, IR_LOOP_END, ctx->control);
2879
0
  ctx->control = IR_UNUSED;
2880
0
  return ref;
2881
0
}
2882
2883
ir_ref _ir_CALL(ir_ctx *ctx, ir_type type, ir_ref func)
2884
0
{
2885
0
  IR_ASSERT(ctx->control);
2886
0
  return ctx->control = ir_emit2(ctx, IR_OPTX(IR_CALL, type, 2), ctx->control, func);
2887
0
}
2888
2889
ir_ref _ir_CALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
2890
0
{
2891
0
  IR_ASSERT(ctx->control);
2892
0
  return ctx->control = ir_emit3(ctx, IR_OPTX(IR_CALL, type, 3), ctx->control, func, arg1);
2893
0
}
2894
2895
ir_ref _ir_CALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
2896
0
{
2897
0
  ir_ref call;
2898
2899
0
  IR_ASSERT(ctx->control);
2900
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 4);
2901
0
  ir_set_op(ctx, call, 1, ctx->control);
2902
0
  ir_set_op(ctx, call, 2, func);
2903
0
  ir_set_op(ctx, call, 3, arg1);
2904
0
  ir_set_op(ctx, call, 4, arg2);
2905
0
  ctx->control = call;
2906
0
  return call;
2907
0
}
2908
2909
ir_ref _ir_CALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
2910
0
{
2911
0
  ir_ref call;
2912
2913
0
  IR_ASSERT(ctx->control);
2914
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 5);
2915
0
  ir_set_op(ctx, call, 1, ctx->control);
2916
0
  ir_set_op(ctx, call, 2, func);
2917
0
  ir_set_op(ctx, call, 3, arg1);
2918
0
  ir_set_op(ctx, call, 4, arg2);
2919
0
  ir_set_op(ctx, call, 5, arg3);
2920
0
  ctx->control = call;
2921
0
  return call;
2922
0
}
2923
2924
ir_ref _ir_CALL_4(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4)
2925
0
{
2926
0
  ir_ref call;
2927
2928
0
  IR_ASSERT(ctx->control);
2929
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 6);
2930
0
  ir_set_op(ctx, call, 1, ctx->control);
2931
0
  ir_set_op(ctx, call, 2, func);
2932
0
  ir_set_op(ctx, call, 3, arg1);
2933
0
  ir_set_op(ctx, call, 4, arg2);
2934
0
  ir_set_op(ctx, call, 5, arg3);
2935
0
  ir_set_op(ctx, call, 6, arg4);
2936
0
  ctx->control = call;
2937
0
  return call;
2938
0
}
2939
2940
ir_ref _ir_CALL_5(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5)
2941
0
{
2942
0
  ir_ref call;
2943
2944
0
  IR_ASSERT(ctx->control);
2945
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 7);
2946
0
  ir_set_op(ctx, call, 1, ctx->control);
2947
0
  ir_set_op(ctx, call, 2, func);
2948
0
  ir_set_op(ctx, call, 3, arg1);
2949
0
  ir_set_op(ctx, call, 4, arg2);
2950
0
  ir_set_op(ctx, call, 5, arg3);
2951
0
  ir_set_op(ctx, call, 6, arg4);
2952
0
  ir_set_op(ctx, call, 7, arg5);
2953
0
  ctx->control = call;
2954
0
  return call;
2955
0
}
2956
2957
ir_ref _ir_CALL_6(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5, ir_ref arg6)
2958
0
{
2959
0
  ir_ref call;
2960
2961
0
  IR_ASSERT(ctx->control);
2962
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 8);
2963
0
  ir_set_op(ctx, call, 1, ctx->control);
2964
0
  ir_set_op(ctx, call, 2, func);
2965
0
  ir_set_op(ctx, call, 3, arg1);
2966
0
  ir_set_op(ctx, call, 4, arg2);
2967
0
  ir_set_op(ctx, call, 5, arg3);
2968
0
  ir_set_op(ctx, call, 6, arg4);
2969
0
  ir_set_op(ctx, call, 7, arg5);
2970
0
  ir_set_op(ctx, call, 8, arg6);
2971
0
  ctx->control = call;
2972
0
  return call;
2973
0
}
2974
2975
ir_ref _ir_CALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
2976
0
{
2977
0
  ir_ref call;
2978
0
  uint32_t i;
2979
2980
0
  IR_ASSERT(ctx->control);
2981
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), count + 2);
2982
0
  ir_set_op(ctx, call, 1, ctx->control);
2983
0
  ir_set_op(ctx, call, 2, func);
2984
0
  for (i = 0; i < count; i++) {
2985
0
    ir_set_op(ctx, call, i + 3, args[i]);
2986
0
  }
2987
0
  ctx->control = call;
2988
0
  return call;
2989
0
}
2990
2991
void _ir_UNREACHABLE(ir_ctx *ctx)
2992
0
{
2993
0
  IR_ASSERT(ctx->control);
2994
0
  ctx->control = ir_emit3(ctx, IR_UNREACHABLE, ctx->control, IR_UNUSED, ctx->ir_base[1].op1);
2995
0
  ctx->ir_base[1].op1 = ctx->control;
2996
0
  ctx->control = IR_UNUSED;
2997
0
}
2998
2999
void _ir_TAILCALL(ir_ctx *ctx, ir_type type, ir_ref func)
3000
0
{
3001
0
  IR_ASSERT(ctx->control);
3002
0
  if (ctx->ret_type == (ir_type)-1) {
3003
0
    ctx->ret_type = type;
3004
0
  }
3005
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3006
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_TAILCALL, type, 2), ctx->control, func);
3007
0
  _ir_UNREACHABLE(ctx);
3008
0
}
3009
3010
void _ir_TAILCALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
3011
0
{
3012
0
  IR_ASSERT(ctx->control);
3013
0
  if (ctx->ret_type == (ir_type)-1) {
3014
0
    ctx->ret_type = type;
3015
0
  }
3016
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3017
0
  ctx->control = ir_emit3(ctx, IR_OPTX(IR_TAILCALL, type, 3), ctx->control, func, arg1);
3018
0
  _ir_UNREACHABLE(ctx);
3019
0
}
3020
3021
void _ir_TAILCALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
3022
0
{
3023
0
  ir_ref call;
3024
3025
0
  IR_ASSERT(ctx->control);
3026
0
  if (ctx->ret_type == (ir_type)-1) {
3027
0
    ctx->ret_type = type;
3028
0
  }
3029
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3030
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 4);
3031
0
  ir_set_op(ctx, call, 1, ctx->control);
3032
0
  ir_set_op(ctx, call, 2, func);
3033
0
  ir_set_op(ctx, call, 3, arg1);
3034
0
  ir_set_op(ctx, call, 4, arg2);
3035
0
  ctx->control = call;
3036
0
  _ir_UNREACHABLE(ctx);
3037
0
}
3038
3039
void _ir_TAILCALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
3040
0
{
3041
0
  ir_ref call;
3042
3043
0
  IR_ASSERT(ctx->control);
3044
0
  if (ctx->ret_type == (ir_type)-1) {
3045
0
    ctx->ret_type = type;
3046
0
  }
3047
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3048
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 5);
3049
0
  ir_set_op(ctx, call, 1, ctx->control);
3050
0
  ir_set_op(ctx, call, 2, func);
3051
0
  ir_set_op(ctx, call, 3, arg1);
3052
0
  ir_set_op(ctx, call, 4, arg2);
3053
0
  ir_set_op(ctx, call, 5, arg3);
3054
0
  ctx->control = call;
3055
0
  _ir_UNREACHABLE(ctx);
3056
0
}
3057
3058
void _ir_TAILCALL_4(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4)
3059
0
{
3060
0
  ir_ref call;
3061
3062
0
  IR_ASSERT(ctx->control);
3063
0
  if (ctx->ret_type == (ir_type)-1) {
3064
0
    ctx->ret_type = type;
3065
0
  }
3066
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3067
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 6);
3068
0
  ir_set_op(ctx, call, 1, ctx->control);
3069
0
  ir_set_op(ctx, call, 2, func);
3070
0
  ir_set_op(ctx, call, 3, arg1);
3071
0
  ir_set_op(ctx, call, 4, arg2);
3072
0
  ir_set_op(ctx, call, 5, arg3);
3073
0
  ir_set_op(ctx, call, 6, arg4);
3074
0
  ctx->control = call;
3075
0
  _ir_UNREACHABLE(ctx);
3076
0
}
3077
3078
void _ir_TAILCALL_5(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5)
3079
0
{
3080
0
  ir_ref call;
3081
3082
0
  IR_ASSERT(ctx->control);
3083
0
  if (ctx->ret_type == (ir_type)-1) {
3084
0
    ctx->ret_type = type;
3085
0
  }
3086
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3087
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 7);
3088
0
  ir_set_op(ctx, call, 1, ctx->control);
3089
0
  ir_set_op(ctx, call, 2, func);
3090
0
  ir_set_op(ctx, call, 3, arg1);
3091
0
  ir_set_op(ctx, call, 4, arg2);
3092
0
  ir_set_op(ctx, call, 5, arg3);
3093
0
  ir_set_op(ctx, call, 6, arg4);
3094
0
  ir_set_op(ctx, call, 7, arg5);
3095
0
  ctx->control = call;
3096
0
  _ir_UNREACHABLE(ctx);
3097
0
}
3098
3099
void _ir_TAILCALL_6(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5, ir_ref arg6)
3100
0
{
3101
0
  ir_ref call;
3102
3103
0
  IR_ASSERT(ctx->control);
3104
0
  if (ctx->ret_type == (ir_type)-1) {
3105
0
    ctx->ret_type = type;
3106
0
  }
3107
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3108
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 8);
3109
0
  ir_set_op(ctx, call, 1, ctx->control);
3110
0
  ir_set_op(ctx, call, 2, func);
3111
0
  ir_set_op(ctx, call, 3, arg1);
3112
0
  ir_set_op(ctx, call, 4, arg2);
3113
0
  ir_set_op(ctx, call, 5, arg3);
3114
0
  ir_set_op(ctx, call, 6, arg4);
3115
0
  ir_set_op(ctx, call, 7, arg5);
3116
0
  ir_set_op(ctx, call, 8, arg6);
3117
0
  ctx->control = call;
3118
0
  _ir_UNREACHABLE(ctx);
3119
0
}
3120
3121
void _ir_TAILCALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
3122
0
{
3123
0
  ir_ref call;
3124
0
  uint32_t i;
3125
3126
0
  IR_ASSERT(ctx->control);
3127
0
  if (ctx->ret_type == (ir_type)-1) {
3128
0
    ctx->ret_type = type;
3129
0
  }
3130
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3131
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), count + 2);
3132
0
  ir_set_op(ctx, call, 1, ctx->control);
3133
0
  ir_set_op(ctx, call, 2, func);
3134
0
  for (i = 0; i < count; i++) {
3135
0
    ir_set_op(ctx, call, i + 3, args[i]);
3136
0
  }
3137
0
  ctx->control = call;
3138
0
  _ir_UNREACHABLE(ctx);
3139
0
}
3140
3141
ir_ref _ir_SWITCH(ir_ctx *ctx, ir_ref val)
3142
0
{
3143
0
  ir_ref ref;
3144
3145
0
  IR_ASSERT(ctx->control);
3146
0
  ref = ir_emit2(ctx, IR_SWITCH, ctx->control, val);
3147
0
  ctx->control = IR_UNUSED;
3148
0
  return ref;
3149
0
}
3150
3151
void _ir_CASE_VAL(ir_ctx *ctx, ir_ref switch_ref, ir_ref val)
3152
0
{
3153
0
  IR_ASSERT(!ctx->control);
3154
0
  ctx->control = ir_emit2(ctx, IR_CASE_VAL, switch_ref, val);
3155
0
}
3156
3157
void _ir_CASE_RANGE(ir_ctx *ctx, ir_ref switch_ref, ir_ref v1, ir_ref v2)
3158
0
{
3159
0
  IR_ASSERT(!ctx->control);
3160
0
  ctx->control = ir_emit3(ctx, IR_CASE_RANGE, switch_ref, v1, v2);
3161
0
}
3162
3163
void _ir_CASE_DEFAULT(ir_ctx *ctx, ir_ref switch_ref)
3164
0
{
3165
0
  IR_ASSERT(!ctx->control);
3166
0
  ctx->control = ir_emit1(ctx, IR_CASE_DEFAULT, switch_ref);
3167
0
}
3168
3169
void _ir_RETURN(ir_ctx *ctx, ir_ref val)
3170
0
{
3171
0
  ir_type type = (val != IR_UNUSED) ? ctx->ir_base[val].type : IR_VOID;
3172
3173
0
  IR_ASSERT(ctx->control);
3174
0
  if (ctx->ret_type == (ir_type)-1) {
3175
0
    ctx->ret_type = type;
3176
0
  }
3177
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3178
0
  ctx->control = ir_emit3(ctx, IR_RETURN, ctx->control, val, ctx->ir_base[1].op1);
3179
0
  ctx->ir_base[1].op1 = ctx->control;
3180
0
  ctx->control = IR_UNUSED;
3181
0
}
3182
3183
void _ir_IJMP(ir_ctx *ctx, ir_ref addr)
3184
0
{
3185
0
  IR_ASSERT(ctx->control);
3186
0
  ctx->control = ir_emit3(ctx, IR_IJMP, ctx->control, addr, ctx->ir_base[1].op1);
3187
0
  ctx->ir_base[1].op1 = ctx->control;
3188
0
  ctx->control = IR_UNUSED;
3189
0
}
3190
3191
ir_ref _ir_IGOTO(ir_ctx *ctx, ir_ref addr)
3192
0
{
3193
0
  ir_ref ref;
3194
3195
0
  IR_ASSERT(ctx->control);
3196
0
  ctx->control = ref = ir_emit2(ctx, IR_IGOTO, ctx->control, addr);
3197
0
  ctx->control = IR_UNUSED;
3198
0
  return ref;
3199
0
}
3200
3201
ir_ref _ir_ADD_OFFSET(ir_ctx *ctx, ir_ref addr, uintptr_t offset)
3202
0
{
3203
0
  if (offset) {
3204
0
    addr = ir_fold2(ctx, IR_OPT(IR_ADD, IR_ADDR), addr, ir_const_addr(ctx, offset));
3205
0
  }
3206
0
  return addr;
3207
0
}
3208
3209
void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr)
3210
0
{
3211
0
  IR_ASSERT(ctx->control);
3212
0
  if (IR_IS_CONST_REF(condition)) {
3213
0
    if (ir_ref_is_true(ctx, condition)) {
3214
0
      return;
3215
0
    }
3216
0
    condition = IR_FALSE;
3217
0
  } else if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3218
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
3219
0
    if (condition == IR_TRUE) {
3220
0
      return;
3221
0
    }
3222
0
  }
3223
0
  if (ctx->snapshot_create) {
3224
0
    ctx->snapshot_create(ctx, addr);
3225
0
  }
3226
0
  ctx->control = ir_emit3(ctx, IR_GUARD, ctx->control, condition, addr);
3227
0
}
3228
3229
void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr)
3230
0
{
3231
0
  IR_ASSERT(ctx->control);
3232
0
  if (IR_IS_CONST_REF(condition)) {
3233
0
    if (!ir_ref_is_true(ctx, condition)) {
3234
0
      return;
3235
0
    }
3236
0
    condition = IR_TRUE;
3237
0
  } else if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3238
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
3239
0
    if (condition == IR_FALSE) {
3240
0
      return;
3241
0
    }
3242
0
  }
3243
0
  if (ctx->snapshot_create) {
3244
0
    ctx->snapshot_create(ctx, addr);
3245
0
  }
3246
0
  ctx->control = ir_emit3(ctx, IR_GUARD_NOT, ctx->control, condition, addr);
3247
0
}
3248
3249
ir_ref _ir_SNAPSHOT(ir_ctx *ctx, ir_ref n)
3250
0
{
3251
0
  ir_ref snapshot;
3252
3253
0
  IR_ASSERT(ctx->control);
3254
0
  snapshot = ir_emit_N(ctx, IR_SNAPSHOT, 1 + n); /* op1 is used for control */
3255
0
  ctx->ir_base[snapshot].op1 = ctx->control;
3256
0
  ctx->control = snapshot;
3257
0
  return snapshot;
3258
0
}
3259
3260
void _ir_SNAPSHOT_SET_OP(ir_ctx *ctx, ir_ref snapshot, ir_ref pos, ir_ref val)
3261
0
{
3262
0
  ir_insn *insn = &ctx->ir_base[snapshot];
3263
0
  ir_ref *ops = insn->ops;
3264
3265
0
  IR_ASSERT(val < snapshot);
3266
0
  IR_ASSERT(insn->op == IR_SNAPSHOT);
3267
0
  pos++; /* op1 is used for control */
3268
0
  IR_ASSERT(pos > 1 && pos <= insn->inputs_count);
3269
0
  ops[pos] = val;
3270
0
}
3271
3272
ir_ref _ir_EXITCALL(ir_ctx *ctx, ir_ref func)
3273
0
{
3274
0
  IR_ASSERT(ctx->control);
3275
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_EXITCALL, IR_I32), ctx->control, func);
3276
0
}
3277
3278
ir_ref _ir_ALLOCA(ir_ctx *ctx, ir_ref size)
3279
0
{
3280
0
  IR_ASSERT(ctx->control);
3281
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_ALLOCA, IR_ADDR), ctx->control, size);
3282
0
}
3283
3284
void _ir_AFREE(ir_ctx *ctx, ir_ref size)
3285
0
{
3286
0
  IR_ASSERT(ctx->control);
3287
0
  ctx->control = ir_emit2(ctx, IR_AFREE, ctx->control, size);
3288
0
}
3289
3290
ir_ref _ir_VLOAD(ir_ctx *ctx, ir_type type, ir_ref var)
3291
0
{
3292
0
  ir_ref ref;
3293
3294
0
  IR_ASSERT(ctx->control);
3295
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3296
0
    ref = ir_find_aliasing_vload_i(ctx, ctx->control, type, var);
3297
0
    if (ref) {
3298
0
      const ir_insn *insn = &ctx->ir_base[ref];
3299
3300
0
      if (insn->type == type) {
3301
0
        return ref;
3302
0
      } else if (ir_type_size[insn->type] == ir_type_size[type]) {
3303
0
        return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), ref); /* load forwarding with bitcast (L2L) */
3304
0
      } else {
3305
0
        return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), ref); /* partial load forwarding (L2L) */
3306
0
      }
3307
0
    }
3308
0
  }
3309
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD, type), ctx->control, var);
3310
0
}
3311
3312
void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val)
3313
0
{
3314
0
  IR_ASSERT(ctx->control);
3315
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3316
0
    if (ir_find_aliasing_vstore_i(ctx, ctx->control, var, val)) {
3317
      /* dead STORE */
3318
0
      return;
3319
0
    }
3320
0
  }
3321
0
  ctx->control = ir_emit3(ctx, IR_VSTORE, ctx->control, var, val);
3322
0
}
3323
3324
ir_ref _ir_VLOAD_v(ir_ctx *ctx, ir_type type, ir_ref var)
3325
0
{
3326
0
  IR_ASSERT(ctx->control);
3327
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD_v, type), ctx->control, var);
3328
0
}
3329
3330
void _ir_VSTORE_v(ir_ctx *ctx, ir_ref var, ir_ref val)
3331
0
{
3332
0
  IR_ASSERT(ctx->control);
3333
0
  ctx->control = ir_emit3(ctx, IR_VSTORE_v, ctx->control, var, val);
3334
0
}
3335
3336
ir_ref _ir_TLS(ir_ctx *ctx, ir_ref index, ir_ref offset)
3337
0
{
3338
0
  IR_ASSERT(ctx->control);
3339
0
  return ctx->control = ir_emit3(ctx, IR_OPT(IR_TLS, IR_ADDR), ctx->control, index, offset);
3340
0
}
3341
3342
ir_ref _ir_RLOAD(ir_ctx *ctx, ir_type type, ir_ref reg)
3343
0
{
3344
0
  IR_ASSERT(ctx->control);
3345
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_RLOAD, type), ctx->control, reg);
3346
0
}
3347
3348
void _ir_RSTORE(ir_ctx *ctx, ir_ref reg, ir_ref val)
3349
0
{
3350
0
  IR_ASSERT(ctx->control);
3351
0
  ctx->control = ir_emit3(ctx, IR_RSTORE, ctx->control, val, reg);
3352
0
}
3353
3354
ir_ref _ir_LOAD(ir_ctx *ctx, ir_type type, ir_ref addr)
3355
0
{
3356
0
  ir_ref ref;
3357
3358
0
  IR_ASSERT(ctx->control);
3359
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3360
0
    if (ctx->ir_base[addr].op == IR_VADDR) {
3361
0
      return _ir_VLOAD(ctx, type, ctx->ir_base[addr].op1);
3362
0
    }
3363
0
    ref = ir_find_aliasing_load_i(ctx, ctx->control, type, addr, (addr > 0) ? addr : 1);
3364
0
    if (ref) {
3365
0
      const ir_insn *insn = &ctx->ir_base[ref];
3366
3367
0
      if (insn->type == type) {
3368
0
        return ref;
3369
0
      } else if (ir_type_size[insn->type] == ir_type_size[type]) {
3370
0
        return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), ref); /* load forwarding with bitcast (L2L) */
3371
0
      } else {
3372
0
        return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), ref); /* partial load forwarding (L2L) */
3373
0
      }
3374
0
    }
3375
0
  }
3376
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD, type), ctx->control, addr);
3377
0
}
3378
3379
void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val)
3380
0
{
3381
0
  IR_ASSERT(ctx->control);
3382
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3383
0
    if (ctx->ir_base[addr].op == IR_VADDR) {
3384
0
      _ir_VSTORE(ctx, ctx->ir_base[addr].op1, val);
3385
0
      return;
3386
0
    }
3387
0
    if (ir_find_aliasing_store_i(ctx, ctx->control, addr, val, (addr > 0) ? addr : 1)) {
3388
      /* dead STORE */
3389
0
      return;
3390
0
    }
3391
0
  }
3392
0
  ctx->control = ir_emit3(ctx, IR_STORE, ctx->control, addr, val);
3393
0
}
3394
3395
ir_ref _ir_LOAD_v(ir_ctx *ctx, ir_type type, ir_ref addr)
3396
0
{
3397
0
  IR_ASSERT(ctx->control);
3398
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD_v, type), ctx->control, addr);
3399
0
}
3400
3401
void _ir_STORE_v(ir_ctx *ctx, ir_ref addr, ir_ref val)
3402
0
{
3403
0
  IR_ASSERT(ctx->control);
3404
0
  ctx->control = ir_emit3(ctx, IR_STORE_v, ctx->control, addr, val);
3405
0
}
3406
3407
void _ir_VA_START(ir_ctx *ctx, ir_ref list)
3408
0
{
3409
0
  IR_ASSERT(ctx->control);
3410
0
  ctx->control = ir_emit2(ctx, IR_VA_START, ctx->control, list);
3411
0
}
3412
3413
void _ir_VA_END(ir_ctx *ctx, ir_ref list)
3414
0
{
3415
0
  IR_ASSERT(ctx->control);
3416
0
  ctx->control = ir_emit2(ctx, IR_VA_END, ctx->control, list);
3417
0
}
3418
3419
void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src)
3420
0
{
3421
0
  IR_ASSERT(ctx->control);
3422
0
  ctx->control = ir_emit3(ctx, IR_VA_COPY, ctx->control, dst, src);
3423
0
}
3424
3425
ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
3426
0
{
3427
0
  IR_ASSERT(ctx->control);
3428
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
3429
0
}
3430
3431
ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size, size_t align)
3432
0
{
3433
0
  IR_ASSERT(ctx->control);
3434
0
  IR_ASSERT(size <= 0x0fffffff);
3435
0
  IR_ASSERT(align != 0 && ((align & (align - 1)) == 0) && align <= 128);
3436
0
  return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list,
3437
0
    (ir_ref)IR_VA_ARG_OP3(size, align));
3438
0
}
3439
3440
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)
3441
0
{
3442
0
  IR_ASSERT(ctx->control);
3443
0
  return ctx->control = ir_emit1(ctx, IR_OPT(IR_BLOCK_BEGIN, IR_ADDR), ctx->control);
3444
0
}