Coverage Report

Created: 2026-02-14 06:52

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