Coverage Report

Created: 2026-10-28 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/jit/ir/ir_sccp.c
Line
Count
Source
1
/*
2
 * IR - Lightweight JIT Compilation Framework
3
 * (SCCP - Sparse Conditional Constant Propagation)
4
 * This file is part of the IR Project distributed under the MIT-style LICENSE.
5
 * Authors: Dmitry Stogov <dmitry@php.net>
6
 *
7
 * The SCCP algorithm is based on M. N. Wegman and F. K. Zadeck publication
8
 * See:  M. N. Wegman and F. K. Zadeck. "Constant propagation with conditional branches"
9
 * ACM Transactions on Programming Languages and Systems, 13(2):181-210, April 1991
10
 */
11
12
#include "ir.h"
13
#include "ir_private.h"
14
15
#include <math.h>
16
17
#define IR_COMBO_COPY_PROPAGATION 1
18
19
3.06M
#define IR_TOP                  IR_UNUSED
20
6.67M
#define IR_BOTTOM               IR_LAST_OP
21
22
1.75M
#define IR_MAKE_BOTTOM(ref)     do {IR_ASSERT(ref > 0); _values[ref].optx = IR_BOTTOM;} while (0)
23
24
114k
#define IR_IS_TOP(ref)          (ref >= 0 && _values[ref].op == IR_TOP)
25
0
#define IR_IS_BOTTOM(ref)       (ref >= 0 && _values[ref].op == IR_BOTTOM)
26
1.37M
#define IR_IS_REACHABLE(ref)    _ir_is_reachable_ctrl(ctx, _values, ref)
27
114k
#define IR_IS_CONST(ref)        (IR_IS_CONST_REF(ref) || IR_IS_CONST_OP(_values[ref].op))
28
29
typedef struct {
30
  union {
31
    struct {
32
      IR_STRUCT_LOHI(
33
        union {
34
          IR_STRUCT_LOHI(
35
            union {
36
              IR_STRUCT_LOHI(
37
                uint8_t        op,   /* [IR_TOP - unreachable, IR_BOTTOM - reachable} for control */
38
                                     /* {IR_TOP | IR_COPY() | IR_CONST() | IR_BOTTOM} for data */
39
                                     /* {IR_TOP | IR_MERGE() | IR_BOTTOM} for IR_MERGE */
40
                                     /* {IR_TOP | IR_IF() | IR_BOTTOM} for IR_IF and IR_SWITCH */
41
                uint8_t        type
42
              );
43
              uint16_t           opt;
44
            },
45
            uint16_t               _space_1
46
          );
47
          uint32_t                   optx;
48
        },
49
        union {
50
          ir_ref                     copy;              /* identity for IR_COPY */
51
          ir_ref                     unfeasible_inputs; /* number of unfeasible inputs for IR_MERGE */
52
          ir_ref                     single_output;     /* reachable output for IR_IF */
53
          ir_ref                     visited;           /* for IR_TOP */
54
        }
55
      );
56
      union {
57
        struct {
58
          ir_ref                     next; /* double-linked identities list for IR_COPY */
59
          ir_ref                     prev; /* double-linked identities list for IR_COPY */
60
        };
61
        ir_val                         val;  /* constant value for IR_CONST */
62
      };
63
    };
64
    ir_insn                                insn; /* constant insn for IR_CONST */
65
  };
66
} ir_sccp_val;
67
68
IR_ALWAYS_INLINE bool _ir_is_reachable_ctrl(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref)
69
1.60M
{
70
1.60M
  IR_ASSERT(!IR_IS_CONST_REF(ref));
71
1.60M
  IR_ASSERT(ir_op_flags[ctx->ir_base[ref].op] & IR_OP_FLAG_CONTROL);
72
1.60M
  return _values[ref].op != IR_TOP; /* BOTTOM, IF or MERGE */
73
1.60M
}
74
75
IR_ALWAYS_INLINE void ir_sccp_add_uses(const ir_ctx *ctx, const ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref)
76
1.76M
{
77
1.76M
  const ir_use_list *use_list;
78
1.76M
  const ir_ref *p;
79
1.76M
  ir_ref n, use;
80
81
1.76M
  IR_ASSERT(!IR_IS_CONST_REF(ref));
82
1.76M
  use_list = &ctx->use_lists[ref];
83
1.76M
  n = use_list->count;
84
4.40M
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
85
2.63M
    use = *p;
86
2.63M
    if (_values[use].op != IR_BOTTOM) {
87
2.61M
      ir_bitqueue_add(worklist, use);
88
2.61M
    }
89
2.63M
  }
90
1.76M
}
91
92
IR_ALWAYS_INLINE void ir_sccp_add_input(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref)
93
372
{
94
372
  IR_ASSERT(!IR_IS_CONST_REF(ref));
95
372
  IR_ASSERT(_values[ref].op == IR_TOP);
96
  /* do backward propagaton only once */
97
372
  if (!_values[ref].visited) {
98
372
    _values[ref].visited = 1;
99
372
    ir_bitqueue_add(worklist, ref);
100
372
  }
101
372
}
102
103
#if IR_COMBO_COPY_PROPAGATION
104
IR_ALWAYS_INLINE ir_ref ir_sccp_identity(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a)
105
90.1k
{
106
90.1k
  if (a > 0 && _values[a].op == IR_COPY) {
107
24.2k
    do {
108
24.2k
      a = _values[a].copy;
109
24.2k
      IR_ASSERT(a > 0);
110
24.2k
    } while (_values[a].op == IR_COPY);
111
24.2k
    IR_ASSERT(_values[a].op == IR_BOTTOM);
112
65.9k
  } else if (a > 0 && _values[a].op == IR_LONG_CONST) {
113
0
    a = _values[a].val.i32;
114
0
  }
115
90.1k
  return a;
116
90.1k
}
117
118
#if 0
119
static void CHECK_LIST(ir_sccp_val *_values, ir_ref ref)
120
{
121
  ir_ref member = _values[ref].op2;
122
  while (member != ref) {
123
    IR_ASSERT(_values[_values[member].op2].op3 == member);
124
    member = _values[member].op2;
125
  }
126
  IR_ASSERT(_values[_values[ref].op2].op3 == ref);
127
}
128
#else
129
# define CHECK_LIST(_values, ref)
130
#endif
131
132
static void ir_sccp_add_identity(const ir_ctx *ctx, ir_sccp_val *_values, ir_ref src, ir_ref dst)
133
6.05k
{
134
6.05k
  IR_ASSERT(dst > 0 && _values[dst].op != IR_BOTTOM && _values[dst].op != IR_COPY);
135
6.05k
  IR_ASSERT((src > 0 && (_values[src].op == IR_BOTTOM || _values[src].op == IR_COPY)));
136
6.05k
  IR_ASSERT(ir_sccp_identity(ctx, _values, src) != dst);
137
138
6.05k
  _values[dst].optx = IR_COPY;
139
6.05k
  _values[dst].copy = src;
140
141
6.05k
  if (_values[src].op == IR_BOTTOM) {
142
    /* initialize empty double-linked list */
143
6.05k
    if (_values[src].copy != src) {
144
6.05k
      _values[src].copy = src;
145
6.05k
      _values[src].next = src;
146
6.05k
      _values[src].prev = src;
147
6.05k
    }
148
6.05k
  } else {
149
0
    src = ir_sccp_identity(ctx, _values, src);
150
0
  }
151
152
  /* insert into circular double-linked list */
153
6.05k
  ir_ref prev = _values[src].prev;
154
6.05k
  _values[dst].next = src;
155
6.05k
  _values[dst].prev = prev;
156
6.05k
  _values[src].prev = dst;
157
6.05k
  _values[prev].next = dst;
158
6.05k
  CHECK_LIST(_values, dst);
159
6.05k
}
160
161
static void ir_sccp_split_partition(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref)
162
6.04k
{
163
6.04k
  ir_ref member, head, tail, next, prev;
164
165
6.04k
  CHECK_LIST(_values, ref);
166
6.04k
  IR_MAKE_BOTTOM(ref);
167
6.04k
  _values[ref].copy = ref;
168
169
6.04k
  member = _values[ref].next;
170
6.04k
  head = tail = IR_UNUSED;
171
12.0k
  while (member != ref) {
172
6.04k
    if (_values[member].op != IR_BOTTOM) {
173
0
      ir_bitqueue_add(worklist, member);
174
0
    }
175
6.04k
    ir_sccp_add_uses(ctx, _values, worklist, member);
176
177
6.04k
    next = _values[member].next;
178
6.04k
    if (ir_sccp_identity(ctx, _values, member) == ref) {
179
      /* remove "member" from the old circular double-linked list */
180
0
      prev = _values[member].prev;
181
0
      _values[prev].next = next;
182
0
      _values[next].prev = prev;
183
184
      /* insert "member" into the new double-linked list */
185
0
      if (!head) {
186
0
        head = tail = member;
187
0
      } else {
188
0
        _values[tail].next = member;
189
0
        _values[member].prev = tail;
190
0
        tail = member;
191
0
      }
192
0
    }
193
6.04k
    member = next;
194
6.04k
  }
195
196
  /* remove "ref" from the old circular double-linked list */
197
6.04k
  next = _values[ref].next;
198
6.04k
  prev = _values[ref].prev;
199
6.04k
  _values[prev].next = next;
200
6.04k
  _values[next].prev = prev;
201
6.04k
  CHECK_LIST(_values, next);
202
203
  /* close the new circle */
204
6.04k
  if (head) {
205
0
    _values[ref].next = head;
206
0
    _values[ref].prev = tail;
207
0
    _values[tail].next = ref;
208
0
    _values[head].prev = ref;
209
6.04k
  } else {
210
6.04k
    _values[ref].next = ref;
211
6.04k
    _values[ref].prev = ref;
212
6.04k
  }
213
6.04k
  CHECK_LIST(_values, ref);
214
6.04k
}
215
216
IR_ALWAYS_INLINE void ir_sccp_make_bottom_ex(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref)
217
355k
{
218
355k
  if (_values[ref].op == IR_COPY) {
219
0
    ir_sccp_split_partition(ctx, _values, worklist, ref);
220
355k
  } else {
221
355k
    IR_MAKE_BOTTOM(ref);
222
355k
  }
223
355k
}
224
225
355k
# define IR_MAKE_BOTTOM_EX(ref) ir_sccp_make_bottom_ex(ctx, _values, worklist, ref)
226
#else
227
# define ir_sccp_identity(_ctx, _values, ref) (ref)
228
# define IR_MAKE_BOTTOM_EX(ref) IR_MAKE_BOTTOM(ref)
229
#endif
230
231
IR_ALWAYS_INLINE bool ir_sccp_meet_long_const(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref const_ref, const ir_insn *const_insn)
232
0
{
233
0
  if (_values[ref].op == IR_TOP) {
234
    /* TOP meet NEW_CONST => NEW_CONST */
235
0
    _values[ref].optx = const_insn->opt;
236
0
    _values[ref].val.i64 = const_ref;
237
0
    return 1;
238
0
  } else if (_values[ref].opt == const_insn->opt) {
239
    /* OLD_CONST meet NEW_CONST => (OLD_CONST == NEW_CONST) ? OLD_CONST : BOTTOM */
240
0
    if (_values[ref].val.i32 == const_ref) {
241
0
      return 0;
242
0
    }
243
0
  }
244
245
0
  IR_MAKE_BOTTOM_EX(ref);
246
0
  return 1;
247
0
}
248
249
IR_ALWAYS_INLINE bool ir_sccp_meet_const(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, const ir_insn *val_insn)
250
2
{
251
2
#if IR_COMBO_COPY_PROPAGATION
252
2
  IR_ASSERT(IR_IS_TYPE_SCALAR(val_insn->type));
253
#else
254
  if (!IR_IS_TYPE_SCALAR(val_insn->type)) {
255
    IR_MAKE_BOTTOM_EX(ref);
256
    return 1;
257
  }
258
#endif
259
2
  IR_ASSERT(IR_IS_CONST_OP(val_insn->op) || IR_IS_SYM_CONST(val_insn->op));
260
261
2
  if (_values[ref].op == IR_TOP) {
262
    /* TOP meet NEW_CONST => NEW_CONST */
263
2
    _values[ref].optx = val_insn->opt;
264
2
    _values[ref].val.u64 = val_insn->val.u64;
265
2
    return 1;
266
2
  } else if (_values[ref].opt == val_insn->opt) {
267
    /* OLD_CONST meet NEW_CONST => (OLD_CONST == NEW_CONST) ? OLD_CONST : BOTTOM */
268
0
    if (_values[ref].val.u64 == val_insn->val.u64) {
269
0
      return 0;
270
0
    }
271
0
  }
272
273
0
  IR_MAKE_BOTTOM_EX(ref);
274
0
  return 1;
275
2
}
276
277
IR_ALWAYS_INLINE bool ir_sccp_meet_copy(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref val)
278
12.1k
{
279
12.1k
#if IR_COMBO_COPY_PROPAGATION
280
12.1k
  if (_values[ref].op == IR_COPY) {
281
    /* COPY(OLD_VAL) meet COPY(NEW_VAL) =>
282
     *   (IDENTITY(OLD_VAL) == IDENTITY(NEW_VAL) ? COPY(OLD_VAL) ? BOTTOM */
283
6.04k
    if (ir_sccp_identity(ctx, _values, ref) == ir_sccp_identity(ctx, _values, val)) {
284
0
      return 0; /* not changed */
285
0
    }
286
6.04k
    ir_sccp_split_partition(ctx, _values, worklist, ref);
287
6.04k
    return 1;
288
6.05k
  } else {
289
6.05k
    IR_ASSERT(_values[ref].op != IR_BOTTOM);
290
    /* TOP       meet COPY(NEW_VAL) -> COPY(NEW_VAL) */
291
    /* OLD_CONST meet COPY(NEW_VAL) -> COPY(NEW_VAL) */
292
6.05k
    ir_sccp_add_identity(ctx, _values, val, ref);
293
6.05k
    return 1;
294
6.05k
  }
295
0
#endif
296
0
  IR_MAKE_BOTTOM(ref);
297
0
  return 1;
298
0
}
299
300
#if 0
301
IR_ALWAYS_INLINE bool ir_sccp_meet(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref val)
302
{
303
  const ir_insn *val_insn;
304
305
  if (IR_IS_CONST_REF(val)) {
306
    val_insn = &ctx->ir_base[val];
307
  } else {
308
    val_insn = &_values[val].insn;
309
310
    if (!IR_IS_CONST_OP(val_insn->op) && !IR_IS_SYM_CONST(val_insn->op)) {
311
      return ir_sccp_meet_copy(ctx, _values, worklist, ref, val);
312
    }
313
  }
314
315
  return ir_sccp_meet_const(ctx, _values, worklist, ref, val_insn);
316
}
317
#endif
318
319
static ir_ref ir_sccp_fold(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, const ir_insn *insn)
320
9.74k
{
321
9.74k
  const ir_insn *op1_insn, *op2_insn, *op3_insn;
322
9.74k
  ir_ref op1, op2, op3, copy;
323
9.74k
  uint32_t opt = insn->opt;
324
325
9.74k
  op1 = ir_sccp_identity(ctx, _values, insn->op1);
326
9.74k
  op2 = ir_sccp_identity(ctx, _values, insn->op2);
327
9.74k
  op3 = ir_sccp_identity(ctx, _values, insn->op3);
328
329
12.7k
restart:
330
12.7k
  op1_insn = (op1 > 0 && IR_IS_CONST_OP(_values[op1].op)) ? &_values[op1].insn : ctx->ir_base + op1;
331
12.7k
  op2_insn = (op2 > 0 && IR_IS_CONST_OP(_values[op2].op)) ? &_values[op2].insn : ctx->ir_base + op2;
332
12.7k
  op3_insn = (op3 > 0 && IR_IS_CONST_OP(_values[op3].op)) ? &_values[op3].insn : ctx->ir_base + op3;
333
334
12.7k
  switch (ir_folding((ir_ctx*)ctx, opt, op1, op2, op3, op1_insn, op2_insn, op3_insn)) {
335
3.02k
    case IR_FOLD_DO_RESTART:
336
3.02k
      opt = ctx->fold_insn.optx;
337
3.02k
      op1 = ctx->fold_insn.op1;
338
3.02k
      op2 = ctx->fold_insn.op2;
339
3.02k
      op3 = ctx->fold_insn.op3;
340
3.02k
      goto restart;
341
6.05k
    case IR_FOLD_DO_CSE:
342
9.74k
    case IR_FOLD_DO_EMIT:
343
9.74k
      IR_MAKE_BOTTOM_EX(ref);
344
9.74k
      return 1;
345
0
    case IR_FOLD_DO_COPY:
346
0
      copy = ctx->fold_insn.op1;
347
0
      if (IR_IS_CONST_REF(copy)) {
348
0
        insn = &ctx->ir_base[copy];
349
0
        if (insn->op == IR_LONG_CONST) {
350
0
          return ir_sccp_meet_long_const(ctx, _values, worklist, ref, copy, insn);
351
0
        }
352
0
      } else {
353
0
        insn = &_values[copy].insn;
354
0
        if (!IR_IS_CONST_OP(insn->op) && !IR_IS_SYM_CONST(insn->op)) {
355
0
          return ir_sccp_meet_copy(ctx, _values, worklist, ref, copy);
356
0
        }
357
0
        }
358
0
      goto meet_const;
359
0
    case IR_FOLD_DO_CONST:
360
0
      insn = &ctx->fold_insn;
361
0
meet_const:
362
0
      return ir_sccp_meet_const(ctx, _values, worklist, ref, insn);
363
0
    default:
364
0
      IR_ASSERT(0);
365
0
      return 0;
366
12.7k
  }
367
12.7k
}
368
369
static bool ir_sccp_analyze_phi(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref i, const ir_insn *insn)
370
36.7k
{
371
36.7k
  ir_ref j, n, input;
372
36.7k
  const ir_ref *merge_input, *p;
373
36.7k
  const ir_insn *v, *new_const = NULL;
374
36.7k
#if IR_COMBO_COPY_PROPAGATION
375
36.7k
  ir_ref new_copy = IR_UNUSED;
376
36.7k
  ir_ref new_copy_identity = IR_UNUSED;
377
36.7k
  ir_ref phi_identity = ir_sccp_identity(ctx, _values, i);
378
36.7k
#endif
379
380
36.7k
  if (!IR_IS_REACHABLE(insn->op1)) {
381
0
    return 0;
382
0
  }
383
36.7k
  n = insn->inputs_count;
384
36.7k
  if (n > 3 && _values[i].op == IR_TOP) {
385
2.97k
    for (j = 0; j < (n>>2); j++) {
386
1.48k
      _values[i+j+1].optx = IR_BOTTOM; /* keep the tail of a long multislot instruction */
387
1.48k
    }
388
1.48k
  }
389
390
36.7k
  p = insn->ops + 2;
391
36.7k
  merge_input = ctx->ir_base[insn->op1].ops + 1;
392
54.8k
  for (; --n > 0; p++, merge_input++) {
393
48.8k
    IR_ASSERT(*merge_input > 0);
394
48.8k
    if (!IR_IS_REACHABLE(*merge_input)) {
395
6.05k
      continue;
396
6.05k
    }
397
398
42.7k
    input = *p;
399
42.7k
    if (IR_IS_CONST_REF(input)) {
400
3.30k
      v = &ctx->ir_base[input];
401
3.30k
#if IR_COMBO_COPY_PROPAGATION
402
3.30k
      if (v->op == IR_LONG_CONST) {
403
0
        new_copy = input;
404
0
        goto next;
405
0
      }
406
3.30k
#endif
407
39.4k
    } else if (input == i) {
408
0
      continue;
409
39.4k
    } else {
410
39.4k
      v = &_values[input].insn;
411
39.4k
      if (v->op == IR_TOP) {
412
0
        ir_sccp_add_input(ctx, _values, worklist, input);
413
0
        continue;
414
0
#if IR_COMBO_COPY_PROPAGATION
415
39.4k
      } else if (v->op == IR_COPY) {
416
0
        input = v->op1;
417
0
        new_copy_identity = ir_sccp_identity(ctx, _values, input);
418
0
        if (new_copy_identity == phi_identity) {
419
0
          new_copy_identity = IR_UNUSED;
420
0
          continue;
421
0
        }
422
0
        new_copy = input;
423
0
        goto next;
424
39.4k
      } else if (v->op == IR_LONG_CONST) {
425
0
        new_copy = v->val.i32;
426
0
        goto next;
427
0
#endif
428
39.4k
      } else if (v->op == IR_BOTTOM) {
429
39.4k
#if IR_COMBO_COPY_PROPAGATION
430
39.4k
        if (input == phi_identity) {
431
12.0k
          continue;
432
12.0k
        }
433
27.3k
        new_copy = new_copy_identity = input;
434
27.3k
        goto next;
435
#else
436
        goto make_bottom;
437
#endif
438
39.4k
      }
439
39.4k
    }
440
3.30k
    new_const = v;
441
3.30k
    goto next;
442
42.7k
  }
443
444
6.04k
  return 0;
445
446
30.6k
next:
447
30.6k
  p++;
448
30.6k
  merge_input++;
449
  /* for all live merge inputs */
450
36.7k
  for (; --n > 0; p++, merge_input++) {
451
24.6k
    IR_ASSERT(*merge_input > 0);
452
24.6k
    if (!IR_IS_REACHABLE(*merge_input)) {
453
6.05k
      continue;
454
6.05k
    }
455
456
18.5k
    input = *p;
457
18.5k
    if (IR_IS_CONST_REF(input)) {
458
494
#if IR_COMBO_COPY_PROPAGATION
459
494
      if (new_copy) {
460
494
        if (new_copy == input) {
461
0
          continue;
462
0
        }
463
494
        goto make_bottom;
464
494
      }
465
0
#endif
466
0
      v = &ctx->ir_base[input];
467
18.0k
    } else if (input == i) {
468
0
      continue;
469
18.0k
    } else {
470
18.0k
      v = &_values[input].insn;
471
18.0k
      if (v->op == IR_TOP) {
472
0
        ir_sccp_add_input(ctx, _values, worklist, input);
473
0
        continue;
474
0
#if IR_COMBO_COPY_PROPAGATION
475
18.0k
      } else if (v->op == IR_COPY) {
476
0
        ir_ref identity = ir_sccp_identity(ctx, _values, v->op1);
477
478
0
        if (identity == phi_identity || identity == new_copy_identity) {
479
0
          continue;
480
0
        }
481
0
        goto make_bottom;
482
18.0k
      } else if (v->op == IR_LONG_CONST) {
483
0
        if (v->val.i32 == new_copy) {
484
0
          continue;
485
0
        }
486
0
        goto make_bottom;
487
0
#endif
488
18.0k
      } else if (v->op == IR_BOTTOM) {
489
18.0k
#if IR_COMBO_COPY_PROPAGATION
490
18.0k
        if (input  == phi_identity || input == new_copy_identity) {
491
0
          continue;
492
0
        }
493
18.0k
#endif
494
18.0k
        goto make_bottom;
495
18.0k
      }
496
18.0k
    }
497
0
    if (!new_const || new_const->opt != v->opt || new_const->val.u64 != v->val.u64) {
498
0
      goto make_bottom;
499
0
    }
500
0
  }
501
502
12.1k
#if IR_COMBO_COPY_PROPAGATION
503
12.1k
  if (new_copy) {
504
12.1k
    if (IR_IS_CONST_REF(new_copy)) {
505
0
      IR_ASSERT(ctx->ir_base[new_copy].op == IR_LONG_CONST);
506
0
      return ir_sccp_meet_long_const(ctx, _values, worklist, i, new_copy, &ctx->ir_base[new_copy]);
507
0
    }
508
12.1k
    IR_ASSERT(!IR_IS_CONST_REF(new_copy));
509
12.1k
    IR_ASSERT(!IR_IS_CONST_OP(_values[new_copy].op) && !IR_IS_SYM_CONST(_values[new_copy].op));
510
12.1k
    return ir_sccp_meet_copy(ctx, _values, worklist, i, new_copy);
511
12.1k
  }
512
2
#endif
513
514
2
  return ir_sccp_meet_const(ctx, _values, worklist, i, new_const);
515
516
18.5k
make_bottom:
517
18.5k
  IR_MAKE_BOTTOM_EX(i);
518
18.5k
  return 1;
519
12.1k
}
520
521
static bool ir_is_dead_load_ex(const ir_ctx *ctx, ir_ref ref, uint32_t flags, const ir_insn *insn)
522
959k
{
523
959k
  return (flags & IR_OP_FLAG_NO_SIDE_EFFECT) && ctx->use_lists[ref].count == 1;
524
959k
}
525
526
static bool ir_is_dead_load(const ir_ctx *ctx, ir_ref ref)
527
117k
{
528
117k
  if (ctx->use_lists[ref].count == 1) {
529
172
    return (ir_op_flags[ctx->ir_base[ref].op] & IR_OP_FLAG_NO_SIDE_EFFECT) != 0;
530
172
  }
531
116k
  return 0;
532
117k
}
533
534
static bool ir_is_dead(const ir_ctx *ctx, ir_ref ref)
535
2.97k
{
536
2.97k
  if (ctx->use_lists[ref].count == 0) {
537
183
    return IR_IS_FOLDABLE_OP(ctx->ir_base[ref].op);
538
2.79k
  } else {
539
2.79k
    return ir_is_dead_load(ctx, ref);
540
2.79k
  }
541
0
  return 0;
542
2.97k
}
543
544
static bool ir_sccp_is_true(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a)
545
43
{
546
43
  const ir_insn *v = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn;
547
548
43
  return ir_const_is_true(v);
549
43
}
550
551
static bool ir_sccp_is_equal(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a, ir_ref b)
552
0
{
553
0
  const ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn;
554
0
  const ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b].insn;
555
556
0
  IR_ASSERT(!IR_IS_SYM_CONST(v1->op));
557
0
  IR_ASSERT(!IR_IS_SYM_CONST(v2->op));
558
0
  return v1->val.u64 == v2->val.u64;
559
0
}
560
561
static bool ir_sccp_in_range(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a, ir_ref b, ir_ref c)
562
0
{
563
0
  const ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn;
564
0
  const ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b].insn;
565
0
  const ir_insn *v3 = IR_IS_CONST_REF(c) ? &ctx->ir_base[c] : &_values[c].insn;
566
567
0
  IR_ASSERT(!IR_IS_SYM_CONST(v1->op));
568
0
  IR_ASSERT(!IR_IS_SYM_CONST(v2->op));
569
0
  IR_ASSERT(!IR_IS_SYM_CONST(v3->op));
570
0
  if (IR_IS_TYPE_SIGNED(v1->type)) {
571
0
    return v1->val.i64 >= v2->val.i64 && v1->val.i64 <= v3->val.i64;
572
0
  } else {
573
0
    return v1->val.u64 >= v2->val.u64 && v1->val.u64 <= v3->val.u64;
574
0
    }
575
0
}
576
577
#ifdef IR_SCCP_TRACE
578
static void ir_sccp_trace_val(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i)
579
{
580
  if (IR_IS_BOTTOM(i)) {
581
    fprintf(stderr, "BOTTOM");
582
  } else if (IR_IS_CONST_OP(_values[i].op) || IR_IS_SYM_CONST(_values[i].op)) {
583
    fprintf(stderr, "CONST(");
584
    ir_print_const(ctx, &_values[i].insn, stderr, true);
585
    fprintf(stderr, ")");
586
#if IR_COMBO_COPY_PROPAGATION
587
  } else if (_values[i].op == IR_COPY) {
588
    fprintf(stderr, "COPY(%d)", _values[i].op1);
589
#endif
590
  } else if (IR_IS_TOP(i)) {
591
    fprintf(stderr, "TOP");
592
  } else if (_values[i].op == IR_IF) {
593
    fprintf(stderr, "IF(%d)", _values[i].op1);
594
  } else if (_values[i].op == IR_MERGE) {
595
    fprintf(stderr, "MERGE(%d)", _values[i].op1);
596
  } else {
597
    fprintf(stderr, "%d", _values[i].op);
598
  }
599
}
600
601
static void ir_sccp_trace_start(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i)
602
{
603
  fprintf(stderr, "%d. ", i);
604
  ir_sccp_trace_val(ctx, _values, i);
605
}
606
607
static void ir_sccp_trace_end(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i)
608
{
609
  fprintf(stderr, " -> ");
610
  ir_sccp_trace_val(ctx, _values, i);
611
  fprintf(stderr, "\n");
612
}
613
#else
614
# define ir_sccp_trace_start(c, v, i)
615
# define ir_sccp_trace_end(c, v, i)
616
#endif
617
618
static IR_NEVER_INLINE void ir_sccp_analyze(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist)
619
9.93k
{
620
9.93k
  ir_ref i, j, n, use;
621
9.93k
  const ir_ref *p;
622
9.93k
  const ir_use_list *use_list;
623
9.93k
  const ir_insn *insn, *use_insn;
624
9.93k
  uint32_t flags;
625
626
  /* A bit modified SCCP algorithm of M. N. Wegman and F. K. Zadeck */
627
9.93k
  worklist->pos = 0;
628
9.93k
  ir_bitset_incl(worklist->set, 1);
629
1.78M
  for (; (i = ir_bitqueue_pop(worklist)) >= 0; ir_sccp_trace_end(ctx, _values, i)) {
630
1.77M
    IR_ASSERT(_values[i].op != IR_BOTTOM);
631
1.77M
    ir_sccp_trace_start(ctx, _values, i);
632
1.77M
    insn = &ctx->ir_base[i];
633
1.77M
    flags = ir_op_flags[insn->op];
634
1.77M
    if (flags & IR_OP_FLAG_DATA) {
635
377k
      if (ctx->use_lists[i].count == 0) {
636
        /* dead code */
637
2.60k
        continue;
638
374k
      } else if (insn->op == IR_PHI) {
639
36.7k
        if (!ir_sccp_analyze_phi(ctx, _values, worklist, i, insn)) {
640
6.04k
          continue;
641
6.04k
        }
642
337k
      } else if (EXPECTED(IR_IS_FOLDABLE_OP(insn->op))) {
643
337k
        bool may_benefit = 0;
644
337k
        bool has_top = 0;
645
646
337k
        if (_values[i].op != IR_TOP || insn->op == IR_COPY) {
647
3.68k
          may_benefit = 1;
648
3.68k
        }
649
650
337k
        IR_ASSERT(!IR_OP_HAS_VAR_INPUTS(flags));
651
337k
        n = IR_INPUT_EDGES_COUNT(flags);
652
337k
        if (insn->op == IR_DIV || insn->op == IR_MOD) {
653
          /* skip data-control guard edge */
654
1.18k
          n--;
655
1.18k
        }
656
998k
        for (p = insn->ops + 1; n > 0; p++, n--) {
657
661k
          ir_ref input = *p;
658
661k
          if (input > 0) {
659
358k
            if (_values[input].op == IR_TOP) {
660
324
              has_top = 1;
661
324
              ir_sccp_add_input(ctx, _values, worklist, input);
662
358k
            } else if (_values[input].op != IR_BOTTOM) {
663
              /* Perform folding only if some of direct inputs
664
               * is going to be replaced by a constant or copy.
665
               * This approach may miss some folding optimizations
666
               * dependent on indirect inputs. e.g. reassociation.
667
               */
668
6.05k
              may_benefit = 1;
669
6.05k
            }
670
358k
          }
671
661k
        }
672
337k
        if (has_top) {
673
324
          continue;
674
324
        }
675
337k
        if (!may_benefit) {
676
327k
          IR_MAKE_BOTTOM_EX(i);
677
327k
          if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC) {
678
76
            ir_bitqueue_add(iter_worklist, i);
679
76
          }
680
327k
        } else if (!ir_sccp_fold(ctx, _values, worklist, i, insn)) {
681
          /* not changed */
682
0
          continue;
683
9.74k
        } else if (_values[i].op == IR_BOTTOM) {
684
9.74k
          insn = &ctx->ir_base[i];
685
9.74k
          if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC) {
686
0
            ir_bitqueue_add(iter_worklist, i);
687
0
          }
688
9.74k
        }
689
337k
      } else {
690
44
        IR_MAKE_BOTTOM_EX(i);
691
44
        n = IR_INPUT_EDGES_COUNT(flags);
692
88
        for (p = insn->ops + 1; n > 0; p++, n--) {
693
44
          ir_ref input = *p;
694
44
          if (input > 0) {
695
44
            if (_values[input].op == IR_TOP) {
696
0
              ir_sccp_add_input(ctx, _values, worklist, input);
697
0
            }
698
44
          }
699
44
        }
700
44
      }
701
1.39M
    } else if (flags & IR_OP_FLAG_BB_START) {
702
321k
      if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_BEGIN) {
703
79.9k
        ir_bitqueue_add(iter_worklist, i);
704
79.9k
      }
705
321k
      if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
706
78.7k
        ir_ref unfeasible_inputs = 0;
707
708
78.7k
        n = insn->inputs_count;
709
78.7k
        if (n > 3 && _values[i].op == IR_TOP) {
710
10.7k
          for (j = 0; j < (n>>2); j++) {
711
5.38k
            _values[i+j+1].optx = IR_BOTTOM; /* keep the tail of a long multislot instruction */
712
5.38k
          }
713
5.35k
        }
714
270k
        for (p = insn->ops + 1; n > 0; p++, n--) {
715
191k
          const ir_ref input = *p;
716
191k
          IR_ASSERT(input > 0);
717
191k
          if (!IR_IS_REACHABLE(input)) {
718
3.26k
            unfeasible_inputs++;
719
3.26k
          }
720
191k
        }
721
78.7k
        if (unfeasible_inputs == 0) {
722
75.5k
          IR_MAKE_BOTTOM(i);
723
75.5k
        } else if (_values[i].op != IR_MERGE || _values[i].unfeasible_inputs != unfeasible_inputs) {
724
3.26k
          _values[i].optx = IR_MERGE;
725
3.26k
          _values[i].unfeasible_inputs = unfeasible_inputs;
726
3.26k
        } else {
727
0
          continue;
728
0
        }
729
78.7k
        if (ctx->flags2 & IR_MEM2SSA_VARS) {
730
          /* MEM2SSA puts new PHI at the bottom, but we like to process them now */
731
0
          use_list = &ctx->use_lists[i];
732
0
          n = use_list->count;
733
0
          for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
734
0
            use = *p;
735
0
            if (_values[use].op != IR_BOTTOM) {
736
0
              if (ctx->ir_base[use].op == IR_PHI) {
737
0
                ir_bitqueue_del(worklist, use);
738
0
                if (ctx->use_lists[use].count != 0) {
739
0
                  if (ir_sccp_analyze_phi(ctx, _values, worklist, use, &ctx->ir_base[use])) {
740
0
                    ir_sccp_add_uses(ctx, _values, worklist, use);
741
0
                  }
742
0
                }
743
0
              } else {
744
0
                ir_bitqueue_add(worklist, use);
745
0
              }
746
0
            }
747
0
          }
748
0
          continue;
749
0
        }
750
242k
      } else {
751
242k
        IR_ASSERT(insn->op == IR_START || IR_IS_REACHABLE(insn->op1));
752
242k
        IR_MAKE_BOTTOM(i);
753
242k
      }
754
1.07M
    } else {
755
1.07M
      IR_ASSERT(insn->op1 > 0);
756
1.07M
      if (!IR_IS_REACHABLE(insn->op1)) {
757
        /* control inpt is not feasible */
758
10
        continue;
759
10
      }
760
1.07M
      if (insn->op == IR_IF) {
761
114k
        if (IR_IS_TOP(insn->op2)) {
762
0
          ir_sccp_add_input(ctx, _values, worklist, insn->op2);
763
0
          continue;
764
0
        }
765
114k
        if (IR_IS_CONST(insn->op2)) {
766
43
          bool b = ir_sccp_is_true(ctx, _values, insn->op2);
767
43
          use_list = &ctx->use_lists[i];
768
43
          IR_ASSERT(use_list->count == 2);
769
43
          p = &ctx->use_edges[use_list->refs];
770
43
          use = *p;
771
43
          use_insn = &ctx->ir_base[use];
772
43
          IR_ASSERT(use_insn->op == IR_IF_TRUE || use_insn->op == IR_IF_FALSE);
773
43
          if ((use_insn->op == IR_IF_TRUE) != b) {
774
22
            use = *(p+1);
775
22
            IR_ASSERT(ctx->ir_base[use].op == IR_IF_TRUE || ctx->ir_base[use].op == IR_IF_FALSE);
776
22
          }
777
43
          if (_values[i].op == IR_TOP) {
778
43
            _values[i].optx = IR_IF;
779
43
            _values[i].single_output = use;
780
43
            ir_bitqueue_add(worklist, use);
781
43
            continue;
782
43
          } else if (_values[i].op == IR_IF && _values[i].single_output == use) {
783
0
            continue;
784
0
          }
785
43
        }
786
114k
        IR_MAKE_BOTTOM(i);
787
114k
        ir_bitqueue_add(iter_worklist, i);
788
959k
      } else if (insn->op == IR_SWITCH) {
789
6
        if (IR_IS_TOP(insn->op2)) {
790
0
          ir_sccp_add_input(ctx, _values, worklist, insn->op2);
791
0
          continue;
792
0
        }
793
6
        if (IR_IS_CONST(insn->op2)) {
794
0
          ir_ref use_case = IR_UNUSED;
795
796
0
          use_list = &ctx->use_lists[i];
797
0
          n = use_list->count;
798
0
          for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
799
0
            use = *p;
800
0
            IR_ASSERT(use > 0);
801
0
            use_insn = &ctx->ir_base[use];
802
0
            if (use_insn->op == IR_CASE_VAL) {
803
0
              if (ir_sccp_is_equal(ctx, _values, insn->op2, use_insn->op2)) {
804
0
                use_case = use;
805
0
                break;
806
0
              }
807
0
            } else if (use_insn->op == IR_CASE_DEFAULT) {
808
0
              use_case = use;
809
0
            } else if (use_insn->op == IR_CASE_RANGE) {
810
0
              if (ir_sccp_in_range(ctx, _values, insn->op2, use_insn->op2, use_insn->op3)) {
811
0
                use_case = use;
812
0
                break;
813
0
              }
814
0
            }
815
0
          }
816
0
          if (use_case) {
817
0
            use_insn = &ctx->ir_base[use_case];
818
0
            if (_values[i].op == IR_TOP) {
819
0
              _values[i].optx = IR_IF;
820
0
              _values[i].single_output = use_case;
821
0
              ir_bitqueue_add(worklist, use_case);
822
0
              continue;
823
0
            } else if (_values[i].op == IR_IF || _values[i].single_output == use_case) {
824
0
              continue;
825
0
            }
826
0
          }
827
0
        }
828
6
        IR_MAKE_BOTTOM(i);
829
959k
      } else if (ir_is_dead_load_ex(ctx, i, flags, insn)) {
830
        /* schedule dead load elimination */
831
101
        ir_bitqueue_add(iter_worklist, i);
832
101
        IR_MAKE_BOTTOM(i);
833
959k
      } else {
834
        /* control, call, load and store instructions may have unprocessed inputs */
835
959k
        n = IR_INPUT_EDGES_COUNT(flags);
836
959k
        if (IR_OP_HAS_VAR_INPUTS(flags) && (n = insn->inputs_count) > 3) {
837
76.1k
          for (j = 0; j < (n>>2); j++) {
838
38.0k
            _values[i+j+1].optx = IR_BOTTOM; /* keep the tail of a long multislot instruction */
839
38.0k
          }
840
156k
          for (j = 2, p = insn->ops + j; j <= n; j++, p++) {
841
118k
            IR_ASSERT(IR_OPND_KIND(flags, j) == IR_OPND_DATA);
842
118k
            use = *p;
843
118k
            if (use > 0 && _values[use].op == IR_TOP) {
844
0
              ir_sccp_add_input(ctx, _values, worklist, use);
845
0
            }
846
118k
          }
847
921k
        } else if (n >= 2) {
848
518k
          IR_ASSERT(IR_OPND_KIND(flags, 2) == IR_OPND_DATA);
849
518k
          use = insn->op2;
850
518k
          if (use > 0 && _values[use].op == IR_TOP) {
851
0
            ir_sccp_add_input(ctx, _values, worklist, use);
852
0
          }
853
518k
          if (n > 2) {
854
232k
            IR_ASSERT(n == 3);
855
232k
            IR_ASSERT(IR_OPND_KIND(flags, 3) == IR_OPND_DATA);
856
232k
            use = insn->op3;
857
232k
            if (use > 0 && _values[use].op == IR_TOP) {
858
48
              ir_sccp_add_input(ctx, _values, worklist, use);
859
48
            }
860
232k
          }
861
518k
        }
862
959k
        IR_MAKE_BOTTOM(i);
863
959k
      }
864
1.07M
    }
865
1.76M
    ir_sccp_add_uses(ctx, _values, worklist, i);
866
1.76M
  }
867
868
9.93k
#ifdef IR_DEBUG
869
9.93k
  if (ctx->flags & IR_DEBUG_SCCP) {
870
0
    for (i = 1; i < ctx->insns_count; i++) {
871
0
      if (IR_IS_CONST_OP(_values[i].op) || IR_IS_SYM_CONST(_values[i].op)) {
872
0
        fprintf(stderr, "%d. CONST(", i);
873
0
        ir_print_const(ctx, &_values[i].insn, stderr, true);
874
0
        fprintf(stderr, ")\n");
875
0
#if IR_COMBO_COPY_PROPAGATION
876
0
      } else if (_values[i].op == IR_COPY) {
877
0
        fprintf(stderr, "%d. COPY(%d)\n", i, _values[i].copy);
878
0
      } else if (_values[i].op == IR_LONG_CONST) {
879
0
        fprintf(stderr, "%d. LONG_CONST(%d)\n", i, _values[i].val.i32);
880
0
#endif
881
0
      } else if (IR_IS_TOP(i)) {
882
0
        if (ctx->ir_base[i].op != IR_TOP) {
883
0
          fprintf(stderr, "%d. TOP\n", i);
884
0
        }
885
0
      } else if (_values[i].op == IR_IF) {
886
0
        fprintf(stderr, "%d. IF(%d)\n", i, _values[i].single_output);
887
0
      } else if (_values[i].op == IR_MERGE) {
888
0
        fprintf(stderr, "%d. MERGE(%d)\n", i, _values[i].unfeasible_inputs);
889
0
      } else if (!IR_IS_BOTTOM(i)) {
890
0
        fprintf(stderr, "%d. %d\n", i, _values[i].op);
891
0
      }
892
0
    }
893
0
  }
894
9.93k
#endif
895
9.93k
}
896
897
/**********************/
898
/* SCCP trasformation */
899
/**********************/
900
901
static void ir_sccp_make_nop(ir_ctx *ctx, ir_ref ref)
902
86
{
903
86
  ir_ref j, n, *p;
904
86
  ir_insn *insn;
905
906
86
  CLEAR_USES(ref);
907
86
  insn = &ctx->ir_base[ref];
908
86
  n = insn->inputs_count;
909
86
  insn->opt = IR_NOP; /* keep "inputs_count" */
910
215
  for (j = 1, p = insn->ops + j; j <= n; j++, p++) {
911
129
    *p = IR_UNUSED;
912
129
  }
913
86
}
914
915
static void ir_sccp_remove_insn(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_bitqueue *worklist)
916
3.77k
{
917
3.77k
  ir_ref j, n, *p;
918
3.77k
  ir_insn *insn;
919
920
3.77k
  CLEAR_USES(ref);
921
3.77k
  insn = &ctx->ir_base[ref];
922
3.77k
  n = insn->inputs_count;
923
3.77k
  insn->opt = IR_NOP; /* keep "inputs_count" */
924
11.4k
  for (j = 1, p = insn->ops + j; j <= n; j++, p++) {
925
7.64k
    ir_ref input = *p;
926
7.64k
    *p = IR_UNUSED;
927
    /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */
928
7.64k
    if (input > 0 && _values[input].op > IR_COPY) {
929
2.64k
      ir_use_list_remove_one(ctx, input, ref);
930
2.64k
      if (ir_is_dead(ctx, input)) {
931
        /* schedule DCE */
932
33
        ir_bitqueue_add(worklist, input);
933
33
      }
934
2.64k
    }
935
7.64k
  }
936
3.77k
}
937
938
static void ir_sccp_replace_insn(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_ref new_ref, ir_bitqueue *worklist)
939
728
{
940
728
  ir_ref j, n, *p, use, i;
941
728
  ir_insn *insn;
942
728
  ir_use_list *use_list;
943
944
728
  IR_ASSERT(ref != new_ref);
945
946
728
  insn = &ctx->ir_base[ref];
947
948
728
#if IR_COMBO_COPY_PROPAGATION
949
728
  if ((ir_op_flags[insn->op] & IR_OP_FLAG_MEM) && IR_IS_REACHABLE(insn->op1)) {
950
    /* remove from control list */
951
0
    ir_ref prev = insn->op1;
952
0
    ir_ref next = ir_next_control(ctx, ref);
953
0
    ctx->ir_base[next].op1 = prev;
954
0
    ir_use_list_remove_one(ctx, ref, next);
955
0
    ir_use_list_replace_one(ctx, prev, ref, next);
956
0
    insn->op1 = IR_UNUSED;
957
0
  }
958
728
#endif
959
960
728
  n = insn->inputs_count;
961
728
  insn->opt = IR_NOP; /* keep "inputs_count" */
962
1.78k
  for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
963
1.05k
    ir_ref input = *p;
964
1.05k
    *p = IR_UNUSED;
965
    /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */
966
1.05k
    if (input > 0 && _values[input].op > IR_COPY) {
967
59
      ir_use_list_remove_one(ctx, input, ref);
968
59
      if (ir_is_dead(ctx, input)) {
969
        /* schedule DCE */
970
49
        ir_bitqueue_add(worklist, input);
971
49
      }
972
59
    }
973
1.05k
  }
974
975
728
  use_list = &ctx->use_lists[ref];
976
728
  n = use_list->count;
977
728
  p = &ctx->use_edges[use_list->refs];
978
728
  if (new_ref <= 0) {
979
    /* constant or IR_UNUSED */
980
1.56k
    for (; n; p++, n--) {
981
837
      use = *p;
982
      /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */
983
837
      if (_values[use].op > IR_COPY) {
984
48
        insn = &ctx->ir_base[use];
985
48
        i = ir_insn_find_op(insn, ref);
986
48
        if (!i) continue;
987
48
        IR_ASSERT(i > 0);
988
48
        ir_insn_set_op(insn, i, new_ref);
989
        /* schedule folding */
990
48
        ir_bitqueue_add(worklist, use);
991
48
      }
992
837
    }
993
724
  } else {
994
18
    for (j = 0; j < n; j++, p++) {
995
14
      use = *p;
996
      /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */
997
14
      if (_values[use].op == IR_BOTTOM) {
998
14
        insn = &ctx->ir_base[use];
999
14
        i = ir_insn_find_op(insn, ref);
1000
14
        IR_ASSERT(i > 0);
1001
14
        ir_insn_set_op(insn, i, new_ref);
1002
14
        if (ir_use_list_add(ctx, new_ref, use)) {
1003
          /* restore after reallocation */
1004
4
          use_list = &ctx->use_lists[ref];
1005
4
          n = use_list->count;
1006
4
          p = &ctx->use_edges[use_list->refs + j];
1007
4
        }
1008
        /* schedule folding */
1009
14
        ir_bitqueue_add(worklist, use);
1010
14
      }
1011
14
    }
1012
4
  }
1013
728
  CLEAR_USES(ref);
1014
728
}
1015
1016
static void ir_sccp_remove_if(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_ref dst)
1017
43
{
1018
43
  ir_ref next;
1019
43
  ir_insn *insn, *next_insn;
1020
1021
43
  insn = &ctx->ir_base[ref];
1022
43
  if (ctx->use_lists[dst].count == 1) {
1023
43
    next = ctx->use_edges[ctx->use_lists[dst].refs];
1024
43
    next_insn = &ctx->ir_base[next];
1025
    /* remove IF and IF_TRUE/FALSE from double linked control list */
1026
43
    next_insn->op1 = insn->op1;
1027
43
    ir_use_list_replace_one(ctx, insn->op1, ref, next);
1028
    /* remove IF and IF_TRUE/FALSE instructions */
1029
43
    ir_sccp_make_nop(ctx, ref);
1030
43
    ir_sccp_make_nop(ctx, dst);
1031
43
  } else {
1032
0
    insn->op2 = IR_UNUSED;
1033
0
    insn->optx = IR_OPTX(IR_END, IR_VOID, 1);
1034
0
    next_insn = &ctx->ir_base[dst];
1035
0
    next_insn->op = IR_BEGIN;
1036
0
    next_insn->op2 = IR_UNUSED;
1037
0
  }
1038
43
}
1039
1040
static bool ir_sccp_remove_unfeasible_merge_inputs(ir_ctx *ctx, ir_ref ref, ir_insn *insn, ir_bitqueue *worklist)
1041
46
{
1042
46
  ir_ref old_merge_inputs, new_merge_inputs, i, *p;
1043
46
  ir_use_list *use_list;
1044
46
  ir_bitset life_inputs;
1045
46
  ir_bitset_base_t holder = 0;
1046
1047
46
  IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
1048
46
  old_merge_inputs = insn->inputs_count;
1049
46
  new_merge_inputs = 0;
1050
46
  life_inputs = (old_merge_inputs < IR_BITSET_BITS) ? &holder : ir_bitset_malloc(old_merge_inputs + 1);
1051
1052
140
  for (i = 1; i <= old_merge_inputs; i++) {
1053
94
    ir_ref input = ir_insn_op(insn, i);
1054
1055
94
    if (input) {
1056
48
      new_merge_inputs++;
1057
48
      if (new_merge_inputs != i) {
1058
31
        ir_insn_set_op(insn, new_merge_inputs, input);
1059
31
      }
1060
48
      ir_bitset_incl(life_inputs, i);
1061
48
    }
1062
94
  }
1063
1064
46
  if (new_merge_inputs == old_merge_inputs) {
1065
    /* All inputs are feasible */
1066
0
    if (life_inputs != &holder) {
1067
0
      ir_mem_free(life_inputs);
1068
0
    }
1069
0
    return 0;
1070
0
  }
1071
1072
92
  for (i = new_merge_inputs + 1; i <= old_merge_inputs; i++) {
1073
46
    ir_insn_set_op(insn, i, IR_UNUSED);
1074
46
  }
1075
1076
46
  if (new_merge_inputs <= 1) {
1077
#if 0
1078
    if (new_merge_inputs == 1
1079
     && insn->op == IR_LOOP_BEGIN
1080
     && insn->op1 > ref) { // TODO: check dominance instead of order
1081
      /* dead loop */
1082
      ir_use_list_remove_one(ctx, insn->op1, ref);
1083
      insn->op1 = IR_UNUSED;
1084
      new_merge_inputs = 0;
1085
    }
1086
#endif
1087
44
    insn->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1);
1088
44
    ir_bitqueue_add(worklist, ref);
1089
44
  } else {
1090
2
    insn->inputs_count = new_merge_inputs;
1091
2
  }
1092
1093
  /* Update PHIs */
1094
46
  use_list = &ctx->use_lists[ref];
1095
46
  if (use_list->count > 1) {
1096
0
    ir_ref use_count = 0;
1097
0
    ir_ref *q;
1098
1099
0
    for (i = 0, p = q = &ctx->use_edges[use_list->refs]; i < use_list->count; p++, i++) {
1100
0
      ir_ref use = *p;
1101
0
      ir_insn *use_insn = &ctx->ir_base[use];
1102
1103
0
      if (use_insn->op == IR_PHI) {
1104
0
        ir_ref j, k;
1105
1106
        /* compress PHI */
1107
0
        for (j = k = 1; j <= old_merge_inputs; j++) {
1108
0
          ir_ref input = ir_insn_op(use_insn, j + 1);
1109
1110
0
          if (ir_bitset_in(life_inputs, j)) {
1111
0
            IR_ASSERT(input);
1112
0
            if (k != j) {
1113
0
              ir_insn_set_op(use_insn, k + 1, input);
1114
0
            }
1115
0
            k++;
1116
0
          } else if (input > 0) {
1117
0
            ir_use_list_remove_one(ctx, input, use);
1118
0
          }
1119
0
        }
1120
0
        while (k <= old_merge_inputs) {
1121
0
          k++;
1122
0
          ir_insn_set_op(use_insn, k, IR_UNUSED);
1123
0
        }
1124
1125
0
        if (new_merge_inputs == 0) {
1126
          /* remove PHI */
1127
#if 0
1128
          use_insn->op1 = IR_UNUSED;
1129
          ir_iter_remove_insn(ctx, use);
1130
#else
1131
0
          IR_ASSERT(0);
1132
0
#endif
1133
0
          continue;
1134
0
        } else if (new_merge_inputs == 1) {
1135
          /* replace PHI by COPY */
1136
0
          use_insn->optx = IR_OPTX(IR_COPY, use_insn->type, 1);
1137
0
          use_insn->op1 = use_insn->op2;
1138
0
          use_insn->op2 = IR_UNUSED;
1139
0
          ir_bitqueue_add(worklist, use);
1140
0
          continue;
1141
0
        } else {
1142
0
          use_insn->inputs_count = new_merge_inputs + 1;
1143
0
        }
1144
0
      }
1145
0
      if (p != q) {
1146
0
        *q = use;
1147
0
      }
1148
0
      q++;
1149
0
      use_count++;
1150
0
    }
1151
0
    for (i = use_count; i < use_list->count; q++, i++) {
1152
0
      *q = IR_UNUSED;
1153
0
    }
1154
0
    use_list->count = use_count;
1155
0
  }
1156
1157
46
  if (life_inputs != &holder) {
1158
0
    ir_mem_free(life_inputs);
1159
0
  }
1160
1161
46
  return 1;
1162
46
}
1163
1164
static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, const ir_sccp_val *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist)
1165
9.93k
{
1166
9.93k
  ir_ref i, j;
1167
9.93k
  const ir_sccp_val *value;
1168
1169
1.81M
  for (i = 1, value = _values + i; i < ctx->insns_count; value++, i++) {
1170
1.80M
    if (value->op == IR_BOTTOM) {
1171
1.79M
      continue;
1172
1.79M
    } else if (IR_IS_CONST_OP(value->op)) {
1173
      /* replace instruction by constant */
1174
2
      j = ir_const(ctx, value->val, value->type);
1175
2
      ir_sccp_replace_insn(ctx, _values, i, j, iter_worklist);
1176
4.62k
    } else if (IR_IS_SYM_CONST(value->op)) {
1177
      /* replace instruction by constant */
1178
0
      j = ir_const_ex(ctx, value->val, value->type, value->optx);
1179
0
      ir_sccp_replace_insn(ctx, _values, i, j, iter_worklist);
1180
0
#if IR_COMBO_COPY_PROPAGATION
1181
4.62k
    } else if (value->op == IR_COPY) {
1182
4
      ir_sccp_replace_insn(ctx, _values, i, ir_sccp_identity(ctx, _values, value->copy), iter_worklist);
1183
4.62k
    } else if (value->op == IR_LONG_CONST) {
1184
0
      ir_sccp_replace_insn(ctx, _values, i, value->val.i32, iter_worklist);
1185
0
#endif
1186
4.62k
    } else if (value->op == IR_TOP) {
1187
      /* remove unreachable instruction */
1188
4.53k
      ir_insn *insn = &ctx->ir_base[i];
1189
1190
4.53k
      if (insn->op == IR_NOP) {
1191
        /* already removed */
1192
4.50k
      } else if (ir_op_flags[insn->op] & (IR_OP_FLAG_DATA|IR_OP_FLAG_MEM)) {
1193
3.77k
        if (insn->op != IR_PARAM) {
1194
3.77k
          ir_sccp_remove_insn(ctx, _values, i, iter_worklist);
1195
3.77k
        }
1196
3.77k
      } else {
1197
722
        if (ir_op_flags[insn->op] & IR_OP_FLAG_TERMINATOR) {
1198
          /* remove from terminators list */
1199
18
          ir_ref prev = ctx->ir_base[1].op1;
1200
18
          if (prev == i) {
1201
10
            ctx->ir_base[1].op1 = insn->op3;
1202
10
          } else {
1203
8
            while (prev) {
1204
8
              if (ctx->ir_base[prev].op3 == i) {
1205
8
                ctx->ir_base[prev].op3 = insn->op3;
1206
8
                break;
1207
8
              }
1208
0
              prev = ctx->ir_base[prev].op3;
1209
0
            }
1210
8
          }
1211
18
        }
1212
722
        ir_sccp_replace_insn(ctx, _values, i, IR_UNUSED, iter_worklist);
1213
722
      }
1214
4.53k
    } else if (value->op == IR_IF) {
1215
      /* remove one way IF/SWITCH */
1216
43
      ir_sccp_remove_if(ctx, _values, i, value->single_output);
1217
46
    } else if (value->op == IR_MERGE) {
1218
      /* schedule merge to remove unfeasible MERGE inputs */
1219
46
      ir_bitqueue_add(worklist, i);
1220
46
    }
1221
1.80M
  }
1222
1223
9.98k
  while ((i = ir_bitqueue_pop(worklist)) >= 0) {
1224
46
    IR_ASSERT(_values[i].op == IR_MERGE);
1225
46
    ir_sccp_remove_unfeasible_merge_inputs(ctx, i, &ctx->ir_base[i], iter_worklist);
1226
46
  }
1227
9.93k
}
1228
1229
/***************************/
1230
/* Iterative Optimizations */
1231
/***************************/
1232
1233
void ir_iter_add_uses(ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist)
1234
4
{
1235
4
  ir_use_list *use_list = &ctx->use_lists[ref];
1236
4
  ir_ref *p, n = use_list->count;
1237
1238
14
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1239
10
    ir_bitqueue_add(worklist, *p);
1240
10
  }
1241
4
}
1242
1243
/* Modification of some instruction may open new optimization oprtunities for other
1244
 * instructions that use this one.
1245
 *
1246
 * For example, let "a = ADD(x, y)" became "a = ADD(x, C1)". In case we also have
1247
 * "b = ADD(a, C2)" we may optimize it into "b = ADD(x, C1 + C2)" and then might
1248
 * also remove "a".
1249
 *
1250
 * This implementation supports only few optimization of combinations from ir_fold.h
1251
 *
1252
 * TODO: Think abput a more general solution ???
1253
 */
1254
static void ir_iter_add_related_uses(const ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist)
1255
20
{
1256
20
  const ir_insn *insn = &ctx->ir_base[ref];
1257
1258
20
  if (insn->op == IR_ADD || insn->op == IR_SUB) {
1259
0
    const ir_use_list *use_list = &ctx->use_lists[ref];
1260
1261
0
    if (use_list->count == 1) {
1262
0
      ir_ref use = ctx->use_edges[use_list->refs];
1263
0
      const ir_insn *use_insn = &ctx->ir_base[ref];
1264
1265
0
      if (use_insn->op == IR_ADD || use_insn->op == IR_SUB) {
1266
0
        ir_bitqueue_add(worklist, use);
1267
0
      }
1268
0
    }
1269
0
  }
1270
20
}
1271
1272
static void ir_iter_remove_insn(ir_ctx *ctx, ir_ref ref)
1273
293
{
1274
293
  ir_ref j, n, *p;
1275
293
  ir_insn *insn;
1276
1277
293
  CLEAR_USES(ref);
1278
293
  insn = &ctx->ir_base[ref];
1279
293
  n = insn->inputs_count;
1280
293
  insn->opt = IR_NOP; /* keep "inputs_count" */
1281
870
  for (j = 1, p = insn->ops + j; j <= n; j++, p++) {
1282
577
    ir_ref input = *p;
1283
577
    *p = IR_UNUSED;
1284
577
    if (input > 0) {
1285
246
      ir_use_list_remove_one(ctx, input, ref);
1286
246
      if (ir_is_dead(ctx, input)) {
1287
        /* schedule DCE */
1288
96
        ir_bitqueue_add(ctx->iter_worklist, input);
1289
150
      } else if (ctx->ir_base[input].op == IR_PHI && ctx->use_lists[input].count == 1) {
1290
        /* try to optimize PHI into ABS/MIN/MAX/COND */
1291
0
        ir_bitqueue_add(ctx->iter_worklist, ctx->ir_base[input].op1);
1292
0
      }
1293
246
    }
1294
577
  }
1295
293
}
1296
1297
void ir_iter_replace(ir_ctx *ctx, ir_ref ref, ir_ref new_ref, ir_bitqueue *worklist)
1298
21
{
1299
21
  ir_ref i, j, n, *p, use;
1300
21
  ir_insn *insn;
1301
21
  ir_use_list *use_list;
1302
1303
21
  IR_ASSERT(ref != new_ref);
1304
1305
21
  use_list = &ctx->use_lists[ref];
1306
21
  n = use_list->count;
1307
21
  p = &ctx->use_edges[use_list->refs];
1308
21
  if (new_ref <= 0) {
1309
    /* constant or IR_UNUSED */
1310
34
    for (; n; p++, n--) {
1311
20
      use = *p;
1312
20
      IR_ASSERT(use != ref);
1313
20
      insn = &ctx->ir_base[use];
1314
20
      i = ir_insn_find_op(insn, ref);
1315
20
      IR_ASSERT(i > 0);
1316
20
      ir_insn_set_op(insn, i, new_ref);
1317
      /* schedule folding */
1318
20
      ir_bitqueue_add(worklist, use);
1319
20
      ir_iter_add_related_uses(ctx, use, worklist);
1320
20
    }
1321
14
  } else {
1322
18
    for (j = 0; j < n; j++, p++) {
1323
11
      use = *p;
1324
11
      IR_ASSERT(use != ref);
1325
11
      insn = &ctx->ir_base[use];
1326
11
      i = ir_insn_find_op(insn, ref);
1327
11
      IR_ASSERT(i > 0);
1328
11
      ir_insn_set_op(insn, i, new_ref);
1329
11
      if (ir_use_list_add(ctx, new_ref, use)) {
1330
        /* restore after reallocation */
1331
4
        use_list = &ctx->use_lists[ref];
1332
4
        n = use_list->count;
1333
4
        p = &ctx->use_edges[use_list->refs + j];
1334
4
      }
1335
      /* schedule folding */
1336
11
      ir_bitqueue_add(worklist, use);
1337
11
    }
1338
7
  }
1339
21
}
1340
1341
static void ir_iter_replace_insn(ir_ctx *ctx, ir_ref ref, ir_ref new_ref)
1342
21
{
1343
21
  ir_ref j, n, *p;
1344
21
  ir_insn *insn;
1345
1346
21
  insn = &ctx->ir_base[ref];
1347
21
  n = insn->inputs_count;
1348
21
  insn->opt = IR_NOP; /* keep "inputs_count" */
1349
59
  for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
1350
38
    ir_ref input = *p;
1351
38
    *p = IR_UNUSED;
1352
38
    if (input > 0) {
1353
7
      ir_use_list_remove_one(ctx, input, ref);
1354
7
      if (ir_is_dead(ctx, input)) {
1355
        /* schedule DCE */
1356
0
        ir_bitqueue_add(ctx->iter_worklist, input);
1357
7
      } else if (ctx->ir_base[input].op == IR_PHI && ctx->use_lists[input].count == 1) {
1358
        /* try to optimize PHI into ABS/MIN/MAX/COND */
1359
0
        ir_bitqueue_add(ctx->iter_worklist, ctx->ir_base[input].op1);
1360
0
      }
1361
7
    }
1362
38
  }
1363
1364
21
  ir_iter_replace(ctx, ref, new_ref, ctx->iter_worklist);
1365
1366
21
  CLEAR_USES(ref);
1367
21
}
1368
1369
static void ir_iter_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val)
1370
14
{
1371
14
  ir_insn *insn = &ctx->ir_base[ref];
1372
14
  ir_ref old_val = ir_insn_op(insn, idx);
1373
1374
14
  IR_ASSERT(old_val != new_val);
1375
14
  if (!IR_IS_CONST_REF(new_val)) {
1376
14
    ir_use_list_add(ctx, new_val, ref);
1377
14
  }
1378
14
  ir_insn_set_op(insn, idx, new_val);
1379
14
  if (!IR_IS_CONST_REF(old_val)) {
1380
14
    ir_use_list_remove_one(ctx, old_val, ref);
1381
14
    if (ir_is_dead(ctx, old_val)) {
1382
      /* schedule DCE */
1383
14
      ir_bitqueue_add(ctx->iter_worklist, old_val);
1384
14
    }
1385
14
  }
1386
14
}
1387
1388
static ir_ref ir_iter_find_cse1(const ir_ctx *ctx, uint32_t optx, ir_ref op1)
1389
0
{
1390
0
  IR_ASSERT(!IR_IS_CONST_REF(op1));
1391
1392
0
  const ir_use_list *use_list = &ctx->use_lists[op1];
1393
0
  const ir_ref *p;
1394
0
  ir_ref n = use_list->count;
1395
1396
0
  for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) {
1397
0
    ir_ref use = *p;
1398
0
    const ir_insn *use_insn = &ctx->ir_base[use];
1399
1400
0
    if (use_insn->optx == optx) {
1401
0
      IR_ASSERT(use_insn->op1 == op1);
1402
0
      return use;
1403
0
    }
1404
0
  }
1405
0
  return IR_UNUSED;
1406
0
}
1407
1408
static ir_ref ir_iter_find_cse(const ir_ctx *ctx, ir_ref ref, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
1409
80
{
1410
80
  uint32_t n = IR_INPUT_EDGES_COUNT(ir_op_flags[opt & IR_OPT_OP_MASK]);
1411
80
  const ir_use_list *use_list = NULL;
1412
80
  const ir_ref *p;
1413
80
  ir_ref use;
1414
80
  const ir_insn *use_insn;
1415
1416
80
  if (n == 2) {
1417
4
    if (!IR_IS_CONST_REF(op1)) {
1418
4
      use_list = &ctx->use_lists[op1];
1419
4
    }
1420
4
    if (!IR_IS_CONST_REF(op2) && (!use_list || use_list->count > ctx->use_lists[op2].count)) {
1421
0
      use_list = &ctx->use_lists[op2];
1422
0
    }
1423
4
    if (use_list) {
1424
4
      n = use_list->count;
1425
12
      for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) {
1426
12
        use = *p;
1427
12
        if (use != ref) {
1428
12
          use_insn = &ctx->ir_base[use];
1429
12
          if (use_insn->opt == opt && use_insn->op1 == op1 && use_insn->op2 == op2) {
1430
4
            IR_ASSERT(use_insn->op3 == op3);
1431
4
            if (use < ref) {
1432
4
              return use;
1433
4
            } else {
1434
0
              ir_bitqueue_add(ctx->iter_worklist, use);
1435
0
            }
1436
4
          }
1437
12
        }
1438
12
      }
1439
4
    }
1440
76
   } else if (n < 2) {
1441
76
    if (op1 > 0) {
1442
76
      IR_ASSERT(n == 1);
1443
76
      use_list = &ctx->use_lists[op1];
1444
76
      n = use_list->count;
1445
232
      for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) {
1446
156
        use = *p;
1447
156
        if (use != ref) {
1448
80
          use_insn = &ctx->ir_base[use];
1449
80
          if (use_insn->opt == opt) {
1450
0
            IR_ASSERT(use_insn->op1 == op1);
1451
0
            IR_ASSERT(use_insn->op2 == op2);
1452
0
            IR_ASSERT(use_insn->op3 == op3);
1453
0
            if (use < ref) {
1454
0
              return use;
1455
0
            } else {
1456
0
              ir_bitqueue_add(ctx->iter_worklist, use);
1457
0
            }
1458
0
          }
1459
80
        }
1460
156
      }
1461
76
    }
1462
76
  } else {
1463
0
    IR_ASSERT(n == 3);
1464
0
    if (!IR_IS_CONST_REF(op1)) {
1465
0
      use_list = &ctx->use_lists[op1];
1466
0
    }
1467
0
    if (!IR_IS_CONST_REF(op2) && (!use_list || use_list->count > ctx->use_lists[op2].count)) {
1468
0
      use_list = &ctx->use_lists[op2];
1469
0
    }
1470
0
    if (op3 > 0 && (!use_list || use_list->count > ctx->use_lists[op3].count)) {
1471
0
      use_list = &ctx->use_lists[op3];
1472
0
    }
1473
0
    if (use_list) {
1474
0
      n = use_list->count;
1475
0
      for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) {
1476
0
        use = *p;
1477
0
        if (use != ref) {
1478
0
          use_insn = &ctx->ir_base[use];
1479
0
          if (use_insn->opt == opt && use_insn->op1 == op1 && use_insn->op2 == op2 && use_insn->op3 == op3) {
1480
0
            if (use < ref) {
1481
0
              return use;
1482
0
            } else {
1483
0
              ir_bitqueue_add(ctx->iter_worklist, use);
1484
0
            }
1485
0
          }
1486
0
        }
1487
0
      }
1488
0
    }
1489
0
  }
1490
76
  return IR_UNUSED;
1491
80
}
1492
1493
static void ir_iter_fold(ir_ctx *ctx, ir_ref ref)
1494
90
{
1495
90
  uint32_t opt;
1496
90
  ir_ref op1, op2, op3, copy;
1497
90
  const ir_insn *op1_insn, *op2_insn, *op3_insn;
1498
90
  ir_insn *insn;
1499
1500
90
  insn = &ctx->ir_base[ref];
1501
90
  opt = insn->opt;
1502
90
  op1 = insn->op1;
1503
90
  op2 = insn->op2;
1504
90
  op3 = insn->op3;
1505
1506
94
restart:
1507
94
  op1_insn = ctx->ir_base + op1;
1508
94
  op2_insn = ctx->ir_base + op2;
1509
94
  op3_insn = ctx->ir_base + op3;
1510
1511
94
  switch (ir_folding(ctx, opt, op1, op2, op3, op1_insn, op2_insn, op3_insn)) {
1512
4
    case IR_FOLD_DO_RESTART:
1513
4
      opt = ctx->fold_insn.optx;
1514
4
      op1 = ctx->fold_insn.op1;
1515
4
      op2 = ctx->fold_insn.op2;
1516
4
      op3 = ctx->fold_insn.op3;
1517
4
      goto restart;
1518
80
    case IR_FOLD_DO_CSE:
1519
80
      copy = ir_iter_find_cse(ctx, ref, ctx->fold_insn.opt,
1520
80
        ctx->fold_insn.op1, ctx->fold_insn.op2, ctx->fold_insn.op3);
1521
80
      if (copy) {
1522
4
        ir_iter_replace_insn(ctx, ref, copy);
1523
4
        break;
1524
4
      }
1525
76
      IR_FALLTHROUGH;
1526
76
    case IR_FOLD_DO_EMIT:
1527
76
      insn = &ctx->ir_base[ref];
1528
76
      if (insn->opt != ctx->fold_insn.opt
1529
76
       || insn->op1 != ctx->fold_insn.op1
1530
76
       || insn->op2 != ctx->fold_insn.op2
1531
76
       || insn->op3 != ctx->fold_insn.op3) {
1532
1533
0
        insn->optx = ctx->fold_insn.opt;
1534
0
        IR_ASSERT(!IR_OP_HAS_VAR_INPUTS(ir_op_flags[opt & IR_OPT_OP_MASK]));
1535
0
        insn->inputs_count = IR_INPUT_EDGES_COUNT(ir_op_flags[opt & IR_OPT_OP_MASK]);
1536
0
        if (insn->op1 != ctx->fold_insn.op1) {
1537
0
          if (insn->op1 > 0) {
1538
0
            ir_use_list_remove_one(ctx, insn->op1, ref);
1539
0
            if (ctx->use_lists[insn->op1].count == 0) ir_bitqueue_add(ctx->iter_worklist, insn->op1);
1540
0
          }
1541
0
          if (ctx->fold_insn.op1 > 0) {
1542
0
            ir_use_list_add(ctx, ctx->fold_insn.op1, ref);
1543
0
          }
1544
0
        }
1545
0
        if (insn->op2 != ctx->fold_insn.op2) {
1546
0
          if (insn->op2 > 0) {
1547
0
            ir_use_list_remove_one(ctx, insn->op2, ref);
1548
0
            if (ctx->use_lists[insn->op2].count == 0) ir_bitqueue_add(ctx->iter_worklist, insn->op2);
1549
0
          }
1550
0
          if (ctx->fold_insn.op2 > 0) {
1551
0
            ir_use_list_add(ctx, ctx->fold_insn.op2, ref);
1552
0
          }
1553
0
        }
1554
0
        if (insn->op3 != ctx->fold_insn.op3) {
1555
0
          if (insn->op3 > 0) {
1556
0
            ir_use_list_remove_one(ctx, insn->op3, ref);
1557
0
            if (ctx->use_lists[insn->op3].count == 0) ir_bitqueue_add(ctx->iter_worklist, insn->op3);
1558
0
          }
1559
0
          if (ctx->fold_insn.op3 > 0) {
1560
0
            ir_use_list_add(ctx, ctx->fold_insn.op3, ref);
1561
0
          }
1562
0
        }
1563
0
        insn->op1 = ctx->fold_insn.op1;
1564
0
        insn->op2 = ctx->fold_insn.op2;
1565
0
        insn->op3 = ctx->fold_insn.op3;
1566
1567
0
        ir_iter_add_uses(ctx, ref, ctx->iter_worklist);
1568
0
      }
1569
76
      break;
1570
76
    case IR_FOLD_DO_COPY:
1571
10
      op1 = ctx->fold_insn.op1;
1572
10
      ir_iter_replace_insn(ctx, ref, op1);
1573
10
      break;
1574
0
    case IR_FOLD_DO_CONST:
1575
0
      op1 = ir_const(ctx, ctx->fold_insn.val, ctx->fold_insn.type);
1576
0
      ir_iter_replace_insn(ctx, ref, op1);
1577
0
      break;
1578
0
    default:
1579
0
      IR_ASSERT(0);
1580
0
      break;
1581
94
  }
1582
94
}
1583
1584
static bool ir_may_promote_d2f(const ir_ctx *ctx, ir_ref ref)
1585
0
{
1586
0
  const ir_insn *insn = &ctx->ir_base[ref];
1587
1588
0
  IR_ASSERT(insn->type == IR_DOUBLE);
1589
0
  if (IR_IS_CONST_REF(ref)) {
1590
0
    return !IR_IS_SYM_CONST(insn->op) && insn->val.d == (double)(float)insn->val.d;
1591
0
  } else {
1592
0
    switch (insn->op) {
1593
0
      case IR_FP2FP:
1594
0
        return 1;
1595
//      case IR_INT2FP:
1596
//        return ctx->use_lists[ref].count == 1;
1597
0
      case IR_NEG:
1598
0
      case IR_ABS:
1599
0
        return ctx->use_lists[ref].count == 1 &&
1600
0
          ir_may_promote_d2f(ctx, insn->op1);
1601
0
      case IR_ADD:
1602
0
      case IR_SUB:
1603
0
      case IR_MUL:
1604
0
      case IR_DIV:
1605
0
      case IR_MIN:
1606
0
      case IR_MAX:
1607
0
        return ctx->use_lists[ref].count == 1 &&
1608
0
          ir_may_promote_d2f(ctx, insn->op1) &&
1609
0
          ir_may_promote_d2f(ctx, insn->op2);
1610
0
      default:
1611
0
        break;
1612
0
    }
1613
0
  }
1614
0
  return 0;
1615
0
}
1616
1617
static bool ir_may_promote_f2d(const ir_ctx *ctx, ir_ref ref)
1618
0
{
1619
0
  const ir_insn *insn = &ctx->ir_base[ref];
1620
1621
0
  IR_ASSERT(insn->type == IR_FLOAT);
1622
0
  if (IR_IS_CONST_REF(ref)) {
1623
0
    return !IR_IS_SYM_CONST(insn->op) && insn->val.f == (float)(double)insn->val.f;
1624
0
  } else {
1625
0
    switch (insn->op) {
1626
0
      case IR_FP2FP:
1627
0
        return 1;
1628
//      case IR_INT2FP:
1629
//        return ctx->use_lists[ref].count == 1;
1630
0
      case IR_NEG:
1631
0
      case IR_ABS:
1632
0
        return ctx->use_lists[ref].count == 1 &&
1633
0
          ir_may_promote_f2d(ctx, insn->op1);
1634
0
      case IR_ADD:
1635
0
      case IR_SUB:
1636
0
      case IR_MUL:
1637
//      case IR_DIV:
1638
0
      case IR_MIN:
1639
0
      case IR_MAX:
1640
0
        return ctx->use_lists[ref].count == 1 &&
1641
0
          ir_may_promote_f2d(ctx, insn->op1) &&
1642
0
          ir_may_promote_f2d(ctx, insn->op2);
1643
0
      default:
1644
0
        break;
1645
0
    }
1646
0
  }
1647
0
  return 0;
1648
0
}
1649
1650
static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use)
1651
0
{
1652
0
  ir_insn *insn = &ctx->ir_base[ref];
1653
0
  uint32_t count;
1654
0
  ir_ref op;
1655
1656
0
  IR_ASSERT(insn->type == IR_DOUBLE);
1657
0
  if (IR_IS_CONST_REF(ref)) {
1658
0
    return ir_const_float(ctx, (float)insn->val.d);
1659
0
  } else {
1660
0
    ir_bitqueue_add(ctx->iter_worklist, ref);
1661
0
    switch (insn->op) {
1662
0
      case IR_FP2FP:
1663
0
        count = ctx->use_lists[ref].count;
1664
0
        ir_use_list_remove_all(ctx, ref, use);
1665
0
        if (ctx->use_lists[ref].count == 0) {
1666
0
          ir_use_list_replace_one(ctx, insn->op1, ref, use);
1667
0
          if (count > 1) {
1668
0
            do {
1669
0
              ir_use_list_add(ctx, insn->op1, use);
1670
0
            } while (--count > 1);
1671
0
          }
1672
0
          ref = insn->op1;
1673
0
          MAKE_NOP(insn);
1674
0
          return ref;
1675
0
        } else {
1676
0
          ir_use_list_add(ctx, insn->op1, use);
1677
0
          count -= ctx->use_lists[ref].count;
1678
0
          if (count > 1) {
1679
0
            do {
1680
0
              ir_use_list_add(ctx, insn->op1, use);
1681
0
            } while (--count > 1);
1682
0
          }
1683
0
        }
1684
0
        return insn->op1;
1685
//      case IR_INT2FP:
1686
//        insn->type = IR_FLOAT;
1687
//        return ref;
1688
0
      case IR_NEG:
1689
0
      case IR_ABS:
1690
0
        op = ir_promote_d2f(ctx, insn->op1, ref);
1691
0
        insn = &ctx->ir_base[ref];
1692
0
        insn->op1 = op;
1693
0
        insn->type = IR_FLOAT;
1694
0
        return ref;
1695
0
      case IR_ADD:
1696
0
      case IR_SUB:
1697
0
      case IR_MUL:
1698
0
      case IR_DIV:
1699
0
      case IR_MIN:
1700
0
      case IR_MAX:
1701
0
        if (insn->op1 == insn->op2) {
1702
0
          op = ir_promote_d2f(ctx, insn->op1, ref);
1703
0
          insn = &ctx->ir_base[ref];
1704
0
          insn->op2 = insn->op1 = op;
1705
0
        } else {
1706
0
          ir_ref op1 = insn->op1;
1707
0
          ir_ref op2 = insn->op2;
1708
0
          op1 = ir_promote_d2f(ctx, op1, ref);
1709
0
          op2 = ir_promote_d2f(ctx, op2, ref);
1710
0
          insn = &ctx->ir_base[ref];
1711
0
          insn->op1 = op1;
1712
0
          insn->op2 = op2;
1713
0
        }
1714
0
        insn->type = IR_FLOAT;
1715
0
        return ref;
1716
0
      default:
1717
0
        break;
1718
0
    }
1719
0
  }
1720
0
  IR_ASSERT(0);
1721
0
  return ref;
1722
0
}
1723
1724
static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use)
1725
0
{
1726
0
  ir_insn *insn = &ctx->ir_base[ref];
1727
0
  uint32_t count;
1728
0
  ir_ref old_ref;
1729
0
  ir_ref op;
1730
1731
0
  IR_ASSERT(insn->type == IR_FLOAT);
1732
0
  if (IR_IS_CONST_REF(ref)) {
1733
0
    return ir_const_double(ctx, (double)insn->val.f);
1734
0
  } else {
1735
0
    ir_bitqueue_add(ctx->iter_worklist, ref);
1736
0
    switch (insn->op) {
1737
0
      case IR_FP2FP:
1738
0
        count = ctx->use_lists[ref].count;
1739
0
        ir_use_list_remove_all(ctx, ref, use);
1740
0
        if (ctx->use_lists[ref].count == 0) {
1741
0
          ir_use_list_replace_one(ctx, insn->op1, ref, use);
1742
0
          if (count > 1) {
1743
0
            do {
1744
0
              ir_use_list_add(ctx, insn->op1, use);
1745
0
            } while (--count > 1);
1746
0
          }
1747
0
          ref = insn->op1;
1748
0
          MAKE_NOP(insn);
1749
0
          return ref;
1750
0
        } else {
1751
0
          ir_use_list_add(ctx, insn->op1, use);
1752
0
          count -= ctx->use_lists[ref].count;
1753
0
          if (count > 1) {
1754
0
            do {
1755
0
              ir_use_list_add(ctx, insn->op1, use);
1756
0
            } while (--count > 1);
1757
0
          }
1758
0
        }
1759
0
        return insn->op1;
1760
0
      case IR_INT2FP:
1761
0
        old_ref = ir_iter_find_cse1(ctx, IR_OPTX(IR_INT2FP, IR_DOUBLE, 1), insn->op1);
1762
0
        if (old_ref) {
1763
0
          IR_ASSERT(ctx->use_lists[ref].count == 1);
1764
0
          ir_use_list_remove_one(ctx, insn->op1, ref);
1765
0
          CLEAR_USES(ref);
1766
0
          MAKE_NOP(insn);
1767
0
          ir_use_list_add(ctx, old_ref, use);
1768
0
          return old_ref;
1769
0
        }
1770
0
        insn->type = IR_DOUBLE;
1771
0
        return ref;
1772
0
      case IR_NEG:
1773
0
      case IR_ABS:
1774
0
        op = ir_promote_f2d(ctx, insn->op1, ref);
1775
0
        insn = &ctx->ir_base[ref];
1776
0
        insn->op1 = op;
1777
0
        insn->type = IR_DOUBLE;
1778
0
        return ref;
1779
0
      case IR_ADD:
1780
0
      case IR_SUB:
1781
0
      case IR_MUL:
1782
//      case IR_DIV:
1783
0
      case IR_MIN:
1784
0
      case IR_MAX:
1785
0
        if (insn->op1 == insn->op2) {
1786
0
          op = ir_promote_f2d(ctx, insn->op1, ref);
1787
0
          insn = &ctx->ir_base[ref];
1788
0
          insn->op2 = insn->op1 = op;
1789
0
        } else {
1790
0
          ir_ref op1 = insn->op1;
1791
0
          ir_ref op2 = insn->op2;
1792
0
          op1 = ir_promote_f2d(ctx, op1, ref);
1793
0
          op2 = ir_promote_f2d(ctx, op2, ref);
1794
0
          insn = &ctx->ir_base[ref];
1795
0
          insn->op1 = op1;
1796
0
          insn->op2 = op2;
1797
0
        }
1798
0
        insn->type = IR_DOUBLE;
1799
0
        return ref;
1800
0
      default:
1801
0
        break;
1802
0
    }
1803
0
  }
1804
0
  IR_ASSERT(0);
1805
0
  return ref;
1806
0
}
1807
1808
static bool ir_may_promote_trunc(const ir_ctx *ctx, ir_type type, ir_ref ref)
1809
80
{
1810
80
  const ir_insn *insn = &ctx->ir_base[ref];
1811
80
  const ir_ref *p;
1812
80
  ir_ref n, input;
1813
1814
80
  if (IR_IS_CONST_REF(ref)) {
1815
4
    return !IR_IS_SYM_CONST(insn->op);
1816
76
  } else {
1817
76
    switch (insn->op) {
1818
0
      case IR_ZEXT:
1819
0
      case IR_SEXT:
1820
0
      case IR_TRUNC:
1821
0
        return ctx->ir_base[insn->op1].type == type || ctx->use_lists[ref].count == 1;
1822
0
      case IR_NEG:
1823
0
      case IR_ABS:
1824
0
      case IR_NOT:
1825
0
        return ctx->use_lists[ref].count == 1 &&
1826
0
          ir_may_promote_trunc(ctx, type, insn->op1);
1827
62
      case IR_ADD:
1828
65
      case IR_SUB:
1829
65
      case IR_MUL:
1830
65
      case IR_MIN:
1831
65
      case IR_MAX:
1832
65
      case IR_OR:
1833
65
      case IR_AND:
1834
65
      case IR_XOR:
1835
65
        return ctx->use_lists[ref].count == 1 &&
1836
0
          ir_may_promote_trunc(ctx, type, insn->op1) &&
1837
0
          ir_may_promote_trunc(ctx, type, insn->op2);
1838
0
      case IR_SHL:
1839
0
        return ctx->use_lists[ref].count == 1 &&
1840
0
          ir_may_promote_trunc(ctx, type, insn->op1) &&
1841
0
          IR_IS_CONST_REF(insn->op2) &&
1842
0
          (IR_IS_TYPE_UNSIGNED(ctx->ir_base[insn->op2].type) || ctx->ir_base[insn->op2].val.i64 >= 0) &&
1843
0
          ctx->ir_base[insn->op2].val.u64 < ir_type_size[type] * 8;
1844
//      case IR_SHR:
1845
//      case IR_SAR:
1846
//      case IR_DIV:
1847
//      case IR_MOD:
1848
//      case IR_FP2INT:
1849
//        TODO: ???
1850
0
      case IR_COND:
1851
0
        return ctx->use_lists[ref].count == 1 &&
1852
0
          insn->op1 != insn->op2 &&
1853
0
          insn->op1 != insn->op3 &&
1854
0
          ir_may_promote_trunc(ctx, type, insn->op2) &&
1855
0
          ir_may_promote_trunc(ctx, type, insn->op3);
1856
0
      case IR_PHI:
1857
0
        if (ctx->use_lists[ref].count != 1) {
1858
0
          ir_use_list *use_list = &ctx->use_lists[ref];
1859
0
          ir_ref count = 0;
1860
1861
0
          for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) {
1862
0
            if (*p != ref) {
1863
0
              if (count) {
1864
0
                return 0;
1865
0
              }
1866
0
              count = 1;
1867
0
            }
1868
0
          }
1869
0
        }
1870
0
        for (p = insn->ops + 2, n = insn->inputs_count - 1; n > 0; p++, n--) {
1871
0
          input = *p;
1872
0
          if (input != ref) {
1873
0
            if (!ir_may_promote_trunc(ctx, type, input)) {
1874
0
              return 0;
1875
0
            }
1876
0
          }
1877
0
        }
1878
0
        return 1;
1879
11
      default:
1880
11
        break;
1881
76
    }
1882
76
  }
1883
11
  return 0;
1884
80
}
1885
1886
static ir_ref ir_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref, ir_ref use)
1887
4
{
1888
4
  ir_insn *insn = &ctx->ir_base[ref];
1889
4
  uint32_t count;
1890
4
  ir_ref n, input, op;
1891
1892
4
  if (IR_IS_CONST_REF(ref)) {
1893
4
    ir_val val;
1894
1895
4
    switch (type) {
1896
0
      case IR_I8:  val.i64 = insn->val.i8; break;
1897
4
      case IR_U8:  val.u64 = insn->val.u8; break;
1898
0
      case IR_I16: val.i64 = insn->val.i16; break;
1899
0
      case IR_U16: val.u64 = insn->val.u16; break;
1900
0
      case IR_I32: val.i64 = insn->val.i32; break;
1901
0
      case IR_U32: val.u64 = insn->val.u32; break;
1902
0
      case IR_CHAR:val.i64 = insn->val.i8; break;
1903
0
      case IR_BOOL:val.u64 = insn->val.u8 != 0; break;
1904
0
      default: IR_ASSERT(0); val.u64 = 0;
1905
4
    }
1906
4
    return ir_const(ctx, val, type);
1907
4
  } else {
1908
0
    ir_bitqueue_add(ctx->iter_worklist, ref);
1909
0
    switch (insn->op) {
1910
0
      case IR_ZEXT:
1911
0
      case IR_SEXT:
1912
0
      case IR_TRUNC:
1913
0
        if (ctx->ir_base[insn->op1].type != type) {
1914
0
          ir_type src_type = ctx->ir_base[insn->op1].type;
1915
1916
0
          IR_ASSERT(IR_IS_TYPE_INT(src_type) && IR_IS_TYPE_INT(type));
1917
0
          if (ir_type_size[src_type] == ir_type_size[type]) {
1918
0
            insn->op = IR_BITCAST;
1919
0
          } else if (ir_type_size[src_type] > ir_type_size[type]) {
1920
0
            insn->op = IR_TRUNC;
1921
0
          } else {
1922
0
            if (insn->op != IR_SEXT && insn->op != IR_ZEXT) {
1923
0
              insn->op = IR_IS_TYPE_SIGNED(type) ? IR_SEXT : IR_ZEXT;
1924
0
            }
1925
0
          }
1926
0
          insn->type = type;
1927
0
          ir_iter_add_uses(ctx, ref, ctx->iter_worklist);
1928
0
          return ref;
1929
0
        }
1930
1931
0
        count = ctx->use_lists[ref].count;
1932
0
        ir_use_list_remove_all(ctx, ref, use);
1933
0
        if (ctx->use_lists[ref].count == 0) {
1934
0
          ir_use_list_replace_one(ctx, insn->op1, ref, use);
1935
0
          if (count > 1) {
1936
0
            do {
1937
0
              ir_use_list_add(ctx, insn->op1, use);
1938
0
            } while (--count > 1);
1939
0
          }
1940
0
          ref = insn->op1;
1941
0
          MAKE_NOP(insn);
1942
0
          return ref;
1943
0
        } else {
1944
0
          ir_use_list_add(ctx, insn->op1, use);
1945
0
          count -= ctx->use_lists[ref].count;
1946
0
          if (count > 1) {
1947
0
            do {
1948
0
              ir_use_list_add(ctx, insn->op1, use);
1949
0
            } while (--count > 1);
1950
0
          }
1951
0
        }
1952
0
        return insn->op1;
1953
0
      case IR_NEG:
1954
0
      case IR_ABS:
1955
0
      case IR_NOT:
1956
0
        op = ir_promote_i2i(ctx, type, insn->op1, ref);
1957
0
        insn = &ctx->ir_base[ref];
1958
0
        insn->op1 = op;
1959
0
        insn->type = type;
1960
0
        return ref;
1961
0
      case IR_ADD:
1962
0
      case IR_SUB:
1963
0
      case IR_MUL:
1964
0
      case IR_MIN:
1965
0
      case IR_MAX:
1966
0
      case IR_OR:
1967
0
      case IR_AND:
1968
0
      case IR_XOR:
1969
0
      case IR_SHL:
1970
0
        if (insn->op1 == insn->op2) {
1971
0
          op = ir_promote_i2i(ctx, type, insn->op1, ref);
1972
0
          insn = &ctx->ir_base[ref];
1973
0
          insn->op2 = insn->op1 = op;
1974
0
        } else {
1975
0
          ir_ref op1 = insn->op1;
1976
0
          ir_ref op2 = insn->op2;
1977
0
          op1 = ir_promote_i2i(ctx, type, op1, ref);
1978
0
          op2 = ir_promote_i2i(ctx, type, op2, ref);
1979
0
          insn = &ctx->ir_base[ref];
1980
0
          insn->op1 = op1;
1981
0
          insn->op2 = op2;
1982
0
        }
1983
0
        insn->type = type;
1984
0
        return ref;
1985
//      case IR_DIV:
1986
//      case IR_MOD:
1987
//      case IR_SHR:
1988
//      case IR_SAR:
1989
//      case IR_FP2INT:
1990
//        TODO: ???
1991
0
      case IR_COND:
1992
0
        if (insn->op2 == insn->op3) {
1993
0
          op = ir_promote_i2i(ctx, type, insn->op2, ref);
1994
0
          insn = &ctx->ir_base[ref];
1995
0
          insn->op3 = insn->op2 = op;
1996
0
        } else {
1997
0
          ir_ref op2 = insn->op2;
1998
0
          ir_ref op3 = insn->op3;
1999
0
          op2 = ir_promote_i2i(ctx, type, op2, ref);
2000
0
          op3 = ir_promote_i2i(ctx, type, op3, ref);
2001
0
          insn = &ctx->ir_base[ref];
2002
0
          insn->op2 = op2;
2003
0
          insn->op3 = op3;
2004
0
        }
2005
0
        insn->type = type;
2006
0
        if (IR_IS_TYPE_SIGNED(type)) {
2007
0
          ir_insn *cond = &ctx->ir_base[insn->op1];
2008
0
          if (cond->op == IR_LT || cond->op == IR_LE || cond->op == IR_GT || cond->op == IR_GE) {
2009
0
            if (cond->op1 == insn->op2 && cond->op2 == insn->op3) {
2010
0
              insn->op = (cond->op == IR_LT || cond->op == IR_LE) ? IR_MIN : IR_MAX;
2011
0
              ir_use_list_remove_one(ctx, insn->op1, ref);
2012
0
              ir_bitqueue_add(ctx->iter_worklist, insn->op1);
2013
0
              insn->op1 = insn->op2;
2014
0
              insn->op2 = insn->op3;
2015
0
              insn->op3 = IR_UNUSED;
2016
0
            } else if (cond->op1 == insn->op3 && cond->op2 == insn->op1) {
2017
0
              insn->op = (cond->op == IR_LT || cond->op == IR_LE) ? IR_MAX : IR_MIN;
2018
0
              ir_use_list_remove_one(ctx, insn->op1, ref);
2019
0
              ir_bitqueue_add(ctx->iter_worklist, insn->op1);
2020
0
              insn->op1 = insn->op2;
2021
0
              insn->op2 = insn->op3;
2022
0
              insn->op3 = IR_UNUSED;
2023
0
            }
2024
0
          }
2025
0
        } else {
2026
0
          IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
2027
0
          ir_insn *cond = &ctx->ir_base[insn->op1];
2028
0
          if (cond->op == IR_ULT || cond->op == IR_ULE || cond->op == IR_UGT || cond->op == IR_UGE) {
2029
0
            if (cond->op1 == insn->op2 && cond->op2 == insn->op3) {
2030
0
              insn->op = (cond->op == IR_ULT || cond->op == IR_ULE) ? IR_MIN : IR_MAX;
2031
0
              ir_use_list_remove_one(ctx, insn->op1, ref);
2032
0
              ir_bitqueue_add(ctx->iter_worklist, insn->op1);
2033
0
              insn->op1 = insn->op2;
2034
0
              insn->op2 = insn->op3;
2035
0
              insn->op3 = IR_UNUSED;
2036
0
            } else if (cond->op1 == insn->op3 && cond->op2 == insn->op1) {
2037
0
              insn->op = (cond->op == IR_ULT || cond->op == IR_ULE) ? IR_MAX : IR_MIN;
2038
0
              ir_use_list_remove_one(ctx, insn->op1, ref);
2039
0
              ir_bitqueue_add(ctx->iter_worklist, insn->op1);
2040
0
              insn->op1 = insn->op2;
2041
0
              insn->op2 = insn->op3;
2042
0
              insn->op3 = IR_UNUSED;
2043
0
            }
2044
0
          }
2045
0
        }
2046
0
        return ref;
2047
0
      case IR_PHI:
2048
0
        for (count = 2, n = insn->inputs_count - 1; n > 0; count++, n--) {
2049
0
          input = ir_get_op(ctx, ref, count);
2050
0
          if (input != ref) {
2051
0
            op = ir_promote_i2i(ctx, type, input, ref);
2052
0
            ir_set_op(ctx, ref, count, op);
2053
0
          }
2054
0
        }
2055
0
        insn = &ctx->ir_base[ref];
2056
0
        insn->type = type;
2057
0
        return ref;
2058
0
      default:
2059
0
        break;
2060
0
    }
2061
0
  }
2062
0
  IR_ASSERT(0);
2063
0
  return ref;
2064
0
}
2065
2066
static ir_ref ir_ext_const(ir_ctx *ctx, const ir_insn *val_insn, ir_op op, ir_type type)
2067
0
{
2068
0
  ir_val new_val;
2069
2070
0
  switch (val_insn->type) {
2071
0
    default:
2072
0
      IR_ASSERT(0);
2073
0
    case IR_I8:
2074
0
    case IR_U8:
2075
0
    case IR_BOOL:
2076
0
    case IR_CHAR:
2077
0
      if (op == IR_SEXT) {
2078
0
        new_val.i64 = (int64_t)val_insn->val.i8;
2079
0
      } else {
2080
0
        new_val.u64 = (uint64_t)val_insn->val.u8;
2081
0
      }
2082
0
      break;
2083
0
    case IR_I16:
2084
0
    case IR_U16:
2085
0
      if (op == IR_SEXT) {
2086
0
        new_val.i64 = (int64_t)val_insn->val.i16;
2087
0
      } else {
2088
0
        new_val.u64 = (uint64_t)val_insn->val.u16;
2089
0
      }
2090
0
      break;
2091
0
    case IR_I32:
2092
0
    case IR_U32:
2093
0
      if (op == IR_SEXT) {
2094
0
        new_val.i64 = (int64_t)val_insn->val.i32;
2095
0
      } else {
2096
0
        new_val.u64 = (uint64_t)val_insn->val.u32;
2097
0
      }
2098
0
      break;
2099
0
  }
2100
0
  return ir_const(ctx, new_val, type);
2101
0
}
2102
2103
static ir_ref ir_ext_ref(ir_ctx *ctx, ir_ref var_ref, ir_ref src_ref, ir_op op, ir_type type)
2104
0
{
2105
0
  uint32_t optx = IR_OPTX(op, type, 1);
2106
0
  ir_ref ref;
2107
2108
0
  if (!IR_IS_CONST_REF(src_ref)) {
2109
0
    ref = ir_iter_find_cse1(ctx, optx, src_ref);
2110
0
    if (ref) {
2111
0
      ir_use_list_add(ctx, ref, var_ref);
2112
0
      if (!IR_IS_CONST_REF(src_ref)) {
2113
0
        ir_use_list_remove_one(ctx, src_ref, var_ref);
2114
0
      }
2115
0
      ir_bitqueue_add(ctx->iter_worklist, ref);
2116
0
      return ref;
2117
0
    }
2118
0
  }
2119
2120
0
  ref = ir_emit1(ctx, optx, src_ref);
2121
0
  ir_use_list_add(ctx, ref, var_ref);
2122
0
  if (!IR_IS_CONST_REF(src_ref)) {
2123
0
    ir_use_list_replace_one(ctx, src_ref, var_ref, ref);
2124
0
  }
2125
0
  ir_bitqueue_grow(ctx->iter_worklist, ref + 1);
2126
0
  ir_bitqueue_add(ctx->iter_worklist, ref);
2127
0
  return ref;
2128
0
}
2129
2130
static uint32_t _ir_estimated_control(const ir_ctx *ctx, ir_ref val, ir_ref loop)
2131
6.04k
{
2132
6.04k
  const ir_insn *insn;
2133
6.04k
  const ir_ref *p;
2134
6.04k
  ir_ref n, input, result, ctrl;
2135
2136
6.04k
  if (val <= 0) { /* constant or IR_UNUSED */
2137
6.04k
    return 1; /* IR_START */
2138
6.04k
  }
2139
2140
0
  insn = &ctx->ir_base[val];
2141
0
  if (ir_op_flags[insn->op] & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM)) {
2142
0
    return val;
2143
0
  }
2144
2145
0
  IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_DATA);
2146
0
  if (IR_OPND_KIND(ir_op_flags[insn->op], 1) == IR_OPND_CONTROL_DEP) {
2147
0
    return insn->op1;
2148
0
  }
2149
2150
0
  n = insn->inputs_count;
2151
0
  p = insn->ops + 1;
2152
2153
0
  result = 1;
2154
0
  for (; n > 0; p++, n--) {
2155
0
    input = *p;
2156
0
    ctrl = _ir_estimated_control(ctx, input, loop);
2157
0
    if (ctrl >= loop) return ctrl;
2158
0
    if (ctrl > result) { // TODO: check dominance depth instead of order
2159
0
      result = ctrl;
2160
0
    }
2161
0
  }
2162
0
  return result;
2163
0
}
2164
2165
static bool ir_is_loop_invariant(const ir_ctx *ctx, ir_ref ref, ir_ref loop)
2166
6.04k
{
2167
6.04k
  ref = _ir_estimated_control(ctx, ref, loop);
2168
6.04k
  return ref < loop; // TODO: check dominance instead of order
2169
6.04k
}
2170
2171
static bool ir_is_cheaper_ext(const ir_ctx *ctx, ir_ref ref, ir_ref loop, ir_ref ext_ref, ir_op op)
2172
0
{
2173
0
  if (IR_IS_CONST_REF(ref)) {
2174
0
    return 1;
2175
0
  } else {
2176
0
    const ir_insn *insn = &ctx->ir_base[ref];
2177
2178
0
    if (insn->op == IR_LOAD) {
2179
0
      if (ir_is_loop_invariant(ctx, ref, loop)) {
2180
0
        return 1;
2181
0
      } else {
2182
        /* ZEXT(LOAD(_, _)) costs the same as LOAD(_, _) */
2183
0
        if (ctx->use_lists[ref].count == 2) {
2184
0
          return 1;
2185
0
        } else if (ctx->use_lists[ref].count == 3) {
2186
0
          ir_use_list *use_list = &ctx->use_lists[ref];
2187
0
          ir_ref *p, n, use;
2188
2189
0
          for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) {
2190
0
            use = *p;
2191
0
            if (use != ext_ref) {
2192
0
              const ir_insn *use_insn = &ctx->ir_base[use];
2193
2194
0
              if (use_insn->op != op
2195
0
               && (!(ir_op_flags[use_insn->op] & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM))
2196
0
                || use_insn->op1 != ref)) {
2197
0
                return 0;
2198
0
              }
2199
0
            }
2200
0
          }
2201
0
          return 1;
2202
0
        }
2203
0
      }
2204
0
      return 0;
2205
0
    } else {
2206
0
      return ir_is_loop_invariant(ctx, ref, loop);
2207
0
    }
2208
0
  }
2209
0
}
2210
2211
static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref phi_ref, ir_ref op_ref)
2212
0
{
2213
0
  ir_op op = ctx->ir_base[ext_ref].op;
2214
0
  ir_type type = ctx->ir_base[ext_ref].type;
2215
0
  ir_insn *phi_insn;
2216
0
  ir_use_list *use_list;
2217
0
  ir_ref n, *p, use, ext_ref_2 = IR_UNUSED;
2218
2219
  /* Check if we may change the type of the induction variable */
2220
0
  use_list = &ctx->use_lists[phi_ref];
2221
0
  n = use_list->count;
2222
0
  if (n > 1) {
2223
0
    for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2224
0
      use = *p;
2225
0
      if (use == op_ref || use == ext_ref) {
2226
0
        continue;
2227
0
      } else {
2228
0
        const ir_insn *use_insn = &ctx->ir_base[use];
2229
2230
0
        if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
2231
0
          if (use_insn->op1 == phi_ref) {
2232
0
            if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
2233
0
              return 0;
2234
0
            }
2235
0
            if (ir_is_cheaper_ext(ctx, use_insn->op2, ctx->ir_base[phi_ref].op1, ext_ref, op)) {
2236
0
              continue;
2237
0
              }
2238
0
          } else if (use_insn->op2 == phi_ref) {
2239
0
            if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op1].type)) {
2240
0
              return 0;
2241
0
            }
2242
0
            if (ir_is_cheaper_ext(ctx, use_insn->op1, ctx->ir_base[phi_ref].op1, ext_ref, op)) {
2243
0
              continue;
2244
0
              }
2245
0
          }
2246
0
          return 0;
2247
0
        } else if (use_insn->op == IR_IF) {
2248
0
          continue;
2249
0
        } else if (!ext_ref_2 && use_insn->op == op && use_insn->type == type) {
2250
0
          ext_ref_2 = use;
2251
0
          continue;
2252
0
        } else {
2253
0
          return 0;
2254
0
        }
2255
0
      }
2256
0
    }
2257
0
  }
2258
2259
0
  use_list = &ctx->use_lists[op_ref];
2260
0
  n = use_list->count;
2261
0
  if (n > 1) {
2262
0
    for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2263
0
      use = *p;
2264
0
      if (use == phi_ref || use == ext_ref) {
2265
0
        continue;
2266
0
      } else {
2267
0
        const ir_insn *use_insn = &ctx->ir_base[use];
2268
2269
0
        if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
2270
0
          if (use_insn->op1 == op_ref) {
2271
0
            if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
2272
0
              return 0;
2273
0
            }
2274
0
            if (ir_is_cheaper_ext(ctx, use_insn->op2, ctx->ir_base[phi_ref].op1, ext_ref, op)) {
2275
0
              continue;
2276
0
              }
2277
0
          } else if (use_insn->op2 == op_ref) {
2278
0
            if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op1].type)) {
2279
0
              return 0;
2280
0
            }
2281
0
            if (ir_is_cheaper_ext(ctx, use_insn->op1, ctx->ir_base[phi_ref].op1, ext_ref, op)) {
2282
0
              continue;
2283
0
              }
2284
0
          }
2285
0
          return 0;
2286
0
        } else if (use_insn->op == IR_IF) {
2287
0
          continue;
2288
0
        } else if (!ext_ref_2 && use_insn->op == op && use_insn->type == type) {
2289
0
          ext_ref_2 = use;
2290
0
          continue;
2291
0
        } else {
2292
0
          return 0;
2293
0
        }
2294
0
      }
2295
0
    }
2296
0
  }
2297
2298
0
  for (n = 0; n < ctx->use_lists[phi_ref].count; n++) {
2299
    /* "use_lists" may be reallocated by ir_ext_ref() */
2300
0
    use = ctx->use_edges[ctx->use_lists[phi_ref].refs + n];
2301
0
    if (use == ext_ref) {
2302
0
      continue;
2303
0
    } else {
2304
0
      ir_insn *use_insn = &ctx->ir_base[use];
2305
2306
0
      if (use_insn->op == IR_IF) {
2307
0
        continue;
2308
0
      } else if (use_insn->op == op) {
2309
0
        IR_ASSERT(ext_ref_2 == use);
2310
0
        continue;
2311
0
      }
2312
0
      IR_ASSERT(((use_insn->op >= IR_EQ && use_insn->op <= IR_UGT)
2313
0
        || use_insn->op == IR_ADD || use_insn->op == IR_SUB || use_insn->op == IR_MUL)
2314
0
       && (use_insn->op1 == phi_ref || use_insn->op2 == phi_ref));
2315
0
      if (use_insn->op1 != phi_ref) {
2316
0
        if (IR_IS_CONST_REF(use_insn->op1)
2317
0
         && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) {
2318
0
          ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type);
2319
0
        } else {
2320
0
          ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op1, op, type);
2321
0
          use_insn = &ctx->ir_base[use];
2322
0
          use_insn->op1 = tmp;
2323
0
        }
2324
0
        ir_bitqueue_add(ctx->iter_worklist, use);
2325
0
      }
2326
0
      if (use_insn->op2 != phi_ref) {
2327
0
        if (IR_IS_CONST_REF(use_insn->op2)
2328
0
         && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) {
2329
0
          ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type);
2330
0
        } else {
2331
0
          ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op2, op, type);
2332
0
          use_insn = &ctx->ir_base[use];
2333
0
          use_insn->op2 = tmp;
2334
0
        }
2335
0
        ir_bitqueue_add(ctx->iter_worklist, use);
2336
0
      }
2337
0
    }
2338
0
  }
2339
2340
0
  if (ctx->use_lists[op_ref].count > 1) {
2341
0
    for (n = 0; n < ctx->use_lists[op_ref].count; n++) {
2342
      /* "use_lists" may be reallocated by ir_ext_ref() */
2343
0
      use = ctx->use_edges[ctx->use_lists[op_ref].refs + n];
2344
0
      if (use == ext_ref || use == phi_ref) {
2345
0
        continue;
2346
0
      } else {
2347
0
        ir_insn *use_insn = &ctx->ir_base[use];
2348
2349
0
        if (use_insn->op == IR_IF) {
2350
0
          continue;
2351
0
        } else if (use_insn->op == op) {
2352
0
          IR_ASSERT(ext_ref_2 == use);
2353
0
          continue;
2354
0
        }
2355
0
        IR_ASSERT(use_insn->op >= IR_EQ && use_insn->op <= IR_UGT);
2356
0
        if (use_insn->op1 != op_ref) {
2357
0
          if (IR_IS_CONST_REF(use_insn->op1)
2358
0
           && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) {
2359
0
            ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type);
2360
0
          } else {
2361
0
            ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op1, op, type);
2362
0
            use_insn = &ctx->ir_base[use];
2363
0
            use_insn->op1 = tmp;
2364
0
          }
2365
0
          ir_bitqueue_add(ctx->iter_worklist, use);
2366
0
        }
2367
0
        if (use_insn->op2 != op_ref) {
2368
0
          if (IR_IS_CONST_REF(use_insn->op2)
2369
0
           && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) {
2370
0
            ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type);
2371
0
          } else {
2372
0
            ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op2, op, type);
2373
0
            use_insn = &ctx->ir_base[use];
2374
0
            use_insn->op2 = tmp;
2375
0
          }
2376
0
          ir_bitqueue_add(ctx->iter_worklist, use);
2377
0
        }
2378
0
      }
2379
0
    }
2380
0
  }
2381
2382
0
  ir_iter_replace_insn(ctx, ext_ref, ctx->ir_base[ext_ref].op1);
2383
2384
0
  if (ext_ref_2) {
2385
0
    ir_iter_replace_insn(ctx, ext_ref_2, ctx->ir_base[ext_ref_2].op1);
2386
0
  }
2387
2388
0
  ctx->ir_base[op_ref].type = type;
2389
2390
0
  phi_insn = &ctx->ir_base[phi_ref];
2391
0
  phi_insn->type = type;
2392
0
  if (IR_IS_CONST_REF(phi_insn->op2)
2393
0
   && !IR_IS_SYM_CONST(ctx->ir_base[phi_insn->op2].op)) {
2394
0
    ctx->ir_base[phi_ref].op2 = ir_ext_const(ctx, &ctx->ir_base[phi_insn->op2], op, type);
2395
0
  } else {
2396
0
    ir_ref tmp = ir_ext_ref(ctx, phi_ref, phi_insn->op2, op, type);
2397
0
    ctx->ir_base[phi_ref].op2 = tmp;
2398
0
  }
2399
2400
0
  return 1;
2401
0
}
2402
2403
static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn)
2404
0
{
2405
0
  ir_ref ref = insn->op1;
2406
2407
  /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */
2408
0
  insn = &ctx->ir_base[ref];
2409
0
  if (insn->op == IR_PHI
2410
0
   && insn->inputs_count == 3 /* (2 values) */
2411
0
   && ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) {
2412
0
    ir_ref op_ref = insn->op3;
2413
0
    ir_insn *op_insn = &ctx->ir_base[op_ref];
2414
2415
0
    if (op_insn->op == IR_ADD || op_insn->op == IR_SUB || op_insn->op == IR_MUL) {
2416
0
      if (op_insn->op1 == ref) {
2417
0
        if (ir_is_loop_invariant(ctx, op_insn->op2, insn->op1)) {
2418
0
          return ir_try_promote_induction_var_ext(ctx, ext_ref, ref, op_ref);
2419
0
        }
2420
0
      } else if (op_insn->op2 == ref) {
2421
0
        if (ir_is_loop_invariant(ctx, op_insn->op1, insn->op1)) {
2422
0
          return ir_try_promote_induction_var_ext(ctx, ext_ref, ref, op_ref);
2423
0
        }
2424
0
      }
2425
0
    }
2426
0
  } else if (insn->op == IR_ADD || insn->op == IR_SUB || insn->op == IR_MUL) {
2427
0
    if (!IR_IS_CONST_REF(insn->op1)
2428
0
     && ctx->ir_base[insn->op1].op == IR_PHI
2429
0
     && ctx->ir_base[insn->op1].inputs_count == 3 /* (2 values) */
2430
0
     && ctx->ir_base[insn->op1].op3 == ref
2431
0
     && ctx->ir_base[ctx->ir_base[insn->op1].op1].op == IR_LOOP_BEGIN
2432
0
     && ir_is_loop_invariant(ctx, insn->op2, ctx->ir_base[insn->op1].op1)) {
2433
0
      return ir_try_promote_induction_var_ext(ctx, ext_ref, insn->op1, ref);
2434
0
    } else if (!IR_IS_CONST_REF(insn->op2)
2435
0
     && ctx->ir_base[insn->op2].op == IR_PHI
2436
0
     && ctx->ir_base[insn->op2].inputs_count == 3 /* (2 values) */
2437
0
     && ctx->ir_base[insn->op2].op3 == ref
2438
0
     && ctx->ir_base[ctx->ir_base[insn->op2].op1].op == IR_LOOP_BEGIN
2439
0
     && ir_is_loop_invariant(ctx, insn->op1, ctx->ir_base[insn->op2].op1)) {
2440
0
      return ir_try_promote_induction_var_ext(ctx, ext_ref, insn->op2, ref);
2441
0
    }
2442
0
  } else if (insn->op == IR_COND
2443
0
    && IR_IS_CONST_REF(insn->op2)
2444
0
    && IR_IS_CONST_REF(insn->op3)
2445
0
    && ctx->use_lists[ref].count == 1) {
2446
0
    IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op));
2447
0
    IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op3].op));
2448
2449
0
    ir_op op = ctx->ir_base[ext_ref].op;
2450
0
    ir_type type = ctx->ir_base[ext_ref].type;
2451
2452
0
    insn->type = type;
2453
0
    insn->op2 = ir_ext_const(ctx, &ctx->ir_base[insn->op2], op, type);;
2454
0
    insn->op3 = ir_ext_const(ctx, &ctx->ir_base[insn->op3], op, type);;
2455
0
    ir_iter_replace_insn(ctx, ext_ref, ref);
2456
0
  }
2457
2458
0
  return 0;
2459
0
}
2460
2461
static void ir_get_true_false_refs(const ir_ctx *ctx, ir_ref if_ref, ir_ref *if_true_ref, ir_ref *if_false_ref)
2462
10
{
2463
10
  ir_use_list *use_list = &ctx->use_lists[if_ref];
2464
10
  ir_ref *p = &ctx->use_edges[use_list->refs];
2465
2466
10
  IR_ASSERT(use_list->count == 2);
2467
10
  if (ctx->ir_base[*p].op == IR_IF_TRUE) {
2468
9
    IR_ASSERT(ctx->ir_base[*(p + 1)].op == IR_IF_FALSE);
2469
9
    *if_true_ref = *p;
2470
9
    *if_false_ref = *(p + 1);
2471
9
  } else {
2472
1
    IR_ASSERT(ctx->ir_base[*p].op == IR_IF_FALSE);
2473
1
    IR_ASSERT(ctx->ir_base[*(p + 1)].op == IR_IF_TRUE);
2474
1
    *if_false_ref = *p;
2475
1
    *if_true_ref = *(p + 1);
2476
1
  }
2477
10
}
2478
2479
static void ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin)
2480
1.17k
{
2481
1.17k
  ir_ref prev, next;
2482
1.17k
  ir_use_list *use_list;
2483
2484
1.17k
  IR_ASSERT(ctx->ir_base[begin].op == IR_BEGIN);
2485
1.17k
  IR_ASSERT(ctx->ir_base[end].op == IR_END);
2486
1.17k
  IR_ASSERT(ctx->ir_base[begin].op1 == end);
2487
1.17k
  IR_ASSERT(ctx->use_lists[end].count == 1);
2488
2489
1.17k
  prev = ctx->ir_base[end].op1;
2490
2491
1.17k
  use_list = &ctx->use_lists[begin];
2492
1.17k
  IR_ASSERT(use_list->count == 1);
2493
1.17k
  next = ctx->use_edges[use_list->refs];
2494
2495
  /* remove BEGIN and END */
2496
1.17k
  MAKE_NOP(&ctx->ir_base[begin]); CLEAR_USES(begin);
2497
1.17k
  MAKE_NOP(&ctx->ir_base[end]);   CLEAR_USES(end);
2498
2499
  /* connect their predecessor and successor */
2500
1.17k
  ctx->ir_base[next].op1 = prev;
2501
1.17k
  ir_use_list_replace_one(ctx, prev, end, next);
2502
2503
1.17k
  if (ctx->ir_base[prev].op == IR_BEGIN || ctx->ir_base[prev].op == IR_MERGE) {
2504
229
    ir_bitqueue_add(ctx->iter_worklist, prev);
2505
229
  }
2506
1.17k
}
2507
2508
static void ir_remove_unused_vars(ir_ctx *ctx, ir_ref start, ir_ref end)
2509
0
{
2510
0
  ir_use_list *use_list = &ctx->use_lists[start];
2511
0
  ir_ref *p, use, n = use_list->count;
2512
2513
0
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2514
0
    use = *p;
2515
0
    if (use != end) {
2516
0
      ir_insn *use_insn = &ctx->ir_base[use];
2517
0
      IR_ASSERT(use_insn->op == IR_VAR);
2518
0
      IR_ASSERT(ctx->use_lists[use].count == 0);
2519
0
      MAKE_NOP(use_insn);
2520
0
    }
2521
0
  }
2522
0
}
2523
2524
static bool ir_try_remove_empty_diamond(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
2525
54.9k
{
2526
54.9k
  if (insn->inputs_count == 2) {
2527
31.3k
    ir_ref end1_ref = insn->op1, end2_ref = insn->op2;
2528
31.3k
    ir_insn *end1 = &ctx->ir_base[end1_ref];
2529
31.3k
    ir_insn *end2 = &ctx->ir_base[end2_ref];
2530
2531
31.3k
    if (end1->op != IR_END || end2->op != IR_END) {
2532
0
      return 0;
2533
0
    }
2534
2535
31.3k
    ir_ref start1_ref = end1->op1, start2_ref = end2->op1;
2536
31.3k
    ir_insn *start1 = &ctx->ir_base[start1_ref];
2537
31.3k
    ir_insn *start2 = &ctx->ir_base[start2_ref];
2538
2539
31.3k
    if (start1->op1 != start2->op1) {
2540
31.3k
      return 0;
2541
31.3k
    }
2542
2543
0
    ir_ref root_ref = start1->op1;
2544
0
    ir_insn *root = &ctx->ir_base[root_ref];
2545
2546
0
    if (root->op != IR_IF
2547
0
     && !(root->op == IR_SWITCH && ctx->use_lists[root_ref].count == 2)) {
2548
0
      return 0;
2549
0
    }
2550
2551
    /* Empty Diamond
2552
     *
2553
     *    prev                     prev
2554
     *    |  condition             |  condition
2555
     *    | /                      |
2556
     *    IF                       |
2557
     *    | \                      |
2558
     *    |  +-----+               |
2559
     *    |        IF_FALSE        |
2560
     *    IF_TRUE  |           =>  |
2561
     *    |        END             |
2562
     *    END     /                |
2563
     *    |  +---+                 |
2564
     *    | /                      |
2565
     *    MERGE                    |
2566
     *    |                        |
2567
     *    next                     next
2568
     */
2569
2570
0
    ir_ref next_ref = ctx->use_edges[ctx->use_lists[ref].refs];
2571
0
    ir_insn *next = &ctx->ir_base[next_ref];
2572
2573
0
    if (ctx->use_lists[start1_ref].count != 1) {
2574
0
      ir_remove_unused_vars(ctx, start1_ref, end1_ref);
2575
0
    }
2576
0
    if (ctx->use_lists[start2_ref].count != 1) {
2577
0
      ir_remove_unused_vars(ctx, start2_ref, end2_ref);
2578
0
    }
2579
2580
0
    next->op1 = root->op1;
2581
0
    ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref);
2582
0
    if (!IR_IS_CONST_REF(root->op2)) {
2583
0
      ir_use_list_remove_one(ctx, root->op2, root_ref);
2584
0
      if (ir_is_dead(ctx, root->op2)) {
2585
0
        ir_bitqueue_add(ctx->iter_worklist, root->op2);
2586
0
      }
2587
0
    }
2588
2589
0
    MAKE_NOP(root);   CLEAR_USES(root_ref);
2590
0
    MAKE_NOP(start1); CLEAR_USES(start1_ref);
2591
0
    MAKE_NOP(start2); CLEAR_USES(start2_ref);
2592
0
    MAKE_NOP(end1);   CLEAR_USES(end1_ref);
2593
0
    MAKE_NOP(end2);   CLEAR_USES(end2_ref);
2594
0
    MAKE_NOP(insn);   CLEAR_USES(ref);
2595
2596
0
    if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
2597
0
      ir_bitqueue_add(ctx->iter_worklist, next->op1);
2598
0
    }
2599
2600
0
    return 1;
2601
23.5k
  } else {
2602
23.5k
    ir_ref i, count = insn->inputs_count, *ops = insn->ops + 1;
2603
23.5k
    ir_ref root_ref = IR_UNUSED;
2604
2605
23.5k
    for (i = 0; i < count; i++) {
2606
23.5k
      ir_ref end_ref, start_ref;
2607
23.5k
      ir_insn *end, *start;
2608
2609
23.5k
      end_ref = ops[i];
2610
23.5k
      end = &ctx->ir_base[end_ref];
2611
23.5k
      if (end->op != IR_END) {
2612
0
        return 0;
2613
0
      }
2614
23.5k
      start_ref = end->op1;
2615
23.5k
      start = &ctx->ir_base[start_ref];
2616
23.5k
      if (start->op != IR_CASE_VAL && start->op != IR_CASE_RANGE && start->op != IR_CASE_DEFAULT) {
2617
23.5k
        return 0;
2618
23.5k
      }
2619
4
      if (ctx->use_lists[start_ref].count != 1) {
2620
0
        ir_remove_unused_vars(ctx, start_ref, end_ref);
2621
0
      }
2622
4
      if (!root_ref) {
2623
4
        root_ref = start->op1;
2624
4
        if (ctx->use_lists[root_ref].count != count) {
2625
4
          return 0;
2626
4
        }
2627
4
      } else if (start->op1 != root_ref) {
2628
0
        return 0;
2629
0
      }
2630
4
    }
2631
2632
    /* Empty N-Diamond */
2633
0
    ir_ref next_ref = ctx->use_edges[ctx->use_lists[ref].refs];
2634
0
    ir_insn *next = &ctx->ir_base[next_ref];
2635
0
    ir_insn *root = &ctx->ir_base[root_ref];
2636
2637
0
    next->op1 = root->op1;
2638
0
    ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref);
2639
2640
0
    if (!IR_IS_CONST_REF(root->op2)) {
2641
0
      ir_use_list_remove_one(ctx, root->op2, root_ref);
2642
0
      if (ir_is_dead(ctx, root->op2)) {
2643
0
        ir_bitqueue_add(ctx->iter_worklist, root->op2);
2644
0
      }
2645
0
    }
2646
2647
0
    MAKE_NOP(root);   CLEAR_USES(root_ref);
2648
2649
0
    for (i = 0; i < count; i++) {
2650
0
      ir_ref end_ref = ops[i];
2651
0
      ir_insn *end = &ctx->ir_base[end_ref];
2652
0
      ir_ref start_ref = end->op1;
2653
0
      ir_insn *start = &ctx->ir_base[start_ref];
2654
2655
0
      MAKE_NOP(start); CLEAR_USES(start_ref);
2656
0
      MAKE_NOP(end);   CLEAR_USES(end_ref);
2657
0
    }
2658
2659
0
    MAKE_NOP(insn);   CLEAR_USES(ref);
2660
2661
0
    if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
2662
0
      ir_bitqueue_add(ctx->iter_worklist, next->op1);
2663
0
    }
2664
2665
0
    return 1;
2666
23.5k
  }
2667
54.9k
}
2668
2669
static bool ir_is_zero(const ir_ctx *ctx, ir_ref ref)
2670
0
{
2671
0
  return IR_IS_CONST_REF(ref)
2672
0
    && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
2673
0
    && ctx->ir_base[ref].val.u32 == 0;
2674
0
}
2675
2676
static bool ir_fix_min_max_const(ir_ctx *ctx, ir_insn *cond, ir_ref ref)
2677
0
{
2678
0
  if (cond->op == IR_ULE) {
2679
    /* (x <= 3 ? 4 : x) => (x < 4 ? 4 : x) =>  max(x, 4) */
2680
    /* (x <= 3 ? x : 4) => (x < 4 ? x : 4) =>  min(x, 4) */
2681
0
    if (!IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)
2682
0
     && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
2683
0
     && ctx->ir_base[cond->op2].val.u64 == ctx->ir_base[ref].val.u64 - 1
2684
0
     && ctx->ir_base[cond->op2].type == ctx->ir_base[ref].type) {
2685
0
      cond->op2 = ref;
2686
0
      return 1;
2687
0
    }
2688
0
  } else if (cond->op == IR_UGE) {
2689
    /* (x >= 3 ? 2 : x) => (x > 2 ? 2 : x) =>  min(x, 2) */
2690
    /* (x >= 3 ? x : 2) => (x > 2 ? x : 2) =>  max(x, 2) */
2691
0
    if (!IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)
2692
0
     && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
2693
0
     && ctx->ir_base[cond->op2].val.u64 == ctx->ir_base[ref].val.u64 + 1
2694
0
     && ctx->ir_base[cond->op2].type == ctx->ir_base[ref].type) {
2695
0
      cond->op2 = ref;
2696
0
      return 1;
2697
0
    }
2698
0
  } else if (cond->op == IR_LE) {
2699
    /* (x <= 3 ? 4 : x) => (x < 4 ? 4 : x) =>  max(x, 4) */
2700
    /* (x <= 3 ? x : 4) => (x < 4 ? x : 4) =>  min(x, 4) */
2701
0
    if (!IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)
2702
0
     && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
2703
0
     && ctx->ir_base[cond->op2].val.u64 == ctx->ir_base[ref].val.u64 - 1
2704
0
     && ctx->ir_base[cond->op2].type == ctx->ir_base[ref].type) {
2705
0
      cond->op2 = ref;
2706
0
      return 1;
2707
0
    }
2708
0
  } else if (cond->op == IR_GE) {
2709
    /* (x >= 3 ? 2 : x) => (x > 2 ? 2 : x) =>  min(x, 2) */
2710
    /* (x >= 3 ? x : 2) => (x > 2 ? x : 2) =>  max(x, 2) */
2711
0
    if (!IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)
2712
0
     && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
2713
0
     && ctx->ir_base[cond->op2].val.i64 == ctx->ir_base[ref].val.i64 + 1
2714
0
     && ctx->ir_base[cond->op2].type == ctx->ir_base[ref].type) {
2715
0
      cond->op2 = ref;
2716
0
      return 1;
2717
0
    }
2718
0
  }
2719
0
  return 0;
2720
0
}
2721
2722
static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_ref ref, ir_insn *insn)
2723
16.1k
{
2724
16.1k
  IR_ASSERT(insn->inputs_count == 3);
2725
16.1k
  IR_ASSERT(ctx->use_lists[merge_ref].count == 2);
2726
2727
16.1k
  ir_ref end1_ref = merge->op1, end2_ref = merge->op2;
2728
16.1k
  ir_insn *end1 = &ctx->ir_base[end1_ref];
2729
16.1k
  ir_insn *end2 = &ctx->ir_base[end2_ref];
2730
2731
16.1k
  if (end1->op == IR_END && end2->op == IR_END) {
2732
16.1k
    ir_ref start1_ref = end1->op1, start2_ref = end2->op1;
2733
16.1k
    ir_insn *start1 = &ctx->ir_base[start1_ref];
2734
16.1k
    ir_insn *start2 = &ctx->ir_base[start2_ref];
2735
2736
16.1k
    if (start1->op1 == start2->op1) {
2737
363
      ir_ref root_ref = start1->op1;
2738
363
      ir_insn *root = &ctx->ir_base[root_ref];
2739
2740
363
      if (root->op == IR_IF && !IR_IS_CONST_REF(root->op2)) {
2741
363
        ir_ref cond_ref = root->op2;
2742
363
        ir_insn *cond = &ctx->ir_base[cond_ref];
2743
363
        ir_type type = insn->type;
2744
363
        bool is_cmp, is_less;
2745
2746
363
        if (IR_IS_TYPE_FP(type)) {
2747
0
          is_cmp = (cond->op == IR_LT || cond->op == IR_LE || cond->op == IR_GT || cond->op == IR_GE ||
2748
0
            cond->op == IR_ULT || cond->op == IR_ULE || cond->op == IR_UGT || cond->op == IR_UGE);
2749
0
          is_less = (cond->op == IR_LT || cond->op == IR_LE ||
2750
0
            cond->op == IR_ULT || cond->op == IR_ULE);
2751
363
        } else if (IR_IS_TYPE_SIGNED(type)) {
2752
363
          is_cmp = (cond->op == IR_LT || cond->op == IR_LE || cond->op == IR_GT || cond->op == IR_GE);
2753
363
          is_less = (cond->op == IR_LT || cond->op == IR_LE);
2754
363
        } else {
2755
0
          IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
2756
0
          is_cmp = (cond->op == IR_ULT || cond->op == IR_ULE || cond->op == IR_UGT || cond->op == IR_UGE);
2757
0
          is_less = (cond->op == IR_ULT || cond->op == IR_ULE);
2758
0
        }
2759
2760
363
        if (is_cmp
2761
0
         && ((insn->op2 == cond->op1
2762
0
           && (insn->op3 == cond->op2
2763
0
            || (IR_IS_CONST_REF(cond->op2)
2764
0
             && (IR_IS_CONST_REF(insn->op3)
2765
0
           && IR_IS_TYPE_INT(insn->type)
2766
0
             && ir_fix_min_max_const(ctx, cond, insn->op3)))))
2767
0
          || (insn->op3 == cond->op1
2768
0
           && (insn->op2 == cond->op2
2769
0
            || (IR_IS_CONST_REF(cond->op2)
2770
0
             && (IR_IS_CONST_REF(insn->op2)
2771
0
           && IR_IS_TYPE_INT(insn->type)
2772
0
             && ir_fix_min_max_const(ctx, cond, insn->op2))))))) {
2773
          /* MAX/MIN
2774
           *
2775
           *    prev                     prev
2776
           *    |  LT(A, B)              |
2777
           *    | /                      |
2778
           *    IF                       |
2779
           *    | \                      |
2780
           *    |  +-----+               |
2781
           *    |        IF_FALSE        |
2782
           *    IF_TRUE  |           =>  |
2783
           *    |        END             |
2784
           *    END     /                |
2785
           *    |  +---+                 |
2786
           *    | /                      |
2787
           *    MERGE                    |
2788
           *    |    \                   |
2789
           *    |     PHI(A, B)          |    MIN(A, B)
2790
           *    next                     next
2791
           */
2792
0
          ir_ref next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs];
2793
0
          ir_insn *next;
2794
2795
0
          if (next_ref == ref) {
2796
0
            next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs + 1];
2797
0
          }
2798
0
          next = &ctx->ir_base[next_ref];
2799
2800
0
          if (ctx->use_lists[start1_ref].count != 1) {
2801
0
            ir_remove_unused_vars(ctx, start1_ref, end1_ref);
2802
0
          }
2803
0
          if (ctx->use_lists[start2_ref].count != 1) {
2804
0
            ir_remove_unused_vars(ctx, start2_ref, end2_ref);
2805
0
          }
2806
2807
0
          insn->op = (
2808
0
            (is_less ? cond->op1 : cond->op2)
2809
0
            ==
2810
0
            ((start1->op == IR_IF_TRUE) ? insn->op2 : insn->op3)
2811
0
            ) ? IR_MIN : IR_MAX;
2812
0
          insn->inputs_count = 2;
2813
0
          if (insn->op2 > insn->op3) {
2814
0
            insn->op1 = insn->op2;
2815
0
            insn->op2 = insn->op3;
2816
0
          } else {
2817
0
            insn->op1 = insn->op3;
2818
0
          }
2819
0
          insn->op3 = IR_UNUSED;
2820
2821
0
          next->op1 = root->op1;
2822
0
          ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref);
2823
2824
0
          if (ctx->use_lists[cond_ref].count == 1) {
2825
0
            if (!IR_IS_CONST_REF(insn->op1)) {
2826
0
              ir_use_list_remove_one(ctx, insn->op1, cond_ref);
2827
0
            }
2828
0
            if (!IR_IS_CONST_REF(insn->op2)) {
2829
0
              ir_use_list_remove_one(ctx, insn->op2, cond_ref);
2830
0
            }
2831
0
            MAKE_NOP(cond);   CLEAR_USES(cond_ref);
2832
0
          } else {
2833
0
            ir_use_list_remove_one(ctx, cond_ref, root_ref);
2834
0
          }
2835
0
          MAKE_NOP(root);   CLEAR_USES(root_ref);
2836
0
          MAKE_NOP(start1); CLEAR_USES(start1_ref);
2837
0
          MAKE_NOP(start2); CLEAR_USES(start2_ref);
2838
0
          MAKE_NOP(end1);   CLEAR_USES(end1_ref);
2839
0
          MAKE_NOP(end2);   CLEAR_USES(end2_ref);
2840
0
          MAKE_NOP(merge);  CLEAR_USES(merge_ref);
2841
2842
0
          ir_bitqueue_add(ctx->iter_worklist, ref);
2843
0
          ir_iter_add_uses(ctx, ref, ctx->iter_worklist);
2844
0
          if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
2845
0
            ir_bitqueue_add(ctx->iter_worklist, next->op1);
2846
0
          }
2847
2848
0
          return 1;
2849
363
        } else if (is_cmp
2850
0
            && ((ctx->ir_base[insn->op2].op == IR_NEG
2851
0
              && ctx->use_lists[insn->op2].count == 1
2852
0
              && ctx->ir_base[insn->op2].op1 == insn->op3
2853
0
              && ((cond->op1 == insn->op3
2854
0
                && ir_is_zero(ctx, cond->op2)
2855
0
                && is_less == (start1->op == IR_IF_TRUE))
2856
0
               || (cond->op2 == insn->op3
2857
0
                && ir_is_zero(ctx, cond->op1)
2858
0
                && is_less != (start1->op == IR_IF_TRUE))))
2859
0
             || (ctx->ir_base[insn->op3].op == IR_NEG
2860
0
              && ctx->use_lists[insn->op3].count == 1
2861
0
              && ctx->ir_base[insn->op3].op1 == insn->op2
2862
0
              && ((cond->op1 == insn->op2
2863
0
                && ir_is_zero(ctx, cond->op2)
2864
0
                && is_less != (start1->op == IR_IF_TRUE))
2865
0
               || (cond->op2 == insn->op2
2866
0
                && ir_is_zero(ctx, cond->op1)
2867
0
                && is_less == (start1->op == IR_IF_TRUE)))))) {
2868
          /* ABS
2869
           *
2870
           *    prev                     prev
2871
           *    |  LT(A, 0)              |
2872
           *    | /                      |
2873
           *    IF                       |
2874
           *    | \                      |
2875
           *    |  +-----+               |
2876
           *    |        IF_FALSE        |
2877
           *    IF_TRUE  |           =>  |
2878
           *    |        END             |
2879
           *    END     /                |
2880
           *    |  +---+                 |
2881
           *    | /                      |
2882
           *    MERGE                    |
2883
           *    |    \                   |
2884
           *    |     PHI(A, NEG(A))     |    ABS(A)
2885
           *    next                     next
2886
           */
2887
0
          ir_ref neg_ref;
2888
0
          ir_ref next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs];
2889
0
          ir_insn *next;
2890
2891
0
          if (next_ref == ref) {
2892
0
            next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs + 1];
2893
0
          }
2894
0
          next = &ctx->ir_base[next_ref];
2895
2896
0
          if (ctx->use_lists[start1_ref].count != 1) {
2897
0
            ir_remove_unused_vars(ctx, start1_ref, end1_ref);
2898
0
          }
2899
0
          if (ctx->use_lists[start2_ref].count != 1) {
2900
0
            ir_remove_unused_vars(ctx, start2_ref, end2_ref);
2901
0
          }
2902
2903
0
          insn->op = IR_ABS;
2904
0
          insn->inputs_count = 1;
2905
0
          if (ctx->ir_base[insn->op2].op == IR_NEG) {
2906
0
            neg_ref = insn->op2;
2907
0
            insn->op1 = insn->op3;
2908
0
          } else {
2909
0
            neg_ref = insn->op3;
2910
0
            insn->op1 = insn->op2;
2911
0
          }
2912
0
          insn->op2 = IR_UNUSED;
2913
0
          insn->op3 = IR_UNUSED;
2914
2915
0
          next->op1 = root->op1;
2916
0
          ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref);
2917
0
          ir_use_list_remove_one(ctx, insn->op1, neg_ref);
2918
2919
0
          if (ctx->use_lists[cond_ref].count == 1) {
2920
0
            if (!IR_IS_CONST_REF(insn->op1)) {
2921
0
              ir_use_list_remove_one(ctx, insn->op1, cond_ref);
2922
0
            }
2923
0
            MAKE_NOP(cond);   CLEAR_USES(cond_ref);
2924
0
          } else {
2925
0
            ir_use_list_remove_one(ctx, cond_ref, root_ref);
2926
0
            }
2927
0
          MAKE_NOP(root);   CLEAR_USES(root_ref);
2928
0
          MAKE_NOP(start1); CLEAR_USES(start1_ref);
2929
0
          MAKE_NOP(start2); CLEAR_USES(start2_ref);
2930
0
          MAKE_NOP(end1);   CLEAR_USES(end1_ref);
2931
0
          MAKE_NOP(end2);   CLEAR_USES(end2_ref);
2932
0
          MAKE_NOP(merge);  CLEAR_USES(merge_ref);
2933
0
          MAKE_NOP(&ctx->ir_base[neg_ref]); CLEAR_USES(neg_ref);
2934
2935
0
          ir_bitqueue_add(ctx->iter_worklist, ref);
2936
0
          ir_iter_add_uses(ctx, ref, ctx->iter_worklist);
2937
0
          if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
2938
0
            ir_bitqueue_add(ctx->iter_worklist, next->op1);
2939
0
          }
2940
2941
0
          return 1;
2942
363
        } else if (insn->op2 <= root_ref && insn->op3 <= root_ref
2943
0
          && cond->op != IR_OVERFLOW
2944
          // TODO: temporary disable IF-conversion for RLOAD.
2945
          // We don't track anti-dependencies in GCM and Local Scheduling.
2946
          // As result COND may be scheduled below the following RSTORE.
2947
          // See: https://github.com/dstogov/ir/issues/132
2948
0
          && cond->op != IR_RLOAD
2949
0
          && !((cond->op >= IR_EQ && cond->op <= IR_UNORDERED)
2950
0
            && ((!IR_IS_CONST_REF(cond->op1) && ctx->ir_base[cond->op1].op == IR_RLOAD)
2951
0
             || (!IR_IS_CONST_REF(cond->op2) && ctx->ir_base[cond->op2].op == IR_RLOAD)))) {
2952
          /* COND
2953
           *
2954
           *    prev                     prev
2955
           *    |  cond                  |
2956
           *    | /                      |
2957
           *    IF                       |
2958
           *    | \                      |
2959
           *    |  +-----+               |
2960
           *    |        IF_FALSE        |
2961
           *    IF_TRUE  |           =>  |
2962
           *    |        END             |
2963
           *    END     /                |
2964
           *    |  +---+                 |
2965
           *    | /                      |
2966
           *    MERGE                    |
2967
           *    |    \                   |
2968
           *    |     PHI(A, B)          |    COND(cond, A, B)
2969
           *    next                     next
2970
           */
2971
0
          ir_ref next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs];
2972
0
          ir_insn *next;
2973
2974
0
          if (next_ref == ref) {
2975
0
            next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs + 1];
2976
0
          }
2977
0
          next = &ctx->ir_base[next_ref];
2978
2979
0
          if (ctx->use_lists[start1_ref].count != 1) {
2980
0
            ir_remove_unused_vars(ctx, start1_ref, end1_ref);
2981
0
          }
2982
0
          if (ctx->use_lists[start2_ref].count != 1) {
2983
0
            ir_remove_unused_vars(ctx, start2_ref, end2_ref);
2984
0
          }
2985
2986
0
          insn->op = IR_COND;
2987
0
          insn->inputs_count = 3;
2988
0
          insn->op1 = cond_ref;
2989
0
          if (start1->op == IR_IF_FALSE) {
2990
0
            SWAP_REFS(insn->op2, insn->op3);
2991
0
          }
2992
2993
0
          next->op1 = root->op1;
2994
0
          ir_use_list_replace_one(ctx, cond_ref, root_ref, ref);
2995
0
          ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref);
2996
0
          ir_use_list_remove_one(ctx, root->op2, root_ref);
2997
2998
0
          MAKE_NOP(root);   CLEAR_USES(root_ref);
2999
0
          MAKE_NOP(start1); CLEAR_USES(start1_ref);
3000
0
          MAKE_NOP(start2); CLEAR_USES(start2_ref);
3001
0
          MAKE_NOP(end1);   CLEAR_USES(end1_ref);
3002
0
          MAKE_NOP(end2);   CLEAR_USES(end2_ref);
3003
0
          MAKE_NOP(merge);  CLEAR_USES(merge_ref);
3004
3005
0
          ir_bitqueue_add(ctx->iter_worklist, ref);
3006
0
          ir_iter_add_uses(ctx, ref, ctx->iter_worklist);
3007
0
          if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
3008
0
            ir_bitqueue_add(ctx->iter_worklist, next->op1);
3009
0
          }
3010
3011
0
          return 1;
3012
0
        }
3013
363
      }
3014
363
    }
3015
16.1k
  }
3016
3017
16.1k
  return 0;
3018
16.1k
}
3019
3020
static bool ir_cmp_is_true(ir_op op, const ir_insn *op1, const ir_insn *op2)
3021
0
{
3022
0
  IR_ASSERT(op1->type == op2->type);
3023
0
  if (IR_IS_TYPE_INT(op1->type)) {
3024
0
    if (op == IR_EQ) {
3025
0
      return op1->val.u64 == op2->val.u64;
3026
0
    } else if (op == IR_NE) {
3027
0
      return op1->val.u64 != op2->val.u64;
3028
0
    } else if (op == IR_LT) {
3029
0
      if (IR_IS_TYPE_SIGNED(op1->type)) {
3030
0
        return op1->val.i64 < op2->val.i64;
3031
0
      } else if (ir_type_size[op1->type] == 8) {
3032
0
        return op1->val.i64 < op2->val.i64;
3033
0
      } else if (ir_type_size[op1->type] == 4) {
3034
0
        return op1->val.i32 < op2->val.i32;
3035
0
      } else if (ir_type_size[op1->type] == 2) {
3036
0
        return op1->val.i16 < op2->val.i16;
3037
0
      } else if (ir_type_size[op1->type] == 1) {
3038
0
        return op1->val.i8 < op2->val.i8;
3039
0
      } else {
3040
0
        IR_ASSERT(0);
3041
0
        return 0;
3042
0
      }
3043
0
    } else if (op == IR_GE) {
3044
0
      if (IR_IS_TYPE_SIGNED(op1->type)) {
3045
0
        return op1->val.i64 >= op2->val.i64;
3046
0
      } else if (ir_type_size[op1->type] == 8) {
3047
0
        return op1->val.i64 >= op2->val.i64;
3048
0
      } else if (ir_type_size[op1->type] == 4) {
3049
0
        return op1->val.i32 >= op2->val.i32;
3050
0
      } else if (ir_type_size[op1->type] == 2) {
3051
0
        return op1->val.i16 >= op2->val.i16;
3052
0
      } else if (ir_type_size[op1->type] == 1) {
3053
0
        return op1->val.i8 >= op2->val.i8;
3054
0
      } else {
3055
0
        IR_ASSERT(0);
3056
0
        return 0;
3057
0
      }
3058
0
    } else if (op == IR_LE) {
3059
0
      if (IR_IS_TYPE_SIGNED(op1->type)) {
3060
0
        return op1->val.i64 <= op2->val.i64;
3061
0
      } else if (ir_type_size[op1->type] == 8) {
3062
0
        return op1->val.i64 <= op2->val.i64;
3063
0
      } else if (ir_type_size[op1->type] == 4) {
3064
0
        return op1->val.i32 <= op2->val.i32;
3065
0
      } else if (ir_type_size[op1->type] == 2) {
3066
0
        return op1->val.i16 <= op2->val.i16;
3067
0
      } else if (ir_type_size[op1->type] == 1) {
3068
0
        return op1->val.i8 <= op2->val.i8;
3069
0
      } else {
3070
0
        IR_ASSERT(0);
3071
0
        return 0;
3072
0
      }
3073
0
    } else if (op == IR_GT) {
3074
0
      if (IR_IS_TYPE_SIGNED(op1->type)) {
3075
0
        return op1->val.i64 > op2->val.i64;
3076
0
      } else if (ir_type_size[op1->type] == 8) {
3077
0
        return op1->val.i64 > op2->val.i64;
3078
0
      } else if (ir_type_size[op1->type] == 4) {
3079
0
        return op1->val.i32 > op2->val.i32;
3080
0
      } else if (ir_type_size[op1->type] == 2) {
3081
0
        return op1->val.i16 > op2->val.i16;
3082
0
      } else if (ir_type_size[op1->type] == 1) {
3083
0
        return op1->val.i8 > op2->val.i8;
3084
0
      } else {
3085
0
        IR_ASSERT(0);
3086
0
        return 0;
3087
0
      }
3088
0
    } else if (op == IR_ULT) {
3089
0
      return op1->val.u64 < op2->val.u64;
3090
0
    } else if (op == IR_UGE) {
3091
0
      return op1->val.u64 >= op2->val.u64;
3092
0
    } else if (op == IR_ULE) {
3093
0
      return op1->val.u64 <= op2->val.u64;
3094
0
    } else if (op == IR_UGT) {
3095
0
      return op1->val.u64 > op2->val.u64;
3096
0
    } else {
3097
0
      IR_ASSERT(0);
3098
0
      return 0;
3099
0
    }
3100
0
  } else if (op1->type == IR_DOUBLE) {
3101
0
    if (op == IR_EQ) {
3102
0
      return op1->val.d == op2->val.d;
3103
0
    } else if (op == IR_NE) {
3104
0
      return op1->val.d != op2->val.d;
3105
0
    } else if (op == IR_LT) {
3106
0
      return op1->val.d < op2->val.d;
3107
0
    } else if (op == IR_GE) {
3108
0
      return op1->val.d >= op2->val.d;
3109
0
    } else if (op == IR_LE) {
3110
0
      return op1->val.d <= op2->val.d;
3111
0
    } else if (op == IR_GT) {
3112
0
      return op1->val.d > op2->val.d;
3113
0
    } else if (op == IR_ULT) {
3114
0
      return !(op1->val.d >= op2->val.d);
3115
0
    } else if (op == IR_UGE) {
3116
0
      return !(op1->val.d < op2->val.d);
3117
0
    } else if (op == IR_ULE) {
3118
0
      return !(op1->val.d > op2->val.d);
3119
0
    } else if (op == IR_UGT) {
3120
0
      return !(op1->val.d <= op2->val.d);
3121
0
    } else if (op == IR_ORDERED) {
3122
0
      return !isnan(op1->val.d) && !isnan(op2->val.d);
3123
0
    } else if (op == IR_UNORDERED) {
3124
0
      return isnan(op1->val.d) || isnan(op2->val.d);
3125
0
    } else {
3126
0
      IR_ASSERT(0);
3127
0
      return 0;
3128
0
    }
3129
0
  } else {
3130
0
    IR_ASSERT(op1->type == IR_FLOAT);
3131
0
    if (op == IR_EQ) {
3132
0
      return op1->val.f == op2->val.f;
3133
0
    } else if (op == IR_NE) {
3134
0
      return op1->val.f != op2->val.f;
3135
0
    } else if (op == IR_LT) {
3136
0
      return op1->val.f < op2->val.f;
3137
0
    } else if (op == IR_GE) {
3138
0
      return op1->val.f >= op2->val.f;
3139
0
    } else if (op == IR_LE) {
3140
0
      return op1->val.f <= op2->val.f;
3141
0
    } else if (op == IR_GT) {
3142
0
      return op1->val.f > op2->val.f;
3143
0
    } else if (op == IR_ULT) {
3144
0
      return !(op1->val.f >= op2->val.f);
3145
0
    } else if (op == IR_UGE) {
3146
0
      return !(op1->val.f < op2->val.f);
3147
0
    } else if (op == IR_ULE) {
3148
0
      return !(op1->val.f > op2->val.f);
3149
0
    } else if (op == IR_UGT) {
3150
0
      return !(op1->val.f <= op2->val.f);
3151
0
    } else if (op == IR_ORDERED) {
3152
0
      return !isnan(op1->val.f) && !isnan(op2->val.f);
3153
0
    } else if (op == IR_UNORDERED) {
3154
0
      return isnan(op1->val.f) || isnan(op2->val.f);
3155
0
    } else {
3156
0
      IR_ASSERT(0);
3157
0
      return 0;
3158
0
    }
3159
0
  }
3160
0
}
3161
3162
static bool ir_try_split_if(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
3163
0
{
3164
0
  ir_ref cond_ref = insn->op2;
3165
0
  ir_insn *cond = &ctx->ir_base[cond_ref];
3166
3167
0
  if (cond->op == IR_PHI
3168
0
   && cond->inputs_count == 3
3169
0
   && cond->op1 == insn->op1
3170
0
   && ((IR_IS_CONST_REF(cond->op2) && !IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op))
3171
0
    || (IR_IS_CONST_REF(cond->op3) && !IR_IS_SYM_CONST(ctx->ir_base[cond->op3].op)))) {
3172
0
    ir_ref merge_ref = insn->op1;
3173
0
    ir_insn *merge = &ctx->ir_base[merge_ref];
3174
3175
0
    if (ctx->use_lists[merge_ref].count == 2) {
3176
0
      ir_ref end1_ref = merge->op1, end2_ref = merge->op2;
3177
0
      ir_insn *end1 = &ctx->ir_base[end1_ref];
3178
0
      ir_insn *end2 = &ctx->ir_base[end2_ref];
3179
3180
0
      if (end1->op == IR_END && end2->op == IR_END) {
3181
0
        ir_ref if_true_ref, if_false_ref;
3182
0
        ir_insn *if_true, *if_false;
3183
0
        ir_op op = IR_IF_FALSE;
3184
3185
0
        ir_get_true_false_refs(ctx, ref, &if_true_ref, &if_false_ref);
3186
3187
0
        if (!IR_IS_CONST_REF(cond->op2) || IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)) {
3188
0
          IR_ASSERT(IR_IS_CONST_REF(cond->op3));
3189
0
          SWAP_REFS(cond->op2, cond->op3);
3190
0
          SWAP_REFS(merge->op1, merge->op2);
3191
0
          SWAP_REFS(end1_ref, end2_ref);
3192
0
          SWAP_INSNS(end1, end2);
3193
0
        }
3194
0
        if (ir_const_is_true(&ctx->ir_base[cond->op2])) {
3195
0
          SWAP_REFS(if_true_ref, if_false_ref);
3196
0
          op = IR_IF_TRUE;
3197
0
        }
3198
0
        if_true = &ctx->ir_base[if_true_ref];
3199
0
        if_false = &ctx->ir_base[if_false_ref];
3200
3201
0
        if (IR_IS_CONST_REF(cond->op3) && !IR_IS_SYM_CONST(ctx->ir_base[cond->op3].op)) {
3202
0
          if (ir_const_is_true(&ctx->ir_base[cond->op3]) ^ (op == IR_IF_TRUE)) {
3203
            /* Simple IF Split
3204
             *
3205
             *    |        |               |        |
3206
             *    |        END             |        END
3207
             *    END     /                END       \
3208
             *    |  +---+                 |          +
3209
             *    | /                      |          |
3210
             *    MERGE                    |          |
3211
             *    | \                      |          |
3212
             *    |  PHI(false, true)      |          |
3213
             *    | /                      |          |
3214
             *    IF                   =>  |          |
3215
             *    | \                      |          |
3216
             *    |  +------+              |          |
3217
             *    |         IF_TRUE        |          BEGIN
3218
             *    IF_FALSE  |              BEGIN
3219
             *    |                        |
3220
             */
3221
0
            ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3222
0
            ir_use_list_replace_one(ctx, end2_ref, merge_ref, if_true_ref);
3223
3224
0
            MAKE_NOP(merge); CLEAR_USES(merge_ref);
3225
0
            MAKE_NOP(cond);  CLEAR_USES(cond_ref);
3226
0
            MAKE_NOP(insn);  CLEAR_USES(ref);
3227
3228
0
            if_false->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1);
3229
0
            if_false->op1 = end1_ref;
3230
0
            if_false->op2 = IR_UNUSED;
3231
3232
0
            if_true->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1);
3233
0
            if_true->op1 = end2_ref;
3234
0
            if_true->op2 = IR_UNUSED;
3235
3236
0
            ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3237
0
            ir_bitqueue_add(ctx->iter_worklist, if_true_ref);
3238
3239
0
            return 1;
3240
0
          } else {
3241
            /* Simple IF Split
3242
             *
3243
             *    |        |               |        |
3244
             *    |        END             |        END
3245
             *    END     /                END      |
3246
             *    |  +---+                 |        |
3247
             *    | /                      |        |
3248
             *    MERGE                    |        +
3249
             *    | \                      |       /
3250
             *    |  PHI(false, false)     |      /
3251
             *    | /                      |     /
3252
             *    IF                   =>  |    /
3253
             *    | \                      |   /
3254
             *    |  +------+              |  /
3255
             *    |         IF_TRUE        | /        BEGIN(unreachable)
3256
             *    IF_FALSE  |              MERGE
3257
             *    |                        |
3258
             */
3259
0
            ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3260
0
            ir_use_list_replace_one(ctx, end2_ref, merge_ref, if_false_ref);
3261
3262
0
            MAKE_NOP(merge); CLEAR_USES(merge_ref);
3263
0
            MAKE_NOP(cond);  CLEAR_USES(cond_ref);
3264
0
            MAKE_NOP(insn);  CLEAR_USES(ref);
3265
3266
0
            if_false->optx = IR_OPTX(IR_MERGE, IR_VOID, 2);
3267
0
            if_false->op1 = end1_ref;
3268
0
            if_false->op2 = end2_ref;
3269
3270
0
            if_true->optx = IR_BEGIN;
3271
0
            if_true->op1 = IR_UNUSED;
3272
0
            if_true->op2 = IR_UNUSED;
3273
3274
0
            ctx->flags2 &= ~IR_CFG_REACHABLE;
3275
3276
0
            ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3277
3278
0
            return 1;
3279
0
          }
3280
0
        }
3281
3282
        /* Simple IF Split
3283
         *
3284
         *    |        |               |        |
3285
         *    |        END             |        IF(X)
3286
         *    END     /                END     / \
3287
         *    |  +---+                 |   +--+   +
3288
         *    | /                      |  /       |
3289
         *    MERGE                    | IF_FALSE |
3290
         *    | \                      | |        |
3291
         *    |  PHI(false, X)         | |        |
3292
         *    | /                      | |        |
3293
         *    IF                   =>  | END      |
3294
         *    | \                      | |        |
3295
         *    |  +------+              | |        |
3296
         *    |         IF_TRUE        | |        IF_TRUE
3297
         *    IF_FALSE  |              MERGE
3298
         *    |                        |
3299
         */
3300
0
        ir_use_list_remove_one(ctx, merge_ref, cond_ref);
3301
0
        ir_use_list_remove_one(ctx, ref, if_true_ref);
3302
0
        if (!IR_IS_CONST_REF(cond->op3)) {
3303
0
          ir_use_list_replace_one(ctx, cond->op3, cond_ref, end2_ref);
3304
0
        }
3305
0
        ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3306
0
        ir_use_list_add(ctx, end2_ref, if_true_ref);
3307
3308
0
        end2->optx = IR_OPTX(IR_IF, IR_VOID, 2);
3309
0
        end2->op2 = cond->op3;
3310
0
        ir_bitqueue_add(ctx->iter_worklist, end2_ref);
3311
3312
0
        merge->optx = IR_OPTX(op, IR_VOID, 1);
3313
0
        merge->op1 = end2_ref;
3314
0
        merge->op2 = IR_UNUSED;
3315
3316
0
        MAKE_NOP(cond);
3317
0
        CLEAR_USES(cond_ref);
3318
3319
0
        insn->optx = IR_OPTX(IR_END, IR_VOID, 1);
3320
0
        insn->op1 = merge_ref;
3321
0
        insn->op2 = IR_UNUSED;
3322
3323
0
        if_true->op1 = end2_ref;
3324
3325
0
        if_false->optx = IR_OPTX(IR_MERGE, IR_VOID, 2);
3326
0
        if_false->op1 = end1_ref;
3327
0
        if_false->op2 = ref;
3328
3329
0
        ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3330
0
        if (ctx->ir_base[end2->op1].op == IR_BEGIN || ctx->ir_base[end2->op1].op == IR_MERGE) {
3331
0
          ir_bitqueue_add(ctx->iter_worklist, end2->op1);
3332
0
        }
3333
3334
0
        return 1;
3335
0
      }
3336
0
    }
3337
0
  }
3338
3339
0
  return 0;
3340
0
}
3341
3342
static bool ir_try_split_if_cmp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
3343
0
{
3344
0
  ir_ref cond_ref = insn->op2;
3345
0
  ir_insn *cond = &ctx->ir_base[cond_ref];
3346
3347
0
  if (cond->op >= IR_EQ && cond->op <= IR_UGT
3348
0
   && IR_IS_CONST_REF(cond->op2)
3349
0
   && !IR_IS_SYM_CONST(ctx->ir_base[cond->op2].op)
3350
0
   && ctx->use_lists[insn->op2].count == 1) {
3351
0
    ir_ref phi_ref = cond->op1;
3352
0
    ir_insn *phi = &ctx->ir_base[phi_ref];
3353
3354
0
    if (phi->op == IR_PHI
3355
0
     && phi->inputs_count == 3
3356
0
     && phi->op1 == insn->op1
3357
0
     && ctx->use_lists[phi_ref].count == 1
3358
0
     && ((IR_IS_CONST_REF(phi->op2) && !IR_IS_SYM_CONST(ctx->ir_base[phi->op2].op))
3359
0
      || (IR_IS_CONST_REF(phi->op3) && !IR_IS_SYM_CONST(ctx->ir_base[phi->op3].op)))) {
3360
0
      ir_ref merge_ref = insn->op1;
3361
0
      ir_insn *merge = &ctx->ir_base[merge_ref];
3362
3363
0
      if (ctx->use_lists[merge_ref].count == 2) {
3364
0
        ir_ref end1_ref = merge->op1, end2_ref = merge->op2;
3365
0
        ir_insn *end1 = &ctx->ir_base[end1_ref];
3366
0
        ir_insn *end2 = &ctx->ir_base[end2_ref];
3367
3368
0
        if (end1->op == IR_END && end2->op == IR_END) {
3369
0
          ir_ref if_true_ref, if_false_ref;
3370
0
          ir_insn *if_true, *if_false;
3371
0
          ir_op op = IR_IF_FALSE;
3372
3373
0
          ir_get_true_false_refs(ctx, ref, &if_true_ref, &if_false_ref);
3374
3375
0
          if (!IR_IS_CONST_REF(phi->op2) || IR_IS_SYM_CONST(ctx->ir_base[phi->op2].op)) {
3376
0
            IR_ASSERT(IR_IS_CONST_REF(phi->op3));
3377
0
            SWAP_REFS(phi->op2, phi->op3);
3378
0
            SWAP_REFS(merge->op1, merge->op2);
3379
0
            SWAP_REFS(end1_ref, end2_ref);
3380
0
            SWAP_INSNS(end1, end2);
3381
0
          }
3382
0
          if (ir_cmp_is_true(cond->op, &ctx->ir_base[phi->op2], &ctx->ir_base[cond->op2])) {
3383
0
            SWAP_REFS(if_true_ref, if_false_ref);
3384
0
            op = IR_IF_TRUE;
3385
0
          }
3386
0
          if_true = &ctx->ir_base[if_true_ref];
3387
0
          if_false = &ctx->ir_base[if_false_ref];
3388
3389
0
          if (IR_IS_CONST_REF(phi->op3) && !IR_IS_SYM_CONST(ctx->ir_base[phi->op3].op)) {
3390
0
            if (ir_cmp_is_true(cond->op, &ctx->ir_base[phi->op3], &ctx->ir_base[cond->op2]) ^ (op == IR_IF_TRUE)) {
3391
              /* IF Split
3392
               *
3393
               *    |        |               |        |
3394
               *    |        END             |        END
3395
               *    END     /                END      |
3396
               *    |  +---+                 |        |
3397
               *    | /                      |        |
3398
               *    MERGE                    |        |
3399
               *    | \                      |        |
3400
               *    |  PHI(C1, X)            |        |
3401
               *    |  |                     |        |
3402
               *    |  CMP(_, C2)            |        |
3403
               *    | /                      |        |
3404
               *    IF                   =>  |        |
3405
               *    | \                      |        |
3406
               *    |  +------+              |        |
3407
               *    |         IF_TRUE        |        BEGIN
3408
               *    IF_FALSE  |              BEGIN    |
3409
               *    |                        |
3410
               */
3411
3412
0
              ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3413
0
              ir_use_list_replace_one(ctx, end2_ref, merge_ref, if_true_ref);
3414
3415
0
              MAKE_NOP(merge); CLEAR_USES(merge_ref);
3416
0
              MAKE_NOP(phi);   CLEAR_USES(phi_ref);
3417
0
              MAKE_NOP(cond);  CLEAR_USES(cond_ref);
3418
0
              MAKE_NOP(insn);  CLEAR_USES(ref);
3419
3420
0
              if_false->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1);
3421
0
              if_false->op1 = end1_ref;
3422
0
              if_false->op2 = IR_UNUSED;
3423
3424
0
              if_true->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1);
3425
0
              if_true->op1 = end2_ref;
3426
0
              if_true->op2 = IR_UNUSED;
3427
3428
0
              ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3429
0
              ir_bitqueue_add(ctx->iter_worklist, if_true_ref);
3430
3431
0
              return 1;
3432
0
            } else {
3433
              /* IF Split
3434
               *
3435
               *    |        |               |        |
3436
               *    |        END             |        END
3437
               *    END     /                END      |
3438
               *    |  +---+                 |        |
3439
               *    | /                      |        |
3440
               *    MERGE                    |        |
3441
               *    | \                      |        |
3442
               *    |  PHI(C1, X)            |        |
3443
               *    |  |                     |        +
3444
               *    |  CMP(_, C2)            |       /
3445
               *    | /                      |      /
3446
               *    IF                   =>  |     /
3447
               *    | \                      |    /
3448
               *    |  +------+              |   /
3449
               *    |         IF_TRUE        |  /      BEGIN(unreachable)
3450
               *    IF_FALSE  |              MERGE     |
3451
               *    |                        |
3452
               */
3453
3454
0
              ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3455
0
              ir_use_list_replace_one(ctx, end2_ref, merge_ref, if_false_ref);
3456
3457
0
              MAKE_NOP(merge); CLEAR_USES(merge_ref);
3458
0
              MAKE_NOP(phi);   CLEAR_USES(phi_ref);
3459
0
              MAKE_NOP(cond);  CLEAR_USES(cond_ref);
3460
0
              MAKE_NOP(insn);  CLEAR_USES(ref);
3461
3462
0
              if_false->optx = IR_OPTX(IR_MERGE, IR_VOID, 2);
3463
0
              if_false->op1 = end1_ref;
3464
0
              if_false->op2 = end2_ref;
3465
3466
0
              if_true->optx = IR_BEGIN;
3467
0
              if_true->op1 = IR_UNUSED;
3468
0
              if_true->op2 = IR_UNUSED;
3469
3470
0
              ctx->flags2 &= ~IR_CFG_REACHABLE;
3471
3472
0
              ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3473
3474
0
              return 1;
3475
0
            }
3476
0
          } else {
3477
            /* IF Split
3478
             *
3479
             *    |        |               |        |
3480
             *    |        END             |        IF<----+
3481
             *    END     /                END     / \     |
3482
             *    |  +---+                 |   +--+   +    |
3483
             *    | /                      |  /       |    |
3484
             *    MERGE                    | IF_FALSE |    |
3485
             *    | \                      | |        |    |
3486
             *    |  PHI(C1, X)            | |        |    |
3487
             *    |  |                     | |        |    |
3488
             *    |  CMP(_, C2)            | |        |    CMP(X, C2)
3489
             *    | /                      | |        |
3490
             *    IF                   =>  | END      |
3491
             *    | \                      | |        |
3492
             *    |  +------+              | |        |
3493
             *    |         IF_TRUE        | |        IF_TRUE
3494
             *    IF_FALSE  |              MERGE
3495
             *    |                        |
3496
             */
3497
3498
0
            ir_use_list_remove_one(ctx, merge_ref, phi_ref);
3499
0
            ir_use_list_remove_one(ctx, ref, if_true_ref);
3500
0
            if (!IR_IS_CONST_REF(phi->op3)) {
3501
0
              ir_use_list_replace_one(ctx, phi->op3, phi_ref, insn->op2);
3502
0
            }
3503
0
            ir_use_list_replace_one(ctx, end1_ref, merge_ref, if_false_ref);
3504
0
            ir_use_list_replace_one(ctx, cond_ref, ref, end2_ref);
3505
0
            ir_use_list_add(ctx, end2_ref, if_true_ref);
3506
3507
0
            end2->optx = IR_OPTX(IR_IF, IR_VOID, 2);
3508
0
            end2->op2 = insn->op2;
3509
0
            ir_bitqueue_add(ctx->iter_worklist, end2_ref);
3510
3511
0
            merge->optx = IR_OPTX(op, IR_VOID, 1);
3512
0
            merge->op1 = end2_ref;
3513
0
            merge->op2 = IR_UNUSED;
3514
3515
0
            cond->op1 = phi->op3;
3516
0
            MAKE_NOP(phi);
3517
0
            CLEAR_USES(phi_ref);
3518
3519
0
            insn->optx = IR_OPTX(IR_END, IR_VOID, 1);
3520
0
            insn->op1 = merge_ref;
3521
0
            insn->op2 = IR_UNUSED;
3522
3523
0
            if_true->op1 = end2_ref;
3524
3525
0
            if_false->optx = IR_OPTX(IR_MERGE, IR_VOID, 2);
3526
0
            if_false->op1 = end1_ref;
3527
0
            if_false->op2 = ref;
3528
3529
0
            ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3530
0
            if (ctx->ir_base[end2->op1].op == IR_BEGIN || ctx->ir_base[end2->op1].op == IR_MERGE) {
3531
0
              ir_bitqueue_add(ctx->iter_worklist, end2->op1);
3532
0
            }
3533
3534
0
            return 1;
3535
0
          }
3536
0
        }
3537
0
      }
3538
0
    }
3539
0
  }
3540
3541
0
  return 0;
3542
0
}
3543
3544
static void ir_iter_optimize_merge(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge)
3545
72.5k
{
3546
72.5k
  ir_use_list *use_list = &ctx->use_lists[merge_ref];
3547
3548
72.5k
  if (use_list->count == 1) {
3549
54.9k
    ir_try_remove_empty_diamond(ctx, merge_ref, merge);
3550
54.9k
  } else if (use_list->count == 2) {
3551
16.6k
    if (merge->inputs_count == 2) {
3552
16.1k
      ir_ref phi_ref = ctx->use_edges[use_list->refs];
3553
16.1k
      ir_insn *phi = &ctx->ir_base[phi_ref];
3554
3555
16.1k
      ir_ref next_ref = ctx->use_edges[use_list->refs + 1];
3556
16.1k
      ir_insn *next = &ctx->ir_base[next_ref];
3557
3558
16.1k
      if (next->op == IR_PHI) {
3559
0
        SWAP_REFS(phi_ref, next_ref);
3560
0
        SWAP_INSNS(phi, next);
3561
0
      }
3562
3563
16.1k
      if (phi->op == IR_PHI && next->op != IR_PHI) {
3564
16.1k
        if (next->op == IR_IF && next->op1 == merge_ref && ctx->use_lists[phi_ref].count == 1) {
3565
1
          if (next->op2 == phi_ref) {
3566
0
            if (ir_try_split_if(ctx, next_ref, next)) {
3567
0
              return;
3568
0
            }
3569
1
          } else {
3570
1
            ir_insn *cmp = &ctx->ir_base[next->op2];
3571
3572
1
            if (cmp->op >= IR_EQ && cmp->op <= IR_UGT
3573
0
             && cmp->op1 == phi_ref
3574
0
             && IR_IS_CONST_REF(cmp->op2)
3575
0
             && !IR_IS_SYM_CONST(ctx->ir_base[cmp->op2].op)
3576
0
             && ctx->use_lists[next->op2].count == 1) {
3577
0
              if (ir_try_split_if_cmp(ctx, next_ref, next)) {
3578
0
                return;
3579
0
              }
3580
0
            }
3581
1
          }
3582
1
        }
3583
16.1k
        if (IR_IS_TYPE_SCALAR(phi->type)) {
3584
16.1k
          ir_optimize_phi(ctx, merge_ref, merge, phi_ref, phi);
3585
16.1k
        }
3586
16.1k
      }
3587
16.1k
    }
3588
16.6k
  }
3589
72.5k
}
3590
3591
static ir_ref ir_find_ext_use(const ir_ctx *ctx, ir_ref ref)
3592
12.0k
{
3593
12.0k
  ir_use_list *use_list = &ctx->use_lists[ref];
3594
12.0k
  ir_ref *p, n, use;
3595
12.0k
  ir_insn *use_insn;
3596
3597
30.2k
  for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) {
3598
18.1k
    use = *p;
3599
18.1k
    use_insn = &ctx->ir_base[use];
3600
18.1k
    if (use_insn->op == IR_SEXT || use_insn->op == IR_ZEXT) {
3601
0
      return use;
3602
0
    }
3603
18.1k
  }
3604
12.0k
  return IR_UNUSED;
3605
12.0k
}
3606
3607
static void ir_iter_optimize_induction_var(ir_ctx *ctx, ir_ref phi_ref, ir_ref op_ref)
3608
6.04k
{
3609
6.04k
  ir_ref ext_ref;
3610
3611
6.04k
  ext_ref = ir_find_ext_use(ctx, phi_ref);
3612
6.04k
  if (!ext_ref) {
3613
6.04k
    ext_ref = ir_find_ext_use(ctx, op_ref);
3614
6.04k
  }
3615
6.04k
  if (ext_ref) {
3616
0
    ir_try_promote_induction_var_ext(ctx, ext_ref, phi_ref, op_ref);
3617
0
  }
3618
6.04k
}
3619
3620
static void ir_iter_optimize_loop(ir_ctx *ctx, ir_ref loop_ref, ir_insn *loop)
3621
3.21k
{
3622
3.21k
  ir_ref n;
3623
3624
3.21k
  if (loop->inputs_count != 2 || ctx->use_lists[loop_ref].count <= 1) {
3625
191
    return;
3626
191
  }
3627
3628
  /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */
3629
12.0k
  for (n = 0; n < ctx->use_lists[loop_ref].count; n++) {
3630
    /* "use_lists" may be reallocated by ir_ext_ref() */
3631
9.07k
    ir_ref use = ctx->use_edges[ctx->use_lists[loop_ref].refs + n];
3632
9.07k
    ir_insn *use_insn = &ctx->ir_base[use];
3633
3634
9.07k
    if (use_insn->op == IR_PHI) {
3635
6.04k
      ir_ref op_ref = use_insn->op3;
3636
6.04k
      ir_insn *op_insn = &ctx->ir_base[op_ref];
3637
3638
6.04k
      if (op_insn->op == IR_ADD || op_insn->op == IR_SUB || op_insn->op == IR_MUL) {
3639
6.04k
        if (op_insn->op1 == use) {
3640
6.04k
          if (ir_is_loop_invariant(ctx, op_insn->op2, loop_ref)) {
3641
6.04k
            ir_iter_optimize_induction_var(ctx, use, op_ref);
3642
6.04k
          }
3643
6.04k
        } else if (op_insn->op2 == use) {
3644
0
          if (ir_is_loop_invariant(ctx, op_insn->op1, loop_ref)) {
3645
0
            ir_iter_optimize_induction_var(ctx, use, op_ref);
3646
0
          }
3647
0
        }
3648
6.04k
        }
3649
6.04k
    }
3650
9.07k
  }
3651
3.02k
}
3652
3653
static ir_ref ir_iter_optimize_condition(ir_ctx *ctx, ir_ref control, ir_ref condition, bool *swap)
3654
114k
{
3655
114k
  ir_insn *condition_insn = &ctx->ir_base[condition];
3656
3657
114k
  while (((condition_insn->op == IR_BITCAST && IR_IS_TYPE_SCALAR(ctx->ir_base[condition_insn->op1].type))
3658
114k
    || condition_insn->op == IR_ZEXT
3659
114k
    || condition_insn->op == IR_SEXT)
3660
0
   && ctx->use_lists[condition].count == 1) {
3661
0
    condition = condition_insn->op1;
3662
0
    condition_insn = &ctx->ir_base[condition];
3663
0
  }
3664
3665
114k
  IR_ASSERT(IR_IS_TYPE_SCALAR(condition_insn->type));
3666
3667
114k
  if (condition_insn->opt == IR_OPT(IR_NOT, IR_BOOL)) {
3668
0
    *swap = 1;
3669
0
    condition = condition_insn->op1;
3670
0
    condition_insn = &ctx->ir_base[condition];
3671
0
  }
3672
3673
114k
  if (condition_insn->op == IR_NE && IR_IS_CONST_REF(condition_insn->op2)) {
3674
565
    ir_insn *val_insn = &ctx->ir_base[condition_insn->op2];
3675
3676
565
    if (IR_IS_TYPE_INT(val_insn->type) && val_insn->val.u64 == 0) {
3677
0
      condition = condition_insn->op1;
3678
0
      condition_insn = &ctx->ir_base[condition];
3679
0
    }
3680
113k
  } else if (condition_insn->op == IR_EQ && IR_IS_CONST_REF(condition_insn->op2)) {
3681
17.7k
    ir_insn *val_insn = &ctx->ir_base[condition_insn->op2];
3682
3683
17.7k
    if (condition_insn->op2 == IR_TRUE) {
3684
0
      condition = condition_insn->op1;
3685
0
      condition_insn = &ctx->ir_base[condition];
3686
17.7k
    } else if (IR_IS_TYPE_INT(val_insn->type) && val_insn->val.u64 == 0) {
3687
14
      condition = condition_insn->op1;
3688
14
      condition_insn = &ctx->ir_base[condition];
3689
14
      *swap = !*swap;
3690
14
    }
3691
17.7k
  }
3692
3693
114k
  if (condition_insn->op == IR_SHL && IR_IS_CONST_REF(condition_insn->op1)) {
3694
0
    ir_insn *val_insn = &ctx->ir_base[condition_insn->op1];
3695
0
    if (!IR_IS_SYM_CONST(val_insn->op) && val_insn->val.u64 == 1) {
3696
0
      return IR_TRUE;
3697
0
    }
3698
114k
  } else if (condition_insn->op == IR_SHR
3699
0
      && ctx->use_lists[condition].count == 1
3700
0
      && IR_IS_CONST_REF(condition_insn->op2)
3701
0
      && !IR_IS_SYM_CONST(ctx->ir_base[condition_insn->op2].op)) {
3702
0
    uint64_t c1, c2 = ctx->ir_base[condition_insn->op2].val.u64;
3703
0
    ir_insn *op1_insn = &ctx->ir_base[condition_insn->op1];
3704
0
    ir_val val = {0};
3705
3706
0
    if (op1_insn->op == IR_SHL
3707
0
     && ctx->use_lists[condition_insn->op1].count == 1
3708
0
     && IR_IS_CONST_REF(op1_insn->op2)
3709
0
     && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
3710
      /* IF(SHR(SHL(X, C1), C2)) => IF(AND(X, ((-1) << C2) >> C1) */
3711
0
      c1 = ctx->ir_base[op1_insn->op2].val.u64;
3712
0
      if (op1_insn->op1 > 0) {
3713
0
        ir_use_list_replace_one(ctx, op1_insn->op1, condition_insn->op1, condition);
3714
0
      }
3715
0
      CLEAR_USES(condition_insn->op1);
3716
0
      condition_insn->op1 = op1_insn->op1;
3717
0
      MAKE_NOP(op1_insn);
3718
0
    } else if (op1_insn->op == IR_ADD
3719
0
     && ctx->use_lists[condition_insn->op1].count == 1
3720
0
     && op1_insn->op1 == op1_insn->op2) {
3721
      /* IF(SHR(ADD(X, X), C2)) => IF(AND(X, ((-1) << C2) >> 1) */
3722
0
      c1 = 1;
3723
0
      if (op1_insn->op1 > 0) {
3724
0
        ir_use_list_replace_one(ctx, op1_insn->op1, condition_insn->op1, condition);
3725
0
        ir_use_list_remove_one(ctx, op1_insn->op1, condition_insn->op1);
3726
0
      }
3727
0
      CLEAR_USES(condition_insn->op1);
3728
0
      condition_insn->op1 = op1_insn->op1;
3729
0
      MAKE_NOP(op1_insn);
3730
0
    } else if (op1_insn->op == IR_MUL
3731
0
     && ctx->use_lists[condition_insn->op1].count == 1
3732
0
     && IR_IS_CONST_REF(op1_insn->op2)
3733
0
     && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)
3734
0
     && IR_IS_POWER_OF_TWO(ctx->ir_base[op1_insn->op2].val.u64)) {
3735
      /* IF(SHR(MUL(X, C1), C2)) => IF(AND(X, ((-1) << C2) >> log2(C1)) */
3736
0
      c1 = IR_LOG2(ctx->ir_base[op1_insn->op2].val.u64);
3737
0
      if (op1_insn->op1 > 0) {
3738
0
        ir_use_list_replace_one(ctx, op1_insn->op1, condition_insn->op1, condition);
3739
0
      }
3740
0
      CLEAR_USES(condition_insn->op1);
3741
0
      condition_insn->op1 = op1_insn->op1;
3742
0
      MAKE_NOP(op1_insn);
3743
0
    } else {
3744
      /* IF(SHR(X, C2)) => IF(AND(X, (-1) << C2) */
3745
0
      c1 = 0;
3746
0
    }
3747
3748
0
    switch (ir_type_size[condition_insn->type]) {
3749
0
      case 1:
3750
0
        val.u64 = (uint8_t)((uint8_t)((uint8_t)(-1) << ((uint8_t)c2 & 7)) >> ((uint8_t)c1 & 7));
3751
0
        break;
3752
0
      case 2:
3753
0
        val.u64 = (uint16_t)((uint16_t)((uint16_t)(-1) << ((uint16_t)c2 & 0xf)) >> ((uint16_t)c1 & 0xf));
3754
0
        break;
3755
0
      case 4:
3756
0
        val.u64 = (uint32_t)((uint32_t)((uint32_t)(-1) << ((uint32_t)c2 & 0x1f)) >> ((uint32_t)c1 & 0x1f));
3757
0
        break;
3758
0
      case 8:
3759
0
        val.u64 = (((uint64_t)(-1) << (c2 & 0x3f)) >> (c1 & 0x3f));
3760
0
        break;
3761
0
      default:
3762
0
        IR_ASSERT(0);
3763
0
    }
3764
0
    if (IR_IS_TYPE_SIGNED(condition_insn->type)) {
3765
0
      val.u64 = ir_fix_signed(condition_insn->type, val.u64);
3766
0
    }
3767
3768
0
    ir_ref c = ir_const(ctx, val, condition_insn->type);
3769
0
    condition_insn = &ctx->ir_base[condition];
3770
0
    condition_insn->op = IR_AND;
3771
0
    condition_insn->op2 = c;
3772
0
  }
3773
3774
114k
  if (condition_insn->op == IR_AND && IR_IS_CONST_REF(condition_insn->op2)) {
3775
36.2k
    ir_insn *val_insn = &ctx->ir_base[condition_insn->op2];
3776
36.2k
    ir_insn *op1_insn = &ctx->ir_base[condition_insn->op1];
3777
3778
36.2k
    if (!IR_IS_SYM_CONST(val_insn->op)
3779
36.2k
     && ctx->use_lists[condition].count == 1
3780
36.1k
     && ctx->use_lists[condition_insn->op1].count == 1
3781
2
     && (op1_insn->op == IR_ZEXT || op1_insn->op == IR_SEXT)
3782
0
     && val_insn->val.u64 <= (((uint64_t)(0-1ULL)) >> (64 - ir_type_size[ctx->ir_base[op1_insn->op1].type] * 8))) {
3783
      /* IF(AND(ZEXT(X), C)) => IF(AND(X, C)) */
3784
0
      if (op1_insn->op1 > 0) {
3785
0
        ir_use_list_replace_one(ctx, op1_insn->op1, condition_insn->op1, condition);
3786
0
      }
3787
0
      ir_ref op1_ref = condition_insn->op1;
3788
0
      CLEAR_USES(condition_insn->op1);
3789
0
      condition_insn->type = ctx->ir_base[op1_insn->op1].type;
3790
0
      condition_insn->op1 = op1_insn->op1;
3791
0
      ir_val val = val_insn->val;
3792
0
      if (IR_IS_TYPE_SIGNED(condition_insn->type)) {
3793
0
        val.u64 = ir_fix_signed(condition_insn->type, val.u64);
3794
0
      }
3795
0
      ir_ref c = ir_const(ctx, val, condition_insn->type);
3796
0
      condition_insn = &ctx->ir_base[condition];
3797
0
      condition_insn->op2 = c;
3798
0
      ir_bitqueue_add(ctx->iter_worklist, condition);
3799
0
      MAKE_NOP(&ctx->ir_base[op1_ref]);
3800
0
      return condition;
3801
0
    }
3802
36.2k
  }
3803
3804
114k
  while (((condition_insn->op == IR_BITCAST && IR_IS_TYPE_SCALAR(ctx->ir_base[condition_insn->op1].type))
3805
114k
    || condition_insn->op == IR_ZEXT
3806
114k
    || condition_insn->op == IR_SEXT)
3807
0
   && ctx->use_lists[condition].count == 1) {
3808
0
    condition = condition_insn->op1;
3809
0
    condition_insn = &ctx->ir_base[condition];
3810
0
  }
3811
3812
114k
  if (condition_insn->op == IR_ALLOCA || condition_insn->op == IR_VADDR) {
3813
0
    return IR_TRUE;
3814
0
  }
3815
3816
114k
  if (!IR_IS_CONST_REF(condition) && ctx->use_lists[condition].count > 1) {
3817
50.2k
    condition = ir_check_dominating_predicates(ctx, control, condition);
3818
50.2k
  }
3819
3820
114k
  return condition;
3821
114k
}
3822
3823
static void ir_iter_optimize_if(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
3824
114k
{
3825
114k
  bool swap = 0;
3826
114k
  ir_ref condition = ir_iter_optimize_condition(ctx, insn->op1, insn->op2, &swap);
3827
3828
114k
  insn = &ctx->ir_base[ref];
3829
3830
114k
  if (swap) {
3831
14
    ir_use_list *use_list = &ctx->use_lists[ref];
3832
14
    ir_ref *p, use;
3833
3834
14
    IR_ASSERT(use_list->count == 2);
3835
14
    p = ctx->use_edges + use_list->refs;
3836
14
    use = *p;
3837
14
    if (ctx->ir_base[use].op == IR_IF_TRUE) {
3838
10
      ctx->ir_base[use].op = IR_IF_FALSE;
3839
10
      use = *(p+1);
3840
10
      ctx->ir_base[use].op = IR_IF_TRUE;
3841
10
    } else {
3842
4
      ctx->ir_base[use].op = IR_IF_TRUE;
3843
4
      use = *(p+1);
3844
4
      ctx->ir_base[use].op = IR_IF_FALSE;
3845
4
    }
3846
14
  }
3847
3848
114k
  if (IR_IS_CONST_REF(condition)) {
3849
    /*
3850
     *    |                        |
3851
     *    IF(TRUE)             =>  END
3852
     *    | \                      |
3853
     *    |  +------+              |
3854
     *    |         IF_TRUE        |        BEGIN(unreachable)
3855
     *    IF_FALSE  |              BEGIN
3856
     *    |                        |
3857
     */
3858
10
    ir_ref if_true_ref, if_false_ref;
3859
10
    ir_insn *if_true, *if_false;
3860
3861
10
    insn->optx = IR_OPTX(IR_END, IR_VOID, 1);
3862
10
    if (!IR_IS_CONST_REF(insn->op2)) {
3863
0
      ir_use_list_remove_one(ctx, insn->op2, ref);
3864
0
      ir_bitqueue_add(ctx->iter_worklist, insn->op2);
3865
0
    }
3866
10
    insn->op2 = IR_UNUSED;
3867
3868
10
    ir_get_true_false_refs(ctx, ref, &if_true_ref, &if_false_ref);
3869
10
    if_true = &ctx->ir_base[if_true_ref];
3870
10
    if_false = &ctx->ir_base[if_false_ref];
3871
10
    if_true->op = IR_BEGIN;
3872
10
    if_true->op2 = IR_UNUSED;
3873
10
    if_false->op = IR_BEGIN;
3874
10
    if_false->op2 = IR_UNUSED;
3875
10
    if (ir_ref_is_true(ctx, condition)) {
3876
3
      if_false->op1 = IR_UNUSED;
3877
3
      ir_use_list_remove_one(ctx, ref, if_false_ref);
3878
3
      ir_bitqueue_add(ctx->iter_worklist, if_true_ref);
3879
7
    } else {
3880
7
      if_true->op1 = IR_UNUSED;
3881
7
      ir_use_list_remove_one(ctx, ref, if_true_ref);
3882
7
      ir_bitqueue_add(ctx->iter_worklist, if_false_ref);
3883
7
    }
3884
10
    ctx->flags2 &= ~IR_CFG_REACHABLE;
3885
114k
  } else if (insn->op2 != condition) {
3886
14
    ir_iter_update_op(ctx, ref, 2, condition);
3887
14
  }
3888
114k
}
3889
3890
static void ir_iter_optimize_guard(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
3891
0
{
3892
0
  bool swap = 0;
3893
0
  ir_ref condition = ir_iter_optimize_condition(ctx, insn->op1, insn->op2, &swap);
3894
3895
0
  insn = &ctx->ir_base[ref];
3896
3897
0
  if (swap) {
3898
0
    if (insn->op == IR_GUARD) {
3899
0
      insn->op = IR_GUARD_NOT;
3900
0
    } else {
3901
0
      insn->op = IR_GUARD;
3902
0
    }
3903
0
  }
3904
3905
0
  if (IR_IS_CONST_REF(condition)) {
3906
0
    if (insn->op == IR_GUARD) {
3907
0
      if (ir_ref_is_true(ctx, condition)) {
3908
0
        ir_ref prev, next;
3909
3910
0
remove_guard:
3911
0
        prev = insn->op1;
3912
0
        next = ir_next_control(ctx, ref);
3913
0
        if (ctx->ir_base[prev].op == IR_SNAPSHOT) {
3914
0
          ir_ref snapshot = prev;
3915
0
          prev = ctx->ir_base[prev].op1;
3916
0
          ir_use_list_remove_one(ctx, snapshot, ref);
3917
0
          ir_use_list_remove_one(ctx, ref, next);
3918
0
          ir_use_list_replace_one(ctx, prev, snapshot, next);
3919
0
          ir_iter_remove_insn(ctx, snapshot);
3920
0
        } else {
3921
0
          ir_use_list_remove_one(ctx, ref, next);
3922
0
          ir_use_list_replace_one(ctx, prev, ref, next);
3923
0
        }
3924
0
        ctx->ir_base[next].op1 = prev;
3925
0
        insn->op1 = IR_UNUSED;
3926
3927
0
        if (!IR_IS_CONST_REF(insn->op2)) {
3928
0
          ir_use_list_remove_one(ctx, insn->op2, ref);
3929
0
          if (ir_is_dead(ctx, insn->op2)) {
3930
            /* schedule DCE */
3931
0
            ir_bitqueue_add(ctx->iter_worklist, insn->op2);
3932
0
          }
3933
0
        }
3934
3935
0
        if (!IR_IS_CONST_REF(insn->op3)) {
3936
0
          ir_use_list_remove_one(ctx, insn->op3, ref);
3937
0
          if (ir_is_dead(ctx, insn->op3)) {
3938
            /* schedule DCE */
3939
0
            ir_bitqueue_add(ctx->iter_worklist, insn->op3);
3940
0
          }
3941
0
        }
3942
3943
0
        MAKE_NOP(insn);
3944
0
        return;
3945
0
      } else {
3946
0
        condition = IR_FALSE;
3947
0
      }
3948
0
    } else {
3949
0
      if (ir_ref_is_true(ctx, condition)) {
3950
0
        condition = IR_TRUE;
3951
0
      } else {
3952
0
        goto remove_guard;
3953
0
      }
3954
0
    }
3955
0
  }
3956
3957
0
  if (insn->op2 != condition) {
3958
0
    ir_iter_update_op(ctx, ref, 2, condition);
3959
0
  }
3960
0
}
3961
3962
void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist)
3963
9.93k
{
3964
9.93k
  ir_ref i, val;
3965
9.93k
  ir_insn *insn;
3966
3967
9.93k
  ctx->iter_worklist = worklist;
3968
201k
  while ((i = ir_bitqueue_pop(ctx->iter_worklist)) >= 0) {
3969
191k
    insn = &ctx->ir_base[i];
3970
191k
    if (IR_IS_FOLDABLE_OP(insn->op)) {
3971
277
      if (ctx->use_lists[i].count == 0) {
3972
183
        if (insn->op == IR_PHI) {
3973
0
          ir_bitqueue_add(ctx->iter_worklist, insn->op1);
3974
0
        }
3975
183
        ir_iter_remove_insn(ctx, i);
3976
183
      } else {
3977
94
        insn = &ctx->ir_base[i];
3978
94
        switch (insn->op) {
3979
0
          case IR_FP2FP:
3980
0
            if (insn->type == IR_FLOAT) {
3981
0
              if (ir_may_promote_d2f(ctx, insn->op1)) {
3982
0
                ir_ref ref = ir_promote_d2f(ctx, insn->op1, i);
3983
0
                insn = &ctx->ir_base[i];
3984
0
                insn->op1 = ref;
3985
0
                ir_iter_replace_insn(ctx, i, ref);
3986
0
                break;
3987
0
              }
3988
0
            } else if (insn->type == IR_DOUBLE) {
3989
0
              if (ir_may_promote_f2d(ctx, insn->op1)) {
3990
0
                ir_ref ref = ir_promote_f2d(ctx, insn->op1, i);
3991
0
                insn = &ctx->ir_base[i];
3992
0
                insn->op1 = ref;
3993
0
                ir_iter_replace_insn(ctx, i, ref);
3994
0
                break;
3995
0
              }
3996
0
            }
3997
0
            goto folding;
3998
0
          case IR_FP2INT:
3999
0
            if (ctx->ir_base[insn->op1].type == IR_DOUBLE) {
4000
0
              if (ir_may_promote_d2f(ctx, insn->op1)) {
4001
0
                ir_ref ref = ir_promote_d2f(ctx, insn->op1, i);
4002
0
                insn = &ctx->ir_base[i];
4003
0
                insn->op1 = ref;
4004
0
              }
4005
0
            } else if (ctx->ir_base[insn->op1].type == IR_FLOAT) {
4006
0
              if (ir_may_promote_f2d(ctx, insn->op1)) {
4007
0
                ir_ref ref = ir_promote_f2d(ctx, insn->op1, i);
4008
0
                insn = &ctx->ir_base[i];
4009
0
                insn->op1 = ref;
4010
0
              }
4011
0
            }
4012
0
            goto folding;
4013
80
          case IR_TRUNC:
4014
80
            if (ir_may_promote_trunc(ctx, insn->type, insn->op1)) {
4015
4
              ir_ref ref = ir_promote_i2i(ctx, insn->type, insn->op1, i);
4016
4
              insn = &ctx->ir_base[i];
4017
4
              insn->op1 = ref;
4018
4
              ir_iter_replace_insn(ctx, i, ref);
4019
4
              break;
4020
4
            }
4021
76
            goto folding;
4022
76
          case IR_SEXT:
4023
0
          case IR_ZEXT:
4024
0
            if (ir_try_promote_ext(ctx, i, insn)) {
4025
0
              break;
4026
0
            }
4027
0
            goto folding;
4028
0
          case IR_PHI:
4029
0
            break;
4030
14
          default:
4031
90
folding:
4032
90
            ir_iter_fold(ctx, i);
4033
90
            break;
4034
94
        }
4035
94
      }
4036
191k
    } else if (ir_op_flags[insn->op] & IR_OP_FLAG_BB_START) {
4037
76.9k
      if (!(ctx->flags & IR_OPT_CFG)) {
4038
        /* pass */
4039
76.9k
      } else if (insn->op == IR_BEGIN) {
4040
1.18k
        if (insn->op1
4041
1.17k
         && !insn->op2 /* no computed goto label */
4042
1.17k
         && ctx->use_lists[i].count == 1
4043
1.17k
         && ctx->ir_base[insn->op1].op == IR_END) {
4044
1.17k
          ir_merge_blocks(ctx, insn->op1, i);
4045
1.17k
        }
4046
75.7k
      } else if (insn->op == IR_MERGE) {
4047
72.5k
        ir_iter_optimize_merge(ctx, i, insn);
4048
72.5k
      } else if (insn->op == IR_LOOP_BEGIN) {
4049
3.21k
        ir_iter_optimize_loop(ctx, i, insn);
4050
3.21k
      }
4051
114k
    } else if (ir_is_dead_load(ctx, i)) {
4052
110
      ir_ref next;
4053
4054
      /* remove LOAD from double linked control list */
4055
110
remove_mem_insn:
4056
110
      next = ctx->use_edges[ctx->use_lists[i].refs];
4057
110
      IR_ASSERT(ctx->use_lists[i].count == 1);
4058
110
      ctx->ir_base[next].op1 = insn->op1;
4059
110
      ir_use_list_replace_one(ctx, insn->op1, i, next);
4060
110
      insn->op1 = IR_UNUSED;
4061
110
      ir_iter_remove_insn(ctx, i);
4062
114k
    } else if (insn->op == IR_LOAD) {
4063
15
      val = ir_find_aliasing_load(ctx, insn->op1, insn->type, insn->op2);
4064
15
      if (val) {
4065
7
        ir_insn *val_insn;
4066
7
        ir_ref prev, next;
4067
4068
7
remove_aliased_load:
4069
7
        prev = insn->op1;
4070
7
        next = ir_next_control(ctx, i);
4071
7
        ctx->ir_base[next].op1 = prev;
4072
7
        ir_use_list_remove_one(ctx, i, next);
4073
7
        ir_use_list_replace_one(ctx, prev, i, next);
4074
7
        insn->op1 = IR_UNUSED;
4075
4076
7
        val_insn = &ctx->ir_base[val];
4077
7
        if (val_insn->type == insn->type) {
4078
3
          ir_iter_replace_insn(ctx, i, val);
4079
4
        } else {
4080
4
          if (!IR_IS_CONST_REF(insn->op2)) {
4081
4
            ir_use_list_remove_one(ctx, insn->op2, i);
4082
4
            if (ir_is_dead(ctx, insn->op2)) {
4083
              /* schedule DCE */
4084
0
              ir_bitqueue_add(ctx->iter_worklist, insn->op2);
4085
0
            }
4086
4
          }
4087
4
          if (!IR_IS_CONST_REF(val)) {
4088
0
            ir_use_list_add(ctx, val, i);
4089
0
          }
4090
4
          if (ir_get_type_size(val_insn->type) == ir_get_type_size(insn->type)) {
4091
            /* load forwarding with bitcast (L2L) */
4092
0
            insn->optx = IR_OPTX(IR_BITCAST, insn->type, 1);
4093
4
          } else {
4094
            /* partial load forwarding (L2L) */
4095
4
            insn->optx = IR_OPTX(IR_TRUNC, insn->type, 1);
4096
4
          }
4097
4
          insn->op1 = val;
4098
4
          insn->op2 = IR_UNUSED;
4099
4
          ir_bitqueue_add(ctx->iter_worklist, i);
4100
4
          ir_iter_add_uses(ctx, i, ctx->iter_worklist);
4101
4
        }
4102
7
      }
4103
114k
    } else if (insn->op == IR_STORE) {
4104
0
      if (ir_find_aliasing_store(ctx, insn->op1, insn->op2, insn->op3)) {
4105
0
        goto remove_mem_insn;
4106
0
      } else {
4107
0
        ir_insn *val_insn;
4108
4109
0
remove_bitcast:
4110
0
        val = insn->op3;
4111
0
        val_insn = &ctx->ir_base[val];
4112
0
        if (val_insn->op == IR_BITCAST
4113
0
         && ir_get_type_size(val_insn->type) == ir_get_type_size(ctx->ir_base[val_insn->op1].type)) {
4114
0
          insn->op3 = val_insn->op1;
4115
0
          ir_use_list_remove_one(ctx, val, i);
4116
0
          if (ctx->use_lists[val].count == 0) {
4117
0
            if (!IR_IS_CONST_REF(val_insn->op1)) {
4118
0
              ir_use_list_replace_one(ctx, val_insn->op1, val, i);
4119
0
            }
4120
0
            ir_iter_remove_insn(ctx, val);
4121
0
          } else {
4122
0
            if (!IR_IS_CONST_REF(val_insn->op1)) {
4123
0
              ir_use_list_add(ctx, val_insn->op1, i);
4124
0
            }
4125
0
          }
4126
0
        }
4127
0
      }
4128
114k
    } else if (insn->op == IR_VLOAD) {
4129
0
      val = ir_find_aliasing_vload(ctx, insn->op1, insn->type, insn->op2);
4130
0
      if (val) {
4131
0
        goto remove_aliased_load;
4132
0
      }
4133
114k
    } else if (insn->op == IR_VSTORE) {
4134
0
      if (ir_find_aliasing_vstore(ctx, insn->op1, insn->op2, insn->op3)) {
4135
0
        goto remove_mem_insn;
4136
0
      } else {
4137
0
        goto remove_bitcast;
4138
0
      }
4139
114k
    } else if (insn->op == IR_IF) {
4140
114k
      ir_iter_optimize_if(ctx, i, insn);
4141
114k
    } else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
4142
0
      ir_iter_optimize_guard(ctx, i, insn);
4143
0
    }
4144
191k
  }
4145
9.93k
  ctx->iter_worklist = NULL;
4146
9.93k
}
4147
4148
void ir_iter_cleanup(ir_ctx *ctx)
4149
0
{
4150
0
  ir_bitqueue iter_worklist;
4151
0
  ir_bitqueue cfg_worklist;
4152
0
  ir_ref i, n;
4153
0
  ir_insn *insn;
4154
4155
0
  ir_bitqueue_init(&cfg_worklist, ctx->insns_count);
4156
0
  ir_bitqueue_init(&iter_worklist, ctx->insns_count);
4157
4158
  /* Remove unused nodes */
4159
0
  ctx->iter_worklist = &iter_worklist;
4160
0
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
4161
0
    if (IR_IS_FOLDABLE_OP(insn->op)) {
4162
0
      if (insn->op != IR_NOP && ctx->use_lists[i].count == 0) {
4163
0
        ir_iter_remove_insn(ctx, i);
4164
0
      }
4165
0
    } else if (insn->op == IR_IF || insn->op == IR_MERGE) {
4166
0
      ir_bitqueue_add(&cfg_worklist, i);
4167
0
    }
4168
0
    n = insn->inputs_count;
4169
0
    n = ir_insn_inputs_to_len(n);
4170
0
    i += n;
4171
0
    insn += n;
4172
0
  }
4173
4174
0
  while ((i = ir_bitqueue_pop(&iter_worklist)) >= 0) {
4175
0
    insn = &ctx->ir_base[i];
4176
0
    if (IR_IS_FOLDABLE_OP(insn->op)) {
4177
0
      if (ctx->use_lists[i].count == 0) {
4178
0
        ir_iter_remove_insn(ctx, i);
4179
0
      }
4180
0
    }
4181
0
  }
4182
4183
0
  ctx->iter_worklist = NULL;
4184
0
  ir_bitqueue_free(&iter_worklist);
4185
4186
  /* Cleanup Control Flow */
4187
0
  ir_iter_opt(ctx, &cfg_worklist);
4188
0
  ir_bitqueue_free(&cfg_worklist);
4189
0
}
4190
4191
int ir_sccp(ir_ctx *ctx)
4192
9.93k
{
4193
9.93k
  ir_bitqueue sccp_worklist, iter_worklist;
4194
9.93k
  ir_sccp_val *_values;
4195
4196
9.93k
  ir_bitqueue_init(&iter_worklist, ctx->insns_count);
4197
9.93k
  ir_bitqueue_init(&sccp_worklist, ctx->insns_count);
4198
9.93k
  _values = ir_mem_calloc(ctx->insns_count, sizeof(ir_sccp_val));
4199
4200
9.93k
  ctx->flags2 |= IR_OPT_IN_SCCP;
4201
9.93k
  ir_sccp_analyze(ctx, _values, &sccp_worklist, &iter_worklist);
4202
9.93k
  ir_sccp_transform(ctx, _values, &sccp_worklist, &iter_worklist);
4203
9.93k
  ctx->flags2 &= ~IR_OPT_IN_SCCP;
4204
4205
9.93k
  ir_mem_free(_values);
4206
9.93k
  ir_bitqueue_free(&sccp_worklist);
4207
4208
9.93k
  ctx->flags2 |= IR_CFG_REACHABLE;
4209
4210
9.93k
  ir_iter_opt(ctx, &iter_worklist);
4211
4212
9.93k
  ir_bitqueue_free(&iter_worklist);
4213
4214
9.93k
  return 1;
4215
9.93k
}