Coverage Report

Created: 2025-09-27 06:26

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