Coverage Report

Created: 2025-12-31 07:28

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
  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, ir_insn *op1_insn, ir_insn *op2_insn, ir_insn *op3_insn)
958
0
{
959
0
  uint8_t op;
960
0
  ir_ref ref;
961
0
  ir_val val;
962
0
  uint32_t key, any;
963
0
  (void) op3_insn;
964
965
0
restart:
966
0
  key = (opt & IR_OPT_OP_MASK) + ((uint32_t)op1_insn->op << 7) + ((uint32_t)op2_insn->op << 14);
967
0
  any = 0x1fffff;
968
0
  do {
969
0
    uint32_t k = key & any;
970
0
    uint32_t h = _ir_fold_hashkey(k);
971
0
    uint32_t fh = _ir_fold_hash[h];
972
0
    if (IR_FOLD_KEY(fh) == k
973
0
#ifdef IR_FOLD_SEMI_PERFECT_HASH
974
0
     || (fh = _ir_fold_hash[h+1], (fh & 0x1fffff) == k)
975
0
#endif
976
0
    ) {
977
0
      switch (IR_FOLD_RULE(fh)) {
978
0
#include "ir_fold.h"
979
0
        default:
980
0
          break;
981
0
      }
982
0
    }
983
0
    if (any == 0x7f) {
984
      /* All parrerns are checked. Pass on to CSE. */
985
0
      goto ir_fold_cse;
986
0
    }
987
    /* op2/op1/op  op2/_/op    _/op1/op    _/_/op
988
     * 0x1fffff -> 0x1fc07f -> 0x003fff -> 0x00007f
989
     * from masks to bis: 11 -> 10 -> 01 -> 00
990
     *
991
     * a b  => x y
992
     * 1 1     1 0
993
     * 1 0     0 1
994
     * 0 1     0 0
995
     *
996
     * x = a & b; y = !b
997
     */
998
0
    any = ((any & (any << 7)) & 0x1fc000) | (~any & 0x3f80) | 0x7f;
999
0
  } while (1);
1000
1001
0
ir_fold_restart:
1002
0
  if (!ctx->use_lists) {
1003
0
    op1_insn = ctx->ir_base + op1;
1004
0
    op2_insn = ctx->ir_base + op2;
1005
0
    op3_insn = ctx->ir_base + op3;
1006
0
    goto restart;
1007
0
  } else {
1008
0
    ctx->fold_insn.optx = opt;
1009
0
    ctx->fold_insn.op1 = op1;
1010
0
    ctx->fold_insn.op2 = op2;
1011
0
    ctx->fold_insn.op3 = op3;
1012
0
    return IR_FOLD_DO_RESTART;
1013
0
  }
1014
0
ir_fold_cse:
1015
0
  if (!ctx->use_lists) {
1016
    /* Local CSE */
1017
0
    ref = _ir_fold_cse(ctx, opt, op1, op2, op3);
1018
0
    if (ref) {
1019
0
      return ref;
1020
0
    }
1021
1022
0
    ref = ir_emit(ctx, opt, op1, op2, op3);
1023
1024
    /* Update local CSE chain */
1025
0
    op = opt & IR_OPT_OP_MASK;
1026
0
    ir_ref prev = ctx->prev_insn_chain[op];
1027
0
    ir_insn *insn = ctx->ir_base + ref;
1028
0
    if (!prev || ref - prev > 0xffff) {
1029
      /* can't fit into 16-bit */
1030
0
      insn->prev_insn_offset = 0;
1031
0
    } else {
1032
0
      insn->prev_insn_offset = ref - prev;
1033
0
    }
1034
0
    ctx->prev_insn_chain[op] = ref;
1035
1036
0
    return ref;
1037
0
  } else {
1038
0
    ctx->fold_insn.optx = opt;
1039
0
    ctx->fold_insn.op1 = op1;
1040
0
    ctx->fold_insn.op2 = op2;
1041
0
    ctx->fold_insn.op3 = op3;
1042
0
    return IR_FOLD_DO_CSE;
1043
0
  }
1044
0
ir_fold_emit:
1045
0
  if (!ctx->use_lists) {
1046
0
    return ir_emit(ctx, opt, op1, op2, op3);
1047
0
  } else {
1048
0
    ctx->fold_insn.optx = opt;
1049
0
    ctx->fold_insn.op1 = op1;
1050
0
    ctx->fold_insn.op2 = op2;
1051
0
    ctx->fold_insn.op3 = op3;
1052
0
    return IR_FOLD_DO_EMIT;
1053
0
  }
1054
0
ir_fold_copy:
1055
0
  if (!ctx->use_lists) {
1056
0
    return ref;
1057
0
  } else {
1058
0
    ctx->fold_insn.op1 = ref;
1059
0
    return IR_FOLD_DO_COPY;
1060
0
  }
1061
0
ir_fold_const:
1062
0
  if (!ctx->use_lists) {
1063
0
    return ir_const(ctx, val, IR_OPT_TYPE(opt));
1064
0
  } else {
1065
0
    ctx->fold_insn.opt = IR_OPT(IR_OPT_TYPE(opt), IR_OPT_TYPE(opt));
1066
0
    ctx->fold_insn.val.u64 = val.u64;
1067
0
    return IR_FOLD_DO_CONST;
1068
0
  }
1069
0
}
1070
1071
ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
1072
0
{
1073
0
  if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
1074
0
    if ((opt & IR_OPT_OP_MASK) == IR_PHI) {
1075
0
      opt |= (3 << IR_OPT_INPUTS_SHIFT);
1076
0
    }
1077
0
    return ir_emit(ctx, opt, op1, op2, op3);
1078
0
  }
1079
0
  return ir_folding(ctx, opt, op1, op2, op3, ctx->ir_base + op1, ctx->ir_base + op2, ctx->ir_base + op3);
1080
0
}
1081
1082
ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt)
1083
0
{
1084
0
  return ir_fold(ctx, opt, IR_UNUSED, IR_UNUSED, IR_UNUSED);
1085
0
}
1086
1087
ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
1088
0
{
1089
0
  return ir_fold(ctx, opt, op1, IR_UNUSED, IR_UNUSED);
1090
0
}
1091
1092
ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
1093
0
{
1094
0
  return ir_fold(ctx, opt, op1, op2, IR_UNUSED);
1095
0
}
1096
1097
ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
1098
0
{
1099
0
  return ir_fold(ctx, opt, op1, op2, op3);
1100
0
}
1101
1102
ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count)
1103
0
{
1104
0
  int i;
1105
0
  ir_ref *p, ref = ctx->insns_count;
1106
0
  ir_insn *insn;
1107
1108
0
  IR_ASSERT(count >= 0 && count < 65536);
1109
0
  while (UNEXPECTED(ref + count/4 >= ctx->insns_limit)) {
1110
0
    ir_grow_top(ctx);
1111
0
  }
1112
0
  ctx->insns_count = ref + 1 + count/4;
1113
1114
0
  insn = &ctx->ir_base[ref];
1115
0
  insn->optx = opt | (count << IR_OPT_INPUTS_SHIFT);
1116
0
  for (i = 1, p = insn->ops + i; i <= (count|3); i++, p++) {
1117
0
    *p = IR_UNUSED;
1118
0
  }
1119
1120
0
  return ref;
1121
0
}
1122
1123
void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val)
1124
0
{
1125
0
  ir_insn *insn = &ctx->ir_base[ref];
1126
1127
0
#ifdef IR_DEBUG
1128
0
  if (n > 3) {
1129
0
    int32_t count;
1130
1131
0
    IR_ASSERT(IR_OP_HAS_VAR_INPUTS(ir_op_flags[insn->op]));
1132
0
    count = insn->inputs_count;
1133
0
    IR_ASSERT(n <= count);
1134
0
  }
1135
0
#endif
1136
0
  ir_insn_set_op(insn, n, val);
1137
0
}
1138
1139
ir_ref ir_get_op(ir_ctx *ctx, ir_ref ref, int32_t n)
1140
0
{
1141
0
  ir_insn *insn = &ctx->ir_base[ref];
1142
1143
0
#ifdef IR_DEBUG
1144
0
  if (n > 3) {
1145
0
    int32_t count;
1146
1147
0
    IR_ASSERT(IR_OP_HAS_VAR_INPUTS(ir_op_flags[insn->op]));
1148
0
    count = insn->inputs_count;
1149
0
    IR_ASSERT(n <= count);
1150
0
  }
1151
0
#endif
1152
0
  return ir_insn_op(insn, n);
1153
0
}
1154
1155
ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos)
1156
0
{
1157
0
  IR_ASSERT(ctx->ir_base[region].op == IR_START);
1158
0
  return ir_emit(ctx, IR_OPT(IR_PARAM, type), region, ir_str(ctx, name), pos);
1159
0
}
1160
1161
ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name)
1162
0
{
1163
0
  IR_ASSERT(IR_IS_BB_START(ctx->ir_base[region].op));
1164
0
  return ir_emit(ctx, IR_OPT(IR_VAR, type), region, ir_str(ctx, name), IR_UNUSED);
1165
0
}
1166
1167
ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def)
1168
0
{
1169
0
  if (IR_IS_CONST_REF(def)) {
1170
0
    return def;
1171
0
  }
1172
0
  if (!ctx->binding) {
1173
0
    ctx->binding = ir_mem_malloc(sizeof(ir_hashtab));;
1174
0
    ir_hashtab_init(ctx->binding, 16);
1175
0
  }
1176
  /* Node may be bound to some special spill slot (using negative "var") */
1177
0
  IR_ASSERT(var < 0);
1178
0
  if (!ir_hashtab_add(ctx->binding, def, var)) {
1179
    /* Add a copy with different binding */
1180
0
    def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, IR_COPY_HARD);
1181
0
    ir_hashtab_add(ctx->binding, def, var);
1182
0
  }
1183
0
  return def;
1184
0
}
1185
1186
ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref)
1187
0
{
1188
0
  ir_ref var = ir_hashtab_find(ctx->binding, ref);
1189
0
  return (var != (ir_ref)IR_INVALID_VAL) ? var : 0;
1190
0
}
1191
1192
/* Batch construction of def->use edges */
1193
#if 0
1194
void ir_build_def_use_lists(ir_ctx *ctx)
1195
{
1196
  ir_ref n, i, j, *p, def;
1197
  ir_insn *insn;
1198
  uint32_t edges_count;
1199
  ir_use_list *lists = ir_mem_calloc(ctx->insns_limit, sizeof(ir_use_list));
1200
  ir_ref *edges;
1201
  ir_use_list *use_list;
1202
1203
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1204
    uint32_t flags = ir_op_flags[insn->op];
1205
1206
    if (UNEXPECTED(IR_OP_HAS_VAR_INPUTS(flags))) {
1207
      n = insn->inputs_count;
1208
    } else {
1209
      n = insn->inputs_count = IR_INPUT_EDGES_COUNT(flags);
1210
    }
1211
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1212
      def = *p;
1213
      if (def > 0) {
1214
        lists[def].count++;
1215
      }
1216
    }
1217
    n = ir_insn_inputs_to_len(n);
1218
    i += n;
1219
    insn += n;
1220
  }
1221
1222
  edges_count = 0;
1223
  for (i = IR_UNUSED + 1, use_list = &lists[i]; i < ctx->insns_count; i++, use_list++) {
1224
    use_list->refs = edges_count;
1225
    edges_count += use_list->count;
1226
    use_list->count = 0;
1227
  }
1228
1229
  edges = ir_mem_malloc(IR_ALIGNED_SIZE(edges_count * sizeof(ir_ref), 4096));
1230
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1231
    n = insn->inputs_count;
1232
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1233
      def = *p;
1234
      if (def > 0) {
1235
        use_list = &lists[def];
1236
        edges[use_list->refs + use_list->count++] = i;
1237
      }
1238
    }
1239
    n = ir_insn_inputs_to_len(n);
1240
    i += n;
1241
    insn += n;
1242
  }
1243
1244
  ctx->use_edges = edges;
1245
  ctx->use_edges_count = edges_count;
1246
  ctx->use_lists = lists;
1247
}
1248
#else
1249
void ir_build_def_use_lists(ir_ctx *ctx)
1250
0
{
1251
0
  ir_ref n, i, j, *p, def;
1252
0
  ir_insn *insn;
1253
0
  size_t linked_lists_size, linked_lists_top = 0, edges_count = 0;
1254
0
  ir_use_list *lists = ir_mem_calloc(ctx->insns_limit, sizeof(ir_use_list));
1255
0
  ir_ref *edges;
1256
0
  ir_use_list *use_list;
1257
0
  ir_ref *linked_lists;
1258
1259
0
  linked_lists_size = IR_ALIGNED_SIZE(ctx->insns_count, 1024);
1260
0
  linked_lists = ir_mem_malloc(linked_lists_size * sizeof(ir_ref));
1261
0
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
1262
0
    uint32_t flags = ir_op_flags[insn->op];
1263
1264
0
    if (UNEXPECTED(IR_OP_HAS_VAR_INPUTS(flags))) {
1265
0
      n = insn->inputs_count;
1266
0
    } else {
1267
0
      n = insn->inputs_count = IR_INPUT_EDGES_COUNT(flags);
1268
0
    }
1269
0
    for (j = n, p = insn->ops + 1; j > 0; j--, p++) {
1270
0
      def = *p;
1271
0
      if (def > 0) {
1272
0
        use_list = &lists[def];
1273
0
        edges_count++;
1274
0
        if (!use_list->refs) {
1275
          /* store a single "use" directly in "refs" using a positive number */
1276
0
          use_list->refs = i;
1277
0
          use_list->count = 1;
1278
0
        } else {
1279
0
          if (UNEXPECTED(linked_lists_top >= linked_lists_size)) {
1280
0
            linked_lists_size += 1024;
1281
0
            linked_lists = ir_mem_realloc(linked_lists, linked_lists_size * sizeof(ir_ref));
1282
0
          }
1283
          /* form a linked list of "uses" (like in binsort) */
1284
0
          linked_lists[linked_lists_top] = i; /* store the "use" */
1285
0
          linked_lists[linked_lists_top + 1] = use_list->refs; /* store list next */
1286
0
          use_list->refs = -(linked_lists_top + 1); /* store a head of the list using a negative number */
1287
0
          linked_lists_top += 2;
1288
0
          use_list->count++;
1289
0
        }
1290
0
      }
1291
0
    }
1292
0
    n = ir_insn_inputs_to_len(n);
1293
0
    i += n;
1294
0
    insn += n;
1295
0
  }
1296
1297
0
  ctx->use_edges_count = edges_count;
1298
0
  edges = ir_mem_malloc(IR_ALIGNED_SIZE(edges_count * sizeof(ir_ref), 4096));
1299
0
  for (use_list = lists + ctx->insns_count - 1; use_list != lists; use_list--) {
1300
0
    n = use_list->refs;
1301
0
    if (n) {
1302
      /* transform linked list to plain array */
1303
0
      while (n < 0) {
1304
0
        n = -n;
1305
0
        edges[--edges_count] = linked_lists[n - 1];
1306
0
        n = linked_lists[n];
1307
0
      }
1308
0
      IR_ASSERT(n > 0);
1309
0
      edges[--edges_count] = n;
1310
0
      use_list->refs = edges_count;
1311
0
    }
1312
0
  }
1313
1314
0
  ctx->use_edges = edges;
1315
0
  ctx->use_lists = lists;
1316
0
  ir_mem_free(linked_lists);
1317
0
}
1318
#endif
1319
1320
void ir_use_list_remove_all(ir_ctx *ctx, ir_ref from, ir_ref ref)
1321
0
{
1322
0
  ir_ref n, *p, *q, use;
1323
0
  ir_use_list *use_list;
1324
1325
0
  IR_ASSERT(from > 0);
1326
0
  use_list = &ctx->use_lists[from];
1327
0
  n = use_list->count;
1328
0
  for (p = q = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1329
0
    use = *p;
1330
0
    if (use != ref) {
1331
0
      if (p != q) {
1332
0
        *q = use;
1333
0
      }
1334
0
      q++;
1335
0
    }
1336
0
  }
1337
0
  if (p != q) {
1338
0
    use_list->count -= (p - q);
1339
0
    do {
1340
0
      *q = IR_UNUSED;
1341
0
      q++;
1342
0
    } while (q != p);
1343
0
  }
1344
0
}
1345
1346
void ir_use_list_remove_one(ir_ctx *ctx, ir_ref from, ir_ref ref)
1347
0
{
1348
0
  ir_ref n, *p;
1349
0
  ir_use_list *use_list;
1350
1351
0
  IR_ASSERT(from > 0);
1352
0
  use_list = &ctx->use_lists[from];
1353
0
  n = use_list->count;
1354
0
  p = &ctx->use_edges[use_list->refs];
1355
0
  while (n > 0) {
1356
0
    if (*p == ref) {
1357
0
      use_list->count--;
1358
0
      n--;
1359
0
      while (n > 0) {
1360
0
        *p = *(p+1);
1361
0
        p++;
1362
0
        n--;
1363
0
      }
1364
0
      *p = IR_UNUSED;
1365
0
      break;
1366
0
    }
1367
0
    p++;
1368
0
    n--;
1369
0
  }
1370
0
}
1371
1372
void ir_use_list_replace_one(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
1373
0
{
1374
0
  ir_use_list *use_list;
1375
0
  ir_ref n, *p;
1376
1377
0
  IR_ASSERT(ref > 0);
1378
0
  use_list = &ctx->use_lists[ref];
1379
0
  n = use_list->count;
1380
0
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1381
0
    if (*p == use) {
1382
0
      *p = new_use;
1383
0
      break;
1384
0
    }
1385
0
  }
1386
0
}
1387
1388
void ir_use_list_replace_all(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
1389
0
{
1390
0
  ir_use_list *use_list;
1391
0
  ir_ref n, *p;
1392
1393
0
  IR_ASSERT(ref > 0);
1394
0
  use_list = &ctx->use_lists[ref];
1395
0
  n = use_list->count;
1396
0
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1397
0
    if (*p == use) {
1398
0
      *p = new_use;
1399
0
    }
1400
0
  }
1401
0
}
1402
1403
bool ir_use_list_add(ir_ctx *ctx, ir_ref to, ir_ref ref)
1404
0
{
1405
0
  ir_use_list *use_list;
1406
0
  ir_ref n;
1407
1408
0
  IR_ASSERT(to > 0);
1409
0
  use_list = &ctx->use_lists[to];
1410
0
  n = use_list->refs + use_list->count;
1411
0
  if (n < ctx->use_edges_count && ctx->use_edges[n] == IR_UNUSED) {
1412
0
    ctx->use_edges[n] = ref;
1413
0
    use_list->count++;
1414
0
    return 0;
1415
0
  } else {
1416
0
    size_t old_size = IR_ALIGNED_SIZE(ctx->use_edges_count * sizeof(ir_ref), 4096);
1417
0
    size_t new_size = IR_ALIGNED_SIZE((ctx->use_edges_count + use_list->count + 1) * sizeof(ir_ref), 4096);
1418
1419
0
    if (old_size < new_size) {
1420
      /* Reallocate the whole edges buffer (this is inefficient) */
1421
0
      ctx->use_edges = ir_mem_realloc(ctx->use_edges, new_size);
1422
0
    } else if (n == ctx->use_edges_count) {
1423
0
      ctx->use_edges[n] = ref;
1424
0
      use_list->count++;
1425
0
      ctx->use_edges_count++;
1426
0
      return 0;
1427
0
    }
1428
0
    memcpy(ctx->use_edges + ctx->use_edges_count, ctx->use_edges + use_list->refs, use_list->count * sizeof(ir_ref));
1429
0
    use_list->refs = ctx->use_edges_count;
1430
0
    ctx->use_edges[use_list->refs + use_list->count] = ref;
1431
0
    use_list->count++;
1432
0
    ctx->use_edges_count += use_list->count;
1433
0
    return 1;
1434
0
  }
1435
0
}
1436
1437
static int ir_ref_cmp(const void *p1, const void *p2)
1438
0
{
1439
0
  return *(ir_ref*)p1 - *(ir_ref*)p2;
1440
0
}
1441
1442
void ir_use_list_sort(ir_ctx *ctx, ir_ref ref)
1443
0
{
1444
0
  ir_use_list *use_list;
1445
0
  uint32_t n;
1446
1447
0
  IR_ASSERT(ref > 0);
1448
0
  use_list = &ctx->use_lists[ref];
1449
0
  n = use_list->count;
1450
0
  if (n > 1) {
1451
0
    qsort(ctx->use_edges + use_list->refs, n, sizeof(ir_ref), ir_ref_cmp);
1452
0
  }
1453
0
}
1454
1455
void ir_replace(ir_ctx *ctx, ir_ref ref, ir_ref new_ref)
1456
0
{
1457
0
  int i, j, n, *p, use;
1458
0
  ir_insn *insn;
1459
0
  ir_use_list *use_list;
1460
1461
0
  IR_ASSERT(ref != new_ref);
1462
0
  use_list = &ctx->use_lists[ref];
1463
0
  n = use_list->count;
1464
0
  p = ctx->use_edges + use_list->refs;
1465
1466
0
  if (new_ref <= 0) {
1467
    /* constant or IR_UNUSED */
1468
0
    for (; n; p++, n--) {
1469
0
      use = *p;
1470
0
      IR_ASSERT(use != ref);
1471
0
      insn = &ctx->ir_base[use];
1472
0
      j = ir_insn_find_op(insn, ref);
1473
0
      IR_ASSERT(j > 0);
1474
0
      ir_insn_set_op(insn, j, new_ref);
1475
0
    }
1476
0
  } else {
1477
0
    for (i = 0; i < n; p++, i++) {
1478
0
      use = *p;
1479
0
      IR_ASSERT(use != ref);
1480
0
      insn = &ctx->ir_base[use];
1481
0
      j = ir_insn_find_op(insn, ref);
1482
0
      IR_ASSERT(j > 0);
1483
0
      ir_insn_set_op(insn, j, new_ref);
1484
0
      if (ir_use_list_add(ctx, new_ref, use)) {
1485
        /* restore after reallocation */
1486
0
        use_list = &ctx->use_lists[ref];
1487
0
        n = use_list->count;
1488
0
        p = &ctx->use_edges[use_list->refs + i];
1489
0
      }
1490
0
    }
1491
0
  }
1492
0
}
1493
1494
void ir_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val)
1495
0
{
1496
0
  ir_insn *insn = &ctx->ir_base[ref];
1497
0
  ir_ref old_val = ir_insn_op(insn, idx);
1498
1499
0
  IR_ASSERT(old_val != new_val);
1500
0
  if (new_val > 0) {
1501
0
    ir_use_list_add(ctx, new_val, ref);
1502
0
  }
1503
0
  ir_insn_set_op(insn, idx, new_val);
1504
0
  if (old_val > 0) {
1505
0
    ir_use_list_remove_one(ctx, old_val, ref);
1506
0
  }
1507
0
}
1508
1509
/* Helper Data Types */
1510
void ir_array_grow(ir_array *a, uint32_t size)
1511
0
{
1512
0
  IR_ASSERT(size > a->size);
1513
0
  if (size >= 256) {
1514
0
    size = IR_ALIGNED_SIZE(size, 256);
1515
0
  } else {
1516
    /* Use big enough power of 2 */
1517
0
    size -= 1;
1518
0
    size |= (size >> 1);
1519
0
    size |= (size >> 2);
1520
0
    size |= (size >> 4);
1521
//    size |= (size >> 8);
1522
//    size |= (size >> 16);
1523
0
    size += 1;
1524
0
  }
1525
0
  a->refs = ir_mem_realloc(a->refs, size * sizeof(ir_ref));
1526
0
  a->size = size;
1527
0
}
1528
1529
void ir_array_insert(ir_array *a, uint32_t i, ir_ref val)
1530
0
{
1531
0
  IR_ASSERT(i < a->size);
1532
0
  if (a->refs[a->size - 1]) {
1533
0
    ir_array_grow(a, a->size + 1);
1534
0
  }
1535
0
  memmove(a->refs + i + 1, a->refs + i, (a->size - i - 1) * sizeof(ir_ref));
1536
0
  a->refs[i] = val;
1537
0
}
1538
1539
void ir_array_remove(ir_array *a, uint32_t i)
1540
0
{
1541
0
  IR_ASSERT(i < a->size);
1542
0
  memmove(a->refs + i, a->refs + i + 1, (a->size - i - 1) * sizeof(ir_ref));
1543
0
  a->refs[a->size - 1] = IR_UNUSED;
1544
0
}
1545
1546
void ir_list_insert(ir_list *l, uint32_t i, ir_ref val)
1547
0
{
1548
0
  IR_ASSERT(i < l->len);
1549
0
  if (l->len >= l->a.size) {
1550
0
    ir_array_grow(&l->a, l->a.size + 1);
1551
0
  }
1552
0
  memmove(l->a.refs + i + 1, l->a.refs + i, (l->len - i) * sizeof(ir_ref));
1553
0
  l->a.refs[i] = val;
1554
0
  l->len++;
1555
0
}
1556
1557
void ir_list_remove(ir_list *l, uint32_t i)
1558
0
{
1559
0
  IR_ASSERT(i < l->len);
1560
0
  memmove(l->a.refs + i, l->a.refs + i + 1, (l->len - i) * sizeof(ir_ref));
1561
0
  l->len--;
1562
0
}
1563
1564
uint32_t ir_list_find(const ir_list *l, ir_ref val)
1565
0
{
1566
0
  uint32_t i;
1567
1568
0
  for (i = 0; i < l->len; i++) {
1569
0
    if (ir_array_at(&l->a, i) == val) {
1570
0
      return i;
1571
0
    }
1572
0
  }
1573
0
  return (uint32_t)-1;
1574
0
}
1575
1576
static uint32_t ir_hashtab_hash_size(uint32_t size)
1577
0
{
1578
0
  size -= 1;
1579
0
  size |= (size >> 1);
1580
0
  size |= (size >> 2);
1581
0
  size |= (size >> 4);
1582
0
  size |= (size >> 8);
1583
0
  size |= (size >> 16);
1584
0
  return IR_MAX(size + 1, 4);
1585
0
}
1586
1587
static void ir_hashtab_resize(ir_hashtab *tab)
1588
0
{
1589
0
  uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->mask);
1590
0
  char *old_data = tab->data;
1591
0
  uint32_t size = tab->size * 2;
1592
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1593
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_hashtab_bucket));
1594
0
  ir_hashtab_bucket *p;
1595
0
  uint32_t pos, i;
1596
1597
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1598
0
  tab->data = data + (hash_size * sizeof(uint32_t));
1599
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1600
0
  tab->size = size;
1601
1602
0
  memcpy(tab->data, old_data, tab->count * sizeof(ir_hashtab_bucket));
1603
0
  ir_mem_free(old_data - (old_hash_size * sizeof(uint32_t)));
1604
1605
0
  i = tab->count;
1606
0
  pos = 0;
1607
0
  p = (ir_hashtab_bucket*)tab->data;
1608
0
  do {
1609
0
    uint32_t key = p->key | tab->mask;
1610
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1611
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1612
0
    pos += sizeof(ir_hashtab_bucket);
1613
0
    p++;
1614
0
  } while (--i);
1615
0
}
1616
1617
void ir_hashtab_init(ir_hashtab *tab, uint32_t size)
1618
0
{
1619
0
  IR_ASSERT(size > 0);
1620
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1621
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_hashtab_bucket));
1622
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1623
0
  tab->data = (data + (hash_size * sizeof(uint32_t)));
1624
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1625
0
  tab->size = size;
1626
0
  tab->count = 0;
1627
0
  tab->pos = 0;
1628
0
}
1629
1630
void ir_hashtab_free(ir_hashtab *tab)
1631
0
{
1632
0
  uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask);
1633
0
  char *data = (char*)tab->data - (hash_size * sizeof(uint32_t));
1634
0
  ir_mem_free(data);
1635
0
  tab->data = NULL;
1636
0
}
1637
1638
ir_ref ir_hashtab_find(const ir_hashtab *tab, uint32_t key)
1639
0
{
1640
0
  const char *data = (const char*)tab->data;
1641
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1642
0
  ir_hashtab_bucket *p;
1643
1644
0
  while (pos != IR_INVALID_IDX) {
1645
0
    p = (ir_hashtab_bucket*)(data + pos);
1646
0
    if (p->key == key) {
1647
0
      return p->val;
1648
0
    }
1649
0
    pos = p->next;
1650
0
  }
1651
0
  return IR_INVALID_VAL;
1652
0
}
1653
1654
bool ir_hashtab_add(ir_hashtab *tab, uint32_t key, ir_ref val)
1655
0
{
1656
0
  char *data = (char*)tab->data;
1657
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1658
0
  ir_hashtab_bucket *p;
1659
1660
0
  while (pos != IR_INVALID_IDX) {
1661
0
    p = (ir_hashtab_bucket*)(data + pos);
1662
0
    if (p->key == key) {
1663
0
      return p->val == val;
1664
0
    }
1665
0
    pos = p->next;
1666
0
  }
1667
1668
0
  if (UNEXPECTED(tab->count >= tab->size)) {
1669
0
    ir_hashtab_resize(tab);
1670
0
    data = tab->data;
1671
0
  }
1672
1673
0
  pos = tab->pos;
1674
0
  tab->pos += sizeof(ir_hashtab_bucket);
1675
0
  tab->count++;
1676
0
  p = (ir_hashtab_bucket*)(data + pos);
1677
0
  p->key = key;
1678
0
  p->val = val;
1679
0
  key |= tab->mask;
1680
0
  p->next = ((uint32_t*)data)[(int32_t)key];
1681
0
  ((uint32_t*)data)[(int32_t)key] = pos;
1682
0
  return 1;
1683
0
}
1684
1685
static int ir_hashtab_key_cmp(const void *b1, const void *b2)
1686
0
{
1687
0
  return ((ir_hashtab_bucket*)b1)->key - ((ir_hashtab_bucket*)b2)->key;
1688
0
}
1689
1690
void ir_hashtab_key_sort(ir_hashtab *tab)
1691
0
{
1692
0
  ir_hashtab_bucket *p;
1693
0
  uint32_t hash_size, pos, i;
1694
1695
0
  if (!tab->count) {
1696
0
    return;
1697
0
  }
1698
1699
0
  qsort(tab->data, tab->count, sizeof(ir_hashtab_bucket), ir_hashtab_key_cmp);
1700
1701
0
  hash_size = ir_hashtab_hash_size(tab->size);
1702
0
  memset((char*)tab->data - (hash_size * sizeof(uint32_t)), -1, hash_size * sizeof(uint32_t));
1703
1704
0
  i = tab->count;
1705
0
  pos = 0;
1706
0
  p = (ir_hashtab_bucket*)tab->data;
1707
0
  do {
1708
0
    uint32_t key = p->key | tab->mask;
1709
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1710
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1711
0
    pos += sizeof(ir_hashtab_bucket);
1712
0
    p++;
1713
0
  } while (--i);
1714
0
}
1715
1716
static void ir_addrtab_resize(ir_hashtab *tab)
1717
0
{
1718
0
  uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->mask);
1719
0
  char *old_data = tab->data;
1720
0
  uint32_t size = tab->size * 2;
1721
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1722
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
1723
0
  ir_addrtab_bucket *p;
1724
0
  uint32_t pos, i;
1725
1726
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1727
0
  tab->data = data + (hash_size * sizeof(uint32_t));
1728
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1729
0
  tab->size = size;
1730
1731
0
  memcpy(tab->data, old_data, tab->count * sizeof(ir_addrtab_bucket));
1732
0
  ir_mem_free(old_data - (old_hash_size * sizeof(uint32_t)));
1733
1734
0
  i = tab->count;
1735
0
  pos = 0;
1736
0
  p = (ir_addrtab_bucket*)tab->data;
1737
0
  do {
1738
0
    uint32_t key = (uint32_t)p->key | tab->mask;
1739
0
    p->next = ((uint32_t*)tab->data)[(int32_t)key];
1740
0
    ((uint32_t*)tab->data)[(int32_t)key] = pos;
1741
0
    pos += sizeof(ir_addrtab_bucket);
1742
0
    p++;
1743
0
  } while (--i);
1744
0
}
1745
1746
void ir_addrtab_init(ir_hashtab *tab, uint32_t size)
1747
0
{
1748
0
  IR_ASSERT(size > 0);
1749
0
  uint32_t hash_size = ir_hashtab_hash_size(size);
1750
0
  char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
1751
0
  memset(data, -1, hash_size * sizeof(uint32_t));
1752
0
  tab->data = (data + (hash_size * sizeof(uint32_t)));
1753
0
  tab->mask = (uint32_t)(-(int32_t)hash_size);
1754
0
  tab->size = size;
1755
0
  tab->count = 0;
1756
0
  tab->pos = 0;
1757
0
}
1758
1759
void ir_addrtab_free(ir_hashtab *tab)
1760
0
{
1761
0
  uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask);
1762
0
  char *data = (char*)tab->data - (hash_size * sizeof(uint32_t));
1763
0
  ir_mem_free(data);
1764
0
  tab->data = NULL;
1765
0
}
1766
1767
ir_ref ir_addrtab_find(const ir_hashtab *tab, uint64_t key)
1768
0
{
1769
0
  const char *data = (const char*)tab->data;
1770
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1771
0
  ir_addrtab_bucket *p;
1772
1773
0
  while (pos != IR_INVALID_IDX) {
1774
0
    p = (ir_addrtab_bucket*)(data + pos);
1775
0
    if (p->key == key) {
1776
0
      return p->val;
1777
0
    }
1778
0
    pos = p->next;
1779
0
  }
1780
0
  return IR_INVALID_VAL;
1781
0
}
1782
1783
void ir_addrtab_set(ir_hashtab *tab, uint64_t key, ir_ref val)
1784
0
{
1785
0
  char *data = (char*)tab->data;
1786
0
  uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
1787
0
  ir_addrtab_bucket *p;
1788
1789
0
  while (pos != IR_INVALID_IDX) {
1790
0
    p = (ir_addrtab_bucket*)(data + pos);
1791
0
    if (p->key == key) {
1792
0
      p->val = val;
1793
0
      return;
1794
0
    }
1795
0
    pos = p->next;
1796
0
  }
1797
1798
0
  if (UNEXPECTED(tab->count >= tab->size)) {
1799
0
    ir_addrtab_resize(tab);
1800
0
    data = tab->data;
1801
0
  }
1802
1803
0
  pos = tab->pos;
1804
0
  tab->pos += sizeof(ir_addrtab_bucket);
1805
0
  tab->count++;
1806
0
  p = (ir_addrtab_bucket*)(data + pos);
1807
0
  p->key = key;
1808
0
  p->val = val;
1809
0
  key |= tab->mask;
1810
0
  p->next = ((uint32_t*)data)[(int32_t)key];
1811
0
  ((uint32_t*)data)[(int32_t)key] = pos;
1812
0
}
1813
1814
/* Memory API */
1815
#ifdef _WIN32
1816
void *ir_mem_mmap(size_t size)
1817
{
1818
  void *ret;
1819
1820
#ifdef _M_X64
1821
  DWORD size_hi = size >> 32, size_lo = size & 0xffffffff;
1822
#else
1823
  DWORD size_hi = 0, size_lo = size;
1824
#endif
1825
1826
  HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, size_hi, size_lo, NULL);
1827
1828
  ret = MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE, 0, 0, size);
1829
  if (!ret) {
1830
    CloseHandle(h);
1831
  }
1832
1833
  return ret;
1834
}
1835
1836
int ir_mem_unmap(void *ptr, size_t size)
1837
{
1838
  /* XXX file handle is leaked. */
1839
  UnmapViewOfFile(ptr);
1840
  return 1;
1841
}
1842
1843
int ir_mem_protect(void *ptr, size_t size)
1844
{
1845
  return 1;
1846
}
1847
1848
int ir_mem_unprotect(void *ptr, size_t size)
1849
{
1850
  return 1;
1851
}
1852
1853
int ir_mem_flush(void *ptr, size_t size)
1854
{
1855
  return 1;
1856
}
1857
#else
1858
1859
#if defined(__linux__) && defined(__x86_64__) && defined(PKEY_DISABLE_WRITE)
1860
# define HAVE_PKEY_MPROTECT 1
1861
#endif
1862
1863
#ifdef HAVE_PKEY_MPROTECT
1864
1865
#ifndef PKEY_DISABLE_EXECUTE
1866
0
# define PKEY_DISABLE_EXECUTE 0
1867
#endif
1868
1869
int pkey_mprotect(void* addr, size_t len, int prot, int pkey) __attribute__((weak));
1870
int pkey_alloc(unsigned int, unsigned int) __attribute__((weak));
1871
int pkey_free(int) __attribute__((weak));
1872
int pkey_set(int, unsigned) __attribute__((weak));
1873
1874
static int ir_pkey = 0;
1875
#endif
1876
1877
void *ir_mem_mmap(size_t size)
1878
0
{
1879
0
#ifdef HAVE_PKEY_MPROTECT
1880
0
  if (!ir_pkey && pkey_mprotect) {
1881
0
    int key = pkey_alloc(0, PKEY_DISABLE_WRITE);
1882
0
    if (key > 0) {
1883
0
      ir_pkey = key;
1884
0
    }
1885
0
  }
1886
0
  if (ir_pkey > 0) {
1887
0
    void *ret = mmap(NULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1888
0
    if (ret == MAP_FAILED) {
1889
0
      return NULL;
1890
0
    }
1891
0
    if (pkey_mprotect(ret, size, PROT_EXEC|PROT_READ|PROT_WRITE, ir_pkey) != 0) {
1892
0
#ifdef IR_DEBUG
1893
0
      fprintf(stderr, "pkey_mprotect() failed\n");
1894
0
#endif
1895
0
      munmap(ret, size);
1896
0
      return NULL;
1897
0
    }
1898
0
    return ret;
1899
0
  }
1900
0
#endif
1901
0
  int prot_flags = PROT_EXEC;
1902
#if defined(__NetBSD__)
1903
  prot_flags |= PROT_MPROTECT(PROT_READ|PROT_WRITE);
1904
#endif
1905
0
  void *ret = mmap(NULL, size, prot_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1906
0
  if (ret == MAP_FAILED) {
1907
0
    ret = NULL;
1908
0
  }
1909
0
  return ret;
1910
0
}
1911
1912
int ir_mem_unmap(void *ptr, size_t size)
1913
0
{
1914
0
  munmap(ptr, size);
1915
0
#ifdef HAVE_PKEY_MPROTECT
1916
//  if (ir_pkey > 0) {
1917
//    pkey_free(ir_pkey);
1918
//    ir_pkey = 0;
1919
//  }
1920
0
#endif
1921
0
  return 1;
1922
0
}
1923
1924
int ir_mem_protect(void *ptr, size_t size)
1925
0
{
1926
0
#ifdef HAVE_PKEY_MPROTECT
1927
0
  if (ir_pkey > 0) {
1928
0
    if (pkey_set(ir_pkey, PKEY_DISABLE_WRITE)) {
1929
0
#ifdef IR_DEBUG
1930
0
      fprintf(stderr, "mprotect() failed\n");
1931
0
#endif
1932
0
      return 0;
1933
0
    }
1934
0
    return 1;
1935
0
  }
1936
0
#endif
1937
0
  if (mprotect(ptr, size, PROT_READ | PROT_EXEC) != 0) {
1938
0
#ifdef IR_DEBUG
1939
0
    fprintf(stderr, "mprotect() failed\n");
1940
0
#endif
1941
0
    return 0;
1942
0
  }
1943
0
  return 1;
1944
0
}
1945
1946
int ir_mem_unprotect(void *ptr, size_t size)
1947
0
{
1948
0
#ifdef HAVE_PKEY_MPROTECT
1949
0
  if (ir_pkey > 0) {
1950
0
    if (pkey_set(ir_pkey, PKEY_DISABLE_EXECUTE)) {
1951
0
#ifdef IR_DEBUG
1952
0
      fprintf(stderr, "mprotect() failed\n");
1953
0
#endif
1954
0
      return 0;
1955
0
    }
1956
0
    return 1;
1957
0
  }
1958
0
#endif
1959
0
  if (mprotect(ptr, size, PROT_READ | PROT_WRITE) != 0) {
1960
0
#ifdef IR_DEBUG
1961
0
    fprintf(stderr, "mprotect() failed\n");
1962
0
#endif
1963
0
    return 0;
1964
0
  }
1965
0
  return 1;
1966
0
}
1967
1968
int ir_mem_flush(void *ptr, size_t size)
1969
0
{
1970
0
#if ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4003) || __has_builtin(__builtin___clear_cache))
1971
0
  __builtin___clear_cache((char*)(ptr), (char*)(ptr) + size);
1972
0
#endif
1973
#if defined(__APPLE__) && defined(__aarch64__)
1974
  sys_icache_invalidate(ptr, size);
1975
#endif
1976
#ifdef HAVE_VALGRIND
1977
  VALGRIND_DISCARD_TRANSLATIONS(ptr, size);
1978
#endif
1979
0
  return 1;
1980
0
}
1981
#endif
1982
1983
/* Alias Analyses */
1984
typedef enum _ir_alias {
1985
  IR_MAY_ALIAS  = -1,
1986
  IR_NO_ALIAS   =  0,
1987
  IR_MUST_ALIAS =  1,
1988
} ir_alias;
1989
1990
#if 0
1991
static ir_alias ir_check_aliasing(ir_ctx *ctx, ir_ref addr1, ir_ref addr2)
1992
{
1993
  ir_insn *insn1, *insn2;
1994
1995
  if (addr1 == addr2) {
1996
    return IR_MUST_ALIAS;
1997
  }
1998
1999
  insn1 = &ctx->ir_base[addr1];
2000
  insn2 = &ctx->ir_base[addr2];
2001
  if (insn1->op == IR_ADD && IR_IS_CONST_REF(insn1->op2)) {
2002
    if (insn1->op1 == addr2) {
2003
      uintptr_t offset1 = ctx->ir_base[insn1->op2].val.u64;
2004
      return (offset1 != 0) ? IR_MUST_ALIAS : IR_NO_ALIAS;
2005
    } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn1->op2) && insn1->op1 == insn2->op1) {
2006
      if (insn1->op2 == insn2->op2) {
2007
        return IR_MUST_ALIAS;
2008
      } else if (IR_IS_CONST_REF(insn1->op2) && IR_IS_CONST_REF(insn2->op2)) {
2009
        uintptr_t offset1 = ctx->ir_base[insn1->op2].val.u64;
2010
        uintptr_t offset2 = ctx->ir_base[insn2->op2].val.u64;
2011
2012
        return (offset1 == offset2) ? IR_MUST_ALIAS : IR_NO_ALIAS;
2013
      }
2014
    }
2015
  } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn2->op2)) {
2016
    if (insn2->op1 == addr1) {
2017
      uintptr_t offset2 = ctx->ir_base[insn2->op2].val.u64;
2018
2019
      return (offset2 != 0) ? IR_MUST_ALIAS : IR_NO_ALIAS;
2020
    }
2021
  }
2022
  return IR_MAY_ALIAS;
2023
}
2024
#endif
2025
2026
ir_alias ir_check_partial_aliasing(const ir_ctx *ctx, ir_ref addr1, ir_ref addr2, ir_type type1, ir_type type2)
2027
0
{
2028
0
  ir_insn *insn1, *insn2;
2029
0
  ir_ref base1, base2, off1, off2;
2030
2031
  /* this must be already check */
2032
0
  IR_ASSERT(addr1 != addr2);
2033
2034
0
  insn1 = &ctx->ir_base[addr1];
2035
0
  insn2 = &ctx->ir_base[addr2];
2036
0
  if (insn1->op != IR_ADD) {
2037
0
    base1 = addr1;
2038
0
    off1 = IR_UNUSED;
2039
0
  } else if (ctx->ir_base[insn1->op2].op == IR_SYM
2040
0
      || ctx->ir_base[insn1->op2].op == IR_ALLOCA
2041
0
      || ctx->ir_base[insn1->op2].op == IR_VADDR) {
2042
0
    base1 = insn1->op2;
2043
0
    off1 = insn1->op1;
2044
0
  } else {
2045
0
    base1 = insn1->op1;
2046
0
    off1 = insn1->op2;
2047
0
  }
2048
0
  if (insn2->op != IR_ADD) {
2049
0
    base2 = addr2;
2050
0
    off2 = IR_UNUSED;
2051
0
  } else if (ctx->ir_base[insn2->op2].op == IR_SYM
2052
0
      || ctx->ir_base[insn2->op2].op == IR_ALLOCA
2053
0
      || ctx->ir_base[insn2->op2].op == IR_VADDR) {
2054
0
    base2 = insn2->op2;
2055
0
    off2 = insn2->op1;
2056
0
  } else {
2057
0
    base2 = insn2->op1;
2058
0
    off2 = insn2->op2;
2059
0
  }
2060
0
  if (base1 == base2) {
2061
0
    uintptr_t offset1, offset2;
2062
2063
0
    if (!off1) {
2064
0
      offset1 = 0;
2065
0
    } else if (IR_IS_CONST_REF(off1) && !IR_IS_SYM_CONST(ctx->ir_base[off1].op)) {
2066
0
      offset1 = ctx->ir_base[off1].val.addr;
2067
0
    } else {
2068
0
      return IR_MAY_ALIAS;
2069
0
    }
2070
0
    if (!off2) {
2071
0
      offset2 = 0;
2072
0
    } else if (IR_IS_CONST_REF(off2) && !IR_IS_SYM_CONST(ctx->ir_base[off2].op)) {
2073
0
      offset2 = ctx->ir_base[off2].val.addr;
2074
0
    } else {
2075
0
      return IR_MAY_ALIAS;
2076
0
    }
2077
0
    if (offset1 == offset2) {
2078
0
      return IR_MUST_ALIAS;
2079
0
    } else if (offset1 < offset2) {
2080
0
      return offset1 + ir_type_size[type1] <= offset2 ? IR_NO_ALIAS : IR_MUST_ALIAS;
2081
0
    } else {
2082
0
      return offset2 + ir_type_size[type2] <= offset1 ? IR_NO_ALIAS : IR_MUST_ALIAS;
2083
0
    }
2084
0
  } else {
2085
0
    insn1 = &ctx->ir_base[base1];
2086
0
    insn2 = &ctx->ir_base[base2];
2087
0
    while (insn1->op == IR_ADD) {
2088
0
      insn1 = &ctx->ir_base[insn1->op2];
2089
0
      if (insn1->op == IR_SYM
2090
0
       || insn1->op == IR_ALLOCA
2091
0
       || insn1->op == IR_VADDR) {
2092
0
        break;
2093
0
      } else {
2094
0
        insn1 = &ctx->ir_base[insn1->op1];
2095
0
      }
2096
0
    }
2097
0
    while (insn2->op == IR_ADD) {
2098
0
      insn2 = &ctx->ir_base[insn2->op2];
2099
0
      if (insn2->op == IR_SYM
2100
0
       || insn2->op == IR_ALLOCA
2101
0
       || insn2->op == IR_VADDR) {
2102
0
        break;
2103
0
      } else {
2104
0
        insn2 = &ctx->ir_base[insn2->op1];
2105
0
      }
2106
0
    }
2107
0
    if (insn1 == insn2) {
2108
0
      return IR_MAY_ALIAS;
2109
0
    }
2110
0
    if ((insn1->op == IR_ALLOCA && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2111
0
     || (insn1->op == IR_VADDR && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2112
0
     || (insn1->op == IR_SYM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM))
2113
0
     || (insn1->op == IR_PARAM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR))) {
2114
0
      return IR_NO_ALIAS;
2115
0
    }
2116
0
  }
2117
0
  return IR_MAY_ALIAS;
2118
0
}
2119
2120
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr, ir_ref limit)
2121
0
{
2122
0
  ir_insn *insn;
2123
0
  uint32_t modified_regset = 0;
2124
2125
0
  while (ref > limit) {
2126
0
    insn = &ctx->ir_base[ref];
2127
0
    if (insn->op == IR_LOAD) {
2128
0
      if (insn->op2 == addr) {
2129
0
        if (insn->type == type) {
2130
0
          return ref; /* load forwarding (L2L) */
2131
0
        } else if (ir_type_size[insn->type] == ir_type_size[type]) {
2132
0
          return ref; /* load forwarding with bitcast (L2L) */
2133
0
        } else if (ir_type_size[insn->type] > ir_type_size[type]
2134
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(insn->type)) {
2135
0
          return ref; /* partial load forwarding (L2L) */
2136
0
        }
2137
0
      }
2138
0
    } else if (insn->op == IR_STORE) {
2139
0
      ir_type type2 = ctx->ir_base[insn->op3].type;
2140
2141
0
      if (insn->op2 == addr) {
2142
0
        if (ctx->ir_base[insn->op3].op == IR_RLOAD
2143
0
         && (modified_regset & (1 << ctx->ir_base[insn->op3].op2))) {
2144
          /* anti-dependency */
2145
0
          return IR_UNUSED;
2146
0
        } else if (type2 == type) {
2147
0
          return insn->op3; /* store forwarding (S2L) */
2148
0
        } else if (ir_type_size[type2] == ir_type_size[type]) {
2149
0
          return insn->op3; /* store forwarding with bitcast (S2L) */
2150
0
        } else if (ir_type_size[type2] > ir_type_size[type]
2151
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(type2)) {
2152
0
          return insn->op3; /* partial store forwarding (S2L) */
2153
0
        } else {
2154
0
          return IR_UNUSED;
2155
0
        }
2156
0
      } else if (ir_check_partial_aliasing(ctx, addr, insn->op2, type, type2) != IR_NO_ALIAS) {
2157
0
        return IR_UNUSED;
2158
0
      }
2159
0
    } else if (insn->op == IR_RSTORE) {
2160
0
      modified_regset |= (1 << insn->op3);
2161
0
    } else if (insn->op == IR_CALL) {
2162
0
      ir_insn *func = &ctx->ir_base[insn->op2];
2163
0
      ir_ref func_proto;
2164
0
      const ir_proto_t *proto;
2165
2166
0
      if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2167
0
        func_proto = func->proto;
2168
0
      } else if (func->op == IR_PROTO) {
2169
0
        func_proto = func->op2;
2170
0
      } else {
2171
0
        break;
2172
0
      }
2173
0
      if (!func_proto) {
2174
0
        break;
2175
0
      }
2176
0
      proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2177
0
      if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2178
0
        break;
2179
0
      }
2180
0
    } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_VSTORE) {
2181
0
      return IR_UNUSED;
2182
0
    }
2183
0
    ref = insn->op1;
2184
0
  }
2185
2186
0
  return IR_UNUSED;
2187
0
}
2188
2189
ir_ref ir_find_aliasing_load(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr)
2190
0
{
2191
0
  return ir_find_aliasing_load_i(ctx, ref, type, addr, (addr > 0 && addr < ref) ? addr : 1);
2192
0
}
2193
2194
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
2195
0
{
2196
0
  ir_insn *insn;
2197
2198
0
  while (ref > var) {
2199
0
    insn = &ctx->ir_base[ref];
2200
0
    if (insn->op == IR_VLOAD) {
2201
0
      if (insn->op2 == var) {
2202
0
        if (insn->type == type) {
2203
0
          return ref; /* load forwarding (L2L) */
2204
0
        } else if (ir_type_size[insn->type] == ir_type_size[type]) {
2205
0
          return ref; /* load forwarding with bitcast (L2L) */
2206
0
        } else if (ir_type_size[insn->type] > ir_type_size[type]
2207
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(insn->type)) {
2208
0
          return ref; /* partial load forwarding (L2L) */
2209
0
        }
2210
0
      }
2211
0
    } else if (insn->op == IR_VSTORE) {
2212
0
      ir_type type2 = ctx->ir_base[insn->op3].type;
2213
2214
0
      if (insn->op2 == var) {
2215
0
        if (type2 == type) {
2216
0
          return insn->op3; /* store forwarding (S2L) */
2217
0
        } else if (ir_type_size[type2] == ir_type_size[type]) {
2218
0
          return insn->op3; /* store forwarding with bitcast (S2L) */
2219
0
        } else if (ir_type_size[type2] > ir_type_size[type]
2220
0
            && IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(type2)) {
2221
0
          return insn->op3; /* partial store forwarding (S2L) */
2222
0
        } else {
2223
0
          break;
2224
0
        }
2225
0
      }
2226
0
    } else if (insn->op == IR_CALL) {
2227
0
      ir_insn *func = &ctx->ir_base[insn->op2];
2228
0
      ir_ref func_proto;
2229
0
      const ir_proto_t *proto;
2230
2231
0
      if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2232
0
        func_proto = func->proto;
2233
0
      } else if (func->op == IR_PROTO) {
2234
0
        func_proto = func->op2;
2235
0
      } else {
2236
0
        break;
2237
0
      }
2238
0
      if (!func_proto) {
2239
0
        break;
2240
0
      }
2241
0
      proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2242
0
      if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2243
0
        break;
2244
0
      }
2245
0
    } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_STORE) {
2246
0
      break;
2247
0
    }
2248
0
    ref = insn->op1;
2249
0
  }
2250
2251
0
  return IR_UNUSED;
2252
0
}
2253
2254
ir_ref ir_find_aliasing_vload(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
2255
0
{
2256
0
  return ir_find_aliasing_vload_i(ctx, ref, type, var);
2257
0
}
2258
2259
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_store_i(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val, ir_ref limit)
2260
0
{
2261
0
  ir_ref next = IR_UNUSED;
2262
0
  ir_insn *insn;
2263
0
  ir_type type = ctx->ir_base[val].type;
2264
0
  ir_type type2;
2265
0
  bool guarded = 0;
2266
2267
//  if (!IR_IS_CONST_REF(val)) {
2268
//    insn = &ctx->ir_base[val];
2269
//    if (insn->op == IR_BITCAST
2270
//     && !IR_IS_CONST_REF(insn->op1)
2271
//     && ir_type_size[insn->type] == ir_type_size[ctx->ir_base[insn->op1].type]) {
2272
//      /* skip BITCAST */
2273
//      val = insn->op1;
2274
//    }
2275
//  }
2276
2277
0
  while (ref > limit) {
2278
0
    insn = &ctx->ir_base[ref];
2279
0
    if (insn->op == IR_STORE) {
2280
0
      if (insn->op2 == addr) {
2281
0
        if (ctx->ir_base[insn->op3].type == type) {
2282
0
          if (insn->op3 == val) {
2283
            /* dead STORE (store the same value once again) */
2284
0
            return ref;
2285
0
          } else {
2286
0
            if (!guarded) {
2287
              /* the previous STORE is dead (there are no LOADs) */
2288
0
              if (!ctx->use_lists) {
2289
0
                if (next) {
2290
0
                  ctx->ir_base[next].op1 = insn->op1;
2291
0
                } else {
2292
0
                  ctx->control = insn->op1;
2293
0
                }
2294
0
              } else {
2295
0
                ir_ref prev = insn->op1;
2296
2297
0
                if (!next) {
2298
0
                  IR_ASSERT(ctx->use_lists[ref].count == 1);
2299
0
                  next = ctx->use_edges[ctx->use_lists[ref].refs];
2300
0
                }
2301
0
                ctx->ir_base[next].op1 = prev;
2302
0
                ir_use_list_remove_one(ctx, ref, next);
2303
0
                ir_use_list_replace_one(ctx, prev, ref, next);
2304
0
                if (!IR_IS_CONST_REF(insn->op2)) {
2305
0
                  ir_use_list_remove_one(ctx, insn->op2, ref);
2306
0
                }
2307
0
                if (!IR_IS_CONST_REF(insn->op3)) {
2308
0
                  ir_use_list_remove_one(ctx, insn->op3, ref);
2309
0
                }
2310
0
                insn->op1 = IR_UNUSED;
2311
0
              }
2312
0
              MAKE_NOP(insn);
2313
0
            }
2314
0
            break;
2315
0
          }
2316
0
        } else {
2317
0
          break;
2318
0
        }
2319
0
      } else {
2320
0
        type2 = ctx->ir_base[insn->op3].type;
2321
0
        goto check_aliasing;
2322
0
      }
2323
0
    } else if (insn->op == IR_LOAD) {
2324
0
      if (insn->op2 == addr) {
2325
0
        if (ref == val) {
2326
          /* dead STORE (store the value that was loaded before) */
2327
0
          return ref;
2328
0
        }
2329
0
        break;
2330
0
      }
2331
0
      type2 = insn->type;
2332
0
check_aliasing:
2333
0
      if (ir_check_partial_aliasing(ctx, addr, insn->op2, type, type2) != IR_NO_ALIAS) {
2334
0
        break;
2335
0
      }
2336
0
    } else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2337
0
      guarded = 1;
2338
0
    } else if (insn->op >= IR_START || insn->op == IR_CALL) {
2339
0
      break;
2340
0
    }
2341
0
    next = ref;
2342
0
    ref = insn->op1;
2343
0
  }
2344
2345
0
  return IR_UNUSED;
2346
0
}
2347
2348
ir_ref ir_find_aliasing_store(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val)
2349
0
{
2350
0
  return ir_find_aliasing_store_i(ctx, ref, addr, val, (addr > 0 && addr < ref) ? addr : 1);
2351
0
}
2352
2353
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vstore_i(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
2354
0
{
2355
0
  ir_ref limit = var;
2356
0
  ir_ref next = IR_UNUSED;
2357
0
  ir_insn *insn;
2358
0
  bool guarded = 0;
2359
2360
//  if (!IR_IS_CONST_REF(val)) {
2361
//    insn = &ctx->ir_base[val];
2362
//    if (insn->op == IR_BITCAST
2363
//     && !IR_IS_CONST_REF(insn->op1)
2364
//     && ir_type_size[insn->type] == ir_type_size[ctx->ir_base[insn->op1].type]) {
2365
//      /* skip BITCAST */
2366
//      val = insn->op1;
2367
//    }
2368
//  }
2369
2370
0
  while (ref > limit) {
2371
0
    insn = &ctx->ir_base[ref];
2372
0
    if (insn->op == IR_VSTORE) {
2373
0
      if (insn->op2 == var) {
2374
0
        if (insn->op3 == val) {
2375
          /* dead VSTORE */
2376
0
          return ref;
2377
0
        } else {
2378
0
          if (!guarded) {
2379
            /* the previous VSTORE is dead (there are no VLOADs) */
2380
0
            if (!ctx->use_lists) {
2381
0
              if (next) {
2382
0
                ctx->ir_base[next].op1 = insn->op1;
2383
0
              } else {
2384
0
                ctx->control = insn->op1;
2385
0
              }
2386
0
            } else {
2387
0
              ir_ref prev = insn->op1;
2388
2389
0
              if (!next) {
2390
0
                IR_ASSERT(ctx->use_lists[ref].count == 1);
2391
0
                next = ctx->use_edges[ctx->use_lists[ref].refs];
2392
0
              }
2393
0
              ctx->ir_base[next].op1 = prev;
2394
0
              ir_use_list_remove_one(ctx, ref, next);
2395
0
              ir_use_list_replace_one(ctx, prev, ref, next);
2396
0
              if (!IR_IS_CONST_REF(insn->op2)) {
2397
0
                ir_use_list_remove_one(ctx, insn->op2, ref);
2398
0
              }
2399
0
              if (!IR_IS_CONST_REF(insn->op3)) {
2400
0
                ir_use_list_remove_one(ctx, insn->op3, ref);
2401
0
              }
2402
0
              insn->op1 = IR_UNUSED;
2403
0
            }
2404
0
            MAKE_NOP(insn);
2405
0
          }
2406
0
          break;
2407
0
        }
2408
0
      }
2409
0
    } else if (insn->op == IR_VLOAD) {
2410
0
      if (insn->op2 == var) {
2411
0
        if (ref == val) {
2412
          /* dead VSTORE */
2413
0
          return ref;
2414
0
        }
2415
0
        break;
2416
0
      }
2417
0
    } else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2418
0
      guarded = 1;
2419
0
    } else if (insn->op >= IR_START || insn->op == IR_CALL || insn->op == IR_LOAD || insn->op == IR_STORE) {
2420
0
      break;
2421
0
    }
2422
0
    next = ref;
2423
0
    ref = insn->op1;
2424
0
  }
2425
0
  return IR_UNUSED;
2426
0
}
2427
2428
ir_ref ir_find_aliasing_vstore(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
2429
0
{
2430
0
  return ir_find_aliasing_vstore_i(ctx, ref, var, val);
2431
0
}
2432
2433
/* IR Construction API */
2434
2435
ir_ref _ir_PARAM(ir_ctx *ctx, ir_type type, const char* name, ir_ref num)
2436
0
{
2437
0
  IR_ASSERT(ctx->control);
2438
0
  IR_ASSERT(ctx->ir_base[ctx->control].op == IR_START);
2439
0
  IR_ASSERT(ctx->insns_count == num + 1);
2440
0
  return ir_param(ctx, type, ctx->control, name, num);
2441
0
}
2442
2443
ir_ref _ir_VAR(ir_ctx *ctx, ir_type type, const char* name)
2444
0
{
2445
//  IR_ASSERT(ctx->control);
2446
//  IR_ASSERT(IR_IS_BB_START(ctx->ir_base[ctx->control].op));
2447
//  TODO: VAR may be insterted after some "memory" instruction
2448
0
  ir_ref ref = ctx->control;
2449
2450
0
  while (1) {
2451
0
    IR_ASSERT(ref);
2452
0
    if (IR_IS_BB_START(ctx->ir_base[ref].op)) {
2453
0
      break;
2454
0
    }
2455
0
    ref = ctx->ir_base[ref].op1;
2456
0
  }
2457
0
  return ir_var(ctx, type, ref, name);
2458
0
}
2459
2460
ir_ref _ir_PHI_2(ir_ctx *ctx, ir_type type, ir_ref src1, ir_ref src2)
2461
0
{
2462
0
  IR_ASSERT(ctx->control);
2463
0
  IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
2464
0
  if (src1 == src2 && src1 != IR_UNUSED) {
2465
0
    return src1;
2466
0
  }
2467
0
  return ir_emit3(ctx, IR_OPTX(IR_PHI, type, 3), ctx->control, src1, src2);
2468
0
}
2469
2470
ir_ref _ir_PHI_N(ir_ctx *ctx, ir_type type, ir_ref n, ir_ref *inputs)
2471
0
{
2472
0
  IR_ASSERT(ctx->control);
2473
0
  IR_ASSERT(n > 0);
2474
0
  if (n == 1) {
2475
0
    return inputs[0];
2476
0
  } else {
2477
0
      ir_ref i;
2478
0
    ir_ref ref;
2479
2480
0
    if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
2481
0
      IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE
2482
0
        || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
2483
0
      ref = inputs[0];
2484
0
      if (ref != IR_UNUSED) {
2485
0
        for (i = 1; i < n; i++) {
2486
0
          if (inputs[i] != ref) {
2487
0
            break;
2488
0
          }
2489
0
        }
2490
0
        if (i == n) {
2491
          /* all the same */
2492
0
          return ref;
2493
0
        }
2494
0
      }
2495
0
    }
2496
2497
0
    ref = ir_emit_N(ctx, IR_OPT(IR_PHI, type), n + 1);
2498
0
    ir_set_op(ctx, ref, 1, ctx->control);
2499
0
    for (i = 0; i < n; i++) {
2500
0
      ir_set_op(ctx, ref, i + 2, inputs[i]);
2501
0
    }
2502
0
    return ref;
2503
0
  }
2504
0
}
2505
2506
void _ir_PHI_SET_OP(ir_ctx *ctx, ir_ref phi, ir_ref pos, ir_ref src)
2507
0
{
2508
0
  ir_insn *insn = &ctx->ir_base[phi];
2509
0
  ir_ref *ops = insn->ops;
2510
2511
0
  IR_ASSERT(insn->op == IR_PHI);
2512
0
  IR_ASSERT(ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN);
2513
0
  IR_ASSERT(pos > 0 && pos < insn->inputs_count);
2514
0
  pos++; /* op1 is used for control */
2515
0
  ops[pos] = src;
2516
0
}
2517
2518
void _ir_START(ir_ctx *ctx)
2519
0
{
2520
0
  IR_ASSERT(!ctx->control);
2521
0
  IR_ASSERT(ctx->insns_count == 1);
2522
0
  ctx->control = ir_emit0(ctx, IR_START);
2523
0
}
2524
2525
void _ir_ENTRY(ir_ctx *ctx, ir_ref src, ir_ref num)
2526
0
{
2527
0
  IR_ASSERT(!ctx->control);
2528
  /* fake control edge */
2529
0
  IR_ASSERT((ir_op_flags[ctx->ir_base[src].op] & IR_OP_FLAG_TERMINATOR)
2530
0
    || ctx->ir_base[src].op == IR_END
2531
0
    || ctx->ir_base[src].op == IR_LOOP_END); /* return from a recursive call */
2532
0
  ctx->control = ir_emit2(ctx, IR_ENTRY, src, num);
2533
0
}
2534
2535
void _ir_BEGIN(ir_ctx *ctx, ir_ref src)
2536
0
{
2537
0
  IR_ASSERT(!ctx->control);
2538
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)
2539
0
   && src
2540
0
   && src + 1 == ctx->insns_count
2541
0
   && ctx->ir_base[src].op == IR_END) {
2542
    /* merge with the last END */
2543
0
    ctx->control = ctx->ir_base[src].op1;
2544
0
    ctx->insns_count--;
2545
0
  } else {
2546
0
    ctx->control = ir_emit1(ctx, IR_BEGIN, src);
2547
0
  }
2548
0
}
2549
2550
static ir_ref _ir_fold_condition(ir_ctx *ctx, ir_ref ref)
2551
0
{
2552
0
  ir_insn *insn = &ctx->ir_base[ref];
2553
2554
0
  if (insn->op == IR_NE && IR_IS_CONST_REF(insn->op2)) {
2555
0
    ir_insn *op2_insn = &ctx->ir_base[insn->op2];
2556
2557
0
    if (IR_IS_TYPE_INT(op2_insn->type) && op2_insn->val.u64 == 0) {
2558
0
      ref = insn->op1;
2559
0
      insn = &ctx->ir_base[ref];
2560
0
      if (insn->op == IR_ALLOCA || insn->op == IR_VADDR) {
2561
0
        return IR_TRUE;
2562
0
      }
2563
0
    }
2564
0
  } else if (insn->op == IR_EQ && insn->op2 == IR_TRUE) {
2565
0
    ref = insn->op1;
2566
0
    insn = &ctx->ir_base[ref];
2567
0
  } else if (insn->op == IR_EQ && insn->op2 == IR_NULL) {
2568
0
    ir_insn *op1_insn = &ctx->ir_base[insn->op1];
2569
0
    if (op1_insn->op == IR_ALLOCA || op1_insn->op == IR_VADDR) {
2570
0
      return IR_FALSE;
2571
0
    }
2572
0
  }
2573
//  while (insn->op == IR_SEXT || insn->op == IR_ZEXT || insn->op == IR_BITCAST) {
2574
//    ref = insn->op1;
2575
//    insn = &ctx->ir_base[ref];
2576
//  }
2577
0
  return ref;
2578
0
}
2579
2580
IR_ALWAYS_INLINE ir_ref ir_check_dominating_predicates_i(ir_ctx *ctx, ir_ref ref, ir_ref condition, ir_ref limit)
2581
0
{
2582
0
  ir_insn *prev = NULL;
2583
0
  ir_insn *insn;
2584
2585
0
  while (ref > limit) {
2586
0
    insn = &ctx->ir_base[ref];
2587
0
    if (insn->op == IR_GUARD_NOT) {
2588
0
      if (insn->op2 == condition) {
2589
0
        return IR_FALSE;
2590
0
      }
2591
0
    } else if (insn->op == IR_GUARD) {
2592
0
      if (insn->op2 == condition) {
2593
0
        return IR_TRUE;
2594
0
      }
2595
0
    } else if (insn->op == IR_IF) {
2596
0
      if (insn->op2 == condition) {
2597
0
        if (prev->op == IR_IF_TRUE) {
2598
0
          return IR_TRUE;
2599
0
        } else if (prev->op == IR_IF_FALSE) {
2600
0
          return IR_FALSE;
2601
0
        }
2602
0
      }
2603
0
    } else if (insn->op == IR_START || insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
2604
0
      break;
2605
0
    }
2606
0
    prev = insn;
2607
0
    ref = insn->op1;
2608
0
  }
2609
2610
0
  return condition;
2611
0
}
2612
2613
ir_ref ir_check_dominating_predicates(ir_ctx *ctx, ir_ref ref, ir_ref condition)
2614
0
{
2615
0
  IR_ASSERT(!IR_IS_CONST_REF(condition));
2616
0
  return ir_check_dominating_predicates_i(ctx, ref, condition, (condition < ref) ? condition : 1);
2617
0
}
2618
2619
ir_ref _ir_IF(ir_ctx *ctx, ir_ref condition)
2620
0
{
2621
0
  ir_ref if_ref;
2622
2623
0
  IR_ASSERT(ctx->control);
2624
0
  if (UNEXPECTED(!(ctx->flags & IR_OPT_FOLDING))) {
2625
0
    if_ref = ir_emit2(ctx, IR_IF, ctx->control, condition);
2626
0
    ctx->control = IR_UNUSED;
2627
0
    return if_ref;
2628
0
  }
2629
2630
0
  condition = _ir_fold_condition(ctx, condition);
2631
0
  if (IR_IS_CONST_REF(condition)) {
2632
0
    condition = ir_ref_is_true(ctx, condition) ? IR_TRUE : IR_FALSE;
2633
0
  } else {
2634
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
2635
0
  }
2636
0
  if_ref = ir_emit2(ctx, IR_IF, ctx->control, condition);
2637
0
  ctx->control = IR_UNUSED;
2638
0
  return if_ref;
2639
0
}
2640
2641
void _ir_IF_TRUE(ir_ctx *ctx, ir_ref if_ref)
2642
0
{
2643
0
  IR_ASSERT(!ctx->control);
2644
0
  IR_ASSERT(if_ref);
2645
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2646
0
  ctx->control = ir_emit1(ctx, IR_IF_TRUE, if_ref);
2647
0
}
2648
2649
void _ir_IF_TRUE_cold(ir_ctx *ctx, ir_ref if_ref)
2650
0
{
2651
0
  IR_ASSERT(!ctx->control);
2652
0
  IR_ASSERT(if_ref);
2653
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2654
  /* op2 is used as an indicator of low-probability branch */
2655
0
  ctx->control = ir_emit2(ctx, IR_IF_TRUE, if_ref, 1);
2656
0
}
2657
2658
void _ir_IF_FALSE(ir_ctx *ctx, ir_ref if_ref)
2659
0
{
2660
0
  IR_ASSERT(!ctx->control);
2661
0
  IR_ASSERT(if_ref);
2662
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2663
0
  ctx->control = ir_emit1(ctx, IR_IF_FALSE, if_ref);
2664
0
}
2665
2666
void _ir_IF_FALSE_cold(ir_ctx *ctx, ir_ref if_ref)
2667
0
{
2668
0
  IR_ASSERT(!ctx->control);
2669
0
  IR_ASSERT(if_ref);
2670
0
  IR_ASSERT(ctx->ir_base[if_ref].op == IR_IF);
2671
  /* op2 is used as an indicator of low-probability branch */
2672
0
  ctx->control = ir_emit2(ctx, IR_IF_FALSE, if_ref, 1);
2673
0
}
2674
2675
ir_ref _ir_END(ir_ctx *ctx)
2676
0
{
2677
0
  ir_ref ref;
2678
2679
0
  IR_ASSERT(ctx->control);
2680
0
  ref = ir_emit1(ctx, IR_END, ctx->control);
2681
0
  ctx->control = IR_UNUSED;
2682
0
  return ref;
2683
0
}
2684
2685
void _ir_MERGE_2(ir_ctx *ctx, ir_ref src1, ir_ref src2)
2686
0
{
2687
0
  IR_ASSERT(!ctx->control);
2688
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_MERGE, IR_VOID, 2), src1, src2);
2689
0
}
2690
2691
void _ir_MERGE_N(ir_ctx *ctx, ir_ref n, ir_ref *inputs)
2692
0
{
2693
0
  IR_ASSERT(!ctx->control);
2694
0
  IR_ASSERT(n > 0);
2695
0
  if (n == 1) {
2696
0
    _ir_BEGIN(ctx, inputs[0]);
2697
0
  } else {
2698
0
    ir_ref *ops;
2699
2700
0
    ctx->control = ir_emit_N(ctx, IR_MERGE, n);
2701
0
    ops = ctx->ir_base[ctx->control].ops;
2702
0
    while (n) {
2703
0
      n--;
2704
0
      ops[n + 1] = inputs[n];
2705
0
    }
2706
0
  }
2707
0
}
2708
2709
void _ir_MERGE_SET_OP(ir_ctx *ctx, ir_ref merge, ir_ref pos, ir_ref src)
2710
0
{
2711
0
  ir_insn *insn = &ctx->ir_base[merge];
2712
0
  ir_ref *ops = insn->ops;
2713
2714
0
  IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
2715
0
  IR_ASSERT(pos > 0 && pos <= insn->inputs_count);
2716
0
  ops[pos] = src;
2717
0
}
2718
2719
ir_ref _ir_END_LIST(ir_ctx *ctx, ir_ref list)
2720
0
{
2721
0
  ir_ref ref;
2722
2723
0
  IR_ASSERT(ctx->control);
2724
0
  IR_ASSERT(!list || ctx->ir_base[list].op == IR_END);
2725
  /* create a liked list of END nodes with the same destination through END.op2 */
2726
0
  ref = ir_emit2(ctx, IR_END, ctx->control, list);
2727
0
  ctx->control = IR_UNUSED;
2728
0
  return ref;
2729
0
}
2730
2731
ir_ref _ir_END_PHI_LIST(ir_ctx *ctx, ir_ref list, ir_ref val)
2732
0
{
2733
0
  ir_ref ref;
2734
2735
0
  IR_ASSERT(ctx->control);
2736
0
  IR_ASSERT(!list || ctx->ir_base[list].op == IR_END);
2737
  /* create a liked list of END nodes with the same destination through END.op2 */
2738
0
  ref = ir_emit3(ctx, IR_END, ctx->control, list, val);
2739
0
  ctx->control = IR_UNUSED;
2740
0
  return ref;
2741
0
}
2742
2743
void _ir_MERGE_LIST(ir_ctx *ctx, ir_ref list)
2744
0
{
2745
0
  ir_ref ref = list;
2746
2747
0
  if (list != IR_UNUSED) {
2748
0
    uint32_t n = 0;
2749
2750
0
    IR_ASSERT(!ctx->control);
2751
2752
    /* count inputs count */
2753
0
    do {
2754
0
      ir_insn *insn = &ctx->ir_base[ref];
2755
2756
0
      IR_ASSERT(insn->op == IR_END);
2757
0
      ref = insn->op2;
2758
0
      n++;
2759
0
    } while (ref != IR_UNUSED);
2760
2761
2762
    /* create MERGE node */
2763
0
    IR_ASSERT(n > 0);
2764
0
    if (n == 1) {
2765
0
      ctx->ir_base[list].op2 = IR_UNUSED;
2766
0
      _ir_BEGIN(ctx, list);
2767
0
    } else {
2768
0
      ctx->control = ir_emit_N(ctx, IR_MERGE, n);
2769
0
      ref = list;
2770
0
      while (n) {
2771
0
        ir_insn *insn = &ctx->ir_base[ref];
2772
2773
0
        ir_set_op(ctx, ctx->control, n, ref);
2774
0
        ref = insn->op2;
2775
0
        insn->op2 = IR_UNUSED;
2776
0
        n--;
2777
0
      }
2778
0
    }
2779
0
  }
2780
0
}
2781
2782
ir_ref _ir_PHI_LIST(ir_ctx *ctx, ir_ref list)
2783
0
{
2784
0
  ir_insn *merge, *end;
2785
0
  ir_ref phi, *ops, i;
2786
0
  ir_type type;
2787
2788
0
  if (list == IR_UNUSED) {
2789
0
    return IR_UNUSED;
2790
0
  }
2791
0
  end = &ctx->ir_base[list];
2792
0
  if (!end->op2) {
2793
0
    phi = end->op3;
2794
0
    end->op3 = IR_UNUSED;
2795
0
    _ir_BEGIN(ctx, list);
2796
0
  } else if (!end->op3) {
2797
0
    _ir_MERGE_LIST(ctx, list);
2798
0
    phi = IR_UNUSED;
2799
0
  } else {
2800
0
    type = ctx->ir_base[end->op3].type;
2801
0
    _ir_MERGE_LIST(ctx, list);
2802
0
    merge = &ctx->ir_base[ctx->control];
2803
0
    IR_ASSERT(merge->op == IR_MERGE);
2804
0
    phi = ir_emit_N(ctx, IR_OPT(IR_PHI, type), merge->inputs_count + 1);
2805
0
    merge = &ctx->ir_base[ctx->control];
2806
0
    ops = merge->ops;
2807
0
    ir_set_op(ctx, phi, 1, ctx->control);
2808
0
    for (i = 0; i < merge->inputs_count; i++) {
2809
0
      end = &ctx->ir_base[ops[i + 1]];
2810
0
      ir_set_op(ctx, phi, i + 2, end->op3);
2811
0
      end->op3 = IR_END;
2812
0
    }
2813
0
  }
2814
0
  return phi;
2815
0
}
2816
2817
ir_ref _ir_LOOP_BEGIN(ir_ctx *ctx, ir_ref src1)
2818
0
{
2819
0
  IR_ASSERT(!ctx->control);
2820
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_LOOP_BEGIN, IR_VOID, 2), src1, IR_UNUSED);
2821
0
  return ctx->control;
2822
0
}
2823
2824
ir_ref _ir_LOOP_END(ir_ctx *ctx)
2825
0
{
2826
0
  ir_ref ref;
2827
2828
0
  IR_ASSERT(ctx->control);
2829
0
  ref = ir_emit1(ctx, IR_LOOP_END, ctx->control);
2830
0
  ctx->control = IR_UNUSED;
2831
0
  return ref;
2832
0
}
2833
2834
ir_ref _ir_CALL(ir_ctx *ctx, ir_type type, ir_ref func)
2835
0
{
2836
0
  IR_ASSERT(ctx->control);
2837
0
  return ctx->control = ir_emit2(ctx, IR_OPTX(IR_CALL, type, 2), ctx->control, func);
2838
0
}
2839
2840
ir_ref _ir_CALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
2841
0
{
2842
0
  IR_ASSERT(ctx->control);
2843
0
  return ctx->control = ir_emit3(ctx, IR_OPTX(IR_CALL, type, 3), ctx->control, func, arg1);
2844
0
}
2845
2846
ir_ref _ir_CALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
2847
0
{
2848
0
  ir_ref call;
2849
2850
0
  IR_ASSERT(ctx->control);
2851
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 4);
2852
0
  ir_set_op(ctx, call, 1, ctx->control);
2853
0
  ir_set_op(ctx, call, 2, func);
2854
0
  ir_set_op(ctx, call, 3, arg1);
2855
0
  ir_set_op(ctx, call, 4, arg2);
2856
0
  ctx->control = call;
2857
0
  return call;
2858
0
}
2859
2860
ir_ref _ir_CALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
2861
0
{
2862
0
  ir_ref call;
2863
2864
0
  IR_ASSERT(ctx->control);
2865
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 5);
2866
0
  ir_set_op(ctx, call, 1, ctx->control);
2867
0
  ir_set_op(ctx, call, 2, func);
2868
0
  ir_set_op(ctx, call, 3, arg1);
2869
0
  ir_set_op(ctx, call, 4, arg2);
2870
0
  ir_set_op(ctx, call, 5, arg3);
2871
0
  ctx->control = call;
2872
0
  return call;
2873
0
}
2874
2875
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)
2876
0
{
2877
0
  ir_ref call;
2878
2879
0
  IR_ASSERT(ctx->control);
2880
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 6);
2881
0
  ir_set_op(ctx, call, 1, ctx->control);
2882
0
  ir_set_op(ctx, call, 2, func);
2883
0
  ir_set_op(ctx, call, 3, arg1);
2884
0
  ir_set_op(ctx, call, 4, arg2);
2885
0
  ir_set_op(ctx, call, 5, arg3);
2886
0
  ir_set_op(ctx, call, 6, arg4);
2887
0
  ctx->control = call;
2888
0
  return call;
2889
0
}
2890
2891
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)
2892
0
{
2893
0
  ir_ref call;
2894
2895
0
  IR_ASSERT(ctx->control);
2896
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 7);
2897
0
  ir_set_op(ctx, call, 1, ctx->control);
2898
0
  ir_set_op(ctx, call, 2, func);
2899
0
  ir_set_op(ctx, call, 3, arg1);
2900
0
  ir_set_op(ctx, call, 4, arg2);
2901
0
  ir_set_op(ctx, call, 5, arg3);
2902
0
  ir_set_op(ctx, call, 6, arg4);
2903
0
  ir_set_op(ctx, call, 7, arg5);
2904
0
  ctx->control = call;
2905
0
  return call;
2906
0
}
2907
2908
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)
2909
0
{
2910
0
  ir_ref call;
2911
2912
0
  IR_ASSERT(ctx->control);
2913
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), 8);
2914
0
  ir_set_op(ctx, call, 1, ctx->control);
2915
0
  ir_set_op(ctx, call, 2, func);
2916
0
  ir_set_op(ctx, call, 3, arg1);
2917
0
  ir_set_op(ctx, call, 4, arg2);
2918
0
  ir_set_op(ctx, call, 5, arg3);
2919
0
  ir_set_op(ctx, call, 6, arg4);
2920
0
  ir_set_op(ctx, call, 7, arg5);
2921
0
  ir_set_op(ctx, call, 8, arg6);
2922
0
  ctx->control = call;
2923
0
  return call;
2924
0
}
2925
2926
ir_ref _ir_CALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
2927
0
{
2928
0
  ir_ref call;
2929
0
  uint32_t i;
2930
2931
0
  IR_ASSERT(ctx->control);
2932
0
  call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), count + 2);
2933
0
  ir_set_op(ctx, call, 1, ctx->control);
2934
0
  ir_set_op(ctx, call, 2, func);
2935
0
  for (i = 0; i < count; i++) {
2936
0
    ir_set_op(ctx, call, i + 3, args[i]);
2937
0
  }
2938
0
  ctx->control = call;
2939
0
  return call;
2940
0
}
2941
2942
void _ir_UNREACHABLE(ir_ctx *ctx)
2943
0
{
2944
0
  IR_ASSERT(ctx->control);
2945
0
  ctx->control = ir_emit3(ctx, IR_UNREACHABLE, ctx->control, IR_UNUSED, ctx->ir_base[1].op1);
2946
0
  ctx->ir_base[1].op1 = ctx->control;
2947
0
  ctx->control = IR_UNUSED;
2948
0
}
2949
2950
void _ir_TAILCALL(ir_ctx *ctx, ir_type type, ir_ref func)
2951
0
{
2952
0
  IR_ASSERT(ctx->control);
2953
0
  if (ctx->ret_type == (ir_type)-1) {
2954
0
    ctx->ret_type = type;
2955
0
  }
2956
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
2957
0
  ctx->control = ir_emit2(ctx, IR_OPTX(IR_TAILCALL, type, 2), ctx->control, func);
2958
0
  _ir_UNREACHABLE(ctx);
2959
0
}
2960
2961
void _ir_TAILCALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
2962
0
{
2963
0
  IR_ASSERT(ctx->control);
2964
0
  if (ctx->ret_type == (ir_type)-1) {
2965
0
    ctx->ret_type = type;
2966
0
  }
2967
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
2968
0
  ctx->control = ir_emit3(ctx, IR_OPTX(IR_TAILCALL, type, 3), ctx->control, func, arg1);
2969
0
  _ir_UNREACHABLE(ctx);
2970
0
}
2971
2972
void _ir_TAILCALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
2973
0
{
2974
0
  ir_ref call;
2975
2976
0
  IR_ASSERT(ctx->control);
2977
0
  if (ctx->ret_type == (ir_type)-1) {
2978
0
    ctx->ret_type = type;
2979
0
  }
2980
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
2981
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 4);
2982
0
  ir_set_op(ctx, call, 1, ctx->control);
2983
0
  ir_set_op(ctx, call, 2, func);
2984
0
  ir_set_op(ctx, call, 3, arg1);
2985
0
  ir_set_op(ctx, call, 4, arg2);
2986
0
  ctx->control = call;
2987
0
  _ir_UNREACHABLE(ctx);
2988
0
}
2989
2990
void _ir_TAILCALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
2991
0
{
2992
0
  ir_ref call;
2993
2994
0
  IR_ASSERT(ctx->control);
2995
0
  if (ctx->ret_type == (ir_type)-1) {
2996
0
    ctx->ret_type = type;
2997
0
  }
2998
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
2999
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 5);
3000
0
  ir_set_op(ctx, call, 1, ctx->control);
3001
0
  ir_set_op(ctx, call, 2, func);
3002
0
  ir_set_op(ctx, call, 3, arg1);
3003
0
  ir_set_op(ctx, call, 4, arg2);
3004
0
  ir_set_op(ctx, call, 5, arg3);
3005
0
  ctx->control = call;
3006
0
  _ir_UNREACHABLE(ctx);
3007
0
}
3008
3009
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)
3010
0
{
3011
0
  ir_ref call;
3012
3013
0
  IR_ASSERT(ctx->control);
3014
0
  if (ctx->ret_type == (ir_type)-1) {
3015
0
    ctx->ret_type = type;
3016
0
  }
3017
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3018
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 6);
3019
0
  ir_set_op(ctx, call, 1, ctx->control);
3020
0
  ir_set_op(ctx, call, 2, func);
3021
0
  ir_set_op(ctx, call, 3, arg1);
3022
0
  ir_set_op(ctx, call, 4, arg2);
3023
0
  ir_set_op(ctx, call, 5, arg3);
3024
0
  ir_set_op(ctx, call, 6, arg4);
3025
0
  ctx->control = call;
3026
0
  _ir_UNREACHABLE(ctx);
3027
0
}
3028
3029
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)
3030
0
{
3031
0
  ir_ref call;
3032
3033
0
  IR_ASSERT(ctx->control);
3034
0
  if (ctx->ret_type == (ir_type)-1) {
3035
0
    ctx->ret_type = type;
3036
0
  }
3037
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3038
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 7);
3039
0
  ir_set_op(ctx, call, 1, ctx->control);
3040
0
  ir_set_op(ctx, call, 2, func);
3041
0
  ir_set_op(ctx, call, 3, arg1);
3042
0
  ir_set_op(ctx, call, 4, arg2);
3043
0
  ir_set_op(ctx, call, 5, arg3);
3044
0
  ir_set_op(ctx, call, 6, arg4);
3045
0
  ir_set_op(ctx, call, 7, arg5);
3046
0
  ctx->control = call;
3047
0
  _ir_UNREACHABLE(ctx);
3048
0
}
3049
3050
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)
3051
0
{
3052
0
  ir_ref call;
3053
3054
0
  IR_ASSERT(ctx->control);
3055
0
  if (ctx->ret_type == (ir_type)-1) {
3056
0
    ctx->ret_type = type;
3057
0
  }
3058
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3059
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), 8);
3060
0
  ir_set_op(ctx, call, 1, ctx->control);
3061
0
  ir_set_op(ctx, call, 2, func);
3062
0
  ir_set_op(ctx, call, 3, arg1);
3063
0
  ir_set_op(ctx, call, 4, arg2);
3064
0
  ir_set_op(ctx, call, 5, arg3);
3065
0
  ir_set_op(ctx, call, 6, arg4);
3066
0
  ir_set_op(ctx, call, 7, arg5);
3067
0
  ir_set_op(ctx, call, 8, arg6);
3068
0
  ctx->control = call;
3069
0
  _ir_UNREACHABLE(ctx);
3070
0
}
3071
3072
void _ir_TAILCALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
3073
0
{
3074
0
  ir_ref call;
3075
0
  uint32_t i;
3076
3077
0
  IR_ASSERT(ctx->control);
3078
0
  if (ctx->ret_type == (ir_type)-1) {
3079
0
    ctx->ret_type = type;
3080
0
  }
3081
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3082
0
  call = ir_emit_N(ctx, IR_OPT(IR_TAILCALL, type), count + 2);
3083
0
  ir_set_op(ctx, call, 1, ctx->control);
3084
0
  ir_set_op(ctx, call, 2, func);
3085
0
  for (i = 0; i < count; i++) {
3086
0
    ir_set_op(ctx, call, i + 3, args[i]);
3087
0
  }
3088
0
  ctx->control = call;
3089
0
  _ir_UNREACHABLE(ctx);
3090
0
}
3091
3092
ir_ref _ir_SWITCH(ir_ctx *ctx, ir_ref val)
3093
0
{
3094
0
  ir_ref ref;
3095
3096
0
  IR_ASSERT(ctx->control);
3097
0
  ref = ir_emit2(ctx, IR_SWITCH, ctx->control, val);
3098
0
  ctx->control = IR_UNUSED;
3099
0
  return ref;
3100
0
}
3101
3102
void _ir_CASE_VAL(ir_ctx *ctx, ir_ref switch_ref, ir_ref val)
3103
0
{
3104
0
  IR_ASSERT(!ctx->control);
3105
0
  ctx->control = ir_emit2(ctx, IR_CASE_VAL, switch_ref, val);
3106
0
}
3107
3108
void _ir_CASE_RANGE(ir_ctx *ctx, ir_ref switch_ref, ir_ref v1, ir_ref v2)
3109
0
{
3110
0
  IR_ASSERT(!ctx->control);
3111
0
  ctx->control = ir_emit3(ctx, IR_CASE_RANGE, switch_ref, v1, v2);
3112
0
}
3113
3114
void _ir_CASE_DEFAULT(ir_ctx *ctx, ir_ref switch_ref)
3115
0
{
3116
0
  IR_ASSERT(!ctx->control);
3117
0
  ctx->control = ir_emit1(ctx, IR_CASE_DEFAULT, switch_ref);
3118
0
}
3119
3120
void _ir_RETURN(ir_ctx *ctx, ir_ref val)
3121
0
{
3122
0
  ir_type type = (val != IR_UNUSED) ? ctx->ir_base[val].type : IR_VOID;
3123
3124
0
  IR_ASSERT(ctx->control);
3125
0
  if (ctx->ret_type == (ir_type)-1) {
3126
0
    ctx->ret_type = type;
3127
0
  }
3128
0
  IR_ASSERT(ctx->ret_type == type && "conflicting return type");
3129
0
  ctx->control = ir_emit3(ctx, IR_RETURN, ctx->control, val, ctx->ir_base[1].op1);
3130
0
  ctx->ir_base[1].op1 = ctx->control;
3131
0
  ctx->control = IR_UNUSED;
3132
0
}
3133
3134
void _ir_IJMP(ir_ctx *ctx, ir_ref addr)
3135
0
{
3136
0
  IR_ASSERT(ctx->control);
3137
0
  ctx->control = ir_emit3(ctx, IR_IJMP, ctx->control, addr, ctx->ir_base[1].op1);
3138
0
  ctx->ir_base[1].op1 = ctx->control;
3139
0
  ctx->control = IR_UNUSED;
3140
0
}
3141
3142
ir_ref _ir_IGOTO(ir_ctx *ctx, ir_ref addr)
3143
0
{
3144
0
  ir_ref ref;
3145
3146
0
  IR_ASSERT(ctx->control);
3147
0
  ctx->control = ref = ir_emit2(ctx, IR_IGOTO, ctx->control, addr);
3148
0
  ctx->control = IR_UNUSED;
3149
0
  return ref;
3150
0
}
3151
3152
ir_ref _ir_ADD_OFFSET(ir_ctx *ctx, ir_ref addr, uintptr_t offset)
3153
0
{
3154
0
  if (offset) {
3155
0
    addr = ir_fold2(ctx, IR_OPT(IR_ADD, IR_ADDR), addr, ir_const_addr(ctx, offset));
3156
0
  }
3157
0
  return addr;
3158
0
}
3159
3160
void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr)
3161
0
{
3162
0
  IR_ASSERT(ctx->control);
3163
0
  if (IR_IS_CONST_REF(condition)) {
3164
0
    if (ir_ref_is_true(ctx, condition)) {
3165
0
      return;
3166
0
    }
3167
0
    condition = IR_FALSE;
3168
0
  } else if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3169
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
3170
0
    if (condition == IR_TRUE) {
3171
0
      return;
3172
0
    }
3173
0
  }
3174
0
  if (ctx->snapshot_create) {
3175
0
    ctx->snapshot_create(ctx, addr);
3176
0
  }
3177
0
  ctx->control = ir_emit3(ctx, IR_GUARD, ctx->control, condition, addr);
3178
0
}
3179
3180
void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr)
3181
0
{
3182
0
  IR_ASSERT(ctx->control);
3183
0
  if (IR_IS_CONST_REF(condition)) {
3184
0
    if (!ir_ref_is_true(ctx, condition)) {
3185
0
      return;
3186
0
    }
3187
0
    condition = IR_TRUE;
3188
0
  } else if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3189
0
    condition = ir_check_dominating_predicates_i(ctx, ctx->control, condition, condition);
3190
0
    if (condition == IR_FALSE) {
3191
0
      return;
3192
0
    }
3193
0
  }
3194
0
  if (ctx->snapshot_create) {
3195
0
    ctx->snapshot_create(ctx, addr);
3196
0
  }
3197
0
  ctx->control = ir_emit3(ctx, IR_GUARD_NOT, ctx->control, condition, addr);
3198
0
}
3199
3200
ir_ref _ir_SNAPSHOT(ir_ctx *ctx, ir_ref n)
3201
0
{
3202
0
  ir_ref snapshot;
3203
3204
0
  IR_ASSERT(ctx->control);
3205
0
  snapshot = ir_emit_N(ctx, IR_SNAPSHOT, 1 + n); /* op1 is used for control */
3206
0
  ctx->ir_base[snapshot].op1 = ctx->control;
3207
0
  ctx->control = snapshot;
3208
0
  return snapshot;
3209
0
}
3210
3211
void _ir_SNAPSHOT_SET_OP(ir_ctx *ctx, ir_ref snapshot, ir_ref pos, ir_ref val)
3212
0
{
3213
0
  ir_insn *insn = &ctx->ir_base[snapshot];
3214
0
  ir_ref *ops = insn->ops;
3215
3216
0
  IR_ASSERT(val < snapshot);
3217
0
  IR_ASSERT(insn->op == IR_SNAPSHOT);
3218
0
  pos++; /* op1 is used for control */
3219
0
  IR_ASSERT(pos > 1 && pos <= insn->inputs_count);
3220
0
  ops[pos] = val;
3221
0
}
3222
3223
ir_ref _ir_EXITCALL(ir_ctx *ctx, ir_ref func)
3224
0
{
3225
0
  IR_ASSERT(ctx->control);
3226
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_EXITCALL, IR_I32), ctx->control, func);
3227
0
}
3228
3229
ir_ref _ir_ALLOCA(ir_ctx *ctx, ir_ref size)
3230
0
{
3231
0
  IR_ASSERT(ctx->control);
3232
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_ALLOCA, IR_ADDR), ctx->control, size);
3233
0
}
3234
3235
void _ir_AFREE(ir_ctx *ctx, ir_ref size)
3236
0
{
3237
0
  IR_ASSERT(ctx->control);
3238
0
  ctx->control = ir_emit2(ctx, IR_AFREE, ctx->control, size);
3239
0
}
3240
3241
ir_ref _ir_VLOAD(ir_ctx *ctx, ir_type type, ir_ref var)
3242
0
{
3243
0
  ir_ref ref;
3244
3245
0
  IR_ASSERT(ctx->control);
3246
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3247
0
    ref = ir_find_aliasing_vload_i(ctx, ctx->control, type, var);
3248
0
    if (ref) {
3249
0
      ir_insn *insn = &ctx->ir_base[ref];
3250
0
      if (insn->type == type) {
3251
0
        return ref;
3252
0
      } else if (ir_type_size[insn->type] == ir_type_size[type]) {
3253
0
        return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), ref); /* load forwarding with bitcast (L2L) */
3254
0
      } else {
3255
0
        return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), ref); /* partial load forwarding (L2L) */
3256
0
      }
3257
0
    }
3258
0
  }
3259
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD, type), ctx->control, var);
3260
0
}
3261
3262
void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val)
3263
0
{
3264
0
  IR_ASSERT(ctx->control);
3265
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3266
0
    if (ir_find_aliasing_vstore_i(ctx, ctx->control, var, val)) {
3267
      /* dead STORE */
3268
0
      return;
3269
0
    }
3270
0
  }
3271
0
  ctx->control = ir_emit3(ctx, IR_VSTORE, ctx->control, var, val);
3272
0
}
3273
3274
ir_ref _ir_VLOAD_v(ir_ctx *ctx, ir_type type, ir_ref var)
3275
0
{
3276
0
  IR_ASSERT(ctx->control);
3277
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD_v, type), ctx->control, var);
3278
0
}
3279
3280
void _ir_VSTORE_v(ir_ctx *ctx, ir_ref var, ir_ref val)
3281
0
{
3282
0
  IR_ASSERT(ctx->control);
3283
0
  ctx->control = ir_emit3(ctx, IR_VSTORE_v, ctx->control, var, val);
3284
0
}
3285
3286
ir_ref _ir_TLS(ir_ctx *ctx, ir_ref index, ir_ref offset)
3287
0
{
3288
0
  IR_ASSERT(ctx->control);
3289
0
  return ctx->control = ir_emit3(ctx, IR_OPT(IR_TLS, IR_ADDR), ctx->control, index, offset);
3290
0
}
3291
3292
ir_ref _ir_RLOAD(ir_ctx *ctx, ir_type type, ir_ref reg)
3293
0
{
3294
0
  IR_ASSERT(ctx->control);
3295
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_RLOAD, type), ctx->control, reg);
3296
0
}
3297
3298
void _ir_RSTORE(ir_ctx *ctx, ir_ref reg, ir_ref val)
3299
0
{
3300
0
  IR_ASSERT(ctx->control);
3301
0
  ctx->control = ir_emit3(ctx, IR_RSTORE, ctx->control, val, reg);
3302
0
}
3303
3304
ir_ref _ir_LOAD(ir_ctx *ctx, ir_type type, ir_ref addr)
3305
0
{
3306
0
  ir_ref ref;
3307
3308
0
  IR_ASSERT(ctx->control);
3309
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3310
0
    if (ctx->ir_base[addr].op == IR_VADDR) {
3311
0
      return _ir_VLOAD(ctx, type, ctx->ir_base[addr].op1);
3312
0
    }
3313
0
    ref = ir_find_aliasing_load_i(ctx, ctx->control, type, addr, (addr > 0) ? addr : 1);
3314
0
    if (ref) {
3315
0
      ir_insn *insn = &ctx->ir_base[ref];
3316
0
      if (insn->type == type) {
3317
0
        return ref;
3318
0
      } else if (ir_type_size[insn->type] == ir_type_size[type]) {
3319
0
        return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), ref); /* load forwarding with bitcast (L2L) */
3320
0
      } else {
3321
0
        return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), ref); /* partial load forwarding (L2L) */
3322
0
      }
3323
0
    }
3324
0
  }
3325
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD, type), ctx->control, addr);
3326
0
}
3327
3328
void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val)
3329
0
{
3330
0
  IR_ASSERT(ctx->control);
3331
0
  if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) {
3332
0
    if (ctx->ir_base[addr].op == IR_VADDR) {
3333
0
      _ir_VSTORE(ctx, ctx->ir_base[addr].op1, val);
3334
0
      return;
3335
0
    }
3336
0
    if (ir_find_aliasing_store_i(ctx, ctx->control, addr, val, (addr > 0) ? addr : 1)) {
3337
      /* dead STORE */
3338
0
      return;
3339
0
    }
3340
0
  }
3341
0
  ctx->control = ir_emit3(ctx, IR_STORE, ctx->control, addr, val);
3342
0
}
3343
3344
ir_ref _ir_LOAD_v(ir_ctx *ctx, ir_type type, ir_ref addr)
3345
0
{
3346
0
  IR_ASSERT(ctx->control);
3347
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD_v, type), ctx->control, addr);
3348
0
}
3349
3350
void _ir_STORE_v(ir_ctx *ctx, ir_ref addr, ir_ref val)
3351
0
{
3352
0
  IR_ASSERT(ctx->control);
3353
0
  ctx->control = ir_emit3(ctx, IR_STORE_v, ctx->control, addr, val);
3354
0
}
3355
3356
void _ir_VA_START(ir_ctx *ctx, ir_ref list)
3357
0
{
3358
0
  IR_ASSERT(ctx->control);
3359
0
  ctx->control = ir_emit2(ctx, IR_VA_START, ctx->control, list);
3360
0
}
3361
3362
void _ir_VA_END(ir_ctx *ctx, ir_ref list)
3363
0
{
3364
0
  IR_ASSERT(ctx->control);
3365
0
  ctx->control = ir_emit2(ctx, IR_VA_END, ctx->control, list);
3366
0
}
3367
3368
void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src)
3369
0
{
3370
0
  IR_ASSERT(ctx->control);
3371
0
  ctx->control = ir_emit3(ctx, IR_VA_COPY, ctx->control, dst, src);
3372
0
}
3373
3374
ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
3375
0
{
3376
0
  IR_ASSERT(ctx->control);
3377
0
  return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
3378
0
}
3379
3380
ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size, size_t align)
3381
0
{
3382
0
  IR_ASSERT(ctx->control);
3383
0
  IR_ASSERT(size <= 0x0fffffff);
3384
0
  IR_ASSERT(align != 0 && ((align & (align - 1)) == 0) && align <= 128);
3385
0
  return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list,
3386
0
    (ir_ref)IR_VA_ARG_OP3(size, align));
3387
0
}
3388
3389
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)
3390
0
{
3391
0
  IR_ASSERT(ctx->control);
3392
0
  return ctx->control = ir_emit1(ctx, IR_OPT(IR_BLOCK_BEGIN, IR_ADDR), ctx->control);
3393
0
}