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_cfg.c
Line
Count
Source
1
/*
2
 * IR - Lightweight JIT Compilation Framework
3
 * (CFG - Control Flow Graph)
4
 * This file is part of the IR Project distributed under the MIT-style LICENSE.
5
 * Authors: Dmitry Stogov <dmitry@php.net>
6
 */
7
8
#ifndef _GNU_SOURCE
9
# define _GNU_SOURCE
10
#endif
11
12
#include "ir.h"
13
#include "ir_private.h"
14
15
static int ir_remove_unreachable_blocks(ir_ctx *ctx);
16
17
IR_ALWAYS_INLINE void _ir_add_successors(const ir_ctx *ctx, ir_ref ref, ir_worklist *worklist)
18
71
{
19
71
  ir_use_list *use_list = &ctx->use_lists[ref];
20
71
  ir_ref *p, use, n = use_list->count;
21
22
71
  if (n < 2) {
23
55
    if (n == 1) {
24
55
      use = ctx->use_edges[use_list->refs];
25
55
      IR_ASSERT(ir_op_flags[ctx->ir_base[use].op] & IR_OP_FLAG_CONTROL);
26
55
      ir_worklist_push(worklist, use);
27
55
    }
28
55
  } else {
29
16
    p = &ctx->use_edges[use_list->refs];
30
16
    if (n == 2) {
31
16
      use = *p;
32
16
      IR_ASSERT(ir_op_flags[ctx->ir_base[use].op] & IR_OP_FLAG_CONTROL);
33
16
      ir_worklist_push(worklist, use);
34
16
      use = *(p + 1);
35
16
      IR_ASSERT(ir_op_flags[ctx->ir_base[use].op] & IR_OP_FLAG_CONTROL);
36
16
      ir_worklist_push(worklist, use);
37
16
    } else {
38
0
      for (; n > 0; p++, n--) {
39
0
        use = *p;
40
0
        IR_ASSERT(ir_op_flags[ctx->ir_base[use].op] & IR_OP_FLAG_CONTROL);
41
0
        ir_worklist_push(worklist, use);
42
0
      }
43
0
    }
44
16
  }
45
71
}
46
47
IR_ALWAYS_INLINE void _ir_add_predecessors(const ir_insn *insn, ir_worklist *worklist)
48
316k
{
49
316k
  ir_ref n, ref;
50
316k
  const ir_ref *p;
51
52
316k
  if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
53
75.5k
    n = insn->inputs_count;
54
260k
    for (p = insn->ops + 1; n > 0; p++, n--) {
55
185k
      ref = *p;
56
185k
      IR_ASSERT(ref);
57
185k
      ir_worklist_push(worklist, ref);
58
185k
    }
59
241k
  } else if (insn->op != IR_START) {
60
231k
    if (EXPECTED(insn->op1)) {
61
231k
      ir_worklist_push(worklist, insn->op1);
62
231k
    }
63
231k
  }
64
316k
}
65
66
void ir_reset_cfg(ir_ctx *ctx)
67
0
{
68
0
  ctx->cfg_blocks_count = 0;
69
0
  ctx->cfg_edges_count = 0;
70
0
  if (ctx->cfg_blocks) {
71
0
    ir_mem_free(ctx->cfg_blocks);
72
0
    ctx->cfg_blocks = NULL;
73
0
    if (ctx->cfg_edges) {
74
0
      ir_mem_free(ctx->cfg_edges);
75
0
      ctx->cfg_edges = NULL;
76
0
    }
77
0
    if (ctx->cfg_map) {
78
0
      ir_mem_free(ctx->cfg_map);
79
0
      ctx->cfg_map = NULL;
80
0
    }
81
0
  }
82
0
}
83
84
static void ir_remove_phis_inputs(ir_ctx *ctx, ir_use_list *use_list, int new_inputs_count, ir_bitset life_inputs)
85
0
{
86
0
  ir_ref i, j, n, k, *p, *q, use;
87
0
  ir_insn *use_insn;
88
89
0
  if (new_inputs_count == 1) {
90
0
    for (k = use_list->count, p = q = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) {
91
0
      use = *p;
92
0
      use_insn = &ctx->ir_base[use];
93
0
      if (use_insn->op == IR_PHI) {
94
        /* Convert PHI to COPY */
95
0
        n = use_insn->inputs_count;
96
0
        i = 2;
97
0
        for (j = 2; j <= n; j++) {
98
0
          ir_ref input = ir_insn_op(use_insn, j);
99
100
0
          if (ir_bitset_in(life_inputs, j - 1)) {
101
0
            use_insn->op1 = ir_insn_op(use_insn, j);
102
0
          } else if (input > 0) {
103
0
            ir_use_list_remove_one(ctx, input, use);
104
0
          }
105
0
        }
106
0
        use_insn->op = IR_COPY;
107
0
        use_insn->inputs_count = 1;
108
0
        for (j = 2; j <= n; j++) {
109
0
          ir_insn_set_op(use_insn, j, IR_UNUSED);
110
0
        }
111
0
        continue;
112
0
      }
113
114
      /*compact use list */
115
0
      if (p != q){
116
0
        *q = use;
117
0
      }
118
0
      q++;
119
0
    }
120
121
0
    if (p != q) {
122
0
      use_list->count -= (ir_ref)(p - q);
123
0
      do {
124
0
        *q = IR_UNUSED; /* clenu-op the removed tail */
125
0
        q++;
126
0
      } while (p != q);
127
0
    }
128
0
  } else {
129
0
    for (k = use_list->count, p = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) {
130
0
      use = *p;
131
0
      use_insn = &ctx->ir_base[use];
132
0
      if (use_insn->op == IR_PHI) {
133
0
        n = use_insn->inputs_count;
134
0
        i = 2;
135
0
        for (j = 2; j <= n; j++) {
136
0
          ir_ref input = ir_insn_op(use_insn, j);
137
138
0
          if (ir_bitset_in(life_inputs, j - 1)) {
139
0
            IR_ASSERT(input);
140
0
            if (i != j) {
141
0
              ir_insn_set_op(use_insn, i, input);
142
0
            }
143
0
            i++;
144
0
          } else if (input > 0) {
145
0
            ir_use_list_remove_one(ctx, input, use);
146
0
          }
147
0
        }
148
0
        use_insn->inputs_count = i - 1;
149
0
        for (j = i; j <= n; j++) {
150
0
          ir_insn_set_op(use_insn, j, IR_UNUSED);
151
0
        }
152
0
      }
153
0
    }
154
0
  }
155
0
}
156
157
static uint32_t IR_NEVER_INLINE ir_cfg_remove_dead_inputs(ir_ctx *ctx, uint32_t *_blocks, ir_block *blocks, uint32_t bb_count)
158
0
{
159
0
  uint32_t b, count = 0;
160
0
  ir_block *bb = blocks + 1;
161
0
  ir_insn *insn;
162
0
  ir_ref i, j, n, *ops, input;
163
0
  ir_bitset life_inputs = NULL;
164
165
0
  for (b = 1; b <= bb_count; b++, bb++) {
166
0
    bb->successors = count;
167
0
    count += ctx->use_lists[bb->end].count;
168
0
    bb->successors_count = 0;
169
0
    bb->predecessors = count;
170
0
    insn = &ctx->ir_base[bb->start];
171
0
    if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
172
0
      n = insn->inputs_count;
173
0
      ops = insn->ops;
174
0
      for (i = 1, j = 1; i <= n; i++) {
175
0
        input = ops[i];
176
0
        if (_blocks[input]) {
177
0
          if (life_inputs) {
178
0
            ir_bitset_incl(life_inputs, i);
179
0
          }
180
0
          if (i != j) {
181
0
            ops[j] = ops[i];
182
0
          }
183
0
          j++;
184
0
        } else {
185
0
          if (ctx->use_lists[bb->start].count > 1) {
186
            /* Some inputs of this MERGE are deleted and we have to update the depended PHIs */
187
0
            if (!life_inputs) {
188
0
              int k;
189
0
              life_inputs = ir_bitset_malloc(n + 1);
190
0
              for (k = 1; k < i; k++) {
191
0
                ir_bitset_incl(life_inputs, k);
192
0
              }
193
0
            }
194
0
          }
195
0
          IR_ASSERT(input > 0);
196
0
          IR_ASSERT(ctx->use_lists[input].count == 1 && ctx->use_edges[ctx->use_lists[input].refs] == bb->start);
197
0
          CLEAR_USES(input);
198
0
        }
199
0
      }
200
0
      j--;
201
0
      if (j != n) {
202
0
        if (j == 1) {
203
0
          insn->op = IR_BEGIN;
204
0
        }
205
0
        insn->inputs_count = j;
206
0
        bb->predecessors_count = j;
207
0
        j++;
208
0
        for (;j <= n; j++) {
209
0
          ops[j] = IR_UNUSED;
210
0
        }
211
0
        if (life_inputs) {
212
0
          ir_remove_phis_inputs(ctx, &ctx->use_lists[bb->start], insn->inputs_count, life_inputs);
213
0
          ir_mem_free(life_inputs);
214
0
          life_inputs = NULL;
215
0
        }
216
0
      }
217
0
    }
218
0
    count += bb->predecessors_count;
219
0
  }
220
0
  return count;
221
0
}
222
223
int ir_build_cfg(ir_ctx *ctx)
224
9.93k
{
225
9.93k
  ir_ref n, *p, ref, start, end;
226
9.93k
  uint32_t b;
227
9.93k
  ir_insn *insn;
228
9.93k
  ir_worklist worklist;
229
9.93k
  uint32_t bb_init_falgs;
230
9.93k
  uint32_t count, bb_count = 0;
231
9.93k
  uint32_t edges_count = 0;
232
9.93k
  ir_block *blocks, *bb;
233
9.93k
  uint32_t *_blocks, *edges;
234
9.93k
  ir_use_list *use_list;
235
9.93k
  uint32_t len = ir_bitset_len(ctx->insns_count);
236
9.93k
  ir_bitset bb_starts = ir_mem_calloc(len * 2, IR_BITSET_BITS / 8);
237
9.93k
  ir_bitset bb_leaks = bb_starts + len;
238
9.93k
  _blocks = ir_mem_calloc(ctx->insns_limit, sizeof(uint32_t));
239
9.93k
  ir_worklist_init(&worklist, ctx->insns_count);
240
241
  /* First try to perform backward DFS search starting from "stop" nodes */
242
243
  /* Add all "stop" nodes */
244
9.93k
  ref = ctx->ir_base[1].op1;
245
27.4k
  while (ref) {
246
17.4k
    ir_worklist_push(&worklist, ref);
247
17.4k
    ref = ctx->ir_base[ref].op3;
248
17.4k
  }
249
250
326k
  while (ir_worklist_len(&worklist)) {
251
316k
    ref = ir_worklist_pop(&worklist);
252
316k
    insn = &ctx->ir_base[ref];
253
254
316k
    if (insn->op == IR_NOP) {
255
0
      continue;
256
0
    }
257
316k
    IR_ASSERT(IR_IS_BB_END(insn->op));
258
    /* Remember BB end */
259
316k
    end = ref;
260
    /* Some successors of IF and SWITCH nodes may be inaccessible by backward DFS */
261
316k
    use_list = &ctx->use_lists[end];
262
316k
    n = use_list->count;
263
316k
    if (n > 1 || (n == 1 && (ir_op_flags[insn->op] & IR_OP_FLAG_TERMINATOR) != 0)) {
264
348k
      for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
265
        /* Remember possible inaccessible successors */
266
231k
        ir_bitset_incl(bb_leaks, *p);
267
231k
      }
268
117k
    }
269
    /* Skip control nodes until BB start */
270
316k
    ref = insn->op1;
271
1.07M
    while (1) {
272
1.07M
      insn = &ctx->ir_base[ref];
273
1.07M
      if (IR_IS_BB_START(insn->op)) {
274
316k
        break;
275
316k
      }
276
754k
      ref = insn->op1; // follow connected control blocks until BB start
277
754k
    }
278
    /* Mark BB Start */
279
316k
    bb_count++;
280
316k
    _blocks[ref] = end;
281
316k
    ir_bitset_incl(bb_starts, ref);
282
    /* Add predecessors */
283
316k
    _ir_add_predecessors(insn, &worklist);
284
316k
  }
285
286
  /* Backward DFS way miss some branches ending by infinite loops.  */
287
  /* Try forward DFS. (in most cases all nodes are already proceed). */
288
289
  /* START node may be inaccessible from "stop" nodes */
290
9.93k
  ir_bitset_incl(bb_leaks, 1);
291
292
  /* Add not processed START and successor of IF and SWITCH */
293
44.1k
  IR_BITSET_FOREACH_DIFFERENCE(bb_leaks, bb_starts, len, start) {
294
44.1k
    ir_worklist_push(&worklist, start);
295
44.1k
  } IR_BITSET_FOREACH_END();
296
297
9.93k
  if (ir_worklist_len(&worklist)) {
298
13
    ir_bitset_union(worklist.visited, bb_starts, len);
299
71
    do {
300
71
      ref = ir_worklist_pop(&worklist);
301
71
      insn = &ctx->ir_base[ref];
302
303
71
      if (insn->op == IR_NOP) {
304
0
        continue;
305
0
      }
306
71
      IR_ASSERT(IR_IS_BB_START(insn->op));
307
      /* Remember BB start */
308
71
      start = ref;
309
      /* Skip control nodes until BB end */
310
743
      while (1) {
311
743
        ref = ir_next_control(ctx, ref);
312
743
        insn = &ctx->ir_base[ref];
313
743
        if (IR_IS_BB_END(insn->op)) {
314
71
          break;
315
71
        }
316
743
      }
317
      /* Mark BB Start */
318
71
      bb_count++;
319
71
      _blocks[start] = ref;
320
71
      ir_bitset_incl(bb_starts, start);
321
      /* Add successors */
322
71
      _ir_add_successors(ctx, ref, &worklist);
323
71
    } while (ir_worklist_len(&worklist));
324
13
  }
325
326
9.93k
  IR_ASSERT(bb_count > 0);
327
328
  /* Create array of basic blocks and count successor/predecessors edges for each BB */
329
9.93k
  blocks = ir_mem_malloc((bb_count + 1) * sizeof(ir_block));
330
9.93k
  b = 1;
331
9.93k
  bb = blocks + 1;
332
9.93k
  count = 0;
333
  /* SCCP already removed UNREACHABKE blocks, otherwise all blocks are marked as UNREACHABLE first */
334
9.93k
  bb_init_falgs = (ctx->flags2 & IR_CFG_REACHABLE) ? 0 : IR_BB_UNREACHABLE;
335
361k
  IR_BITSET_FOREACH(bb_starts, len, start) {
336
361k
    insn = &ctx->ir_base[start];
337
361k
    if (insn->op == IR_NOP) {
338
0
      _blocks[start] = 0;
339
0
      continue;
340
0
    }
341
316k
    end = _blocks[start];
342
316k
    _blocks[start] = b;
343
316k
    _blocks[end] = b;
344
316k
    IR_ASSERT(IR_IS_BB_START(insn->op));
345
316k
    bb->start = start;
346
316k
    bb->end = end;
347
316k
    bb->successors = count;
348
316k
    count += ctx->use_lists[end].count;
349
316k
    bb->successors_count = 0;
350
316k
    bb->predecessors = count;
351
316k
    bb->dom_parent = 0;
352
316k
    bb->dom_depth = 0;
353
316k
    bb->dom_child = 0;
354
316k
    bb->dom_next_child = 0;
355
316k
    bb->loop_header = 0;
356
316k
    bb->loop_depth = 0;
357
316k
    if (insn->op == IR_START) {
358
9.93k
      bb->flags = IR_BB_START;
359
9.93k
      bb->predecessors_count = 0;
360
307k
    } else {
361
307k
      bb->flags = bb_init_falgs;
362
307k
      if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
363
75.5k
        n = insn->inputs_count;
364
75.5k
        bb->predecessors_count = n;
365
75.5k
        edges_count += n;
366
75.5k
        count += n;
367
231k
      } else if (EXPECTED(insn->op1)) {
368
231k
        if (insn->op == IR_ENTRY) {
369
3.16k
          bb->flags |= IR_BB_ENTRY;
370
3.16k
          ctx->entries_count++;
371
3.16k
        }
372
231k
        bb->predecessors_count = 1;
373
231k
        edges_count++;
374
231k
        count++;
375
231k
      } else {
376
10
        IR_ASSERT(insn->op == IR_BEGIN); /* start of unreachable block */
377
10
        bb->predecessors_count = 0;
378
10
      }
379
307k
    }
380
316k
    b++;
381
316k
    bb++;
382
316k
  } IR_BITSET_FOREACH_END();
383
9.93k
  bb_count = b - 1;
384
9.93k
  if (UNEXPECTED(count != edges_count * 2)) {
385
0
    count = ir_cfg_remove_dead_inputs(ctx, _blocks, blocks, bb_count);
386
0
    IR_ASSERT(count != edges_count * 2);
387
0
  }
388
9.93k
  ir_mem_free(bb_starts);
389
390
  /* Create an array of successor/predecessors control edges */
391
9.93k
  edges = ir_mem_malloc(edges_count * 2 * sizeof(uint32_t));
392
9.93k
  bb = blocks + 1;
393
326k
  for (b = 1; b <= bb_count; b++, bb++) {
394
316k
    insn = &ctx->ir_base[bb->start];
395
316k
    if (bb->predecessors_count > 1) {
396
75.5k
      uint32_t *q = edges + bb->predecessors;
397
75.5k
      n = insn->inputs_count;
398
260k
      for (p = insn->ops + 1; n > 0; p++, q++, n--) {
399
185k
        ref = *p;
400
185k
        IR_ASSERT(ref);
401
185k
        ir_ref pred_b = _blocks[ref];
402
185k
        ir_block *pred_bb = &blocks[pred_b];
403
185k
        IR_ASSERT(pred_b > 0);
404
185k
        *q = pred_b;
405
185k
        edges[pred_bb->successors + pred_bb->successors_count++] = b;
406
185k
      }
407
241k
    } else if (bb->predecessors_count == 1) {
408
231k
      ref = insn->op1;
409
231k
      IR_ASSERT(ref);
410
231k
      IR_ASSERT(IR_OPND_KIND(ir_op_flags[insn->op], 1) == IR_OPND_CONTROL);
411
231k
      ir_ref pred_b = _blocks[ref];
412
231k
      ir_block *pred_bb = &blocks[pred_b];
413
231k
      edges[bb->predecessors] = pred_b;
414
231k
      edges[pred_bb->successors + pred_bb->successors_count++] = b;
415
231k
    }
416
316k
  }
417
418
9.93k
  ctx->cfg_blocks_count = bb_count;
419
9.93k
  ctx->cfg_edges_count = edges_count * 2;
420
9.93k
  ctx->cfg_blocks = blocks;
421
9.93k
  ctx->cfg_edges = edges;
422
9.93k
  ctx->cfg_map = _blocks;
423
424
9.93k
  if (!(ctx->flags2 & IR_CFG_REACHABLE)) {
425
4
    uint32_t reachable_count = 0;
426
427
    /* Mark reachable blocks */
428
4
    ir_worklist_clear(&worklist);
429
4
    ir_worklist_push(&worklist, 1);
430
90
    while (ir_worklist_len(&worklist) != 0) {
431
86
      uint32_t *p;
432
433
86
      reachable_count++;
434
86
      b = ir_worklist_pop(&worklist);
435
86
      bb = &blocks[b];
436
86
      bb->flags &= ~IR_BB_UNREACHABLE;
437
86
      n = bb->successors_count;
438
86
      if (n > 1) {
439
93
        for (p = edges + bb->successors; n > 0; p++, n--) {
440
62
          ir_worklist_push(&worklist, *p);
441
62
        }
442
55
      } else if (n == 1) {
443
51
        ir_worklist_push(&worklist, edges[bb->successors]);
444
51
      }
445
86
    }
446
4
    if (reachable_count != ctx->cfg_blocks_count) {
447
4
      ir_remove_unreachable_blocks(ctx);
448
4
    }
449
4
  }
450
451
9.93k
  ir_worklist_free(&worklist);
452
453
9.93k
  return 1;
454
9.93k
}
455
456
static void ir_remove_predecessor(ir_ctx *ctx, ir_block *bb, uint32_t from)
457
21
{
458
21
  uint32_t i, *p, *q, n = 0;
459
460
21
  p = q = &ctx->cfg_edges[bb->predecessors];
461
111
  for (i = 0; i < bb->predecessors_count; i++, p++) {
462
90
    if (*p != from) {
463
69
      if (p != q) {
464
60
        *q = *p;
465
60
      }
466
69
      q++;
467
69
      n++;
468
69
    }
469
90
  }
470
21
  IR_ASSERT(n != bb->predecessors_count);
471
21
  bb->predecessors_count = n;
472
21
}
473
474
static void ir_remove_merge_input(ir_ctx *ctx, ir_ref merge, ir_ref from)
475
21
{
476
21
  ir_ref i, j, n;
477
21
  ir_use_list *use_list;
478
21
  ir_bitset life_inputs;
479
21
  ir_insn *insn = &ctx->ir_base[merge];
480
481
21
  IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
482
21
  n = insn->inputs_count;
483
21
  i = 1;
484
21
  life_inputs = ir_bitset_malloc(n + 1);
485
111
  for (j = 1; j <= n; j++) {
486
90
    ir_ref input = ir_insn_op(insn, j);
487
488
90
    if (input != from) {
489
69
      if (i != j) {
490
60
        ir_insn_set_op(insn, i, input);
491
60
      }
492
69
      ir_bitset_incl(life_inputs, j);
493
69
      i++;
494
69
    }
495
90
  }
496
21
  i--;
497
42
  for (j = i + 1; j <= n; j++) {
498
21
    ir_insn_set_op(insn, j, IR_UNUSED);
499
21
  }
500
21
  if (i == 1) {
501
4
    insn->op = IR_BEGIN;
502
4
  }
503
21
  insn->inputs_count = i;
504
505
21
  use_list = &ctx->use_lists[merge];
506
21
  if (use_list->count > 1) {
507
0
    ir_remove_phis_inputs(ctx, use_list, i, life_inputs);
508
0
  }
509
510
21
  ir_mem_free(life_inputs);
511
21
  IR_ASSERT(ctx->use_lists[from].count == 1 && ctx->use_edges[ctx->use_lists[from].refs] == merge);
512
21
  CLEAR_USES(from);
513
21
}
514
515
/* CFG constructed after SCCP pass doesn't have unreachable BBs, otherwise they should be removed */
516
static int ir_remove_unreachable_blocks(ir_ctx *ctx)
517
4
{
518
4
  uint32_t b, *p, i;
519
4
  uint32_t unreachable_count = 0;
520
4
  uint32_t bb_count = ctx->cfg_blocks_count;
521
4
  ir_block *bb = ctx->cfg_blocks + 1;
522
523
214
  for (b = 1; b <= bb_count; b++, bb++) {
524
210
    if (bb->flags & IR_BB_UNREACHABLE) {
525
#if 0
526
      do {if (!unreachable_count) ir_dump_cfg(ctx, stderr);} while(0);
527
#endif
528
124
      if (bb->successors_count) {
529
293
        for (i = 0, p = &ctx->cfg_edges[bb->successors]; i < bb->successors_count; i++, p++) {
530
169
          ir_block *succ_bb = &ctx->cfg_blocks[*p];
531
532
169
          if (!(succ_bb->flags & IR_BB_UNREACHABLE)) {
533
21
            ir_remove_predecessor(ctx, succ_bb, b);
534
21
            ir_remove_merge_input(ctx, succ_bb->start, bb->end);
535
21
          }
536
169
        }
537
124
      } else {
538
0
        ir_ref prev, ref = bb->end;
539
0
        ir_insn *insn = &ctx->ir_base[ref];
540
541
0
        IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_TERMINATOR);
542
        /* remove from terminators list */
543
0
        prev = ctx->ir_base[1].op1;
544
0
        if (prev == ref) {
545
0
          ctx->ir_base[1].op1 = insn->op3;
546
0
        } else {
547
0
          while (prev) {
548
0
            if (ctx->ir_base[prev].op3 == ref) {
549
0
              ctx->ir_base[prev].op3 = insn->op3;
550
0
              break;
551
0
            }
552
0
            prev = ctx->ir_base[prev].op3;
553
0
          }
554
0
        }
555
0
      }
556
124
      ctx->cfg_map[bb->start] = 0;
557
124
      ctx->cfg_map[bb->end] = 0;
558
124
      unreachable_count++;
559
124
    }
560
210
  }
561
562
4
  if (unreachable_count) {
563
4
    ir_block *dst_bb;
564
4
    uint32_t n = 1;
565
4
    uint32_t *edges;
566
567
4
    dst_bb = bb = ctx->cfg_blocks + 1;
568
214
    for (b = 1; b <= bb_count; b++, bb++) {
569
210
      if (!(bb->flags & IR_BB_UNREACHABLE)) {
570
86
        if (dst_bb != bb) {
571
39
          memcpy(dst_bb, bb, sizeof(ir_block));
572
39
          ctx->cfg_map[dst_bb->start] = n;
573
39
          ctx->cfg_map[dst_bb->end] = n;
574
39
        }
575
86
        dst_bb->successors_count = 0;
576
86
        dst_bb++;
577
86
        n++;
578
86
      }
579
210
    }
580
4
    ctx->cfg_blocks_count = bb_count = n - 1;
581
582
    /* Rebuild successor/predecessors control edges */
583
4
    edges = ctx->cfg_edges;
584
4
    bb = ctx->cfg_blocks + 1;
585
90
    for (b = 1; b <= bb_count; b++, bb++) {
586
86
      ir_insn *insn = &ctx->ir_base[bb->start];
587
86
      ir_ref *p, ref;
588
589
86
      n = bb->predecessors_count;
590
86
      if (n > 1) {
591
16
        uint32_t *q = edges + bb->predecessors;
592
593
16
        IR_ASSERT(n == insn->inputs_count);
594
63
        for (p = insn->ops + 1; n > 0; p++, q++, n--) {
595
47
          ref = *p;
596
47
          IR_ASSERT(ref);
597
47
          ir_ref pred_b = ctx->cfg_map[ref];
598
47
          ir_block *pred_bb = &ctx->cfg_blocks[pred_b];
599
47
          *q = pred_b;
600
47
          edges[pred_bb->successors + pred_bb->successors_count++] = b;
601
47
        }
602
70
      } else if (n == 1) {
603
66
        ref = insn->op1;
604
66
        IR_ASSERT(ref);
605
66
        IR_ASSERT(IR_OPND_KIND(ir_op_flags[insn->op], 1) == IR_OPND_CONTROL);
606
66
        ir_ref pred_b = ctx->cfg_map[ref];
607
66
        ir_block *pred_bb = &ctx->cfg_blocks[pred_b];
608
66
        edges[bb->predecessors] = pred_b;
609
66
        edges[pred_bb->successors + pred_bb->successors_count++] = b;
610
66
      }
611
86
    }
612
4
  }
613
614
4
  return 1;
615
4
}
616
617
/* Computes dominator tree using algorithm from "A Simple, Fast Dominance Algorithm" by
618
 * Cooper, Harvey and Kennedy. */
619
static IR_NEVER_INLINE int ir_build_dominators_tree_slow(ir_ctx *ctx)
620
0
{
621
0
  uint32_t blocks_count, b, postnum, i;
622
0
  ir_block *blocks, *bb;
623
0
  uint32_t *edges;
624
0
  uint32_t *rpo = ir_mem_malloc((ctx->cfg_blocks_count + 1) * sizeof(uint32_t));
625
0
  bool changed;
626
627
0
  blocks = ctx->cfg_blocks;
628
0
  edges  = ctx->cfg_edges;
629
0
  blocks_count = ctx->cfg_blocks_count;
630
631
0
  ctx->flags2 &= ~IR_NO_LOOPS;
632
633
0
  postnum = 1;
634
0
  ir_worklist work;
635
0
  ir_worklist_init(&work, ctx->cfg_blocks_count + 1);
636
0
  ir_worklist_push(&work, 1);
637
0
  IR_ASSERT(blocks[1].next_succ == 0);
638
0
  while (ir_worklist_len(&work)) {
639
0
next:
640
0
    b = ir_worklist_peek(&work);
641
0
    bb = &blocks[b];
642
0
    uint32_t n = bb->successors_count - bb->next_succ;
643
0
    if (n) {
644
0
      uint32_t *p = edges + bb->successors + bb->next_succ;
645
0
      for (; n > 0; p++, n--) {
646
0
        uint32_t succ = *p;
647
0
        if (ir_worklist_push(&work, succ)) {
648
0
          bb->next_succ = bb->successors_count - n + 1;
649
0
          IR_ASSERT(blocks[succ].next_succ == 0);
650
0
          goto next;
651
0
        }
652
0
      }
653
0
    }
654
655
    /* Start from bb->idom calculated by the fast dominators algorithm */
656
    // bb->idom = 0;
657
0
    bb->next_succ = 0;
658
0
    rpo[postnum] = b;
659
0
    bb->postnum = postnum++;
660
0
    ir_worklist_pop(&work);
661
0
  }
662
0
  ir_worklist_free(&work);
663
664
0
  IR_ASSERT(rpo[blocks_count] == 1);
665
666
  /* Find immediate dominators by iterative fixed-point algorithm */
667
0
  blocks[1].idom = 1;
668
0
  do {
669
0
    changed = 0;
670
671
    /* Iterating in Reverse Post Order */
672
0
    for (i = blocks_count - 1; i > 0; i--) {
673
0
      b = rpo[i];
674
0
      bb = &blocks[b];
675
0
      IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
676
0
      IR_ASSERT(bb->predecessors_count > 0);
677
0
      if (bb->predecessors_count == 1) {
678
0
        uint32_t pred_b = edges[bb->predecessors];
679
680
0
        if (blocks[pred_b].idom > 0 && bb->idom != pred_b) {
681
0
          bb->idom = pred_b;
682
0
          changed = 1;
683
0
        }
684
0
      } else if (bb->predecessors_count) {
685
0
        uint32_t idom = 0;
686
0
        uint32_t k = bb->predecessors_count;
687
0
        uint32_t *p = edges + bb->predecessors;
688
689
0
        do {
690
0
          uint32_t pred_b = *p;
691
0
          ir_block *pred_bb = &blocks[pred_b];
692
0
          ir_block *idom_bb;
693
694
0
          if (pred_bb->idom > 0) {
695
0
            idom = pred_b;
696
0
            idom_bb = &blocks[idom];
697
698
0
            while (--k > 0) {
699
0
              pred_b = *(++p);
700
0
              pred_bb = &blocks[pred_b];
701
0
              if (pred_bb->idom > 0) {
702
0
                while (idom != pred_b) {
703
0
                  while (pred_bb->postnum < idom_bb->postnum) {
704
0
                    pred_b = pred_bb->idom;
705
0
                    pred_bb = &blocks[pred_b];
706
0
                  }
707
0
                  while (idom_bb->postnum < pred_bb->postnum) {
708
0
                    idom = idom_bb->idom;
709
0
                    idom_bb = &blocks[idom];
710
0
                  }
711
0
                }
712
0
              }
713
0
            }
714
715
0
            if (bb->idom != idom) {
716
0
              bb->idom = idom;
717
0
              changed = 1;
718
0
            }
719
0
            break;
720
0
          }
721
0
          p++;
722
0
        } while (--k > 0);
723
0
      }
724
0
    }
725
0
  } while (changed);
726
727
0
  ir_mem_free(rpo);
728
729
  /* Build dominators tree */
730
0
  blocks[1].idom = 0;
731
0
  blocks[1].dom_depth = 0;
732
733
  /* Construct children lists sorted by block number */
734
0
  for (b = blocks_count, bb = &blocks[b]; b >= 2; b--, bb--) {
735
0
    ir_block *idom_bb = &blocks[bb->idom];
736
0
    bb->dom_depth = 0;
737
0
    bb->dom_next_child = idom_bb->dom_child;
738
0
    idom_bb->dom_child = b;
739
0
  }
740
741
  /* Recalculate dom_depth for all blocks */
742
0
  for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
743
0
    uint32_t idom = bb->idom;
744
0
    uint32_t dom_depth = 0;
745
0
    while (idom) {
746
0
      dom_depth++;
747
0
      if (blocks[idom].dom_depth > 0) {
748
0
        dom_depth += blocks[idom].dom_depth;
749
0
        break;
750
0
      } else {
751
0
        idom = blocks[idom].idom;
752
0
      }
753
0
    }
754
0
    bb->dom_depth = dom_depth;
755
0
  }
756
757
0
  return 1;
758
0
}
759
760
/* A single pass modification of "A Simple, Fast Dominance Algorithm" by
761
 * Cooper, Harvey and Kennedy, that relays on IR block ordering.
762
 * It may fallback to the general slow fixed-point algorithm.  */
763
static int ir_build_dominators_tree_iterative(ir_ctx *ctx);
764
int ir_build_dominators_tree(ir_ctx *ctx)
765
9.93k
{
766
9.93k
  uint32_t blocks_count, b;
767
9.93k
  ir_block *blocks, *bb;
768
9.93k
  uint32_t *edges;
769
9.93k
  ir_list worklist;
770
771
9.93k
  ir_list_init(&worklist, ctx->cfg_blocks_count / 2);
772
773
9.93k
  ctx->flags2 |= IR_NO_LOOPS;
774
775
  /* Find immediate dominators */
776
9.93k
  blocks = ctx->cfg_blocks;
777
9.93k
  edges  = ctx->cfg_edges;
778
9.93k
  blocks_count = ctx->cfg_blocks_count;
779
9.93k
  blocks[1].idom = 1;
780
9.93k
  blocks[1].dom_depth = 0;
781
782
  /* Iterating in Reverse Post Order (relay on existing BB order and fall-back to slow algorithm) */
783
316k
  for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
784
306k
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
785
306k
    IR_ASSERT(bb->predecessors_count > 0);
786
306k
    uint32_t k = bb->predecessors_count;
787
306k
    uint32_t *p = edges + bb->predecessors;
788
306k
    uint32_t idom = *p;
789
306k
    ir_block *idom_bb;
790
791
306k
    if (UNEXPECTED(idom >= b)) {
792
      /* In rare cases, LOOP_BEGIN.op1 may be a back-edge. Skip back-edges. */
793
2
      ctx->flags2 &= ~IR_NO_LOOPS;
794
2
      if (UNEXPECTED(k <= 1)) {
795
        // IR_ASSERT(k > 1 && "Wrong blocks order: BB is before its single predecessor");
796
0
slow_case:
797
0
        ir_list_free(&worklist);
798
0
        return ir_build_dominators_tree_slow(ctx);
799
0
      }
800
2
      ir_list_push(&worklist, idom);
801
2
      while (1) {
802
2
        k--;
803
2
        p++;
804
2
        idom = *p;
805
2
        if (idom < b) {
806
2
          break;
807
2
        }
808
0
        if (UNEXPECTED(k == 0)) {
809
          // IR_ASSERT(0 && "Wrong blocks order: BB is before all its predecessors");
810
0
          goto slow_case;
811
0
        }
812
0
        ir_list_push(&worklist, idom);
813
0
      }
814
2
    }
815
306k
    IR_ASSERT(blocks[idom].idom > 0);
816
306k
    IR_ASSERT(k != 0);
817
818
416k
    while (--k > 0) {
819
109k
      uint32_t pred_b = *(++p);
820
821
109k
      if (pred_b < b) {
822
106k
        IR_ASSERT(blocks[pred_b].idom > 0);
823
227k
        while (idom != pred_b) {
824
347k
          while (pred_b > idom) {
825
226k
            pred_b = blocks[pred_b].idom;
826
226k
          }
827
226k
          while (idom > pred_b) {
828
106k
            idom = blocks[idom].idom;
829
106k
          }
830
120k
        }
831
106k
      } else {
832
3.21k
        ctx->flags2 &= ~IR_NO_LOOPS;
833
3.21k
        IR_ASSERT(bb->predecessors_count > 1);
834
3.21k
        ir_list_push(&worklist, pred_b);
835
3.21k
      }
836
109k
    }
837
306k
    bb->idom = idom;
838
306k
    idom_bb = &blocks[idom];
839
306k
    bb->dom_depth = idom_bb->dom_depth + 1;
840
306k
  }
841
842
9.93k
  blocks[1].idom = 0;
843
844
9.93k
  if (ir_list_len(&worklist) != 0) {
845
3.09k
    uint32_t dom_depth;
846
3.09k
    uint32_t succ_b;
847
3.09k
    bool complete = 1;
848
849
    /* Check if all the back-edges lead to the loop headers */
850
3.21k
    do {
851
3.21k
      b = ir_list_pop(&worklist);
852
3.21k
      bb = &blocks[b];
853
3.21k
      succ_b = ctx->cfg_edges[bb->successors];
854
3.21k
      if (bb->successors_count != 1) {
855
        /* LOOP_END/END may be linked with the following ENTRY by a fake edge */
856
0
        if (bb->successors_count != 2) {
857
0
          complete = 0;
858
0
          break;
859
0
        } else if (blocks[succ_b].flags & IR_BB_ENTRY) {
860
0
          succ_b = ctx->cfg_edges[bb->successors + 1];
861
0
        } else if (!(blocks[ctx->cfg_edges[bb->successors + 1]].flags & IR_BB_ENTRY)) {
862
0
          complete = 0;
863
0
          break;
864
0
        }
865
0
      }
866
3.21k
      dom_depth = blocks[succ_b].dom_depth;;
867
7.16k
      while (bb->dom_depth > dom_depth) {
868
3.95k
        b = bb->dom_parent;
869
3.95k
        bb = &blocks[b];
870
3.95k
      }
871
3.21k
      if (UNEXPECTED(b != succ_b)) {
872
0
        complete = 0;
873
0
        break;
874
0
      }
875
3.21k
    } while (ir_list_len(&worklist) != 0);
876
877
3.09k
    if (UNEXPECTED(!complete)) {
878
0
      ir_list_free(&worklist);
879
      // TODO: this algorithm may be incorrect. Prove and/or switch to ir_build_dominators_tree_slow() ???
880
0
      return ir_build_dominators_tree_iterative(ctx);
881
0
    }
882
3.09k
  }
883
884
  /* Construct children lists sorted by block number */
885
316k
  for (b = blocks_count, bb = &blocks[b]; b >= 2; b--, bb--) {
886
306k
    ir_block *idom_bb = &blocks[bb->idom];
887
306k
    bb->dom_next_child = idom_bb->dom_child;
888
306k
    idom_bb->dom_child = b;
889
306k
  }
890
891
9.93k
  ir_list_free(&worklist);
892
893
9.93k
  return 1;
894
9.93k
}
895
896
static int ir_build_dominators_tree_iterative(ir_ctx *ctx)
897
0
{
898
0
  bool changed;
899
0
  uint32_t blocks_count, b;
900
0
  ir_block *blocks, *bb;
901
0
  uint32_t *edges;
902
903
  /* Find immediate dominators */
904
0
  blocks = ctx->cfg_blocks;
905
0
  edges  = ctx->cfg_edges;
906
0
  blocks_count = ctx->cfg_blocks_count;
907
908
  /* Clear the dominators tree, but keep already found dominators */
909
0
  for (b = 0, bb = &blocks[0]; b <= blocks_count; b++, bb++) {
910
0
    bb->dom_depth = 0;
911
0
  }
912
913
  /* Find immediate dominators by iterative fixed-point algorithm */
914
0
  blocks[1].idom = 1;
915
0
  do {
916
0
    changed = 0;
917
918
0
    for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
919
0
      IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
920
0
      IR_ASSERT(bb->predecessors_count > 0);
921
0
      uint32_t k = bb->predecessors_count;
922
0
      uint32_t *p = edges + bb->predecessors;
923
0
      uint32_t idom = *p;
924
925
0
      if (blocks[idom].idom == 0) {
926
0
        while (1) {
927
0
          k--;
928
0
          if (UNEXPECTED(k == 0)) break;
929
0
          p++;
930
0
          idom = *p;
931
0
          if (blocks[idom].idom > 0) {
932
0
            break;
933
0
          }
934
0
        }
935
0
        if (UNEXPECTED(k == 0)) continue;
936
0
      }
937
0
      IR_ASSERT(k != 0);
938
0
      while (--k > 0) {
939
0
        uint32_t pred_b = *(++p);
940
941
0
        if (blocks[pred_b].idom > 0) {
942
0
          while (idom != pred_b) {
943
0
            while (pred_b > idom) {
944
0
              pred_b = blocks[pred_b].idom;
945
0
            }
946
0
            while (idom > pred_b) {
947
0
              idom = blocks[idom].idom;
948
0
            }
949
0
          }
950
0
        }
951
0
      }
952
0
      if (bb->idom != idom) {
953
0
        bb->idom = idom;
954
0
        changed = 1;
955
0
      }
956
0
    }
957
0
  } while (changed);
958
959
  /* Build dominators tree */
960
0
  blocks[1].idom = 0;
961
0
  blocks[1].dom_depth = 0;
962
0
  for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
963
0
    uint32_t idom = bb->idom;
964
0
    ir_block *idom_bb = &blocks[idom];
965
966
0
    bb->dom_depth = idom_bb->dom_depth + 1;
967
0
  }
968
969
  /* Construct children lists sorted by block number */
970
0
  for (b = blocks_count, bb = &blocks[b]; b >= 2; b--, bb--) {
971
0
    ir_block *idom_bb = &blocks[bb->idom];
972
0
    bb->dom_next_child = idom_bb->dom_child;
973
0
    idom_bb->dom_child = b;
974
0
  }
975
976
0
  return 1;
977
0
}
978
979
static bool ir_dominates(const ir_block *blocks, uint32_t b1, uint32_t b2)
980
3.21k
{
981
3.21k
  uint32_t b1_depth = blocks[b1].dom_depth;
982
3.21k
  const ir_block *bb2 = &blocks[b2];
983
984
7.16k
  while (bb2->dom_depth > b1_depth) {
985
3.95k
    b2 = bb2->dom_parent;
986
3.95k
    bb2 = &blocks[b2];
987
3.95k
  }
988
3.21k
  return b1 == b2;
989
3.21k
}
990
991
/* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ Graphs" and
992
 * G. Ramalingam "Identifying Loops In Almost Linear Time". */
993
994
321k
#define ENTRY_TIME(b) times[(b) * 2]
995
279k
#define EXIT_TIME(b)  times[(b) * 2 + 1]
996
997
0
#define IRR_FIRST_ENTRY(b) irreducible_loops[(b) * 2]
998
0
#define IRR_NEXT_ENTRY(b)  irreducible_loops[(b) * 2 + 1]
999
1000
static IR_NEVER_INLINE void ir_push_irreducible_loop_entries(ir_worklist *work, uint32_t *irreducible_loops, uint32_t b)
1001
0
{
1002
0
  b = IRR_FIRST_ENTRY(b);
1003
0
  while (b) {
1004
0
    ir_worklist_push(work, b);
1005
0
    b = IRR_NEXT_ENTRY(b);
1006
0
  }
1007
0
}
1008
1009
static IR_NEVER_INLINE uint32_t ir_collect_irreducible_loops(ir_ctx *ctx, uint32_t loops, uint32_t *times, ir_worklist *work, ir_list *list, uint32_t *irreducible_loops)
1010
0
{
1011
0
  ir_block *blocks = ctx->cfg_blocks;
1012
0
  uint32_t *edges = ctx->cfg_edges;
1013
1014
0
  IR_ASSERT(ir_list_len(list) != 0);
1015
0
  if (ir_list_len(list) > 1) {
1016
    /* Sort list to process irreducible loops in DFS order (insertion sort) */
1017
0
    ir_ref *a = list->a.refs;
1018
0
    uint32_t n = ir_list_len(list);
1019
0
    uint32_t i = 1;
1020
0
    while (i < n) {
1021
0
      uint32_t j = i;
1022
0
      while (j > 0 && ENTRY_TIME(a[j-1]) > ENTRY_TIME(a[j])) {
1023
0
        ir_ref tmp = a[j];
1024
0
        a[j] = a[j-1];
1025
0
        a[j-1] = tmp;
1026
0
        j--;
1027
0
      }
1028
0
      i++;
1029
0
    }
1030
0
  }
1031
0
  while (ir_list_len(list)) {
1032
0
    uint32_t hdr = ir_list_pop(list);
1033
0
    ir_block *bb = &blocks[hdr];
1034
1035
0
    IR_ASSERT(bb->flags & IR_BB_IRREDUCIBLE_LOOP);
1036
0
    IR_ASSERT(!(bb->flags & IR_BB_LOOP_HEADER));
1037
0
    if (!(bb->flags & IR_BB_LOOP_HEADER)) {
1038
      /* process irreducible loop */
1039
1040
0
      bb->flags |= IR_BB_LOOP_HEADER;
1041
0
      bb->next_loop = loops;
1042
0
      loops = hdr;
1043
0
      IRR_FIRST_ENTRY(hdr) = 0;
1044
1045
0
      if (ctx->ir_base[bb->start].op == IR_MERGE) {
1046
0
        ctx->ir_base[bb->start].op = IR_LOOP_BEGIN;
1047
0
      }
1048
1049
      /* find the closing edge(s) of the irreucible loop */
1050
0
      IR_ASSERT(bb->predecessors_count > 1);
1051
0
      IR_ASSERT(ir_worklist_len(work) == 0);
1052
0
      ir_bitset_clear(work->visited, ir_bitset_len(ir_worklist_capasity(work)));
1053
0
      ir_bitset_incl(work->visited, hdr);
1054
1055
0
      uint32_t *p = &edges[bb->predecessors];
1056
0
      uint32_t n = bb->predecessors_count;
1057
0
      do {
1058
0
        uint32_t pred = *p;
1059
0
        if (ENTRY_TIME(pred) > ENTRY_TIME(hdr) && EXIT_TIME(pred) < EXIT_TIME(hdr)) {
1060
0
          ir_worklist_push(work, pred);
1061
0
        }
1062
0
        p++;
1063
0
      } while (--n);
1064
1065
      /* collect members of the irreducible loop */
1066
0
      while (ir_worklist_len(work)) {
1067
0
        uint32_t b = ir_worklist_pop(work);
1068
1069
0
        bb = &blocks[b];
1070
0
        if (!bb->loop_header) {
1071
0
          bb->loop_header = hdr;
1072
0
        }
1073
1074
0
        uint32_t *p = &edges[bb->predecessors];
1075
0
        uint32_t n = bb->predecessors_count;
1076
1077
0
        for (; n > 0; p++, n--) {
1078
0
          uint32_t pred = *p;
1079
0
          if (!ir_bitset_in(work->visited, pred)) {
1080
0
            if (blocks[pred].loop_header == b) continue;
1081
0
            while (1) {
1082
0
              if (UNEXPECTED(blocks[pred].flags & IR_BB_IRREDUCIBLE_LOOP)) {
1083
0
                ir_push_irreducible_loop_entries(work, irreducible_loops, pred);
1084
0
              }
1085
0
              if (!blocks[pred].loop_header) break;
1086
0
              pred = blocks[pred].loop_header;
1087
0
            }
1088
0
            if (ENTRY_TIME(pred) > ENTRY_TIME(hdr) && EXIT_TIME(pred) < EXIT_TIME(hdr)) {
1089
              /* "pred" is a descendant of "hdr" */
1090
0
              ir_worklist_push(work, pred);
1091
0
            } else if (bb->predecessors_count > 1 && !(bb->flags & IR_BB_IRREDUCIBLE_ENTRY)) {
1092
              /* another entry to the irreducible loop */
1093
0
              bb->flags |= IR_BB_IRREDUCIBLE_ENTRY;
1094
0
              IRR_NEXT_ENTRY(b) = IRR_FIRST_ENTRY(hdr);
1095
0
              IRR_FIRST_ENTRY(hdr) = b;
1096
0
              if (ctx->ir_base[bb->start].op == IR_MERGE) {
1097
0
                ctx->ir_base[bb->start].op = IR_LOOP_BEGIN;
1098
0
              }
1099
0
            }
1100
0
          }
1101
0
        }
1102
0
      }
1103
0
    }
1104
0
  }
1105
1106
0
  return loops;
1107
0
}
1108
1109
int ir_find_loops(ir_ctx *ctx)
1110
9.93k
{
1111
9.93k
  uint32_t b, j, n;
1112
9.93k
  uint32_t *times, *sorted_blocks, time = 1;
1113
9.93k
  ir_block *blocks = ctx->cfg_blocks;
1114
9.93k
  uint32_t *edges = ctx->cfg_edges;
1115
9.93k
  ir_worklist work;
1116
9.93k
  uint32_t loops = 0; /* linked list of identified loops ordered by dom_depth */
1117
9.93k
  uint32_t *irreducible_loops = NULL;
1118
1119
9.93k
  if (ctx->flags2 & IR_NO_LOOPS) {
1120
6.84k
    return 1;
1121
6.84k
  }
1122
1123
  /* Compute entry/exit times for the CFG DFS spanning tree to perform ancestor and back-edge queries. */
1124
3.09k
  ir_worklist_init(&work, ctx->cfg_blocks_count + 1);
1125
3.09k
  times = ir_mem_malloc((ctx->cfg_blocks_count + 1) * 3 * sizeof(uint32_t));
1126
3.09k
  sorted_blocks = times + (ctx->cfg_blocks_count + 1) * 2;
1127
1128
3.09k
  ir_bitset visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
1129
3.09k
  ir_worklist_push(&work, 1);
1130
179k
  while (ir_worklist_len(&work)) {
1131
350k
next:
1132
350k
    b = ir_worklist_peek(&work);
1133
350k
    ir_block *bb = &blocks[b];
1134
1135
350k
    if (!ir_bitset_in(visited, b)) {
1136
176k
      ir_bitset_incl(visited, b);
1137
176k
      ENTRY_TIME(b) = time++;
1138
176k
    }
1139
1140
350k
    uint32_t n = bb->successors_count - bb->next_succ;
1141
350k
    if (n) {
1142
234k
      uint32_t *p = edges + bb->successors + bb->next_succ;
1143
295k
      for (; n > 0; p++, n--) {
1144
234k
        uint32_t succ = *p;
1145
234k
        if (ir_worklist_push(&work, succ)) {
1146
173k
          bb->next_succ = bb->successors_count - n + 1;
1147
173k
          IR_ASSERT(blocks[succ].next_succ == 0);
1148
173k
          goto next;
1149
173k
        }
1150
234k
      }
1151
234k
    }
1152
1153
176k
    bb->next_succ = 0;
1154
176k
    EXIT_TIME(b) = time++;
1155
176k
    ir_worklist_pop(&work);
1156
176k
  }
1157
3.09k
  ir_mem_free(visited);
1158
1159
  /* Sort blocks by level, which is the opposite order in which we want to process them */
1160
  /* (Breadth First Search using "sorted_blocks" as a queue) */
1161
3.09k
  sorted_blocks[1] = 1;
1162
3.09k
  j = 1;
1163
3.09k
  n = 2;
1164
33.5k
  while (j != n) {
1165
30.4k
    uint32_t i = j;
1166
30.4k
    j = n;
1167
207k
    for (; i < j; i++) {
1168
176k
      int child;
1169
350k
      for (child = blocks[sorted_blocks[i]].dom_child; child > 0; child = blocks[child].dom_next_child) {
1170
173k
        sorted_blocks[n++] = child;
1171
173k
      }
1172
176k
    }
1173
30.4k
  }
1174
3.09k
  IR_ASSERT(n == ctx->cfg_blocks_count + 1);
1175
1176
3.09k
#if IR_DEBUG
1177
3.09k
  uint32_t prev_dom_depth = blocks[sorted_blocks[n - 1]].dom_depth;
1178
3.09k
#endif
1179
3.09k
  uint32_t irreducible_depth = 0;
1180
3.09k
  ir_list irreducible_list = {0};
1181
1182
179k
  while (n > 1) {
1183
176k
    b = sorted_blocks[--n];
1184
176k
    ir_block *bb = &blocks[b];
1185
1186
176k
    IR_ASSERT(bb->dom_depth <= prev_dom_depth);
1187
1188
176k
    if (UNEXPECTED(bb->dom_depth < irreducible_depth)) {
1189
0
      if (!irreducible_loops) {
1190
0
        irreducible_loops = ir_mem_malloc(sizeof(uint32_t) * 2 * (ctx->cfg_blocks_count + 1));
1191
0
      }
1192
0
      loops = ir_collect_irreducible_loops(ctx, loops, times, &work, &irreducible_list, irreducible_loops);
1193
0
      irreducible_depth = 0;
1194
0
    }
1195
1196
176k
    if (bb->predecessors_count > 1) {
1197
41.5k
      bool irreducible = 0;
1198
41.5k
      uint32_t b_entry_time = ENTRY_TIME(b);
1199
41.5k
      uint32_t b_exit_time = EXIT_TIME(b);
1200
41.5k
      uint32_t *p = &edges[bb->predecessors];
1201
1202
144k
      for (j = bb->predecessors_count; j > 0; p++, j--) {
1203
102k
        uint32_t pred = *p;
1204
1205
        /* Check back-edges */
1206
102k
        if (ENTRY_TIME(pred) >= b_entry_time && EXIT_TIME(pred) <= b_exit_time) {
1207
3.21k
          if (ir_dominates(blocks, b, pred)) {
1208
            /* In a loop back-edge (back-join edge), the successor dominates
1209
               the predecessor.  */
1210
3.21k
            if (!ir_worklist_len(&work)) {
1211
3.21k
              ir_bitset_clear(work.visited, ir_bitset_len(ir_worklist_capasity(&work)));
1212
3.21k
            }
1213
3.21k
            ir_worklist_push(&work, pred);
1214
3.21k
          } else {
1215
            /* Otherwise it's a back-edge of irreducible loop. */
1216
0
            irreducible = 1;
1217
0
            break;
1218
0
          }
1219
3.21k
        }
1220
102k
      }
1221
1222
41.5k
      if (UNEXPECTED(irreducible)) {
1223
0
        bb->flags |= IR_BB_IRREDUCIBLE_LOOP;
1224
0
        ctx->flags2 |= IR_CFG_HAS_LOOPS | IR_IRREDUCIBLE_CFG;
1225
        /* Delay processing of all irreducible loops
1226
         * after all reducible loops with the same dominator tree depth
1227
         */
1228
0
        irreducible_depth = bb->dom_depth;
1229
0
        if (!ir_list_capasity(&irreducible_list)) {
1230
0
          ir_list_init(&irreducible_list, 16);
1231
0
        }
1232
0
        ir_list_push(&irreducible_list, b);
1233
0
        ir_list_clear(&work.l);
1234
41.5k
      } else if (ir_worklist_len(&work)) {
1235
        /* collect members of the reducible loop */
1236
3.21k
        uint32_t hdr = b;
1237
1238
3.21k
        bb->flags |= IR_BB_LOOP_HEADER;
1239
3.21k
        bb->next_loop = loops;
1240
3.21k
        loops = b;
1241
3.21k
        ctx->flags2 |= IR_CFG_HAS_LOOPS;
1242
3.21k
        if (ctx->ir_base[bb->start].op == IR_MERGE) {
1243
0
          ctx->ir_base[bb->start].op = IR_LOOP_BEGIN;
1244
0
        }
1245
3.21k
        ir_bitset_incl(work.visited, hdr);
1246
11.9k
        while (ir_worklist_len(&work)) {
1247
8.70k
          b = ir_worklist_pop(&work);
1248
8.70k
          if (b != hdr) {
1249
8.69k
            ir_block *bb = &blocks[b];
1250
1251
8.69k
            if (!bb->loop_header) {
1252
8.69k
              bb->loop_header = hdr;
1253
8.69k
            }
1254
1255
8.69k
            uint32_t *p = &edges[bb->predecessors];
1256
8.69k
            uint32_t n = bb->predecessors_count;
1257
19.2k
            for (; n > 0; p++, n--) {
1258
10.5k
              uint32_t pred = *p;
1259
10.5k
              if (!ir_bitset_in(work.visited, pred)) {
1260
5.50k
                if (UNEXPECTED(blocks[pred].flags & IR_BB_IRREDUCIBLE_LOOP)) {
1261
0
                  ir_push_irreducible_loop_entries(&work, irreducible_loops, pred);
1262
0
                }
1263
5.50k
                if (blocks[pred].loop_header) {
1264
18
                  if (blocks[pred].loop_header == b) continue;
1265
17
                  do {
1266
17
                    pred = blocks[pred].loop_header;
1267
17
                    if (UNEXPECTED(blocks[pred].flags & IR_BB_IRREDUCIBLE_LOOP)) {
1268
0
                      ir_push_irreducible_loop_entries(&work, irreducible_loops, pred);
1269
0
                    }
1270
17
                  } while (blocks[pred].loop_header > 0);
1271
10
                  ir_worklist_push(&work, pred);
1272
5.48k
                } else {
1273
5.48k
                  ir_bitset_incl(work.visited, pred);
1274
5.48k
                  ir_list_push_unchecked(&work.l, pred);
1275
5.48k
                }
1276
5.50k
              }
1277
10.5k
            }
1278
8.69k
          }
1279
8.70k
        }
1280
3.21k
      }
1281
41.5k
    }
1282
176k
  }
1283
1284
3.09k
  IR_ASSERT(!irreducible_depth);
1285
3.09k
  if (ir_list_capasity(&irreducible_list)) {
1286
0
    IR_ASSERT(irreducible_loops);
1287
0
    ir_mem_free(irreducible_loops);
1288
0
    ir_list_free(&irreducible_list);
1289
0
  }
1290
1291
3.09k
  if (loops) {
1292
3.09k
    ir_block *bb;
1293
1294
    /* Set loop_depth for loop headers */
1295
3.09k
    b = loops;
1296
3.21k
    do {
1297
3.21k
      bb = &blocks[b];
1298
3.21k
      b = bb->next_loop;
1299
3.21k
      IR_ASSERT(bb->flags & IR_BB_LOOP_HEADER);
1300
3.21k
      bb->loop_depth = (bb->loop_header) ? blocks[bb->loop_header].loop_depth + 1 : 1;
1301
3.21k
    } while (b);
1302
1303
    /* Set loop_depth for loop members */
1304
3.09k
    n = ctx->cfg_blocks_count + 1;
1305
179k
    for (j = 1, bb = blocks + 1; j < n; bb++, j++) {
1306
176k
      if (bb->loop_header) {
1307
8.69k
        if (!(bb->flags & IR_BB_LOOP_HEADER)) {
1308
8.68k
          bb->loop_depth = blocks[bb->loop_header].loop_depth;
1309
8.68k
        }
1310
8.69k
        if (bb->flags & IR_BB_ENTRY) {
1311
3
          if (bb->flags & IR_BB_LOOP_HEADER) {
1312
0
            bb->flags |= IR_BB_LOOP_WITH_ENTRY;
1313
0
          }
1314
          /* Set IR_BB_LOOP_WITH_ENTRY flag for all the enclosing loops */
1315
3
          b = bb->loop_header;
1316
3
          do {
1317
3
            ir_block *loop = &blocks[b];
1318
3
            if (loop->flags & IR_BB_LOOP_WITH_ENTRY) {
1319
0
              break;
1320
0
            }
1321
3
            loop->flags |= IR_BB_LOOP_WITH_ENTRY;
1322
3
            b = loop->loop_header;
1323
3
          } while (b);
1324
3
        }
1325
168k
      } else if ((bb->flags & (IR_BB_LOOP_HEADER|IR_BB_ENTRY|IR_BB_LOOP_WITH_ENTRY)) ==
1326
168k
          (IR_BB_LOOP_HEADER|IR_BB_ENTRY)) {
1327
0
        bb->flags |= IR_BB_LOOP_WITH_ENTRY;
1328
0
      }
1329
176k
    }
1330
3.09k
  }
1331
1332
3.09k
  ir_mem_free(times);
1333
3.09k
  ir_worklist_free(&work);
1334
1335
3.09k
  return 1;
1336
3.09k
}
1337
1338
static uint32_t _ir_skip_empty_blocks(const ir_ctx *ctx, uint32_t b)
1339
636k
{
1340
831k
  while (1) {
1341
831k
    ir_block *bb = &ctx->cfg_blocks[b];
1342
1343
831k
    if ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY) {
1344
194k
      IR_ASSERT(bb->successors_count == 1);
1345
194k
      b = ctx->cfg_edges[bb->successors];
1346
636k
    } else {
1347
636k
      return b;
1348
636k
    }
1349
831k
  }
1350
636k
}
1351
1352
/* A variation of "Bottom-up Positioning" algorithm described by
1353
 * Karl Pettis and Robert C. Hansen "Profile Guided Code Positioning"
1354
 */
1355
typedef struct _ir_edge_info {
1356
  uint32_t from;
1357
  uint32_t to;
1358
  float    freq;
1359
} ir_edge_info;
1360
1361
typedef struct _ir_chain {
1362
  uint32_t head;
1363
  uint32_t next;
1364
  union {
1365
    uint32_t prev;
1366
    uint32_t tail;
1367
  };
1368
} ir_chain;
1369
1370
static int ir_edge_info_cmp(const void *b1, const void *b2)
1371
1.35M
{
1372
1.35M
  ir_edge_info *e1 = (ir_edge_info*)b1;
1373
1.35M
  ir_edge_info *e2 = (ir_edge_info*)b2;
1374
1375
1.35M
  if (e1->freq != e2->freq) {
1376
1.11M
    return e1->freq < e2->freq ? 1 : -1;
1377
1.11M
  }
1378
  /* In case of equal frequencies, try to avoid penalization of one of the "equal" paths by
1379
   * preferring the first RPO successor (in conditional branches) and the last RPO predecessor
1380
   * (in merge points).
1381
   *
1382
   * See "Static Basic Block Reordering Heuristics for Implicit Control Flow in Baseline JITs"
1383
   * Polito Guillermo, Ducasse Stephane, and Tesone Pablo (2021)
1384
   */
1385
235k
  if (e1->from != e2->from) {
1386
222k
    return e2->from - e1->from;
1387
222k
  } else {
1388
12.2k
    return e1->to - e2->to;
1389
12.2k
  }
1390
235k
}
1391
1392
static IR_NEVER_INLINE uint32_t ir_chain_head_path_compress(ir_chain *chains, uint32_t src, uint32_t head)
1393
139k
{
1394
139k
  IR_ASSERT(head != 0);
1395
166k
  do {
1396
166k
    head = chains[head].head;
1397
166k
  } while (chains[head].head != head);
1398
166k
  do {
1399
166k
    uint32_t next = chains[src].head;
1400
166k
    chains[src].head = head;
1401
166k
    src = next;
1402
166k
  } while (chains[src].head != head);
1403
139k
  return head;
1404
139k
}
1405
1406
IR_ALWAYS_INLINE uint32_t ir_chain_head(ir_chain *chains, uint32_t src)
1407
794k
{
1408
794k
  uint32_t head = chains[src].head;
1409
794k
  if (chains[head].head == head) {
1410
655k
    return head;
1411
655k
  } else {
1412
139k
    return ir_chain_head_path_compress(chains, src, head);
1413
139k
  }
1414
794k
}
1415
1416
static void ir_join_chains(ir_chain *chains, uint32_t src, uint32_t dst)
1417
206k
{
1418
206k
  uint32_t dst_tail = chains[dst].tail;
1419
206k
  uint32_t src_tail = chains[src].tail;
1420
1421
206k
  chains[dst_tail].next = src;
1422
206k
  chains[dst].prev = src_tail;
1423
206k
  chains[src_tail].next = dst;
1424
206k
  chains[src].tail = dst_tail;
1425
206k
  chains[dst].head = src;
1426
206k
}
1427
1428
static void ir_insert_chain_before(ir_chain *chains, uint32_t c, uint32_t before)
1429
0
{
1430
0
  ir_chain *this = &chains[c];
1431
0
  ir_chain *next = &chains[before];
1432
1433
0
  IR_ASSERT(chains[c].head == c);
1434
0
  if (chains[before].head != before) {
1435
0
    this->head = next->head;
1436
0
  } else {
1437
0
    next->head = c;
1438
0
  }
1439
0
  this->next = before;
1440
0
  this->prev = next->prev;
1441
0
  next->prev = c;
1442
0
  chains[this->prev].next = c;
1443
0
}
1444
1445
#ifndef IR_DEBUG_BB_SCHEDULE_GRAPH
1446
# ifdef IR_DEBUG
1447
84.2k
#  define IR_DEBUG_BB_SCHEDULE_GRAPH 1
1448
# else
1449
#  define IR_DEBUG_BB_SCHEDULE_GRAPH 0
1450
# endif
1451
#endif
1452
1453
#if IR_DEBUG_BB_SCHEDULE_GRAPH
1454
static void ir_dump_cfg_freq_graph(ir_ctx *ctx, float *bb_freq, uint32_t edges_count, ir_edge_info *edges, ir_chain *chains)
1455
0
{
1456
0
  uint32_t b, i;
1457
0
  ir_block *bb;
1458
0
  uint8_t c, *colors;
1459
0
  bool is_head, is_empty;
1460
0
  uint32_t max_colors = 12;
1461
1462
0
  colors = alloca(sizeof(uint8_t) * (ctx->cfg_blocks_count + 1));
1463
0
  memset(colors, 0, sizeof(uint8_t) * (ctx->cfg_blocks_count + 1));
1464
0
  i = 0;
1465
0
  for (b = 1; b < ctx->cfg_blocks_count + 1; b++) {
1466
0
    if (chains[b].head == b) {
1467
0
      colors[b] = (i % max_colors) + 1;
1468
0
      i++;
1469
0
    }
1470
0
  }
1471
1472
0
  fprintf(stderr, "digraph {\n");
1473
0
  fprintf(stderr, "\trankdir=TB;\n");
1474
0
  for (b = 1; b <= ctx->cfg_blocks_count; b++) {
1475
0
    bb = &ctx->cfg_blocks[b];
1476
0
    c = (chains[b].head) ? colors[ir_chain_head(chains, b)] : 0;
1477
0
    is_head = chains[b].head == b;
1478
0
    is_empty = (bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY;
1479
0
    if (c) {
1480
0
      fprintf(stderr, "\tBB%d [label=\"BB%d: (%d),%0.3f\\n%s\\n%s\",colorscheme=set312,fillcolor=%d%s%s]\n", b, b,
1481
0
        bb->loop_depth, bb_freq[b],
1482
0
        ir_op_name[ctx->ir_base[bb->start].op], ir_op_name[ctx->ir_base[bb->end].op],
1483
0
        c,
1484
0
        is_head ? ",penwidth=3" : "",
1485
0
        is_empty ? ",style=\"dotted,filled\"" : ",style=\"filled\"");
1486
0
    } else {
1487
0
      fprintf(stderr, "\tBB%d [label=\"BB%d: (%d),%0.3f\\n%s\\n%s\"%s%s]\n", b, b,
1488
0
        bb->loop_depth, bb_freq[b],
1489
0
        ir_op_name[ctx->ir_base[bb->start].op], ir_op_name[ctx->ir_base[bb->end].op],
1490
0
        is_head ? ",penwidth=3" : "",
1491
0
        is_empty ? ",style=\"dotted\"" : "");
1492
0
    }
1493
0
  }
1494
0
  fprintf(stderr, "\n");
1495
1496
0
  for (i = 0; i < edges_count; i++) {
1497
0
    fprintf(stderr, "\tBB%d -> BB%d [label=\"%0.3f\"]\n", edges[i].from, edges[i].to, edges[i].freq);
1498
0
  }
1499
0
  fprintf(stderr, "}\n");
1500
0
}
1501
#endif
1502
1503
#ifdef IR_DEBUG
1504
static void ir_dump_edges(ir_ctx *ctx, uint32_t edges_count, ir_edge_info *edges)
1505
0
{
1506
0
  uint32_t i;
1507
1508
0
  fprintf(stderr, "Edges:\n");
1509
0
  for (i = 0; i < edges_count; i++) {
1510
0
    fprintf(stderr, "\tBB%d -> BB%d %0.3f\n", edges[i].from, edges[i].to, edges[i].freq);
1511
0
  }
1512
0
}
1513
1514
static void ir_dump_chains(ir_ctx *ctx, ir_chain *chains)
1515
0
{
1516
0
  uint32_t b, tail, i;
1517
1518
0
  fprintf(stderr, "Chains:\n");
1519
0
  for (b = 1; b < ctx->cfg_blocks_count + 1; b++) {
1520
0
    if (chains[b].head == b) {
1521
0
      tail = chains[b].tail;
1522
0
      i = b;
1523
0
      fprintf(stderr, "(BB%d", i);
1524
0
      while (i != tail) {
1525
0
        i = chains[i].next;
1526
0
        fprintf(stderr, ", BB%d", i);
1527
0
      }
1528
0
      fprintf(stderr, ")\n");
1529
0
    }
1530
0
  }
1531
0
}
1532
1533
static bool ir_is_merged_loop_back_edge(ir_ctx *ctx, uint32_t hdr, uint32_t b)
1534
0
{
1535
0
  if (ctx->cfg_blocks[hdr].flags & IR_BB_LOOP_HEADER) {
1536
0
    uint32_t loop_depth = ctx->cfg_blocks[hdr].loop_depth;
1537
1538
0
    while (ctx->cfg_blocks[b].loop_depth > loop_depth) {
1539
0
      b = ctx->cfg_blocks[b].loop_header;
1540
0
    }
1541
0
    return b == hdr;
1542
0
  }
1543
0
  return 0;
1544
0
}
1545
#endif
1546
1547
static bool ir_should_align_loop(ir_ctx *ctx, ir_chain *chains, uint32_t b, ir_block *bb)
1548
4.26k
{
1549
4.26k
  uint32_t n = bb->predecessors_count;
1550
4.26k
  uint32_t *p = ctx->cfg_edges + bb->predecessors;
1551
1552
5.64k
  for (; n > 0; p++, n--) {
1553
4.46k
    uint32_t pred = *p;
1554
4.46k
    if (chains[pred].head) {
1555
4.08k
      if (ir_chain_head(chains, pred) == b) return 1;
1556
4.08k
    } else {
1557
381
      if (ir_should_align_loop(ctx, chains, b, &ctx->cfg_blocks[pred])) return 1;
1558
381
    }
1559
4.46k
  }
1560
1561
1.17k
  return 0;
1562
4.26k
}
1563
1564
static int ir_schedule_blocks_bottom_up(ir_ctx *ctx)
1565
6.84k
{
1566
6.84k
  uint32_t max_edges_count = ctx->cfg_edges_count / 2;
1567
6.84k
  uint32_t edges_count = 0;
1568
6.84k
  uint32_t b, i, loop_depth;
1569
6.84k
  float *bb_freq, freq;
1570
6.84k
  ir_block *bb;
1571
6.84k
  ir_edge_info *edges, *e;
1572
6.84k
  ir_chain *chains;
1573
6.84k
  ir_bitqueue worklist;
1574
6.84k
  ir_bitset visited;
1575
6.84k
  uint32_t *schedule_end, count;
1576
1577
6.84k
  ctx->cfg_schedule = ir_mem_malloc(sizeof(uint32_t) * (ctx->cfg_blocks_count + 2));
1578
6.84k
  schedule_end = ctx->cfg_schedule + ctx->cfg_blocks_count;
1579
1580
  /* 1. Create initial chains for each BB */
1581
6.84k
  chains = ir_mem_malloc(sizeof(ir_chain) * (ctx->cfg_blocks_count + 1));
1582
6.84k
  chains[0].head = 0;
1583
6.84k
  chains[0].next = 0;
1584
6.84k
  chains[0].prev = 0;
1585
309k
  for (b = 1; b <= ctx->cfg_blocks_count; b++) {
1586
302k
    chains[b].head = b;
1587
302k
    chains[b].next = b;
1588
302k
    chains[b].prev = b;
1589
302k
  }
1590
1591
  /* 2. Collect information about BBs and EDGEs frequencies */
1592
6.84k
  edges = ir_mem_malloc(sizeof(ir_edge_info) * max_edges_count);
1593
6.84k
  bb_freq = ir_mem_calloc(ctx->cfg_blocks_count + 1, sizeof(float));
1594
6.84k
  bb_freq[1] = 1.0f;
1595
6.84k
  visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
1596
6.84k
  ir_bitqueue_init(&worklist, ctx->cfg_blocks_count + 1);
1597
6.84k
  ir_bitqueue_add(&worklist, 1);
1598
220k
  while ((b = ir_bitqueue_pop(&worklist)) != (uint32_t)-1) {
1599
370k
restart:
1600
370k
    bb = &ctx->cfg_blocks[b];
1601
370k
    if (bb->predecessors_count) {
1602
364k
      uint32_t n = bb->predecessors_count;
1603
364k
      uint32_t *p = ctx->cfg_edges + bb->predecessors;
1604
828k
      for (; n > 0; p++, n--) {
1605
536k
        uint32_t predecessor = *p;
1606
        /* Basic Blocks are ordered in a way that usual predecessors ids are less than successors.
1607
         * So we may compare blocks ids (predecessor < b) instead of a more expensive check for back edge
1608
         * (b != predecessor && ctx->cfg_blocks[predecessor].loop_header != b)
1609
         */
1610
536k
        if (predecessor < b) {
1611
533k
          if (!ir_bitset_in(visited, predecessor)) {
1612
72.0k
            b = predecessor;
1613
72.0k
            ir_bitqueue_del(&worklist, b);
1614
72.0k
            goto restart;
1615
72.0k
          }
1616
533k
        } else if (b != predecessor && ctx->cfg_blocks[predecessor].loop_header != b) {
1617
          /* not a loop back-edge */
1618
0
          IR_ASSERT(b == predecessor || ctx->cfg_blocks[predecessor].loop_header == b ||
1619
0
            ir_is_merged_loop_back_edge(ctx, b, predecessor));
1620
0
        }
1621
536k
      }
1622
364k
    }
1623
1624
298k
    ir_bitset_incl(visited, b);
1625
1626
298k
    if ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY) {
1627
85.5k
      uint32_t successor = ctx->cfg_edges[bb->successors];
1628
1629
      /* move empty blocks to the end */
1630
85.5k
      IR_ASSERT(chains[b].head == b);
1631
85.5k
      chains[b].head = 0;
1632
85.5k
      *schedule_end = b;
1633
85.5k
      schedule_end--;
1634
1635
85.5k
      if (successor > b) {
1636
85.4k
        bb_freq[successor] += bb_freq[b];
1637
85.4k
        b = successor;
1638
85.4k
        ir_bitqueue_del(&worklist, b);
1639
85.4k
        goto restart;
1640
85.4k
      } else {
1641
85
        continue;
1642
85
      }
1643
85.5k
    }
1644
1645
213k
    loop_depth = bb->loop_depth;
1646
213k
    if (bb->flags & IR_BB_LOOP_HEADER) {
1647
      // TODO: Estimate the loop iterations count
1648
3.17k
      bb_freq[b] *= 10;
1649
3.17k
    }
1650
1651
213k
    if (bb->successors_count) {
1652
205k
      uint32_t n = bb->successors_count;
1653
205k
      uint32_t *p = ctx->cfg_edges + bb->successors;
1654
1655
205k
      if (n == 1) {
1656
95.9k
        uint32_t successor = *p;
1657
1658
95.9k
        IR_ASSERT(edges_count < max_edges_count);
1659
95.9k
        freq = bb_freq[b];
1660
95.9k
        if (successor > b) {
1661
92.8k
          IR_ASSERT(!ir_bitset_in(visited, successor));
1662
92.8k
          bb_freq[successor] += freq;
1663
92.8k
          ir_bitqueue_add(&worklist, successor);
1664
92.8k
        }
1665
95.9k
        successor = _ir_skip_empty_blocks(ctx, successor);
1666
95.9k
        edges[edges_count].from = b;
1667
95.9k
        edges[edges_count].to = successor;
1668
95.9k
        edges[edges_count].freq = freq;
1669
95.9k
        edges_count++;
1670
110k
      } else if (n == 2 && ctx->ir_base[bb->end].op == IR_IF) {
1671
109k
        uint32_t successor1 = *p;
1672
109k
        ir_block *successor1_bb = &ctx->cfg_blocks[successor1];
1673
109k
        ir_insn *insn1 = &ctx->ir_base[successor1_bb->start];
1674
109k
        uint32_t successor2 = *(p + 1);
1675
109k
        ir_block *successor2_bb = &ctx->cfg_blocks[successor2];
1676
109k
        ir_insn *insn2 = &ctx->ir_base[successor2_bb->start];
1677
109k
        int prob1, prob2, probN = 100;
1678
1679
109k
        if (insn1->op2) {
1680
34.6k
          prob1 = insn1->op2;
1681
34.6k
          if (insn2->op2) {
1682
0
            prob2 = insn2->op2;
1683
0
            probN = prob1 + prob2;
1684
34.6k
          } else {
1685
34.6k
            if (prob1 > 100) {
1686
0
              prob1 = 100;
1687
0
            }
1688
34.6k
            prob2 = 100 - prob1;
1689
34.6k
          }
1690
1691
75.3k
        } else if (insn2->op2) {
1692
6.33k
          prob2 = insn2->op2;
1693
6.33k
          if (prob2 > 100) {
1694
0
            prob2 = 100;
1695
0
          }
1696
6.33k
          prob1 = 100 - prob2;
1697
69.0k
        } else if (successor1_bb->loop_depth >= loop_depth
1698
69.0k
            && successor2_bb->loop_depth < loop_depth) {
1699
3.40k
          prob1 = 90;
1700
3.40k
          prob2 = 10;
1701
65.6k
        } else if (successor1_bb->loop_depth < loop_depth
1702
2
            && successor2_bb->loop_depth >= loop_depth) {
1703
2
          prob1 = 10;
1704
2
          prob2 = 90;
1705
65.5k
        } else if (successor2_bb->flags & IR_BB_EMPTY) {
1706
26.9k
          prob1 = 51;
1707
26.9k
          prob2 = 49;
1708
38.6k
        } else if (successor1_bb->flags & IR_BB_EMPTY) {
1709
26.4k
          prob1 = 49;
1710
26.4k
          prob2 = 51;
1711
26.4k
        } else {
1712
12.2k
          prob1 = prob2 = 50;
1713
12.2k
        }
1714
109k
        do {
1715
109k
          freq = bb_freq[b] * (float)prob1 / (float)probN;
1716
109k
          if (successor1 > b) {
1717
109k
            IR_ASSERT(!ir_bitset_in(visited, successor1));
1718
109k
            bb_freq[successor1] += freq;
1719
109k
            if (successor1_bb->successors_count == 0 && insn1->op2 == 1) {
1720
              /* move cold block without successors to the end */
1721
3.86k
              IR_ASSERT(chains[successor1].head == successor1);
1722
3.86k
              chains[successor1].head = 0;
1723
3.86k
              *schedule_end = successor1;
1724
3.86k
              schedule_end--;
1725
3.86k
              break;
1726
106k
            } else {
1727
106k
              ir_bitqueue_add(&worklist, successor1);
1728
106k
            }
1729
109k
          }
1730
          /* try to join edges early to reduce number of edges and the cost of their sorting */
1731
106k
          if (prob1 > prob2
1732
36.6k
           && (successor1_bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) != IR_BB_EMPTY) {
1733
34.6k
            uint32_t src = chains[b].next;
1734
34.6k
            IR_ASSERT(chains[src].head == src);
1735
34.6k
            IR_ASSERT(src == ir_chain_head(chains, b));
1736
34.6k
            IR_ASSERT(chains[successor1].head == successor1);
1737
34.6k
            ir_join_chains(chains, src, successor1);
1738
34.6k
            if (!IR_DEBUG_BB_SCHEDULE_GRAPH) break;
1739
34.6k
          }
1740
106k
          successor1 = _ir_skip_empty_blocks(ctx, successor1);
1741
106k
          IR_ASSERT(edges_count < max_edges_count);
1742
106k
          edges[edges_count].from = b;
1743
106k
          edges[edges_count].to = successor1;
1744
106k
          edges[edges_count].freq = freq;
1745
106k
          edges_count++;
1746
106k
        } while (0);
1747
109k
        do {
1748
109k
          freq = bb_freq[b] * (float)prob2 / (float)probN;
1749
109k
          if (successor2 > b) {
1750
109k
            IR_ASSERT(!ir_bitset_in(visited, successor2));
1751
109k
            bb_freq[successor2] += freq;
1752
109k
            if (successor2_bb->successors_count == 0 && insn2->op2 == 1) {
1753
              /* move cold block without successors to the end */
1754
0
              IR_ASSERT(chains[successor2].head == successor2);
1755
0
              chains[successor2].head = 0;
1756
0
              *schedule_end = successor2;
1757
0
              schedule_end--;
1758
0
              break;
1759
109k
            } else {
1760
109k
              ir_bitqueue_add(&worklist, successor2);
1761
109k
            }
1762
109k
          }
1763
109k
          if (prob2 > prob1
1764
61.0k
           && (successor2_bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) != IR_BB_EMPTY) {
1765
49.5k
            uint32_t src = chains[b].next;
1766
49.5k
            IR_ASSERT(chains[src].head == src);
1767
49.5k
            IR_ASSERT(src == ir_chain_head(chains, b));
1768
49.5k
            IR_ASSERT(chains[successor2].head == successor2);
1769
49.5k
            ir_join_chains(chains, src, successor2);
1770
49.5k
            if (!IR_DEBUG_BB_SCHEDULE_GRAPH) break;
1771
49.5k
          }
1772
109k
          successor2 = _ir_skip_empty_blocks(ctx, successor2);
1773
109k
          IR_ASSERT(edges_count < max_edges_count);
1774
109k
          edges[edges_count].from = b;
1775
109k
          edges[edges_count].to = successor2;
1776
109k
          edges[edges_count].freq = freq;
1777
109k
          edges_count++;
1778
109k
        } while (0);
1779
109k
      } else {
1780
39
        int prob;
1781
1782
119
        for (; n > 0; p++, n--) {
1783
80
          uint32_t successor = *p;
1784
80
          ir_block *successor_bb = &ctx->cfg_blocks[successor];
1785
80
          ir_insn *insn = &ctx->ir_base[successor_bb->start];
1786
1787
80
          if (insn->op == IR_CASE_DEFAULT) {
1788
6
            prob = insn->op2;
1789
6
            if (!prob) {
1790
6
              prob = 100 / bb->successors_count;
1791
6
            }
1792
74
          } else if (insn->op == IR_CASE_VAL) {
1793
8
            prob = insn->op3;
1794
8
            if (!prob) {
1795
8
              prob = 100 / bb->successors_count;
1796
8
            }
1797
66
          } else if (insn->op == IR_ENTRY) {
1798
33
            if ((ctx->flags & IR_MERGE_EMPTY_ENTRIES) && (successor_bb->flags & IR_BB_EMPTY)) {
1799
0
              prob = 99; /* prefer empty ENTRY block to go first */
1800
33
            } else {
1801
33
              prob = 1;
1802
33
            }
1803
33
          } else {
1804
33
            prob = 100 / bb->successors_count;
1805
33
          }
1806
80
          freq = bb_freq[b] * (float)prob / 100.0f;
1807
80
          if (successor > b) {
1808
80
            IR_ASSERT(!ir_bitset_in(visited, successor));
1809
80
            bb_freq[successor] += freq;
1810
80
            ir_bitqueue_add(&worklist, successor);
1811
80
          }
1812
80
          successor = _ir_skip_empty_blocks(ctx, successor);
1813
80
          IR_ASSERT(edges_count < max_edges_count);
1814
80
          edges[edges_count].from = b;
1815
80
          edges[edges_count].to = successor;
1816
80
          edges[edges_count].freq = freq;
1817
80
          edges_count++;
1818
80
        }
1819
39
      }
1820
205k
    }
1821
213k
  }
1822
6.84k
  ir_bitqueue_free(&worklist);
1823
6.84k
  ir_mem_free(visited);
1824
1825
  /* 2. Sort EDGEs according to their frequencies */
1826
6.84k
  qsort(edges, edges_count, sizeof(ir_edge_info), ir_edge_info_cmp);
1827
1828
6.84k
#ifdef IR_DEBUG
1829
6.84k
  if (ctx->flags & IR_DEBUG_BB_SCHEDULE) {
1830
0
    ir_dump_edges(ctx, edges_count, edges);
1831
0
  }
1832
6.84k
#endif
1833
1834
  /* 3. Process EDGEs in the decreasing frequency order and join the connected chains */
1835
318k
  for (e = edges, i = edges_count; i > 0; e++, i--) {
1836
312k
    uint32_t dst = chains[e->to].head;
1837
312k
    if (dst == e->to) {
1838
146k
      uint32_t src = chains[e->from].next;
1839
146k
      if (chains[src].head == src) {
1840
81.9k
        IR_ASSERT(src == ir_chain_head(chains, e->from) && chains[src].tail == e->from);
1841
81.9k
        if (src != dst) {
1842
75.6k
          ir_join_chains(chains, src, dst);
1843
75.6k
        } else if (ctx->cfg_blocks[e->from].successors_count < 2) {
1844
          /* Try to rotate loop chian to finish it with a conditional branch */
1845
3.08k
          uint32_t tail = e->from;
1846
3.08k
          uint32_t prev = src;
1847
3.08k
          uint32_t next = chains[prev].next;
1848
3.08k
          uint32_t best = 0;
1849
1850
6.92k
          while (prev != tail) {
1851
3.85k
            if (ctx->ir_base[ctx->cfg_blocks[prev].end].op == IR_IF) {
1852
3.66k
              if (ctx->ir_base[ctx->cfg_blocks[prev].start].op == IR_LOOP_BEGIN
1853
3.08k
               && ctx->cfg_blocks[prev].loop_depth > 1) {
1854
7
                best = next;
1855
7
                break;
1856
3.66k
              } else if (!best || bb_freq[next] < bb_freq[best]) {
1857
                /* Find the successor of IF with the least frequency */
1858
3.35k
                best = next;
1859
3.35k
              }
1860
3.66k
            }
1861
3.84k
            prev = next;
1862
3.84k
            next = chains[next].next;
1863
3.84k
          }
1864
3.08k
          if (best) {
1865
            /* change the head of the chain */
1866
3.08k
            chains[src].head = best;
1867
3.08k
            chains[best].head = best;
1868
3.08k
          }
1869
3.08k
        }
1870
#if !IR_DEBUG_BB_SCHEDULE_GRAPH
1871
        e->from = 0; /* reset "from" to avoid check on step #5 */
1872
#endif
1873
81.9k
      }
1874
146k
    }
1875
312k
  }
1876
1877
6.84k
#if IR_DEBUG_BB_SCHEDULE_GRAPH
1878
6.84k
  if (ctx->flags & IR_DEBUG_BB_SCHEDULE) {
1879
0
    ir_dump_cfg_freq_graph(ctx, bb_freq, edges_count, edges, chains);
1880
0
  }
1881
6.84k
#endif
1882
1883
6.84k
  ir_mem_free(bb_freq);
1884
1885
6.84k
#ifdef IR_DEBUG
1886
6.84k
  if (ctx->flags & IR_DEBUG_BB_SCHEDULE) {
1887
0
    ir_dump_chains(ctx, chains);
1888
0
  }
1889
6.84k
#endif
1890
1891
  /* 4. Merge empty entry blocks */
1892
6.84k
  if ((ctx->flags & IR_MERGE_EMPTY_ENTRIES) && ctx->entries_count) {
1893
0
    for (i = 0; i < ctx->entries_count; i++) {
1894
0
      b = ctx->entries[i];
1895
0
      IR_ASSERT(ctx->cfg_blocks[b].flags & IR_BB_ENTRY);
1896
0
      if (b && chains[b].head == b && chains[b].tail == b) {
1897
0
        bb = &ctx->cfg_blocks[b];
1898
0
        if (bb->flags & IR_BB_EMPTY) {
1899
0
          uint32_t successor;
1900
1901
0
          do {
1902
0
            IR_ASSERT(bb->successors_count == 1);
1903
0
            successor = ctx->cfg_edges[bb->successors];
1904
0
            bb = &ctx->cfg_blocks[successor];
1905
0
          } while ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY);
1906
0
          IR_ASSERT(chains[successor].head);
1907
0
          ir_insert_chain_before(chains, b, successor);
1908
0
        }
1909
0
      }
1910
0
    }
1911
1912
0
#ifdef IR_DEBUG
1913
0
    if (ctx->flags & IR_DEBUG_BB_SCHEDULE) {
1914
0
      ir_dump_chains(ctx, chains);
1915
0
    }
1916
0
#endif
1917
0
  }
1918
1919
  /* 5. Align loop headers */
1920
309k
  for (b = 1; b <= ctx->cfg_blocks_count; b++) {
1921
302k
    if (chains[b].head == b) {
1922
53.3k
      bb = &ctx->cfg_blocks[b];
1923
53.3k
      if (bb->loop_depth) {
1924
3.88k
        if (ir_should_align_loop(ctx, chains, b, bb)) {
1925
3.08k
          bb->flags |= IR_BB_ALIGN_LOOP;
1926
3.08k
        }
1927
3.88k
      }
1928
53.3k
    }
1929
302k
  }
1930
1931
  /* 6. Group chains according to the most frequent edge between them */
1932
  // TODO: Try to find a better heuristic
1933
318k
  for (e = edges, i = edges_count; i > 0; e++, i--) {
1934
#if !IR_DEBUG_BB_SCHEDULE_GRAPH
1935
    if (!e->from) continue;
1936
#endif
1937
312k
    uint32_t src = ir_chain_head(chains, e->from);
1938
312k
    uint32_t dst = ir_chain_head(chains, e->to);
1939
312k
    if (src != dst) {
1940
46.5k
      if (dst == 1) {
1941
24.8k
        ir_join_chains(chains, dst, src);
1942
24.8k
      } else {
1943
21.6k
        ir_join_chains(chains, src, dst);
1944
21.6k
      }
1945
46.5k
    }
1946
312k
  }
1947
1948
6.84k
#ifdef IR_DEBUG
1949
6.84k
  if (ctx->flags & IR_DEBUG_BB_SCHEDULE) {
1950
0
    ir_dump_chains(ctx, chains);
1951
0
  }
1952
6.84k
#endif
1953
1954
  /* 7. Form a final BB order */
1955
6.84k
  count = 0;
1956
309k
  for (b = 1; b <= ctx->cfg_blocks_count; b++) {
1957
302k
    if (chains[b].head == b) {
1958
6.84k
      uint32_t tail = chains[b].tail;
1959
6.84k
      uint32_t i = b;
1960
213k
      while (1) {
1961
213k
        count++;
1962
213k
        ctx->cfg_schedule[count] = i;
1963
213k
        if (i == tail) break;
1964
206k
        i = chains[i].next;
1965
206k
      }
1966
6.84k
    }
1967
302k
  }
1968
1969
6.84k
  IR_ASSERT(ctx->cfg_schedule + count == schedule_end);
1970
6.84k
  ctx->cfg_schedule[ctx->cfg_blocks_count + 1] = 0;
1971
1972
6.84k
  ir_mem_free(edges);
1973
6.84k
  ir_mem_free(chains);
1974
1975
6.84k
  return 1;
1976
6.84k
}
1977
1978
/* A variation of "Top-down Positioning" algorithm described by
1979
 * Karl Pettis and Robert C. Hansen "Profile Guided Code Positioning"
1980
 */
1981
static int ir_schedule_blocks_top_down(ir_ctx *ctx)
1982
38
{
1983
38
  ir_bitqueue blocks;
1984
38
  uint32_t b, best_successor, last_non_empty;
1985
38
  ir_block *bb, *best_successor_bb;
1986
38
  ir_insn *insn;
1987
38
  uint32_t *list, *schedule_end;
1988
38
  uint32_t count = 0;
1989
1990
38
  ir_bitqueue_init(&blocks, ctx->cfg_blocks_count + 1);
1991
38
  blocks.pos = 0;
1992
38
  list = ir_mem_malloc(sizeof(uint32_t) * (ctx->cfg_blocks_count + 2));
1993
38
  list[ctx->cfg_blocks_count + 1] = 0;
1994
38
  schedule_end = list + ctx->cfg_blocks_count;
1995
11.0k
  for (b = 1; b <= ctx->cfg_blocks_count; b++) {
1996
11.0k
    ir_bitset_incl(blocks.set, b);
1997
11.0k
  }
1998
1999
4.07k
  while ((b = ir_bitqueue_pop(&blocks)) != (uint32_t)-1) {
2000
4.03k
    bb = &ctx->cfg_blocks[b];
2001
    /* Start trace */
2002
4.03k
    last_non_empty = 0;
2003
11.0k
    do {
2004
11.0k
      if (UNEXPECTED(bb->flags & IR_BB_PREV_EMPTY_ENTRY) && ir_bitqueue_in(&blocks, b - 1)) {
2005
        /* Schedule the previous empty ENTRY block before this one */
2006
0
        uint32_t predecessor = b - 1;
2007
2008
0
        ir_bitqueue_del(&blocks, predecessor);
2009
0
        count++;
2010
0
        list[count] = predecessor;
2011
0
      }
2012
11.0k
      if ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY) {
2013
        /* move empty blocks to the end */
2014
3.50k
        *schedule_end = b;
2015
3.50k
        schedule_end--;
2016
7.55k
      } else {
2017
7.55k
        count++;
2018
7.55k
        list[count] = b;
2019
7.55k
        last_non_empty = b;
2020
7.55k
      }
2021
11.0k
      best_successor_bb = NULL;
2022
11.0k
      if (bb->successors_count == 1) {
2023
6.81k
        best_successor = ctx->cfg_edges[bb->successors];
2024
6.81k
        if (ir_bitqueue_in(&blocks, best_successor)) {
2025
2.76k
          best_successor_bb = &ctx->cfg_blocks[best_successor];
2026
2.76k
        }
2027
6.81k
      } else if (bb->successors_count > 1) {
2028
4.12k
        uint32_t prob, best_successor_prob;
2029
4.12k
        uint32_t *p, successor;
2030
4.12k
        ir_block *successor_bb;
2031
2032
12.3k
        for (b = 0, p = &ctx->cfg_edges[bb->successors]; b < bb->successors_count; b++, p++) {
2033
8.25k
          successor = *p;
2034
8.25k
          if (ir_bitqueue_in(&blocks, successor)) {
2035
8.25k
            successor_bb = &ctx->cfg_blocks[successor];
2036
8.25k
            insn = &ctx->ir_base[successor_bb->start];
2037
8.25k
            if (insn->op == IR_IF_TRUE || insn->op == IR_IF_FALSE) {
2038
8.25k
              prob = insn->op2;
2039
8.25k
              if (!prob) {
2040
6.32k
                prob = 100 / bb->successors_count;
2041
6.32k
                if (!(successor_bb->flags & IR_BB_EMPTY)) {
2042
3.86k
                  prob++;
2043
3.86k
                }
2044
6.32k
              }
2045
8.25k
            } else if (insn->op == IR_CASE_DEFAULT) {
2046
0
              prob = insn->op2;
2047
0
              if (!prob) {
2048
0
                prob = 100 / bb->successors_count;
2049
0
              }
2050
0
            } else if (insn->op == IR_CASE_VAL) {
2051
0
              prob = insn->op3;
2052
0
              if (!prob) {
2053
0
                prob = 100 / bb->successors_count;
2054
0
              }
2055
0
            } else if (insn->op == IR_ENTRY) {
2056
0
              if ((ctx->flags & IR_MERGE_EMPTY_ENTRIES) && (successor_bb->flags & IR_BB_EMPTY)) {
2057
0
                prob = 99; /* prefer empty ENTRY block to go first */
2058
0
              } else {
2059
0
                prob = 1;
2060
0
              }
2061
0
            } else {
2062
0
              prob = 100 / bb->successors_count;
2063
0
            }
2064
8.25k
            if (!best_successor_bb
2065
4.12k
             || successor_bb->loop_depth > best_successor_bb->loop_depth
2066
6.15k
             || prob > best_successor_prob) {
2067
6.15k
              best_successor = successor;
2068
6.15k
              best_successor_bb = successor_bb;
2069
6.15k
              best_successor_prob = prob;
2070
6.15k
            }
2071
8.25k
          }
2072
8.25k
        }
2073
4.12k
      }
2074
11.0k
      if (!best_successor_bb) {
2075
        /* Try to continue trace using the other successor of the last IF */
2076
4.16k
        if ((bb->flags & IR_BB_EMPTY) && last_non_empty) {
2077
275
          bb = &ctx->cfg_blocks[last_non_empty];
2078
275
          if (bb->successors_count == 2 && ctx->ir_base[bb->end].op == IR_IF) {
2079
210
            b = ctx->cfg_edges[bb->successors];
2080
2081
210
            if (!ir_bitqueue_in(&blocks, b)) {
2082
162
              b = ctx->cfg_edges[bb->successors + 1];
2083
162
            }
2084
210
            if (ir_bitqueue_in(&blocks, b)) {
2085
129
              bb = &ctx->cfg_blocks[b];
2086
129
              ir_bitqueue_del(&blocks, b);
2087
129
              continue;
2088
129
            }
2089
210
          }
2090
275
        }
2091
        /* End trace */
2092
4.03k
        break;
2093
4.16k
      }
2094
6.89k
      b = best_successor;
2095
6.89k
      bb = best_successor_bb;
2096
6.89k
      ir_bitqueue_del(&blocks, b);
2097
7.02k
    } while (1);
2098
4.03k
  }
2099
2100
38
  IR_ASSERT(list + count == schedule_end);
2101
38
  ctx->cfg_schedule = list;
2102
38
  ir_bitqueue_free(&blocks);
2103
2104
38
  return 1;
2105
38
}
2106
2107
int ir_schedule_blocks(ir_ctx *ctx)
2108
9.93k
{
2109
9.93k
  ir_ref ref;
2110
2111
9.93k
  if (ctx->cfg_blocks_count <= 2) {
2112
3.06k
    return 1;
2113
3.06k
  }
2114
2115
  /* Mark "stop" blocks termintated with UNREACHABLE as "unexpected" */
2116
6.87k
  ref = ctx->ir_base[1].op1;
2117
21.2k
  while (ref) {
2118
14.3k
    ir_insn *insn = &ctx->ir_base[ref];
2119
2120
14.3k
    if (insn->op == IR_UNREACHABLE && ctx->ir_base[insn->op1].op != IR_TAILCALL) {
2121
0
      ir_block *bb = &ctx->cfg_blocks[ctx->cfg_map[ref]];
2122
0
      uint32_t n = bb->predecessors_count;
2123
2124
0
      if (n == 1) {
2125
0
        ir_insn *start_insn = &ctx->ir_base[bb->start];
2126
0
        if (start_insn->op == IR_IF_TRUE
2127
0
         || start_insn->op == IR_IF_FALSE
2128
0
         || start_insn->op == IR_CASE_DEFAULT) {
2129
0
          if (!start_insn->op2) start_insn->op2 = 1;
2130
0
        } else if (start_insn->op == IR_CASE_VAL) {
2131
0
          if (!start_insn->op3) start_insn->op3 = 1;
2132
0
        }
2133
0
      } else if (n > 1) {
2134
0
        uint32_t *p = &ctx->cfg_edges[bb->predecessors];
2135
2136
0
        for (; n > 0; p++, n--) {
2137
0
          bb = &ctx->cfg_blocks[*p];
2138
0
          if (bb->predecessors_count == 1) {
2139
0
            ir_insn *start_insn = &ctx->ir_base[bb->start];
2140
0
            if (start_insn->op == IR_IF_TRUE
2141
0
             || start_insn->op == IR_IF_FALSE
2142
0
             || start_insn->op == IR_CASE_DEFAULT) {
2143
0
              if (!start_insn->op2) start_insn->op2 = 1;
2144
0
            } else if (start_insn->op == IR_CASE_VAL) {
2145
0
              if (!start_insn->op3) start_insn->op3 = 1;
2146
0
            }
2147
0
          }
2148
0
        }
2149
0
      }
2150
0
    }
2151
14.3k
    ref = insn->op3;
2152
14.3k
  }
2153
2154
  /* The bottom-up Pettis-Hansen algorithm is expensive - O(n^3),
2155
   * use it only for relatively small functions.
2156
   *
2157
   * TODO: make the choice between top-down and bottom-up algorithm configurable
2158
   */
2159
6.87k
  if (UNEXPECTED(ctx->flags2 & IR_IRREDUCIBLE_CFG) || ctx->cfg_blocks_count > 256) {
2160
38
    return ir_schedule_blocks_top_down(ctx);
2161
6.84k
  } else {
2162
6.84k
    return ir_schedule_blocks_bottom_up(ctx);
2163
6.84k
  }
2164
6.87k
}
2165
2166
/* JMP target optimisation */
2167
uint32_t ir_skip_empty_target_blocks(const ir_ctx *ctx, uint32_t b)
2168
324k
{
2169
324k
  return _ir_skip_empty_blocks(ctx, b);
2170
324k
}
2171
2172
uint32_t ir_next_block(const ir_ctx *ctx, uint32_t b)
2173
0
{
2174
0
  ir_block *bb;
2175
2176
0
  if (ctx->cfg_schedule) {
2177
0
    uint32_t ret = ctx->cfg_schedule[++b];
2178
2179
    /* Check for empty ENTRY block */
2180
0
    while (ret && ((ctx->cfg_blocks[ret].flags & (IR_BB_START|IR_BB_EMPTY)) == IR_BB_EMPTY)) {
2181
0
      ret = ctx->cfg_schedule[++b];
2182
0
    }
2183
0
    return ret;
2184
0
  }
2185
2186
0
  b++;
2187
0
  while (1) {
2188
0
    if (b > ctx->cfg_blocks_count) {
2189
0
      return 0;
2190
0
    }
2191
2192
0
    bb = &ctx->cfg_blocks[b];
2193
2194
0
    if ((bb->flags & (IR_BB_START|IR_BB_EMPTY)) == IR_BB_EMPTY) {
2195
0
      b++;
2196
0
    } else {
2197
0
      break;
2198
0
    }
2199
0
  }
2200
0
  return b;
2201
0
}
2202
2203
void ir_get_true_false_blocks(const ir_ctx *ctx, uint32_t b, uint32_t *true_block, uint32_t *false_block)
2204
114k
{
2205
114k
  ir_block *bb;
2206
114k
  uint32_t *p, use_block;
2207
2208
114k
  *true_block = 0;
2209
114k
  *false_block = 0;
2210
114k
  bb = &ctx->cfg_blocks[b];
2211
114k
  IR_ASSERT(ctx->ir_base[bb->end].op == IR_IF);
2212
114k
  IR_ASSERT(bb->successors_count == 2);
2213
114k
  p = &ctx->cfg_edges[bb->successors];
2214
114k
  use_block = *p;
2215
114k
  if (ctx->ir_base[ctx->cfg_blocks[use_block].start].op == IR_IF_TRUE) {
2216
63.4k
    *true_block = ir_skip_empty_target_blocks(ctx, use_block);
2217
63.4k
    use_block = *(p+1);
2218
63.4k
    IR_ASSERT(ctx->ir_base[ctx->cfg_blocks[use_block].start].op == IR_IF_FALSE);
2219
63.4k
    *false_block = ir_skip_empty_target_blocks(ctx, use_block);
2220
63.4k
  } else {
2221
50.6k
    IR_ASSERT(ctx->ir_base[ctx->cfg_blocks[use_block].start].op == IR_IF_FALSE);
2222
50.6k
    *false_block = ir_skip_empty_target_blocks(ctx, use_block);
2223
50.6k
    use_block = *(p+1);
2224
50.6k
    IR_ASSERT(ctx->ir_base[ctx->cfg_blocks[use_block].start].op == IR_IF_TRUE);
2225
50.6k
    *true_block = ir_skip_empty_target_blocks(ctx, use_block);
2226
50.6k
  }
2227
114k
  IR_ASSERT(*true_block && *false_block);
2228
114k
}