Coverage Report

Created: 2026-10-28 06:20

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