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_ra.c
Line
Count
Source
1
/*
2
 * IR - Lightweight JIT Compilation Framework
3
 * (RA - Register Allocation, Liveness, Coalescing, SSA Deconstruction)
4
 * This file is part of the IR Project distributed under the MIT-style LICENSE.
5
 * Authors: Dmitry Stogov <dmitry@php.net>
6
 *
7
 * See: "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
8
 * Michael Franz, CGO'10 (2010)
9
 * See: "Optimized Interval Splitting in a Linear Scan Register Allocator",
10
 * Christian Wimmer VEE'10 (2005)
11
 */
12
13
#ifndef _GNU_SOURCE
14
# define _GNU_SOURCE
15
#endif
16
17
#include <stdlib.h>
18
#include "ir.h"
19
20
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
21
# include "ir_x86.h"
22
#elif defined(IR_TARGET_AARCH64)
23
# include "ir_aarch64.h"
24
#else
25
# error "Unknown IR target"
26
#endif
27
28
#include "ir_private.h"
29
30
int ir_regs_number(void)
31
0
{
32
0
  return IR_REG_NUM;
33
0
}
34
35
bool ir_reg_is_int(int32_t reg)
36
0
{
37
0
  IR_ASSERT(reg >= 0 && reg < IR_REG_NUM);
38
0
  return reg >= IR_REG_GP_FIRST && reg <= IR_REG_GP_LAST;
39
0
}
40
41
static int ir_assign_virtual_registers_slow(ir_ctx *ctx)
42
0
{
43
0
  int32_t *vregs;
44
0
  int32_t vregs_count = 0;
45
0
  uint32_t b;
46
0
  ir_ref i, n;
47
0
  ir_block *bb;
48
0
  ir_insn *insn;
49
0
  uint32_t flags;
50
51
  /* Assign unique virtual register to each data node */
52
0
  vregs = ir_mem_calloc(ctx->insns_count, sizeof(ir_ref));
53
0
  n = 1;
54
0
  for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
55
0
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
56
0
    i = bb->start;
57
58
    /* skip first instruction */
59
0
    insn = ctx->ir_base + i;
60
0
    n = ir_insn_len(insn);
61
0
    i += n;
62
0
    insn += n;
63
0
    while (i < bb->end) {
64
0
      flags = ir_op_flags[insn->op];
65
0
      if (((flags & IR_OP_FLAG_DATA) && insn->op != IR_VAR && (insn->op != IR_PARAM || ctx->use_lists[i].count > 0))
66
0
       || ((flags & IR_OP_FLAG_MEM) && ctx->use_lists[i].count > 1)) {
67
0
        if (!ctx->rules || !(ctx->rules[i] & (IR_FUSED|IR_SKIPPED|IR_NO_REG))) {
68
0
          vregs[i] = ++vregs_count;
69
0
        }
70
0
      }
71
0
      n = ir_insn_len(insn);
72
0
      i += n;
73
0
      insn += n;
74
0
    }
75
0
  }
76
0
  ctx->vregs_count = vregs_count;
77
0
  ctx->vregs = vregs;
78
79
0
  return 1;
80
0
}
81
82
int ir_assign_virtual_registers(ir_ctx *ctx)
83
9.93k
{
84
9.93k
  int32_t *vregs;
85
9.93k
  int32_t vregs_count = 0;
86
9.93k
  ir_ref i;
87
9.93k
  ir_insn *insn;
88
89
9.93k
  if (!ctx->rules) {
90
0
    return ir_assign_virtual_registers_slow(ctx);
91
0
  }
92
93
  /* Assign unique virtual register to each rule that needs it */
94
9.93k
  vregs = ir_mem_malloc(ctx->insns_count * sizeof(ir_ref));
95
96
1.80M
  for (i = 1, insn = &ctx->ir_base[1]; i < ctx->insns_count; i++, insn++) {
97
1.79M
    int32_t v = 0;
98
99
1.79M
    if (ctx->rules[i] && !(ctx->rules[i] & (IR_FUSED|IR_SKIPPED|IR_NO_REG))) {
100
799k
      uint32_t flags = ir_op_flags[insn->op];
101
102
799k
      if ((flags & IR_OP_FLAG_DATA)
103
711k
       || ((flags & IR_OP_FLAG_MEM) && ctx->use_lists[i].count > 1)) {
104
185k
        v = ++vregs_count;
105
185k
      }
106
799k
    }
107
1.79M
    vregs[i] = v;
108
1.79M
  }
109
110
9.93k
  ctx->vregs_count = vregs_count;
111
9.93k
  ctx->vregs = vregs;
112
113
9.93k
  return 1;
114
9.93k
}
115
116
/* Lifetime intervals construction */
117
118
static ir_live_interval *ir_new_live_range(ir_ctx *ctx, int v, ir_live_pos start, ir_live_pos end)
119
185k
{
120
185k
  ir_live_interval *ival = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval));
121
122
185k
  ival->type = IR_VOID;
123
185k
  ival->reg = IR_REG_NONE;
124
#if IR_X86_I64
125
  ival->reg_hi = IR_REG_NONE;
126
#endif
127
185k
  ival->flags = 0;
128
185k
  ival->vreg = v;
129
185k
  ival->stack_spill_pos = -1; // not allocated
130
185k
  ival->range.start = start;
131
185k
  ival->range.end = ival->end = end;
132
185k
  ival->range.next = NULL;
133
185k
  ival->use_pos = NULL;
134
185k
  ival->next = NULL;
135
136
185k
  ctx->live_intervals[v] = ival;
137
185k
  return ival;
138
185k
}
139
140
static ir_live_interval *ir_add_live_range(ir_ctx *ctx, int v, ir_live_pos start, ir_live_pos end)
141
293k
{
142
293k
  ir_live_interval *ival = ctx->live_intervals[v];
143
293k
  ir_live_range *p, *q;
144
145
293k
  if (!ival) {
146
185k
    return ir_new_live_range(ctx, v, start, end);
147
185k
  }
148
149
107k
  p = &ival->range;
150
107k
  if (end >= p->start) {
151
55.3k
    ir_live_range *prev = NULL;
152
153
101k
    do {
154
101k
      if (p->end >= start) {
155
37.0k
        if (start < p->start) {
156
9.34k
          p->start = start;
157
9.34k
        }
158
37.0k
        if (end > p->end) {
159
          /* merge with next */
160
26.4k
          ir_live_range *next = p->next;
161
162
26.4k
          p->end = end;
163
26.7k
          while (next && p->end >= next->start) {
164
320
            if (next->end > p->end) {
165
320
              p->end = next->end;
166
320
            }
167
320
            p->next = next->next;
168
            /* remember in the "unused_ranges" list */
169
320
            next->next = ctx->unused_ranges;
170
320
            ctx->unused_ranges = next;
171
320
            next = p->next;
172
320
          }
173
26.4k
          if (!p->next) {
174
25.5k
            ival->end = p->end;
175
25.5k
          }
176
26.4k
        }
177
37.0k
        return ival;
178
37.0k
      }
179
64.3k
      prev = p;
180
64.3k
      p = prev->next;
181
64.3k
    } while (p && end >= p->start);
182
18.3k
    if (!p) {
183
9.86k
      ival->end = end;
184
9.86k
    }
185
18.3k
    if (prev) {
186
18.3k
      if (ctx->unused_ranges) {
187
        /* reuse */
188
15.4k
        q = ctx->unused_ranges;
189
15.4k
        ctx->unused_ranges = q->next;
190
15.4k
      } else {
191
2.88k
        q = ir_arena_alloc(&ctx->arena, sizeof(ir_live_range));
192
2.88k
      }
193
18.3k
      prev->next = q;
194
18.3k
      q->start = start;
195
18.3k
      q->end = end;
196
18.3k
      q->next = p;
197
18.3k
      return ival;
198
18.3k
    }
199
18.3k
  }
200
201
52.4k
  if (ctx->unused_ranges) {
202
    /* reuse */
203
868
    q = ctx->unused_ranges;
204
868
    ctx->unused_ranges = q->next;
205
51.6k
  } else {
206
51.6k
    q = ir_arena_alloc(&ctx->arena, sizeof(ir_live_range));
207
51.6k
  }
208
52.4k
  q->start = p->start;
209
52.4k
  q->end = p->end;
210
52.4k
  q->next = p->next;
211
52.4k
  p->start = start;
212
52.4k
  p->end = end;
213
52.4k
  p->next = q;
214
52.4k
  return ival;
215
107k
}
216
217
IR_ALWAYS_INLINE ir_live_interval *ir_add_prev_live_range(ir_ctx *ctx, int v, ir_live_pos start, ir_live_pos end)
218
191k
{
219
191k
  ir_live_interval *ival = ctx->live_intervals[v];
220
221
191k
  if (ival && ival->range.start == end) {
222
122k
    ival->range.start = start;
223
122k
    return ival;
224
122k
  }
225
68.7k
  return ir_add_live_range(ctx, v, start, end);
226
191k
}
227
228
static void ir_add_fixed_live_range(ir_ctx *ctx, ir_reg reg, ir_live_pos start, ir_live_pos end)
229
206k
{
230
206k
  int v = ctx->vregs_count + 1 + reg;
231
206k
  ir_live_interval *ival = ctx->live_intervals[v];
232
206k
  ir_live_range *q;
233
234
206k
  if (!ival) {
235
31.6k
    ival = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval));
236
31.6k
    ival->type = IR_VOID;
237
31.6k
    ival->reg = reg;
238
#if IR_X86_I64
239
    ival->reg_hi = IR_REG_NONE;
240
#endif
241
31.6k
    ival->flags = IR_LIVE_INTERVAL_FIXED;
242
31.6k
    ival->vreg = v;
243
31.6k
    ival->stack_spill_pos = -1; // not allocated
244
31.6k
    ival->range.start = start;
245
31.6k
    ival->range.end = ival->end = end;
246
31.6k
    ival->range.next = NULL;
247
31.6k
    ival->use_pos = NULL;
248
31.6k
    ival->next = NULL;
249
250
31.6k
    ctx->live_intervals[v] = ival;
251
175k
  } else if (EXPECTED(end < ival->range.start)) {
252
173k
    if (ctx->unused_ranges) {
253
      /* reuse */
254
0
      q = ctx->unused_ranges;
255
0
      ctx->unused_ranges = q->next;
256
173k
    } else {
257
173k
      q = ir_arena_alloc(&ctx->arena, sizeof(ir_live_range));
258
173k
    }
259
260
173k
    q->start = ival->range.start;
261
173k
    q->end = ival->range.end;
262
173k
    q->next = ival->range.next;
263
173k
    ival->range.start = start;
264
173k
    ival->range.end = end;
265
173k
    ival->range.next = q;
266
173k
  } else if (end == ival->range.start) {
267
0
    ival->range.start = start;
268
1.25k
  } else {
269
1.25k
    ir_add_live_range(ctx, v, start, end);
270
1.25k
  }
271
206k
}
272
273
static void ir_add_tmp(ir_ctx *ctx, ir_ref ref, ir_ref tmp_ref, int32_t tmp_op_num, ir_tmp_reg tmp_reg)
274
95.9k
{
275
95.9k
  ir_live_interval *ival = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval));
276
277
95.9k
  ival->type = tmp_reg.type;
278
95.9k
  ival->reg = IR_REG_NONE;
279
#if IR_X86_I64
280
  ival->reg_hi = IR_REG_NONE;
281
#endif
282
95.9k
  ival->flags = IR_LIVE_INTERVAL_TEMP;
283
95.9k
  ival->tmp_ref = tmp_ref;
284
95.9k
  ival->tmp_op_num = tmp_op_num;
285
95.9k
  ival->range.start = IR_START_LIVE_POS_FROM_REF(ref) + tmp_reg.start;
286
95.9k
  ival->range.end = ival->end = IR_START_LIVE_POS_FROM_REF(ref) + tmp_reg.end;
287
95.9k
  ival->range.next = NULL;
288
95.9k
  ival->use_pos = NULL;
289
290
95.9k
  if (!ctx->live_intervals[0]) {
291
9.54k
    ival->next = NULL;
292
9.54k
    ctx->live_intervals[0] = ival;
293
86.4k
  } else if (ival->range.start >= ctx->live_intervals[0]->range.start) {
294
3.85k
    ir_live_interval *prev = ctx->live_intervals[0];
295
296
34.2k
    while (prev->next && ival->range.start >= prev->next->range.start) {
297
30.4k
      prev = prev->next;
298
30.4k
    }
299
3.85k
    ival->next = prev->next;
300
3.85k
    prev->next = ival;
301
82.5k
  } else {
302
82.5k
    ir_live_interval *next = ctx->live_intervals[0];
303
304
82.5k
    ival->next = next;
305
82.5k
    ctx->live_intervals[0] = ival;
306
82.5k
  }
307
95.9k
  return;
308
95.9k
}
309
310
static ir_live_interval *ir_fix_live_range(ir_ctx *ctx, int v, ir_live_pos old_start, ir_live_pos new_start)
311
161k
{
312
161k
  ir_live_interval *ival = ctx->live_intervals[v];
313
161k
  ir_live_range *p = &ival->range;
314
315
#if 0
316
  while (p && p->start < old_start) {
317
    p = p->next;
318
  }
319
#endif
320
161k
  IR_ASSERT(ival && p->start == old_start);
321
161k
  p->start = new_start;
322
161k
  return ival;
323
161k
}
324
325
static void ir_add_use_pos(ir_ctx *ctx, ir_live_interval *ival, ir_use_pos *use_pos)
326
511k
{
327
511k
  ir_use_pos *p = ival->use_pos;
328
329
511k
  if (EXPECTED(!p || p->pos > use_pos->pos)) {
330
510k
    use_pos->next = p;
331
510k
    ival->use_pos = use_pos;
332
510k
  } else {
333
505
    ir_use_pos *prev;
334
335
505
    do {
336
505
      prev = p;
337
505
      p = p->next;
338
505
    } while (p && p->pos < use_pos->pos);
339
340
505
    use_pos->next = prev->next;
341
505
    prev->next = use_pos;
342
505
  }
343
511k
}
344
345
346
IR_ALWAYS_INLINE void ir_add_use(ir_ctx *ctx, ir_live_interval *ival, int op_num, ir_live_pos pos, ir_reg hint, uint8_t use_flags, ir_ref hint_ref)
347
464k
{
348
464k
  ir_use_pos *use_pos;
349
350
464k
  use_pos = ir_arena_alloc(&ctx->arena, sizeof(ir_use_pos));
351
464k
  use_pos->op_num = op_num;
352
464k
  use_pos->hint = hint;
353
464k
  use_pos->flags = use_flags;
354
464k
  use_pos->hint_ref = hint_ref;
355
464k
  use_pos->pos = pos;
356
357
464k
  if (hint != IR_REG_NONE) {
358
76.9k
    ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REGS;
359
76.9k
  }
360
464k
  if (hint_ref > 0) {
361
62.3k
    ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REFS;
362
62.3k
  }
363
364
464k
  ir_add_use_pos(ctx, ival, use_pos);
365
464k
}
366
367
static void ir_add_phi_use(ir_ctx *ctx, ir_live_interval *ival, int op_num, ir_live_pos pos, ir_ref phi_ref)
368
46.9k
{
369
46.9k
  ir_use_pos *use_pos;
370
371
46.9k
  IR_ASSERT(phi_ref > 0);
372
46.9k
  use_pos = ir_arena_alloc(&ctx->arena, sizeof(ir_use_pos));
373
46.9k
  use_pos->op_num = op_num;
374
46.9k
  use_pos->hint = IR_REG_NONE;
375
46.9k
  use_pos->flags = IR_PHI_USE | IR_USE_SHOULD_BE_IN_REG; // TODO: ???
376
46.9k
  use_pos->hint_ref = -phi_ref;
377
46.9k
  use_pos->pos = pos;
378
379
46.9k
  ir_add_use_pos(ctx, ival, use_pos);
380
46.9k
}
381
382
static void ir_add_hint(ir_ctx *ctx, ir_live_interval *ival, ir_live_pos pos, ir_reg hint, uint8_t flags)
383
70
{
384
70
  if (!(ival->flags & IR_LIVE_INTERVAL_HAS_HINT_REGS)) {
385
49
    ir_use_pos *use_pos = ival->use_pos;
386
387
167
    while (use_pos) {
388
118
      if (use_pos->pos == pos) {
389
49
        if (use_pos->hint == IR_REG_NONE) {
390
49
          use_pos->flags |= flags;
391
49
          use_pos->hint = hint;
392
49
          ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REGS;
393
49
        }
394
49
      }
395
118
      use_pos = use_pos->next;
396
118
    }
397
49
  }
398
70
}
399
400
static void ir_hint_propagation(ir_ctx *ctx)
401
9.93k
{
402
9.93k
  int i;
403
9.93k
  ir_live_interval *ival;
404
9.93k
  ir_use_pos *use_pos;
405
9.93k
  ir_use_pos *hint_use_pos;
406
407
195k
  for (i = ctx->vregs_count; i > 0; i--) {
408
185k
    ival = ctx->live_intervals[i];
409
185k
    if (ival
410
140k
     && (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)) == (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)) {
411
3.50k
      use_pos = ival->use_pos;
412
3.50k
      hint_use_pos = NULL;
413
16.9k
      while (use_pos) {
414
13.4k
        if (use_pos->op_num == 0) {
415
5.35k
          if (use_pos->hint_ref > 0) {
416
287
            hint_use_pos = use_pos;
417
287
          }
418
8.11k
        } else if (use_pos->hint != IR_REG_NONE) {
419
648
          if (hint_use_pos) {
420
70
            ir_live_interval *hint_ival = ctx->live_intervals[ctx->vregs[hint_use_pos->hint_ref]];
421
422
#if IR_X86_I64
423
            if (use_pos->flags & IR_HINT_TWO_REGS) {
424
425
              if (hint_ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
426
                ir_add_hint(ctx, hint_ival, hint_use_pos->pos, use_pos->hint, IR_HINT_TWO_REGS);
427
              } else {
428
                ir_add_hint(ctx, hint_ival, hint_use_pos->pos, IR_REG_I64_LO(use_pos->hint), 0);
429
              }
430
            } else
431
#endif
432
70
            ir_add_hint(ctx, hint_ival, hint_use_pos->pos, use_pos->hint, 0);
433
70
            hint_use_pos = NULL;
434
70
          }
435
648
        }
436
13.4k
        use_pos = use_pos->next;
437
13.4k
      }
438
3.50k
    }
439
185k
  }
440
9.93k
}
441
442
#ifdef IR_BITSET_LIVENESS
443
/* DFS + Loop-Forest livness for SSA using bitset(s) */
444
static void ir_add_osr_entry_loads(ir_ctx *ctx, ir_block *bb, ir_bitset live, uint32_t len, uint32_t b)
445
{
446
  bool ok = 1;
447
  int count = 0;
448
  ir_list *list = (ir_list*)ctx->osr_entry_loads;
449
  ir_ref i;
450
451
  IR_BITSET_FOREACH(live, len, i) {
452
    /* Skip live references from ENTRY to PARAM. TODO: duplicate PARAM in each ENTRY ??? */
453
    ir_use_pos *use_pos = ctx->live_intervals[i]->use_pos;
454
    ir_ref ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos);
455
456
    if (use_pos->op_num) {
457
      ir_ref *ops = ctx->ir_base[ref].ops;
458
      ref = ops[use_pos->op_num];
459
    }
460
461
    if (ctx->ir_base[ref].op == IR_PARAM) {
462
      continue;
463
    }
464
    if (ctx->binding) {
465
      ir_ref var = ir_binding_find(ctx, ref);
466
      if (var < 0) {
467
        /* We may load the value at OSR entry-point */
468
        if (!count) {
469
          bb->flags &= ~IR_BB_EMPTY;
470
          bb->flags |= IR_BB_OSR_ENTRY_LOADS;
471
          if (!ctx->osr_entry_loads) {
472
            list = ctx->osr_entry_loads = ir_mem_malloc(sizeof(ir_list));
473
            ir_list_init(list, 16);
474
          }
475
          ir_list_push(list, b);
476
          ir_list_push(list, 0);
477
        }
478
        ir_list_push(list, ref);
479
        count++;
480
        continue;
481
      }
482
    }
483
    fprintf(stderr, "ENTRY %d (block %d start %d) - live var %d\n", ctx->ir_base[bb->start].op2, b, bb->start, ref);
484
    ok = 0;
485
  } IR_BITSET_FOREACH_END();
486
487
  if (!ok) {
488
    IR_ASSERT(0);
489
  }
490
  if (count) {
491
    ir_list_set(list, ir_list_len(ctx->osr_entry_loads) - (count + 1), count);
492
493
#if 0
494
    /* ENTRY "clobbers" all registers */
495
    ir_ref ref = ctx->ir_base[bb->start].op1;
496
    ir_add_fixed_live_range(ctx, IR_REG_ALL,
497
      IR_DEF_LIVE_POS_FROM_REF(ref),
498
      IR_SAVE_LIVE_POS_FROM_REF(ref));
499
#endif
500
  }
501
}
502
503
static void ir_add_fusion_ranges(ir_ctx *ctx, ir_ref ref, ir_ref input, ir_block *bb, ir_bitset live)
504
{
505
  ir_ref stack[4];
506
  int stack_pos = 0;
507
  ir_target_constraints constraints;
508
  ir_insn *insn;
509
  uint32_t j, n, flags, def_flags;
510
  ir_ref *p, child;
511
  uint8_t use_flags;
512
  ir_reg reg;
513
  ir_live_pos use_pos;
514
  ir_live_interval *ival;
515
516
  while (1) {
517
    IR_ASSERT(input > 0 && ctx->rules[input] & IR_FUSED);
518
519
    if (!(ctx->rules[input] & IR_SIMPLE)) {
520
      def_flags = ir_get_target_constraints(ctx, input, &constraints);
521
      n = constraints.tmps_count;
522
      while (n > 0) {
523
        n--;
524
        if (constraints.tmp_regs[n].type) {
525
          ir_add_tmp(ctx, ref, input, constraints.tmp_regs[n].num, constraints.tmp_regs[n]);
526
        } else {
527
          /* CPU specific constraints */
528
          ir_add_fixed_live_range(ctx, constraints.tmp_regs[n].reg,
529
            IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].start,
530
            IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].end);
531
        }
532
      }
533
    } else {
534
      def_flags = IR_OP1_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG;
535
      constraints.hints_count = 0;
536
    }
537
538
    insn = &ctx->ir_base[input];
539
    flags = ir_op_flags[insn->op];
540
    n = IR_INPUT_EDGES_COUNT(flags);
541
    j = 1;
542
    p = insn->ops + j;
543
    if (flags & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_PINNED)) {
544
      j++;
545
      p++;
546
    }
547
    for (; j <= n; j++, p++) {
548
      IR_ASSERT(IR_OPND_KIND(flags, j) == IR_OPND_DATA);
549
      child = *p;
550
      if (child > 0) {
551
        int32_t v = ctx->vregs[child];
552
553
        if (v > 0) {
554
          use_flags = IR_FUSED_USE | IR_USE_FLAGS(def_flags, j);
555
          reg = (j < constraints.hints_count) ? constraints.hints[j] : IR_REG_NONE;
556
          use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
557
          if (EXPECTED(reg == IR_REG_NONE)) {
558
            use_pos += IR_USE_SUB_REF;
559
          }
560
561
          if (!ir_bitset_in(live, v)) {
562
            /* live.add(opd) */
563
            ir_bitset_incl(live, v);
564
            /* intervals[opd].addRange(b.from, op.id) */
565
            ival = ir_add_live_range(ctx, v,
566
              IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
567
          } else if (reg != IR_REG_NONE && (IR_USE_FLAGS(def_flags, j) & IR_HINT_NEEDS_HOLE)) {
568
            ir_fix_live_range(ctx, v,
569
              IR_START_LIVE_POS_FROM_REF(bb->start), use_pos + IR_DEF_SUB_REF);
570
            ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
571
          } else {
572
            ival = ctx->live_intervals[v];
573
          }
574
          ir_add_use(ctx, ival, j, use_pos, reg, use_flags, -input);
575
        } else if (ctx->rules[child] & IR_FUSED) {
576
          IR_ASSERT(stack_pos < (int)(sizeof(stack)/sizeof(stack_pos)));
577
          stack[stack_pos++] = child;
578
        } else if (ctx->rules[child] == (IR_SKIPPED|IR_RLOAD)) {
579
          ir_set_alocated_reg(ctx, input, j, ctx->ir_base[child].op2);
580
        }
581
      }
582
    }
583
    if (!stack_pos) {
584
      break;
585
    }
586
    input = stack[--stack_pos];
587
  }
588
}
589
590
int ir_compute_live_ranges(ir_ctx *ctx)
591
{
592
  uint32_t b, i, j, k, n, succ, *p;
593
  ir_ref ref;
594
  uint32_t len;
595
  ir_insn *insn;
596
  ir_block *bb, *succ_bb;
597
#ifdef IR_DEBUG
598
  ir_bitset visited;
599
#endif
600
  ir_bitset live, bb_live;
601
  ir_bitset loops = NULL;
602
  ir_bitqueue queue;
603
  ir_live_interval *ival;
604
605
  if (!(ctx->flags2 & IR_LINEAR) || !ctx->vregs) {
606
    return 0;
607
  }
608
609
  if (ctx->rules) {
610
    ctx->regs = ir_mem_malloc(sizeof(ir_regs) * ctx->insns_count);
611
    memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count);
612
  }
613
614
  /* Root of the list of IR_VARs */
615
  ctx->vars = IR_UNUSED;
616
617
  /* Compute Live Ranges */
618
  ctx->flags2 &= ~IR_LR_HAVE_DESSA_MOVES;
619
  len = ir_bitset_len(ctx->vregs_count + 1);
620
  bb_live = ir_mem_malloc((ctx->cfg_blocks_count + 1) * len * sizeof(ir_bitset_base_t));
621
622
  /* vregs + tmp + fixed + ALL + SCRATCH_N */
623
  ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*));
624
625
#ifdef IR_DEBUG
626
  visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
627
#endif
628
629
    if (!ctx->arena) {
630
    ctx->arena = ir_arena_create(16 * 1024);
631
  }
632
633
  /* for each basic block in reverse order */
634
  for (b = ctx->cfg_blocks_count; b > 0; b--) {
635
    bb = &ctx->cfg_blocks[b];
636
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
637
    /* for each successor of b */
638
639
#ifdef IR_DEBUG
640
    ir_bitset_incl(visited, b);
641
#endif
642
    live = bb_live + (len * b);
643
    n = bb->successors_count;
644
    if (n == 0) {
645
      ir_bitset_clear(live, len);
646
    } else {
647
      p = &ctx->cfg_edges[bb->successors];
648
      succ = *p;
649
650
#ifdef IR_DEBUG
651
      /* blocks must be ordered where all dominators of a block are before this block */
652
      IR_ASSERT(ir_bitset_in(visited, succ) || bb->loop_header == succ);
653
#endif
654
655
      /* live = union of successors.liveIn */
656
      if (EXPECTED(succ > b) && EXPECTED(!(ctx->cfg_blocks[succ].flags & IR_BB_ENTRY))) {
657
        ir_bitset_copy(live, bb_live + (len * succ), len);
658
      } else {
659
        IR_ASSERT(succ > b || (ctx->cfg_blocks[succ].flags & IR_BB_LOOP_HEADER));
660
        ir_bitset_clear(live, len);
661
      }
662
      if (n > 1) {
663
        for (p++, n--; n > 0; p++, n--) {
664
          succ = *p;
665
          if (EXPECTED(succ > b) && EXPECTED(!(ctx->cfg_blocks[succ].flags & IR_BB_ENTRY))) {
666
            ir_bitset_union(live, bb_live + (len * succ), len);
667
          } else {
668
            IR_ASSERT(succ > b || (ctx->cfg_blocks[succ].flags & IR_BB_LOOP_HEADER));
669
          }
670
        }
671
      }
672
673
      /* for each opd in live */
674
      IR_BITSET_FOREACH(live, len, i) {
675
        /* intervals[opd].addRange(b.from, b.to) */
676
        ir_add_prev_live_range(ctx, i,
677
          IR_START_LIVE_POS_FROM_REF(bb->start),
678
          IR_END_LIVE_POS_FROM_REF(bb->end));
679
      } IR_BITSET_FOREACH_END();
680
    }
681
682
    if (bb->successors_count == 1) {
683
      /* for each phi function phi of successor */
684
      succ = ctx->cfg_edges[bb->successors];
685
      succ_bb = &ctx->cfg_blocks[succ];
686
      if (succ_bb->flags & IR_BB_HAS_PHI) {
687
        ir_use_list *use_list = &ctx->use_lists[succ_bb->start];
688
689
        k = ir_phi_input_number(ctx, succ_bb, b);
690
        IR_ASSERT(k != 0);
691
        for (ref = 0; ref < use_list->count; ref++) {
692
          ir_ref use = ctx->use_edges[use_list->refs + ref];
693
          insn = &ctx->ir_base[use];
694
          if (insn->op == IR_PHI) {
695
            ir_ref input = ir_insn_op(insn, k);
696
            if (input > 0) {
697
              int32_t v = ctx->vregs[input];
698
699
              if (v > 0) {
700
                /* live.add(phi.inputOf(b)) */
701
                ir_bitset_incl(live, v);
702
                /* intervals[phi.inputOf(b)].addRange(b.from, b.to) */
703
                ival = ir_add_prev_live_range(ctx, v,
704
                  IR_START_LIVE_POS_FROM_REF(bb->start),
705
                  IR_END_LIVE_POS_FROM_REF(bb->end));
706
                ir_add_phi_use(ctx, ival, k, IR_DEF_LIVE_POS_FROM_REF(bb->end), use);
707
              }
708
            }
709
          }
710
        }
711
      }
712
    }
713
714
    /* for each operation op of b in reverse order */
715
    ref = bb->end;
716
    insn = &ctx->ir_base[ref];
717
    if (insn->op == IR_END || insn->op == IR_LOOP_END) {
718
      ref = ctx->prev_ref[ref];
719
    }
720
    for (; ref > bb->start; ref = ctx->prev_ref[ref]) {
721
      uint32_t def_flags;
722
      uint32_t flags;
723
      ir_ref *p;
724
      ir_target_constraints constraints;
725
      int32_t v;
726
727
      if (ctx->rules) {
728
        int n;
729
730
#if IR_X86_I64
731
        if (ctx->rules[ref] & IR_TWO_REGS) {
732
          v = ctx->vregs[ref];
733
          if (v > 0) {
734
            IR_ASSERT(ctx->live_intervals[v]);
735
            ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_TWO_REGS;
736
          }
737
        }
738
#endif
739
740
        if (ctx->rules[ref] & (IR_FUSED|IR_SKIPPED)) {
741
          if (((ctx->rules[ref] & IR_RULE_MASK) == IR_ALLOCA)
742
           && ctx->use_lists[ref].count > 0) {
743
            insn = &ctx->ir_base[ref];
744
            if (insn->op == IR_VAR || insn->op == IR_ALLOCA) {
745
              ctx->vregs[ref] = IR_STACK_SLOT_TO_VREG(ctx->vars);
746
              ctx->vars = ref;
747
            }
748
          }
749
          continue;
750
        }
751
752
        def_flags = ir_get_target_constraints(ctx, ref, &constraints);
753
        n = constraints.tmps_count;
754
        while (n > 0) {
755
          n--;
756
          if (constraints.tmp_regs[n].type) {
757
            ir_add_tmp(ctx, ref, ref, constraints.tmp_regs[n].num, constraints.tmp_regs[n]);
758
          } else {
759
            /* CPU specific constraints */
760
            ir_add_fixed_live_range(ctx, constraints.tmp_regs[n].reg,
761
              IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].start,
762
              IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].end);
763
          }
764
        }
765
      } else {
766
        def_flags = 0;
767
        constraints.def_reg = IR_REG_NONE;
768
        constraints.hints_count = 0;
769
      }
770
771
      insn = &ctx->ir_base[ref];
772
      v = ctx->vregs[ref];
773
      if (v > 0) {
774
        if (insn->op != IR_PHI) {
775
          ir_live_pos def_pos;
776
          ir_ref hint_ref = 0;
777
          ir_reg reg = constraints.def_reg;
778
779
          if (reg != IR_REG_NONE) {
780
            def_pos = IR_SAVE_LIVE_POS_FROM_REF(ref);
781
            if (insn->op == IR_PARAM || insn->op == IR_RLOAD) {
782
              /* parameter register must be kept before it's copied */
783
#if IR_X86_I64
784
              if (def_flags & IR_HINT_TWO_REGS) {
785
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
786
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
787
              } else
788
#endif
789
              ir_add_fixed_live_range(ctx, reg, IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
790
            }
791
          } else if (def_flags & IR_DEF_REUSES_OP1_REG) {
792
            if (!IR_IS_CONST_REF(insn->op1) && ctx->vregs[insn->op1] > 0) {
793
              hint_ref = insn->op1;
794
            }
795
            def_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
796
          } else if (def_flags & IR_DEF_CONFLICTS_WITH_INPUT_REGS) {
797
            def_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
798
          } else {
799
            if (insn->op == IR_PARAM) {
800
              /* We may reuse parameter stack slot for spilling */
801
              ir_live_interval *param_ival = ctx->live_intervals[v];
802
803
              param_ival->flags |= IR_LIVE_INTERVAL_MEM_PARAM;
804
              if (ctx->rules && ctx->use_lists[ref].count > 0) {
805
                ir_ref use = ctx->use_edges[ctx->use_lists[ref].refs];
806
                if (use < bb->end) {
807
                  ir_insn *use_insn = &ctx->ir_base[use];
808
                  if (use_insn->op == IR_VSTORE
809
                   && !(ctx->rules[use] & IR_SKIPPED)
810
                   /* first use of VAR is VSTORE(_, VAR, PARAM) */
811
                   && ctx->use_edges[ctx->use_lists[use_insn->op2].refs] == use) {
812
                    IR_ASSERT(use_insn->op3 == ref);
813
                    /* skip VSTORE (VAR is going to be remapped to PARAM) */
814
                    param_ival->flags |= IR_LIVE_INTERVAL_VAR_MEM_PARAM;
815
                    param_ival->use_pos = param_ival->use_pos->next;
816
                    ctx->rules[use] = IR_SKIPPED | IR_NOP;
817
                  }
818
                }
819
              }
820
            }
821
            def_pos = IR_DEF_LIVE_POS_FROM_REF(ref);
822
          }
823
          /* live.remove(opd) */
824
          ir_bitset_excl(live, v);
825
          /* intervals[opd].setFrom(op.id) */
826
          ival = ir_fix_live_range(ctx, v,
827
            IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
828
          ival->type = insn->type;
829
          ir_add_use(ctx, ival, 0, def_pos, reg, def_flags, hint_ref);
830
        } else {
831
          /* live.remove(opd) */
832
          ir_bitset_excl(live, v);
833
          /* PHIs inputs must not be processed */
834
          ival = ctx->live_intervals[v];
835
          if (UNEXPECTED(!ival)) {
836
            /* Dead PHI */
837
            ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
838
          }
839
          ival->type = insn->type;
840
          ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
841
          continue;
842
        }
843
      } else if (def_flags & IR_EXTEND_INPUTS_TO_NEXT) {
844
        ir_ref next = ir_next_control(ctx, ref);
845
        ir_live_pos use_pos;
846
847
        IR_ASSERT(insn->op == IR_SNAPSHOT);
848
        j = 2;
849
        p = insn->ops + 2;
850
        for (; j <= insn->inputs_count; j++, p++) {
851
          ir_ref input = *p;
852
          int32_t v;
853
854
          if (input > 0) {
855
            v = ctx->vregs[input];
856
            IR_ASSERT(v > 0);
857
            use_pos = IR_USE_LIVE_POS_FROM_REF(next);
858
            if (!ir_bitset_in(live, v)) {
859
              /* live.add(opd) */
860
              ir_bitset_incl(live, v);
861
              /* intervals[opd].addRange(b.from, op.id) */
862
              ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
863
            } else {
864
              ival = ctx->live_intervals[v];
865
            }
866
            use_pos = IR_USE_LIVE_POS_FROM_REF(ref);
867
            ir_add_use(ctx, ival, j, use_pos, IR_REG_NONE, 0, IR_UNUSED);
868
          }
869
        }
870
        continue;
871
      }
872
873
      IR_ASSERT(insn->op != IR_PHI && (!ctx->rules || !(ctx->rules[ref] & (IR_FUSED|IR_SKIPPED))));
874
      flags = ir_op_flags[insn->op];
875
      j = 1;
876
      p = insn->ops + 1;
877
      if (flags & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_PINNED)) {
878
        j++;
879
        p++;
880
      }
881
      for (; j <= insn->inputs_count; j++, p++) {
882
        ir_ref input = *p;
883
        ir_reg reg = (j < constraints.hints_count) ? constraints.hints[j] : IR_REG_NONE;
884
        ir_live_pos use_pos;
885
        ir_ref hint_ref = 0;
886
        int32_t v;
887
        uint32_t use_flags = IR_USE_FLAGS(def_flags, j);
888
889
        if (input > 0) {
890
          v = ctx->vregs[input];
891
          if (v > 0) {
892
            use_pos = IR_USE_LIVE_POS_FROM_REF(ref);
893
            if (reg != IR_REG_NONE) {
894
              use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
895
#if IR_X86_I64
896
              if (use_flags & IR_HINT_TWO_REGS) {
897
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
898
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
899
              } else
900
#endif
901
              ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
902
              if ((use_flags & IR_HINT_NEEDS_HOLE) && ir_bitset_in(live, v)) {
903
                /* This is a special case for x86 SHIFT instructions that uses %rcx for op2.
904
                 * SHIFT adds short fixed live range for %rcx and this makes a conflict with
905
                 * operand live interval, if the operand is still alive after the SHIFT.
906
                 * To avoid the conflict we create a "fake" hole in the operand live interval.
907
                 * See: ./tests/debug/ra_004.irt
908
                 */
909
                ir_fix_live_range(ctx, v,
910
                  IR_START_LIVE_POS_FROM_REF(bb->start), use_pos + IR_DEF_SUB_REF);
911
                ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
912
              }
913
            } else if (def_flags & IR_DEF_REUSES_OP1_REG) {
914
              if (j == 1) {
915
                use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
916
                IR_ASSERT(ctx->vregs[ref] > 0);
917
                hint_ref = ref;
918
              } else if (input == insn->op1) {
919
                /* Input is the same as "op1" */
920
                use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
921
              }
922
            }
923
            if (!ir_bitset_in(live, v)) {
924
              /* live.add(opd) */
925
              ir_bitset_incl(live, v);
926
              /* intervals[opd].addRange(b.from, op.id) */
927
              ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
928
            } else {
929
              ival = ctx->live_intervals[v];
930
            }
931
            ir_add_use(ctx, ival, j, use_pos, reg, use_flags, hint_ref);
932
          } else {
933
            if (ctx->rules) {
934
              if ((ctx->rules[input] & (IR_FUSED|IR_SKIPPED)) == IR_FUSED) {
935
                ir_add_fusion_ranges(ctx, ref, input, bb, live);
936
              } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) {
937
                ir_set_alocated_reg(ctx, ref, j, ctx->ir_base[input].op2);
938
              }
939
            }
940
            if (reg != IR_REG_NONE) {
941
              use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
942
#if IR_X86_I64
943
              if (use_flags & IR_HINT_TWO_REGS) {
944
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
945
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
946
              } else
947
#endif
948
              ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
949
            }
950
          }
951
        } else if (reg != IR_REG_NONE) {
952
          use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
953
#if IR_X86_I64
954
          if (use_flags & IR_HINT_TWO_REGS) {
955
            ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
956
            ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
957
          } else
958
#endif
959
          ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
960
        }
961
      }
962
    }
963
964
    /* if b is loop header */
965
    if ((bb->flags & IR_BB_LOOP_HEADER)
966
     && !ir_bitset_empty(live, len)) {
967
      /* variables live at loop header are alive at the whole loop body */
968
      uint32_t bb_set_len = ir_bitset_len(ctx->cfg_blocks_count + 1);
969
      uint32_t child;
970
      ir_block *child_bb;
971
      ir_bitset child_live_in;
972
973
      if (!loops) {
974
        loops = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
975
        ir_bitqueue_init(&queue, ctx->cfg_blocks_count + 1);
976
      } else {
977
        ir_bitset_clear(loops, bb_set_len);
978
        ir_bitqueue_clear(&queue);
979
      }
980
      ir_bitset_incl(loops, b);
981
      child = b;
982
      do {
983
        child_bb = &ctx->cfg_blocks[child];
984
        child_live_in = bb_live + (len * child);
985
986
        IR_BITSET_FOREACH(live, len, i) {
987
          ir_bitset_incl(child_live_in, i);
988
          ir_add_live_range(ctx, i,
989
            IR_START_LIVE_POS_FROM_REF(child_bb->start),
990
            IR_END_LIVE_POS_FROM_REF(child_bb->end));
991
        } IR_BITSET_FOREACH_END();
992
993
        child = child_bb->dom_child;
994
        while (child) {
995
          child_bb = &ctx->cfg_blocks[child];
996
          if (child_bb->loop_header && ir_bitset_in(loops, child_bb->loop_header)) {
997
            ir_bitqueue_add(&queue, child);
998
            if (child_bb->flags & IR_BB_LOOP_HEADER) {
999
              ir_bitset_incl(loops, child);
1000
            }
1001
          }
1002
          child = child_bb->dom_next_child;
1003
        }
1004
      } while ((child = ir_bitqueue_pop(&queue)) != (uint32_t)-1);
1005
    }
1006
  }
1007
1008
  if (ctx->entries) {
1009
    for (i = 0; i < ctx->entries_count; i++) {
1010
      b = ctx->entries[i];
1011
      bb = &ctx->cfg_blocks[b];
1012
      live = bb_live + (len * b);
1013
      ir_add_osr_entry_loads(ctx, bb, live, len, b);
1014
    }
1015
    if (ctx->osr_entry_loads) {
1016
      ir_list_push((ir_list*)ctx->osr_entry_loads, 0);
1017
    }
1018
  }
1019
1020
  if (loops) {
1021
    ir_mem_free(loops);
1022
    ir_bitqueue_free(&queue);
1023
  }
1024
1025
  ir_mem_free(bb_live);
1026
#ifdef IR_DEBUG
1027
  ir_mem_free(visited);
1028
#endif
1029
1030
  return 1;
1031
}
1032
1033
#else
1034
/* Path exploration by definition liveness for SSA using sets represented by linked lists */
1035
1036
#define IS_LIVE_IN_BLOCK(v, b) \
1037
278k
  (live_in_block[v] == b)
1038
354k
#define SET_LIVE_IN_BLOCK(v, b) do { \
1039
354k
    live_in_block[v] = b; \
1040
354k
  } while (0)
1041
1042
/* Returns the last virtual register alive at the end of the block (it is used as an already-visited marker) */
1043
IR_ALWAYS_INLINE int32_t ir_live_out_top(ir_ctx *ctx, int32_t *live_outs, ir_list *live_lists, uint32_t b)
1044
462k
{
1045
#if 0
1046
  return live_outs[b];
1047
#else
1048
462k
  if (!live_outs[b]) {
1049
215k
    return -1;
1050
215k
  }
1051
247k
  return ir_list_at(live_lists, live_outs[b]);
1052
462k
#endif
1053
462k
}
1054
1055
/* Remember a virtual register alive at the end of the block */
1056
IR_ALWAYS_INLINE void ir_live_out_push(ir_ctx *ctx, int32_t *live_outs, ir_list *live_lists, uint32_t b, int32_t v)
1057
191k
{
1058
#if 0
1059
  ir_block *bb = &ctx->cfg_blocks[b];
1060
  live_outs[b] = v;
1061
  ir_add_prev_live_range(ctx, v,
1062
    IR_START_LIVE_POS_FROM_REF(bb->start),
1063
    IR_END_LIVE_POS_FROM_REF(bb->end));
1064
#else
1065
191k
  if (live_lists->len >= live_lists->a.size) {
1066
0
    ir_array_grow(&live_lists->a, live_lists->a.size + 1024);
1067
0
  }
1068
  /* Form a linked list of virtual register live at the end of the block */
1069
191k
  ir_list_push_unchecked(live_lists, live_outs[b]); /* push old root of the list (previous element of the list) */
1070
191k
  live_outs[b] = ir_list_len(live_lists);           /* remember the new root */
1071
191k
  ir_list_push_unchecked(live_lists, v);            /* push a virtual register */
1072
191k
#endif
1073
191k
}
1074
1075
/*
1076
 * Computes live-out sets for each basic-block per variable using def-use chains.
1077
 *
1078
 * The implementation is based on algorithms 6 and 7 desriebed in
1079
 * "Computing Liveness Sets for SSA-Form Programs", Florian Brandner, Benoit Boissinot.
1080
 * Alain Darte, Benoit Dupont de Dinechin, Fabrice Rastello. TR Inria RR-7503, 2011
1081
 */
1082
static void ir_compute_live_sets(ir_ctx *ctx, int32_t *live_outs, ir_list *live_lists)
1083
9.93k
{
1084
9.93k
  ir_list block_queue, fuse_queue;
1085
9.93k
  ir_ref i;
1086
1087
9.93k
  ir_list_init(&fuse_queue, 16);
1088
9.93k
  ir_list_init(&block_queue, 256);
1089
1090
  /* For each virtual register explore paths from all uses to definition */
1091
1.80M
  for (i = ctx->insns_count - 1; i > 0; i--) {
1092
1.79M
    int32_t v = ctx->vregs[i];
1093
1094
1.79M
    if (v > 0) {
1095
185k
      uint32_t def_block = ctx->cfg_map[i];
1096
185k
      ir_use_list *use_list = &ctx->use_lists[i];
1097
185k
      ir_ref *p, n = use_list->count;
1098
1099
      /* Collect all blocks where 'v' is used into a 'block_queue' */
1100
627k
      for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1101
441k
        ir_ref use = *p;
1102
441k
        ir_insn *insn = &ctx->ir_base[use];
1103
1104
441k
        if (UNEXPECTED(insn->op == IR_PHI)) {
1105
46.9k
          ir_ref n = insn->inputs_count - 1;
1106
46.9k
          ir_ref *p = insn->ops + 2; /* PHI data inputs */
1107
46.9k
          ir_ref *q = ctx->ir_base[insn->op1].ops + 1; /* MERGE inputs */
1108
1109
145k
          for (;n > 0; p++, q++, n--) {
1110
98.7k
            if (*p == i) {
1111
46.9k
              uint32_t pred_block = ctx->cfg_map[*q];
1112
1113
46.9k
              if (ir_live_out_top(ctx, live_outs, live_lists, pred_block) != v) {
1114
46.9k
                ir_live_out_push(ctx, live_outs, live_lists, pred_block, v);
1115
46.9k
                if (pred_block != def_block) {
1116
23.0k
                  ir_list_push(&block_queue, pred_block);
1117
23.0k
                }
1118
46.9k
              }
1119
46.9k
            }
1120
98.7k
          }
1121
394k
        } else if (ctx->rules && UNEXPECTED(ctx->rules[use] & IR_FUSED)) {
1122
152k
          while (1) {
1123
152k
            ir_use_list *use_list = &ctx->use_lists[use];
1124
152k
            ir_ref *p, n = use_list->count;
1125
1126
351k
            for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1127
198k
              ir_ref use = *p;
1128
1129
198k
              if (ctx->rules[use] & IR_FUSED) {
1130
60.0k
                ir_list_push(&fuse_queue, use);
1131
138k
              } else {
1132
138k
                uint32_t use_block = ctx->cfg_map[use];
1133
1134
138k
                if (def_block != use_block && ir_live_out_top(ctx, live_outs, live_lists, use_block) != v) {
1135
62.5k
                  ir_list_push(&block_queue, use_block);
1136
62.5k
                }
1137
138k
              }
1138
198k
            }
1139
152k
            if (!ir_list_len(&fuse_queue)) {
1140
92.9k
              break;
1141
92.9k
            }
1142
60.0k
            use = ir_list_pop(&fuse_queue);
1143
60.0k
          }
1144
301k
        } else {
1145
301k
          uint32_t use_block = ctx->cfg_map[use];
1146
1147
          /* Check if the virtual register is alive at the start of 'use_block' */
1148
301k
          if (def_block != use_block && ir_live_out_top(ctx, live_outs, live_lists, use_block) != v) {
1149
66.3k
            ir_list_push(&block_queue, use_block);
1150
66.3k
          }
1151
301k
        }
1152
441k
      }
1153
1154
      /* UP_AND_MARK: Traverse through predecessor blocks until we reach the block where 'v' is defined*/
1155
420k
      while (ir_list_len(&block_queue)) {
1156
235k
        uint32_t b = ir_list_pop(&block_queue);
1157
235k
        ir_block *bb = &ctx->cfg_blocks[b];
1158
235k
        uint32_t *p, n = bb->predecessors_count;
1159
1160
235k
        if (bb->flags & IR_BB_ENTRY) {
1161
          /* live_in_push(ENTRY, v) */
1162
0
          ir_insn *insn = &ctx->ir_base[bb->start];
1163
1164
0
          IR_ASSERT(insn->op == IR_ENTRY);
1165
0
          IR_ASSERT(insn->op3 >= 0 && insn->op3 < (ir_ref)ctx->entries_count);
1166
0
          if (live_lists->len >= live_lists->a.size) {
1167
0
            ir_array_grow(&live_lists->a, live_lists->a.size + 1024);
1168
0
          }
1169
0
          ir_list_push_unchecked(live_lists, live_outs[ctx->cfg_blocks_count + 1 + insn->op3]);
1170
0
          ir_list_push_unchecked(live_lists, v);
1171
0
          live_outs[ctx->cfg_blocks_count + 1 + insn->op3] = ir_list_len(live_lists) - 1;
1172
0
          continue;
1173
0
        }
1174
521k
        for (p = &ctx->cfg_edges[bb->predecessors]; n > 0; p++, n--) {
1175
286k
          uint32_t pred_block = *p;
1176
1177
          /* Check if 'pred_block' wasn't traversed before */
1178
286k
          if (ir_live_out_top(ctx, live_outs, live_lists, pred_block) != v) {
1179
            /* Mark a virtual register 'v' alive at the end of 'pred_block' */
1180
144k
            ir_live_out_push(ctx, live_outs, live_lists, pred_block, v);
1181
144k
            if (pred_block != def_block) {
1182
83.1k
              ir_list_push(&block_queue, pred_block);
1183
83.1k
            }
1184
144k
          }
1185
286k
        }
1186
235k
      }
1187
185k
    }
1188
1.79M
  }
1189
1190
9.93k
  ir_list_free(&block_queue);
1191
9.93k
  ir_list_free(&fuse_queue);
1192
9.93k
}
1193
1194
static void ir_add_osr_entry_loads(ir_ctx *ctx, ir_block *bb, uint32_t pos, ir_list *live_lists, uint32_t b)
1195
3.16k
{
1196
3.16k
  bool ok = 1;
1197
3.16k
  int count = 0;
1198
3.16k
  ir_list *list = (ir_list*)ctx->osr_entry_loads;
1199
3.16k
  ir_ref i;
1200
1201
3.16k
  while (pos) {
1202
0
    i = ir_list_at(live_lists, pos);
1203
0
    pos = ir_list_at(live_lists, pos - 1);
1204
1205
    /* Skip live references from ENTRY to PARAM. TODO: duplicate PARAM in each ENTRY ??? */
1206
0
    ir_use_pos *use_pos = ctx->live_intervals[i]->use_pos;
1207
0
    ir_ref ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos);
1208
1209
0
    if (use_pos->op_num) {
1210
0
      ir_ref *ops = ctx->ir_base[ref].ops;
1211
0
      ref = ops[use_pos->op_num];
1212
0
    }
1213
1214
0
    if (ctx->ir_base[ref].op == IR_PARAM) {
1215
0
      continue;
1216
0
    }
1217
0
    if (ctx->binding) {
1218
0
      ir_ref var = ir_binding_find(ctx, ref);
1219
0
      if (var < 0) {
1220
        /* We may load the value at OSR entry-point */
1221
0
        if (!count) {
1222
0
          bb->flags &= ~IR_BB_EMPTY;
1223
0
          bb->flags |= IR_BB_OSR_ENTRY_LOADS;
1224
0
          if (!ctx->osr_entry_loads) {
1225
0
            list = ctx->osr_entry_loads = ir_mem_malloc(sizeof(ir_list));
1226
0
            ir_list_init(list, 16);
1227
0
          }
1228
0
          ir_list_push(list, b);
1229
0
          ir_list_push(list, 0);
1230
0
        }
1231
0
        ir_list_push(list, ref);
1232
0
        count++;
1233
0
        continue;
1234
0
      }
1235
0
    }
1236
0
    fprintf(stderr, "ENTRY %d (block %d start %d) - live var %d\n", ctx->ir_base[bb->start].op2, b, bb->start, ref);
1237
0
    ok = 0;
1238
0
  }
1239
1240
3.16k
  if (!ok) {
1241
0
    IR_ASSERT(0);
1242
0
  }
1243
3.16k
  if (count) {
1244
0
    ir_list_set(list, ir_list_len(ctx->osr_entry_loads) - (count + 1), count);
1245
1246
#if 0
1247
    /* ENTRY "clobbers" all registers */
1248
    ir_ref ref = ctx->ir_base[bb->start].op1;
1249
    ir_add_fixed_live_range(ctx, IR_REG_ALL,
1250
      IR_DEF_LIVE_POS_FROM_REF(ref),
1251
      IR_SAVE_LIVE_POS_FROM_REF(ref));
1252
#endif
1253
0
  }
1254
3.16k
}
1255
1256
static void ir_add_fusion_ranges(ir_ctx *ctx, ir_ref ref, ir_ref input, ir_block *bb, uint32_t *live_in_block, uint32_t b)
1257
312k
{
1258
312k
  ir_ref stack[4];
1259
312k
  int stack_pos = 0;
1260
312k
  ir_target_constraints constraints;
1261
312k
  ir_insn *insn;
1262
312k
  uint32_t j, n, flags, def_flags;
1263
312k
  ir_ref *p, child;
1264
312k
  uint8_t use_flags;
1265
312k
  ir_reg reg;
1266
312k
  ir_live_pos pos = IR_START_LIVE_POS_FROM_REF(ref);
1267
312k
  ir_live_pos use_pos;
1268
312k
  ir_live_interval *ival;
1269
1270
425k
  while (1) {
1271
425k
    IR_ASSERT(input > 0 && ctx->rules[input] & IR_FUSED);
1272
1273
425k
    if (!(ctx->rules[input] & IR_SIMPLE)) {
1274
164k
      def_flags = ir_get_target_constraints(ctx, input, &constraints);
1275
164k
      n = constraints.tmps_count;
1276
207k
      while (n > 0) {
1277
42.4k
        n--;
1278
42.4k
        if (constraints.tmp_regs[n].type) {
1279
42.4k
          ir_add_tmp(ctx, ref, input, constraints.tmp_regs[n].num, constraints.tmp_regs[n]);
1280
42.4k
        } else {
1281
          /* CPU specific constraints */
1282
0
          ir_add_fixed_live_range(ctx, constraints.tmp_regs[n].reg,
1283
0
            pos + constraints.tmp_regs[n].start,
1284
0
            pos + constraints.tmp_regs[n].end);
1285
0
        }
1286
42.4k
      }
1287
260k
    } else {
1288
260k
      def_flags = IR_OP1_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG;
1289
260k
      constraints.hints_count = 0;
1290
260k
    }
1291
1292
425k
    insn = &ctx->ir_base[input];
1293
425k
    flags = ir_op_flags[insn->op];
1294
425k
    IR_ASSERT(!IR_OP_HAS_VAR_INPUTS(flags));
1295
425k
    n = IR_INPUT_EDGES_COUNT(flags);
1296
425k
    j = 1;
1297
425k
    p = insn->ops + j;
1298
425k
    if (flags & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_PINNED)) {
1299
121k
      j++;
1300
121k
      p++;
1301
121k
    }
1302
1.15M
    for (; j <= n; j++, p++) {
1303
728k
      IR_ASSERT(IR_OPND_KIND(flags, j) == IR_OPND_DATA);
1304
728k
      child = *p;
1305
728k
      if (child > 0) {
1306
393k
        int32_t v = ctx->vregs[child];
1307
1308
393k
        if (v > 0) {
1309
89.1k
          reg = (j < constraints.hints_count) ? constraints.hints[j] : IR_REG_NONE;
1310
89.1k
          use_pos = pos;
1311
89.1k
          if (EXPECTED(reg == IR_REG_NONE)) {
1312
89.1k
            use_pos += IR_USE_SUB_REF;
1313
89.1k
          }
1314
1315
89.1k
          if (!IS_LIVE_IN_BLOCK(v, b)) {
1316
            /* live.add(opd) */
1317
30.7k
            SET_LIVE_IN_BLOCK(v, b);
1318
            /* intervals[opd].addRange(b.from, op.id) */
1319
30.7k
            ival = ir_add_live_range(ctx, v,
1320
30.7k
              IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
1321
58.3k
          } else if (reg != IR_REG_NONE && (IR_USE_FLAGS(def_flags, j) & IR_HINT_NEEDS_HOLE)) {
1322
0
            ir_fix_live_range(ctx, v,
1323
0
              IR_START_LIVE_POS_FROM_REF(bb->start), use_pos + IR_DEF_SUB_REF);
1324
0
            ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
1325
58.3k
          } else {
1326
58.3k
            ival = ctx->live_intervals[v];
1327
58.3k
          }
1328
89.1k
          use_flags = IR_FUSED_USE | IR_USE_FLAGS(def_flags, j);
1329
89.1k
          ir_add_use(ctx, ival, j, use_pos, reg, use_flags, -input);
1330
304k
        } else if (ctx->rules[child] & IR_FUSED) {
1331
112k
          IR_ASSERT(stack_pos < (int)(sizeof(stack)/sizeof(stack_pos)));
1332
112k
          stack[stack_pos++] = child;
1333
191k
        } else if (ctx->rules[child] == (IR_SKIPPED|IR_RLOAD)) {
1334
150k
          ir_set_alocated_reg(ctx, input, j, ctx->ir_base[child].op2);
1335
150k
        }
1336
393k
      }
1337
728k
    }
1338
425k
    if (!stack_pos) {
1339
312k
      break;
1340
312k
    }
1341
112k
    input = stack[--stack_pos];
1342
112k
  }
1343
312k
}
1344
1345
int ir_compute_live_ranges(ir_ctx *ctx)
1346
9.93k
{
1347
9.93k
  uint32_t b, i, j, k, n, succ;
1348
9.93k
  ir_ref ref;
1349
9.93k
  ir_insn *insn;
1350
9.93k
  ir_block *bb, *succ_bb;
1351
9.93k
  int32_t *live_outs;
1352
9.93k
  uint32_t *live_in_block;
1353
9.93k
  ir_list live_lists;
1354
9.93k
  ir_live_interval *ival;
1355
1356
9.93k
  if (!(ctx->flags2 & IR_LINEAR) || !ctx->vregs) {
1357
0
    return 0;
1358
0
  }
1359
1360
9.93k
  if (ctx->rules) {
1361
9.93k
    ctx->regs = ir_mem_malloc(sizeof(ir_regs) * ctx->insns_count);
1362
9.93k
    memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count);
1363
9.93k
  }
1364
1365
  /* Root of the list of IR_VARs */
1366
9.93k
  ctx->vars = IR_UNUSED;
1367
1368
  /* Compute Live Ranges */
1369
9.93k
  ctx->flags2 &= ~IR_LR_HAVE_DESSA_MOVES;
1370
1371
  /* vregs + tmp + fixed + ALL + SCRATCH_N */
1372
9.93k
  ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*));
1373
1374
9.93k
    if (!ctx->arena) {
1375
9.93k
    ctx->arena = ir_arena_create(16 * 1024);
1376
9.93k
  }
1377
1378
9.93k
  live_outs = ir_mem_calloc(ctx->cfg_blocks_count + 1 + ctx->entries_count, sizeof(uint32_t));
1379
9.93k
  ir_list_init(&live_lists, 1024);
1380
9.93k
  ir_compute_live_sets(ctx, live_outs, &live_lists);
1381
9.93k
  live_in_block = ir_mem_calloc(ctx->vregs_count + 1, sizeof(uint32_t));
1382
1383
  /* for each basic block in reverse order */
1384
326k
  for (b = ctx->cfg_blocks_count; b > 0; b--) {
1385
316k
    bb = &ctx->cfg_blocks[b];
1386
316k
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
1387
1388
    /* For all virtual register alive at the end of the block */
1389
316k
    n = live_outs[b];
1390
508k
    while (n != 0) {
1391
191k
      i = ir_list_at(&live_lists, n);
1392
191k
      SET_LIVE_IN_BLOCK(i, b);
1393
191k
      ir_add_prev_live_range(ctx, i,
1394
191k
        IR_START_LIVE_POS_FROM_REF(bb->start),
1395
191k
        IR_END_LIVE_POS_FROM_REF(bb->end));
1396
191k
      n = ir_list_at(&live_lists, n - 1);
1397
191k
    }
1398
1399
316k
    if (bb->successors_count == 1) {
1400
      /* for each phi function of the successor */
1401
188k
      succ = ctx->cfg_edges[bb->successors];
1402
188k
      succ_bb = &ctx->cfg_blocks[succ];
1403
188k
      if (succ_bb->flags & IR_BB_HAS_PHI) {
1404
42.3k
        ir_use_list *use_list = &ctx->use_lists[succ_bb->start];
1405
42.3k
        ir_ref n, *p;
1406
1407
42.3k
        k = ir_phi_input_number(ctx, succ_bb, b);
1408
42.3k
        IR_ASSERT(k != 0);
1409
42.3k
        n = use_list->count;
1410
135k
        for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
1411
93.0k
          ir_ref use = *p;
1412
93.0k
          insn = &ctx->ir_base[use];
1413
93.0k
          if (insn->op == IR_PHI) {
1414
50.7k
            ir_ref input = ir_insn_op(insn, k);
1415
50.7k
            if (input > 0) {
1416
46.9k
              int32_t v = ctx->vregs[input];
1417
1418
46.9k
              if (v > 0) {
1419
46.9k
                ival = ctx->live_intervals[v];
1420
46.9k
                ir_add_phi_use(ctx, ival, k, IR_DEF_LIVE_POS_FROM_REF(bb->end), use);
1421
46.9k
              }
1422
46.9k
            }
1423
50.7k
          }
1424
93.0k
        }
1425
42.3k
      }
1426
188k
    }
1427
1428
    /* for each operation of the block in reverse order */
1429
316k
    ref = bb->end;
1430
316k
    insn = &ctx->ir_base[ref];
1431
316k
    if (insn->op == IR_END || insn->op == IR_LOOP_END) {
1432
185k
      ref = ctx->prev_ref[ref];
1433
185k
    }
1434
1.56M
    for (; ref > bb->start; ref = ctx->prev_ref[ref]) {
1435
1.24M
      uint32_t def_flags;
1436
1.24M
      uint32_t flags;
1437
1.24M
      ir_ref *p;
1438
1.24M
      ir_target_constraints constraints;
1439
1.24M
      int32_t v;
1440
1441
1.24M
      if (ctx->rules) {
1442
1.24M
        int n;
1443
1444
#if IR_X86_I64
1445
        if (ctx->rules[ref] & IR_TWO_REGS) {
1446
          v = ctx->vregs[ref];
1447
          if (v > 0) {
1448
            IR_ASSERT(ctx->live_intervals[v]);
1449
            ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_TWO_REGS;
1450
          }
1451
        }
1452
#endif
1453
1454
1.24M
        if (ctx->rules[ref] & (IR_FUSED|IR_SKIPPED)) {
1455
634k
          if (((ctx->rules[ref] & IR_RULE_MASK) == IR_ALLOCA)
1456
0
           && ctx->use_lists[ref].count > 0) {
1457
0
            insn = &ctx->ir_base[ref];
1458
0
            if (insn->op == IR_VAR || insn->op == IR_ALLOCA) {
1459
0
              ctx->vregs[ref] = IR_STACK_SLOT_TO_VREG(ctx->vars);
1460
0
              ctx->vars = ref;
1461
0
            }
1462
0
          }
1463
634k
          continue;
1464
634k
        }
1465
1466
613k
        def_flags = ir_get_target_constraints(ctx, ref, &constraints);
1467
613k
        n = constraints.tmps_count;
1468
746k
        while (n > 0) {
1469
132k
          n--;
1470
132k
          if (constraints.tmp_regs[n].type) {
1471
49.7k
            ir_add_tmp(ctx, ref, ref, constraints.tmp_regs[n].num, constraints.tmp_regs[n]);
1472
83.2k
          } else {
1473
            /* CPU specific constraints */
1474
83.2k
            ir_add_fixed_live_range(ctx, constraints.tmp_regs[n].reg,
1475
83.2k
              IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].start,
1476
83.2k
              IR_START_LIVE_POS_FROM_REF(ref) + constraints.tmp_regs[n].end);
1477
83.2k
          }
1478
132k
        }
1479
613k
      } else {
1480
0
        def_flags = 0;
1481
0
        constraints.def_reg = IR_REG_NONE;
1482
0
        constraints.hints_count = 0;
1483
0
      }
1484
1485
613k
      insn = &ctx->ir_base[ref];
1486
613k
      v = ctx->vregs[ref];
1487
613k
      if (v > 0) {
1488
185k
        if (insn->op != IR_PHI) {
1489
161k
          ir_live_pos def_pos;
1490
161k
          ir_ref hint_ref = 0;
1491
161k
          ir_reg reg = constraints.def_reg;
1492
1493
161k
          if (reg != IR_REG_NONE) {
1494
31.0k
            def_pos = IR_SAVE_LIVE_POS_FROM_REF(ref);
1495
31.0k
            if (insn->op == IR_PARAM || insn->op == IR_RLOAD) {
1496
              /* parameter register must be kept before it's copied */
1497
#if IR_X86_I64
1498
              if (def_flags & IR_HINT_TWO_REGS) {
1499
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
1500
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
1501
              } else
1502
#endif
1503
48
              ir_add_fixed_live_range(ctx, reg, IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
1504
48
            }
1505
130k
          } else if (def_flags & IR_DEF_REUSES_OP1_REG) {
1506
35.6k
            if (!IR_IS_CONST_REF(insn->op1) && ctx->vregs[insn->op1] > 0) {
1507
31.1k
              hint_ref = insn->op1;
1508
31.1k
            }
1509
35.6k
            if (def_flags & IR_DEF_CONFLICTS_WITH_INPUT_REGS) {
1510
133
              def_pos = IR_USE_LIVE_POS_FROM_REF(ref);
1511
35.5k
            } else {
1512
35.5k
              def_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1513
35.5k
            }
1514
94.5k
          } else if (def_flags & IR_DEF_CONFLICTS_WITH_INPUT_REGS) {
1515
0
            def_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1516
94.5k
          } else {
1517
94.5k
            if (insn->op == IR_PARAM) {
1518
              /* We may reuse parameter stack slot for spilling */
1519
0
              ir_live_interval *param_ival = ctx->live_intervals[v];
1520
1521
0
              param_ival->flags |= IR_LIVE_INTERVAL_MEM_PARAM;
1522
0
              if (ctx->rules && ctx->use_lists[ref].count > 0) {
1523
0
                ir_ref use = ctx->use_edges[ctx->use_lists[ref].refs];
1524
0
                if (use < bb->end) {
1525
0
                  ir_insn *use_insn = &ctx->ir_base[use];
1526
0
                  if (use_insn->op == IR_VSTORE
1527
0
                   && !(ctx->rules[use] & IR_SKIPPED)
1528
                   /* first use of VAR is VSTORE(_, VAR, PARAM) */
1529
0
                   && ctx->use_edges[ctx->use_lists[use_insn->op2].refs] == use) {
1530
0
                    IR_ASSERT(use_insn->op3 == ref);
1531
                    /* skip VSTORE (VAR is going to be remapped to PARAM) */
1532
0
                    param_ival->flags |= IR_LIVE_INTERVAL_VAR_MEM_PARAM;
1533
0
                    param_ival->use_pos = param_ival->use_pos->next;
1534
0
                    ctx->rules[use] = IR_SKIPPED | IR_NOP;
1535
0
                  }
1536
0
                }
1537
0
              }
1538
0
            }
1539
94.5k
            def_pos = IR_DEF_LIVE_POS_FROM_REF(ref);
1540
94.5k
          }
1541
          /* intervals[opd].setFrom(op.id) */
1542
161k
          ival = ir_fix_live_range(ctx, v,
1543
161k
            IR_START_LIVE_POS_FROM_REF(bb->start), def_pos);
1544
161k
          ival->type = insn->type;
1545
161k
          ir_add_use(ctx, ival, 0, def_pos, reg, def_flags, hint_ref);
1546
161k
        } else {
1547
          /* PHIs inputs must not be processed */
1548
24.6k
          ival = ctx->live_intervals[v];
1549
24.6k
          if (UNEXPECTED(!ival)) {
1550
            /* Dead PHI */
1551
0
            ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
1552
0
          }
1553
24.6k
          ival->type = insn->type;
1554
24.6k
          ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
1555
24.6k
          continue;
1556
24.6k
        }
1557
428k
      } else if (def_flags & IR_EXTEND_INPUTS_TO_NEXT) {
1558
188
        ir_ref next = ir_next_control(ctx, ref);
1559
188
        ir_live_pos use_pos;
1560
1561
188
        IR_ASSERT(insn->op == IR_SNAPSHOT);
1562
188
        j = 2;
1563
188
        p = insn->ops + 2;
1564
783
        for (; j <= insn->inputs_count; j++, p++) {
1565
595
          ir_ref input = *p;
1566
595
          int32_t v;
1567
1568
595
          if (input > 0) {
1569
179
            v = ctx->vregs[input];
1570
179
            IR_ASSERT(v > 0);
1571
179
            use_pos = IR_USE_LIVE_POS_FROM_REF(next);
1572
179
            if (!IS_LIVE_IN_BLOCK(v, b)) {
1573
              /* live.add(opd) */
1574
94
              SET_LIVE_IN_BLOCK(v, b);
1575
              /* intervals[opd].addRange(b.from, op.id) */
1576
94
              ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
1577
94
            } else {
1578
85
              ival = ctx->live_intervals[v];
1579
85
            }
1580
179
            use_pos = IR_USE_LIVE_POS_FROM_REF(ref);
1581
179
            ir_add_use(ctx, ival, j, use_pos, IR_REG_NONE, 0, IR_UNUSED);
1582
179
          }
1583
595
        }
1584
188
        continue;
1585
188
      }
1586
1587
589k
      IR_ASSERT(insn->op != IR_PHI && (!ctx->rules || !(ctx->rules[ref] & (IR_FUSED|IR_SKIPPED))));
1588
589k
      flags = ir_op_flags[insn->op];
1589
589k
      j = 1;
1590
589k
      p = insn->ops + 1;
1591
589k
      if (flags & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_PINNED)) {
1592
526k
        j++;
1593
526k
        p++;
1594
526k
      }
1595
1.54M
      for (; j <= insn->inputs_count; j++, p++) {
1596
951k
        ir_ref input = *p;
1597
951k
        ir_reg reg = (j < constraints.hints_count) ? constraints.hints[j] : IR_REG_NONE;
1598
951k
        ir_live_pos use_pos;
1599
951k
        ir_ref hint_ref = 0;
1600
951k
        int32_t v;
1601
951k
        uint32_t use_flags = IR_USE_FLAGS(def_flags, j);
1602
1603
951k
        if (input > 0) {
1604
658k
          v = ctx->vregs[input];
1605
658k
          if (v > 0) {
1606
189k
            use_pos = IR_USE_LIVE_POS_FROM_REF(ref);
1607
189k
            if (reg != IR_REG_NONE) {
1608
45.8k
              use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1609
#if IR_X86_I64
1610
              if (use_flags & IR_HINT_TWO_REGS) {
1611
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
1612
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
1613
              } else
1614
#endif
1615
45.8k
              ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
1616
45.8k
              if ((use_flags & IR_HINT_NEEDS_HOLE) && IS_LIVE_IN_BLOCK(v, b)) {
1617
                /* This is a special case for x86 SHIFT instructions that uses %rcx for op2.
1618
                 * SHIFT adds short fixed live range for %rcx and this makes a conflict with
1619
                 * operand live interval, if the operand is still alive after the SHIFT.
1620
                 * To avoid the conflict we create a "fake" hole in the operand live interval.
1621
                 * See: ./tests/debug/ra_004.irt
1622
                 */
1623
0
                ir_fix_live_range(ctx, v,
1624
0
                  IR_START_LIVE_POS_FROM_REF(bb->start), use_pos + IR_DEF_SUB_REF);
1625
0
                ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
1626
0
              }
1627
143k
            } else if (def_flags & IR_DEF_REUSES_OP1_REG) {
1628
34.9k
              if (j == 1) {
1629
31.1k
                if (def_flags & IR_DEF_CONFLICTS_WITH_INPUT_REGS) {
1630
80
                  use_pos = IR_USE_LIVE_POS_FROM_REF(ref);
1631
31.1k
                } else {
1632
31.1k
                  use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1633
31.1k
                }
1634
31.1k
                IR_ASSERT(ctx->vregs[ref] > 0);
1635
31.1k
                hint_ref = ref;
1636
31.1k
              } else if (input == insn->op1) {
1637
                /* Input is the same as "op1" */
1638
1
                use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1639
1
              }
1640
34.9k
            }
1641
189k
            if (!IS_LIVE_IN_BLOCK(v, b)) {
1642
              /* live.add(opd) */
1643
131k
              SET_LIVE_IN_BLOCK(v, b);
1644
              /* intervals[opd].addRange(b.from, op.id) */
1645
131k
              ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), use_pos);
1646
131k
            } else {
1647
57.5k
              ival = ctx->live_intervals[v];
1648
57.5k
            }
1649
189k
            ir_add_use(ctx, ival, j, use_pos, reg, use_flags, hint_ref);
1650
469k
          } else {
1651
469k
            if (ctx->rules) {
1652
469k
              if ((ctx->rules[input] & (IR_FUSED|IR_SKIPPED)) == IR_FUSED) {
1653
312k
                ir_add_fusion_ranges(ctx, ref, input, bb, live_in_block, b);
1654
312k
              } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) {
1655
156k
                ir_set_alocated_reg(ctx, ref, j, ctx->ir_base[input].op2);
1656
156k
              }
1657
469k
            }
1658
469k
            if (reg != IR_REG_NONE) {
1659
48.4k
              use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1660
#if IR_X86_I64
1661
              if (use_flags & IR_HINT_TWO_REGS) {
1662
                ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
1663
                ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
1664
              } else
1665
#endif
1666
48.4k
              ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
1667
48.4k
            }
1668
469k
          }
1669
658k
        } else if (reg != IR_REG_NONE) {
1670
29.0k
          use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref);
1671
#if IR_X86_I64
1672
          if (use_flags & IR_HINT_TWO_REGS) {
1673
            ir_add_fixed_live_range(ctx, IR_REG_I64_LO(reg), use_pos, use_pos + IR_USE_SUB_REF);
1674
            ir_add_fixed_live_range(ctx, IR_REG_I64_HI(reg), use_pos, use_pos + IR_USE_SUB_REF);
1675
          } else
1676
#endif
1677
29.0k
          ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF);
1678
29.0k
        }
1679
951k
      }
1680
589k
    }
1681
316k
  }
1682
1683
9.93k
  if (ctx->entries) {
1684
6.19k
    for (i = 0; i < ctx->entries_count; i++) {
1685
3.16k
      b = ctx->entries[i];
1686
3.16k
      bb = &ctx->cfg_blocks[b];
1687
3.16k
      IR_ASSERT(bb->predecessors_count == 1);
1688
3.16k
      ir_add_osr_entry_loads(ctx, bb, live_outs[ctx->cfg_blocks_count + 1 + i], &live_lists, b);
1689
3.16k
    }
1690
3.03k
    if (ctx->osr_entry_loads) {
1691
0
      ir_list_push((ir_list*)ctx->osr_entry_loads, 0);
1692
0
    }
1693
3.03k
  }
1694
1695
9.93k
  ir_list_free(&live_lists);
1696
9.93k
  ir_mem_free(live_outs);
1697
9.93k
  ir_mem_free(live_in_block);
1698
1699
9.93k
  return 1;
1700
9.93k
}
1701
1702
#endif
1703
1704
/* Live Ranges coalescing */
1705
1706
static ir_live_pos ir_ivals_overlap(ir_live_range *lrg1, ir_live_range *lrg2)
1707
112k
{
1708
326k
  while (1) {
1709
326k
    if (lrg2->start < lrg1->end) {
1710
106k
      if (lrg1->start < lrg2->end) {
1711
24.4k
        return IR_MAX(lrg1->start, lrg2->start);
1712
82.4k
      } else {
1713
82.4k
        lrg2 = lrg2->next;
1714
82.4k
        if (!lrg2) {
1715
11.1k
          return 0;
1716
11.1k
        }
1717
82.4k
      }
1718
219k
    } else {
1719
219k
      lrg1 = lrg1->next;
1720
219k
      if (!lrg1) {
1721
77.4k
        return 0;
1722
77.4k
      }
1723
219k
    }
1724
326k
  }
1725
112k
}
1726
1727
static ir_live_pos ir_vregs_overlap(ir_ctx *ctx, int32_t r1, int32_t r2)
1728
48.8k
{
1729
48.8k
  ir_live_interval *ival1 = ctx->live_intervals[r1];
1730
48.8k
  ir_live_interval *ival2 = ctx->live_intervals[r2];
1731
1732
#if 0
1733
  if (ival2->range.start >= ival1->end
1734
   || ival1->range.start >= ival2->end) {
1735
    return 0;
1736
  }
1737
#endif
1738
48.8k
  return ir_ivals_overlap(&ival1->range, &ival2->range);
1739
48.8k
}
1740
1741
static bool ir_ivals_inside(ir_live_range *parent, ir_live_range *child)
1742
318
{
1743
330
  do {
1744
339
    while (parent && parent->end < child->start) {
1745
9
      parent = parent->next;
1746
9
    }
1747
330
    if (!parent || parent->start > child->start || parent->end < child->end) {
1748
315
      return 0;
1749
315
    }
1750
15
    child = child->next;
1751
15
  } while (child);
1752
3
  return 1;
1753
318
}
1754
1755
static bool ir_vregs_inside(ir_ctx *ctx, int32_t parent, int32_t child)
1756
318
{
1757
318
  ir_live_interval *child_ival = ctx->live_intervals[child];
1758
318
  ir_live_interval *parent_ival = ctx->live_intervals[parent];
1759
1760
318
  if ((child_ival->flags | parent_ival->flags) & IR_LIVE_INTERVAL_COALESCED) {
1761
    // TODO: Support valid cases with already coalesced "parent_ival
1762
0
    return 0;
1763
0
  }
1764
#if 0
1765
  if (child_ival->end >= parent_ival->end) {
1766
    return 0;
1767
  }
1768
#endif
1769
318
  return ir_ivals_inside(&parent_ival->range, &child_ival->range);
1770
318
}
1771
1772
static void ir_vregs_join(ir_ctx *ctx, int32_t r1, int32_t r2)
1773
45.0k
{
1774
45.0k
  ir_live_interval *ival = ctx->live_intervals[r2];
1775
45.0k
  ir_live_range *live_range = &ival->range;
1776
45.0k
  ir_live_range *next;
1777
45.0k
  ir_use_pos *use_pos, *next_pos, **prev;
1778
1779
#if 0
1780
  fprintf(stderr, "COALESCE %d -> %d\n", r2, r1);
1781
#endif
1782
1783
45.0k
  ir_add_live_range(ctx, r1, live_range->start, live_range->end);
1784
45.0k
  live_range = live_range->next;
1785
61.3k
  while (live_range) {
1786
16.2k
    next = live_range->next;
1787
16.2k
    live_range->next = ctx->unused_ranges;
1788
16.2k
    ctx->unused_ranges = live_range;
1789
16.2k
    ir_add_live_range(ctx, r1, live_range->start, live_range->end);
1790
16.2k
    live_range = next;
1791
16.2k
  }
1792
1793
  /* merge sorted use_pos lists */
1794
45.0k
  prev = &ctx->live_intervals[r1]->use_pos;
1795
45.0k
  use_pos = ival->use_pos;
1796
171k
  while (use_pos) {
1797
126k
    if (use_pos->hint_ref > 0 && ctx->vregs[use_pos->hint_ref] == r1) {
1798
3.34k
      use_pos->hint_ref = 0;
1799
3.34k
    }
1800
259k
    while (*prev && ((*prev)->pos < use_pos->pos ||
1801
50.4k
      ((*prev)->pos == use_pos->pos &&
1802
133k
        (use_pos->op_num == 0 || ((*prev)->op_num != 0 && (*prev)->op_num < use_pos->op_num))))) {
1803
133k
      if ((*prev)->hint_ref > 0 && ctx->vregs[(*prev)->hint_ref] == r2) {
1804
3.34k
        (*prev)->hint_ref = 0;
1805
3.34k
      }
1806
133k
      prev = &(*prev)->next;
1807
133k
    }
1808
126k
    next_pos = use_pos->next;
1809
126k
    use_pos->next = *prev;
1810
126k
    *prev = use_pos;
1811
126k
    prev = &use_pos->next;
1812
126k
      use_pos = next_pos;
1813
126k
  }
1814
45.0k
  use_pos = *prev;
1815
136k
  while (use_pos) {
1816
91.2k
    if (use_pos->hint_ref > 0 && ctx->vregs[use_pos->hint_ref] == r2) {
1817
0
      use_pos->hint_ref = 0;
1818
0
    }
1819
91.2k
    use_pos = use_pos->next;
1820
91.2k
  }
1821
1822
45.0k
  ctx->live_intervals[r1]->flags |=
1823
45.0k
    IR_LIVE_INTERVAL_COALESCED | (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS));
1824
45.0k
  if (ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) {
1825
0
    IR_ASSERT(!(ctx->live_intervals[r1]->flags & IR_LIVE_INTERVAL_MEM_PARAM));
1826
0
    ctx->live_intervals[r1]->flags |= IR_LIVE_INTERVAL_MEM_PARAM;
1827
0
  }
1828
45.0k
  ctx->live_intervals[r2] = NULL;
1829
1830
  // TODO: remember to reuse ???
1831
  //ir_mem_free(ival);
1832
45.0k
}
1833
1834
static void ir_vregs_coalesce(ir_ctx *ctx, int32_t v1, int32_t v2, ir_ref from, ir_ref to)
1835
45.0k
{
1836
45.0k
  ir_ref i;
1837
45.0k
  uint16_t f1 = ctx->live_intervals[v1]->flags;
1838
45.0k
  uint16_t f2 = ctx->live_intervals[v2]->flags;
1839
1840
#if 0
1841
  if (ctx->binding) {
1842
    ir_ref b1 = ir_binding_find(ctx, from);
1843
    ir_ref b2 = ir_binding_find(ctx, to);
1844
    IR_ASSERT(b1 == b2);
1845
  }
1846
#endif
1847
45.0k
  if ((f1 & IR_LIVE_INTERVAL_COALESCED) && !(f2 & IR_LIVE_INTERVAL_COALESCED)) {
1848
5
    ir_vregs_join(ctx, v1, v2);
1849
5
    ctx->vregs[to] = v1;
1850
45.0k
  } else if ((f2 & IR_LIVE_INTERVAL_COALESCED) && !(f1 & IR_LIVE_INTERVAL_COALESCED)) {
1851
21.9k
    ir_vregs_join(ctx, v2, v1);
1852
21.9k
    ctx->vregs[from] = v2;
1853
23.1k
  } else if (from < to) {
1854
23.1k
    ir_vregs_join(ctx, v1, v2);
1855
23.1k
    if (f2 & IR_LIVE_INTERVAL_COALESCED) {
1856
0
      for (i = 1; i < ctx->insns_count; i++) {
1857
0
        if (ctx->vregs[i] == v2) {
1858
0
          ctx->vregs[i] = v1;
1859
0
        }
1860
0
      }
1861
23.1k
    } else {
1862
23.1k
      ctx->vregs[to] = v1;
1863
23.1k
    }
1864
23.1k
  } else {
1865
0
    ir_vregs_join(ctx, v2, v1);
1866
0
    if (f1 & IR_LIVE_INTERVAL_COALESCED) {
1867
0
      for (i = 1; i < ctx->insns_count; i++) {
1868
0
        if (ctx->vregs[i] == v1) {
1869
0
          ctx->vregs[i] = v2;
1870
0
        }
1871
0
      }
1872
0
    } else {
1873
0
      ctx->vregs[from] = v2;
1874
0
    }
1875
0
  }
1876
45.0k
}
1877
1878
static void ir_add_phi_move(ir_ctx *ctx, uint32_t b, ir_type type, ir_ref from, ir_ref to)
1879
3.79k
{
1880
3.79k
  if (IR_IS_CONST_REF(from) || ctx->vregs[from] != ctx->vregs[to]) {
1881
3.79k
    ctx->cfg_blocks[b].flags &= ~IR_BB_EMPTY;
1882
3.79k
    ctx->cfg_blocks[b].flags |= IR_BB_DESSA_MOVES;
1883
3.79k
    if (IR_IS_TYPE_INT(type)) {
1884
3.79k
      ctx->cfg_blocks[b].flags |= IR_BB_DESSA_TMP_INT;
1885
3.79k
    } else {
1886
0
      ctx->cfg_blocks[b].flags |= IR_BB_DESSA_TMP_FP;
1887
0
    }
1888
3.79k
    ctx->flags2 |= IR_LR_HAVE_DESSA_MOVES;
1889
#if 0
1890
    fprintf(stderr, "BB%d: MOV %d -> %d\n", b, from, to);
1891
#endif
1892
3.79k
  }
1893
3.79k
}
1894
1895
typedef struct _ir_coalesce_block {
1896
  uint32_t b;
1897
  uint32_t loop_depth;
1898
} ir_coalesce_block;
1899
1900
static int ir_block_cmp(const void *b1, const void *b2)
1901
72.8k
{
1902
72.8k
  ir_coalesce_block *d1 = (ir_coalesce_block*)b1;
1903
72.8k
  ir_coalesce_block *d2 = (ir_coalesce_block*)b2;
1904
1905
72.8k
  if (d1->loop_depth > d2->loop_depth) {
1906
3.26k
    return -1;
1907
69.6k
  } else if (d1->loop_depth == d2->loop_depth) {
1908
63.2k
    if (d1->b < d2->b) {
1909
47.7k
      return -1;
1910
47.7k
    } else {
1911
15.4k
      return 1;
1912
15.4k
    }
1913
63.2k
  } else {
1914
6.39k
    return 1;
1915
6.39k
  }
1916
72.8k
}
1917
1918
static void ir_swap_operands(ir_ctx *ctx, ir_ref i, ir_insn *insn)
1919
0
{
1920
0
  ir_live_pos pos = IR_USE_LIVE_POS_FROM_REF(i);
1921
0
  ir_live_pos load_pos = IR_LOAD_LIVE_POS_FROM_REF(i);
1922
0
  ir_live_interval *ival;
1923
0
  ir_live_range *r;
1924
0
  ir_use_pos *p, *p1 = NULL, *p2 = NULL;
1925
0
  ir_ref tmp;
1926
1927
0
  tmp = insn->op1;
1928
0
  insn->op1 = insn->op2;
1929
0
  insn->op2 = tmp;
1930
1931
0
  ival = ctx->live_intervals[ctx->vregs[insn->op1]];
1932
0
  p = ival->use_pos;
1933
0
  while (p) {
1934
0
    if (p->pos == pos) {
1935
0
      p->pos = load_pos;
1936
0
      p->op_num = 1;
1937
0
      p1 = p;
1938
0
      break;
1939
0
    }
1940
0
    p = p->next;
1941
0
  }
1942
1943
0
  ival = ctx->live_intervals[ctx->vregs[i]];
1944
0
  p = ival->use_pos;
1945
0
  while (p) {
1946
0
    if (p->pos == load_pos) {
1947
0
      p->hint_ref = insn->op1;
1948
0
      break;
1949
0
    }
1950
0
    p = p->next;
1951
0
  }
1952
1953
0
  if (insn->op2 > 0 && ctx->vregs[insn->op2] > 0) {
1954
0
    ival = ctx->live_intervals[ctx->vregs[insn->op2]];
1955
0
    r = &ival->range;
1956
0
    while (r) {
1957
0
      if (r->end == load_pos) {
1958
0
        r->end = pos;
1959
0
        if (!r->next) {
1960
0
          ival->end = pos;
1961
0
        }
1962
0
        break;
1963
0
      }
1964
0
      r = r->next;
1965
0
    }
1966
0
    p = ival->use_pos;
1967
0
    while (p) {
1968
0
      if (p->pos == load_pos) {
1969
0
        p->pos = pos;
1970
0
        p->op_num = 2;
1971
0
        p2 = p;
1972
0
        break;
1973
0
      }
1974
0
      p = p->next;
1975
0
    }
1976
0
  }
1977
0
  if (p1 && p2) {
1978
0
    uint8_t tmp = p1->flags;
1979
0
    p1->flags = p2->flags;
1980
0
    p2->flags = tmp;
1981
0
  }
1982
0
}
1983
1984
static int ir_hint_conflict(ir_ctx *ctx, ir_ref ref, int use, int def)
1985
3.72k
{
1986
3.72k
  ir_use_pos *p;
1987
3.72k
  ir_reg r1 = IR_REG_NONE;
1988
3.72k
  ir_reg r2 = IR_REG_NONE;
1989
1990
3.72k
  p = ctx->live_intervals[use]->use_pos;
1991
10.4k
  while (p) {
1992
10.4k
    if (IR_LIVE_POS_TO_REF(p->pos) == ref) {
1993
3.72k
      break;
1994
3.72k
    }
1995
6.75k
    if (p->hint != IR_REG_NONE) {
1996
0
      r1 = p->hint;
1997
0
    }
1998
6.75k
    p = p->next;
1999
6.75k
  }
2000
2001
3.72k
  p = ctx->live_intervals[def]->use_pos;
2002
11.4k
  while (p) {
2003
7.94k
    if (IR_LIVE_POS_TO_REF(p->pos) > ref) {
2004
4.22k
      if (p->hint != IR_REG_NONE) {
2005
235
        r2 = p->hint;
2006
235
        break;
2007
235
      }
2008
4.22k
    }
2009
7.71k
    p = p->next;
2010
7.71k
  }
2011
3.72k
  return r1 != r2 && r1 != IR_REG_NONE && r2 != IR_REG_NONE;
2012
3.72k
}
2013
2014
static int ir_try_swap_operands(ir_ctx *ctx, ir_ref i, ir_insn *insn)
2015
3.73k
{
2016
3.73k
  if (ctx->vregs[insn->op1] > 0
2017
3.72k
   && ctx->vregs[insn->op1] != ctx->vregs[i]
2018
3.72k
   && !ir_vregs_overlap(ctx, ctx->vregs[insn->op1], ctx->vregs[i])
2019
3.72k
   && !ir_hint_conflict(ctx, i, ctx->vregs[insn->op1], ctx->vregs[i])) {
2020
    /* pass */
2021
3.72k
  } else {
2022
10
    if (ctx->vregs[insn->op2] > 0 && ctx->vregs[insn->op2] != ctx->vregs[i]) {
2023
0
      ir_live_pos pos = IR_USE_LIVE_POS_FROM_REF(i);
2024
0
      ir_live_pos load_pos = IR_LOAD_LIVE_POS_FROM_REF(i);
2025
0
      ir_live_interval *ival = ctx->live_intervals[ctx->vregs[insn->op2]];
2026
0
      ir_live_range *r = &ival->range;
2027
2028
0
      if ((ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) && ctx->use_lists[insn->op2].count == 1) {
2029
0
        return 0;
2030
0
      }
2031
0
      while (r) {
2032
0
        if (r->end == pos) {
2033
0
          r->end = load_pos;
2034
0
          if (!r->next) {
2035
0
            ival->end = load_pos;
2036
0
          }
2037
0
          if (!ir_vregs_overlap(ctx, ctx->vregs[insn->op2], ctx->vregs[i])
2038
0
           && !ir_hint_conflict(ctx, i, ctx->vregs[insn->op2], ctx->vregs[i])) {
2039
0
            ir_swap_operands(ctx, i, insn);
2040
0
            return 1;
2041
0
          } else {
2042
0
            r->end = pos;
2043
0
            if (!r->next) {
2044
0
              ival->end = pos;
2045
0
            }
2046
0
          }
2047
0
          break;
2048
0
        }
2049
0
        r = r->next;
2050
0
      }
2051
0
    }
2052
10
  }
2053
3.73k
  return 0;
2054
3.73k
}
2055
2056
int ir_coalesce(ir_ctx *ctx)
2057
9.93k
{
2058
9.93k
  uint32_t b, n, succ, pred_b, count = 0;
2059
9.93k
  ir_ref *p, use, input, k, j;
2060
9.93k
  ir_block *bb, *succ_bb;
2061
9.93k
  ir_use_list *use_list;
2062
9.93k
  ir_insn *insn;
2063
9.93k
  ir_bitset visited;
2064
9.93k
  ir_coalesce_block *list;
2065
9.93k
  bool compact = 0;
2066
2067
  /* Collect a list of blocks which are predecossors to block with phi functions */
2068
9.93k
  list = ir_mem_malloc(sizeof(ir_coalesce_block) * ctx->cfg_blocks_count);
2069
9.93k
  visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
2070
326k
  for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
2071
316k
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
2072
316k
    if (bb->flags & IR_BB_HAS_PHI) {
2073
20.6k
      k = bb->predecessors_count;
2074
20.6k
      if (k > 1) {
2075
20.6k
        use_list = &ctx->use_lists[bb->start];
2076
20.6k
        n = use_list->count;
2077
20.6k
        IR_ASSERT(k == ctx->ir_base[bb->start].inputs_count);
2078
20.6k
        for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2079
20.6k
          use = *p;
2080
20.6k
          insn = &ctx->ir_base[use];
2081
20.6k
          if (insn->op == IR_PHI) {
2082
42.3k
            do {
2083
42.3k
              k--;
2084
42.3k
              pred_b = ctx->cfg_edges[bb->predecessors + k];
2085
42.3k
              if (!ir_bitset_in(visited, pred_b)) {
2086
42.3k
                ir_bitset_incl(visited, pred_b);
2087
42.3k
                list[count].b = pred_b;
2088
42.3k
                list[count].loop_depth = ctx->cfg_blocks[pred_b].loop_depth;
2089
42.3k
                count++;
2090
42.3k
              }
2091
42.3k
            } while (k > 0);
2092
20.6k
            break;
2093
20.6k
          }
2094
20.6k
        }
2095
20.6k
      }
2096
20.6k
    }
2097
316k
  }
2098
9.93k
  ir_mem_free(visited);
2099
2100
  /* Sort blocks according to their loop depth */
2101
9.93k
  qsort(list, count, sizeof(ir_coalesce_block), ir_block_cmp);
2102
2103
52.2k
  while (count > 0) {
2104
2105
42.3k
    count--;
2106
42.3k
    b = list[count].b;
2107
42.3k
    bb = &ctx->cfg_blocks[b];
2108
42.3k
    IR_ASSERT(bb->successors_count == 1);
2109
42.3k
    succ = ctx->cfg_edges[bb->successors];
2110
42.3k
    succ_bb = &ctx->cfg_blocks[succ];
2111
42.3k
    IR_ASSERT(succ_bb->predecessors_count > 1);
2112
42.3k
    k = ir_phi_input_number(ctx, succ_bb, b);
2113
42.3k
    use_list = &ctx->use_lists[succ_bb->start];
2114
42.3k
    n = use_list->count;
2115
135k
    for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2116
93.0k
      use = *p;
2117
93.0k
      insn = &ctx->ir_base[use];
2118
93.0k
      if (insn->op == IR_PHI) {
2119
50.7k
        input = ir_insn_op(insn, k);
2120
50.7k
        if (input > 0 && ctx->vregs[input] > 0) {
2121
46.9k
          uint32_t v1 = ctx->vregs[input];
2122
46.9k
          uint32_t v2 = ctx->vregs[use];
2123
2124
46.9k
          if (v1 == v2) {
2125
            /* already coalesced */
2126
45.0k
          } else {
2127
45.0k
            if (!ir_vregs_overlap(ctx, v1, v2)) {
2128
45.0k
              ir_vregs_coalesce(ctx, v1, v2, input, use);
2129
45.0k
              compact = 1;
2130
45.0k
            } else {
2131
5
#if 1
2132
5
              if (ctx->rules && (ctx->rules[input] & IR_MAY_SWAP)) {
2133
0
                ir_insn *input_insn = &ctx->ir_base[input];
2134
2135
0
                IR_ASSERT(ir_op_flags[input_insn->op] & IR_OP_FLAG_COMMUTATIVE);
2136
0
                if (input_insn->op2 == use
2137
0
                 && input_insn->op1 != use
2138
0
                 && (ctx->live_intervals[v1]->use_pos->flags & IR_DEF_REUSES_OP1_REG)) {
2139
0
                  ir_live_range *r = &ctx->live_intervals[v2]->range;
2140
2141
0
                  do {
2142
0
                    if (r->end == IR_USE_LIVE_POS_FROM_REF(input)) {
2143
0
                      break;
2144
0
                    }
2145
0
                    r = r->next;
2146
0
                  } while (r);
2147
0
                  if (r) {
2148
0
                    r->end = IR_LOAD_LIVE_POS_FROM_REF(input);
2149
0
                    if (!r->next) {
2150
0
                      ctx->live_intervals[v2]->end = IR_LOAD_LIVE_POS_FROM_REF(input);
2151
0
                    }
2152
0
                    if (ir_vregs_overlap(ctx, v1, v2)) {
2153
0
                      r->end = IR_USE_LIVE_POS_FROM_REF(input);
2154
0
                      if (!r->next) {
2155
0
                        ctx->live_intervals[v2]->end = IR_USE_LIVE_POS_FROM_REF(input);
2156
0
                      }
2157
0
                    } else {
2158
0
                      ir_swap_operands(ctx, input, input_insn);
2159
0
                      IR_ASSERT(!ir_vregs_overlap(ctx, v1, v2));
2160
0
                      ir_vregs_coalesce(ctx, v1, v2, input, use);
2161
0
                      compact = 1;
2162
0
                      continue;
2163
0
                    }
2164
0
                  }
2165
0
                }
2166
0
              }
2167
5
#endif
2168
5
              ir_add_phi_move(ctx, b, insn->type, input, use);
2169
5
            }
2170
45.0k
          }
2171
46.9k
        } else {
2172
          /* Move for constant input */
2173
3.79k
          ir_add_phi_move(ctx, b, insn->type, input, use);
2174
3.79k
        }
2175
50.7k
      }
2176
93.0k
    }
2177
42.3k
  }
2178
9.93k
  ir_mem_free(list);
2179
2180
9.93k
  ir_hint_propagation(ctx);
2181
2182
9.93k
  if (ctx->rules) {
2183
    /* try to swap operands of commutative instructions for better register allocation */
2184
9.93k
    uint32_t *rule = ctx->rules + 1;
2185
9.93k
    ir_ref i;
2186
2187
1.80M
    for (i = 1; i < ctx->insns_count; rule++, i++) {
2188
1.79M
      if ((*rule) & (IR_MAY_SWAP|IR_MAY_REUSE)) {
2189
11.2k
        insn = &ctx->ir_base[i];
2190
11.2k
        IR_ASSERT(ctx->vregs[i] > 0);
2191
11.2k
        if ((*rule) & IR_MAY_SWAP) {
2192
7.21k
          IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_COMMUTATIVE);
2193
7.21k
          if (ctx->live_intervals[ctx->vregs[i]]->use_pos
2194
7.21k
           && (ctx->live_intervals[ctx->vregs[i]]->use_pos->flags & IR_DEF_REUSES_OP1_REG)
2195
7.21k
           && insn->op2 > 0
2196
3.74k
           && insn->op1 > 0
2197
3.73k
           && insn->op1 != insn->op2) {
2198
3.73k
            ir_try_swap_operands(ctx, i, insn);
2199
3.73k
          }
2200
7.21k
        } else {
2201
3.99k
          IR_ASSERT((*rule) & IR_MAY_REUSE);
2202
3.99k
          if (insn->op1 > 0
2203
3.62k
           && ctx->vregs[insn->op1] > 0
2204
318
           && ctx->vregs[i] != ctx->vregs[insn->op1]) {
2205
318
            if (ir_vregs_inside(ctx, ctx->vregs[insn->op1], ctx->vregs[i])) {
2206
3
              if (ctx->binding) {
2207
3
                ir_ref b1 = ir_binding_find(ctx, i);
2208
3
                ir_ref b2 = ir_binding_find(ctx, insn->op1);
2209
3
                if (b1 && b1 != b2) {
2210
3
                  continue;
2211
3
                }
2212
3
              }
2213
0
              ir_vregs_coalesce(ctx, ctx->vregs[i], ctx->vregs[insn->op1], i, insn->op1);
2214
0
              compact = 1;
2215
0
            }
2216
318
          }
2217
3.99k
        }
2218
11.2k
      }
2219
1.79M
    }
2220
9.93k
  }
2221
2222
9.93k
  if (compact) {
2223
5.69k
    ir_ref i, n;
2224
5.69k
    uint32_t *xlat = ir_mem_malloc((ctx->vregs_count + 1) * sizeof(uint32_t));
2225
2226
175k
    for (i = 1, n = 1; i <= ctx->vregs_count; i++) {
2227
170k
      if (ctx->live_intervals[i]) {
2228
125k
        xlat[i] = n;
2229
125k
        if (i != n) {
2230
104k
          ctx->live_intervals[n] = ctx->live_intervals[i];
2231
104k
          ctx->live_intervals[n]->vreg = n;
2232
104k
        }
2233
125k
        n++;
2234
125k
      }
2235
170k
    }
2236
5.69k
    n--;
2237
5.69k
    if (n != ctx->vregs_count) {
2238
5.69k
      j = ctx->vregs_count - n;
2239
      /* vregs + tmp + fixed + ALL + SCRATCH_N */
2240
210k
      for (i = n + 1; i <= n + IR_REG_SET_NUM; i++) {
2241
204k
        ctx->live_intervals[i] = ctx->live_intervals[i + j];
2242
204k
        if (ctx->live_intervals[i]) {
2243
19.8k
          ctx->live_intervals[i]->vreg = i;
2244
19.8k
        }
2245
204k
      }
2246
1.61M
      for (j = 1; j < ctx->insns_count; j++) {
2247
1.61M
        if (ctx->vregs[j] > 0) {
2248
170k
          ctx->vregs[j] = xlat[ctx->vregs[j]];
2249
170k
        }
2250
1.61M
      }
2251
5.69k
      ctx->vregs_count = n;
2252
5.69k
    }
2253
5.69k
    ir_mem_free(xlat);
2254
5.69k
  }
2255
2256
9.93k
  return 1;
2257
9.93k
}
2258
2259
/* SSA Deconstruction */
2260
2261
int ir_compute_dessa_moves(ir_ctx *ctx)
2262
0
{
2263
0
  uint32_t b, n;
2264
0
  ir_ref j, k, *p, use;
2265
0
  ir_block *bb;
2266
0
  ir_use_list *use_list;
2267
0
  ir_insn *insn;
2268
2269
0
  for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
2270
0
    IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
2271
0
    k = bb->predecessors_count;
2272
0
    if (k > 1) {
2273
0
      use_list = &ctx->use_lists[bb->start];
2274
0
      n = use_list->count;
2275
0
      if (n > 1) {
2276
0
        IR_ASSERT(k == ctx->ir_base[bb->start].inputs_count);
2277
0
        k++;
2278
0
        for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
2279
0
          use = *p;
2280
0
          insn = &ctx->ir_base[use];
2281
0
          if (insn->op == IR_PHI) {
2282
0
            if (ctx->use_lists[use].count == 0) {
2283
0
              ctx->rules[use] = IR_SKIPPED | IR_NOP;
2284
0
              ctx->vregs[use] = 0;
2285
0
              continue;
2286
0
            }
2287
0
            IR_ASSERT(ctx->vregs[use] > 0);
2288
0
            for (j = 2; j <= k; j++) {
2289
0
              ir_ref input = ir_insn_op(insn, j);
2290
2291
0
              if (IR_IS_CONST_REF(input) || ctx->vregs[input] != ctx->vregs[use]) {
2292
0
                int pred = ctx->cfg_edges[bb->predecessors + (j-2)];
2293
0
                ctx->cfg_blocks[pred].flags &= ~IR_BB_EMPTY;
2294
0
                ctx->cfg_blocks[pred].flags |= IR_BB_DESSA_MOVES;
2295
0
                if (IR_IS_TYPE_INT(insn->type)) {
2296
0
                  ctx->cfg_blocks[pred].flags |= IR_BB_DESSA_TMP_INT;
2297
0
                } else {
2298
0
                  ctx->cfg_blocks[pred].flags |= IR_BB_DESSA_TMP_FP;
2299
0
                }
2300
0
                ctx->flags2 |= IR_LR_HAVE_DESSA_MOVES;
2301
0
              }
2302
0
            }
2303
0
          }
2304
0
        }
2305
0
      }
2306
0
    }
2307
0
  }
2308
0
  return 1;
2309
0
}
2310
2311
/*
2312
 * Parallel copy sequentialization algorithm
2313
 *
2314
 * The implementation is based on algorithm 1 desriebed in
2315
 * "Revisiting Out-of-SSA Translation for Correctness, Code Quality and Efficiency",
2316
 * Benoit Boissinot, Alain Darte, Fabrice Rastello, Benoit Dupont de Dinechin, Christophe Guillon.
2317
 * 2009 International Symposium on Code Generation and Optimization, Seattle, WA, USA, 2009,
2318
 * pp. 114-125, doi: 10.1109/CGO.2009.19.
2319
 */
2320
int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy, void *data)
2321
0
{
2322
0
  uint32_t succ, k, n = 0;
2323
0
  ir_block *bb, *succ_bb;
2324
0
  ir_use_list *use_list;
2325
0
  ir_ref *loc, *pred, *src, *dst, i, *p, ref, input;
2326
0
  ir_ref s, d;
2327
0
  ir_insn *insn;
2328
0
  uint32_t len;
2329
0
  ir_bitset todo, ready;
2330
0
  bool have_constants_or_addresses = 0;
2331
2332
0
  bb = &ctx->cfg_blocks[b];
2333
0
  if (!(bb->flags & IR_BB_DESSA_MOVES)) {
2334
0
    return 0;
2335
0
  }
2336
0
  IR_ASSERT(bb->successors_count == 1);
2337
0
  succ = ctx->cfg_edges[bb->successors];
2338
0
  succ_bb = &ctx->cfg_blocks[succ];
2339
0
  IR_ASSERT(succ_bb->predecessors_count > 1);
2340
0
  use_list = &ctx->use_lists[succ_bb->start];
2341
2342
0
  k = ir_phi_input_number(ctx, succ_bb, b);
2343
2344
0
  if (use_list->count == 2) {
2345
    /* Simple version for BB with single PHI */
2346
0
    ref = ctx->use_edges[use_list->refs];
2347
0
    insn = &ctx->ir_base[ref];
2348
0
    if (insn->op != IR_PHI) {
2349
0
      ref = ctx->use_edges[use_list->refs + 1];
2350
0
      insn = &ctx->ir_base[ref];
2351
0
    }
2352
0
    IR_ASSERT(insn->op == IR_PHI);
2353
0
    input = ir_insn_op(insn, k);
2354
0
    emit_copy(ctx, insn->type, input, ref, data);
2355
0
    return 1;
2356
0
  }
2357
2358
0
  loc = ir_mem_malloc((ctx->vregs_count + 1) * 4 * sizeof(ir_ref));
2359
0
  pred = loc + ctx->vregs_count + 1;
2360
0
  src = pred + ctx->vregs_count + 1;
2361
0
  dst = src + ctx->vregs_count + 1;
2362
0
  len = ir_bitset_len(ctx->vregs_count + 1);
2363
0
  todo = ir_bitset_malloc(ctx->vregs_count + 1);
2364
2365
0
  for (i = use_list->count, p = &ctx->use_edges[use_list->refs]; i > 0; p++, i--) {
2366
0
    ref = *p;
2367
0
    insn = &ctx->ir_base[ref];
2368
0
    if (insn->op == IR_PHI) {
2369
0
      input = ir_insn_op(insn, k);
2370
0
      if (IR_IS_CONST_REF(input) || !(ctx->vregs[input] > 0)) {
2371
0
        have_constants_or_addresses = 1;
2372
0
      } else if (ctx->vregs[input] != ctx->vregs[ref]) {
2373
0
        s = ctx->vregs[input];
2374
0
        d = ctx->vregs[ref];
2375
0
        src[s] = input;
2376
0
        dst[d] = ref;
2377
0
        loc[d] = pred[s] = 0;
2378
0
        ir_bitset_incl(todo, d);
2379
0
        n++;
2380
0
      }
2381
0
    }
2382
0
  }
2383
2384
0
  if (n > 0) {
2385
0
    src[0] = dst[0] = 0;
2386
0
    ready = ir_bitset_malloc(ctx->vregs_count + 1);
2387
0
    IR_BITSET_FOREACH(todo, len, d) {
2388
0
      ref = dst[d];
2389
0
      insn = &ctx->ir_base[ref];
2390
0
      IR_ASSERT(insn->op == IR_PHI);
2391
0
      input = ir_insn_op(insn, k);
2392
0
      s = ctx->vregs[input];
2393
0
      loc[s] = s;
2394
0
      pred[d] = s;
2395
0
    } IR_BITSET_FOREACH_END();
2396
2397
0
    IR_BITSET_FOREACH(todo, len, i) {
2398
0
      if (!loc[i]) {
2399
0
        ir_bitset_incl(ready, i);
2400
0
      }
2401
0
    } IR_BITSET_FOREACH_END();
2402
2403
0
    while (1) {
2404
0
      ir_ref a, b, c;
2405
2406
0
      while ((b = ir_bitset_pop_first(ready, len)) >= 0) {
2407
0
        a = pred[b];
2408
0
        c = loc[a];
2409
0
        emit_copy(ctx, ctx->ir_base[dst[b]].type, src[c], dst[b], data);
2410
0
        ir_bitset_excl(todo, b);
2411
0
        loc[a] = b;
2412
0
        src[b] = dst[b];
2413
0
        if (a == c && pred[a]) {
2414
0
          ir_bitset_incl(ready, a);
2415
0
        }
2416
0
      }
2417
0
      b = ir_bitset_pop_first(todo, len);
2418
0
      if (b < 0) {
2419
0
        break;
2420
0
      }
2421
0
      IR_ASSERT(b != loc[pred[b]]);
2422
0
      emit_copy(ctx, ctx->ir_base[src[b]].type, src[b], 0, data);
2423
0
      loc[b] = 0;
2424
0
      ir_bitset_incl(ready, b);
2425
0
    }
2426
2427
0
    ir_mem_free(ready);
2428
0
  }
2429
2430
0
  ir_mem_free(todo);
2431
0
  ir_mem_free(loc);
2432
2433
0
  if (have_constants_or_addresses) {
2434
0
    for (i = use_list->count, p = &ctx->use_edges[use_list->refs]; i > 0; p++, i--) {
2435
0
      ref = *p;
2436
0
      insn = &ctx->ir_base[ref];
2437
0
      if (insn->op == IR_PHI) {
2438
0
        input = ir_insn_op(insn, k);
2439
0
        if (IR_IS_CONST_REF(input) || !(ctx->vregs[input] > 0)) {
2440
0
          emit_copy(ctx, insn->type, input, ref, data);
2441
0
        }
2442
0
      }
2443
0
    }
2444
0
  }
2445
2446
0
  return 1;
2447
0
}
2448
2449
/* Linear Scan Register Allocation */
2450
2451
#ifdef IR_DEBUG
2452
# if IR_X86_I64
2453
#  define IR_REG_NAME_FMT        "%s%s%s"
2454
#  define IR_REG_NAME_VAL(_ival) ((_ival->flags & IR_LIVE_INTERVAL_TWO_REGS) ? \
2455
                  ir_reg_name((_ival)->reg, IR_U32) : \
2456
                  ir_reg_name((_ival)->reg, (_ival)->type)), \
2457
                                 ((_ival->flags & IR_LIVE_INTERVAL_TWO_REGS) ? " and " : ""), \
2458
                                 ((_ival->flags & IR_LIVE_INTERVAL_TWO_REGS) ? \
2459
                  ir_reg_name((_ival)->reg_hi, IR_U32) : "")
2460
# else
2461
#  define IR_REG_NAME_FMT        "%s"
2462
0
#  define IR_REG_NAME_VAL(_ival) ir_reg_name((_ival)->reg, (_ival)->type)
2463
# endif
2464
238k
# define IR_LOG_LSRA(action, ival, comment) do { \
2465
238k
    if (ctx->flags & IR_DEBUG_RA) { \
2466
0
      ir_live_interval *_ival = (ival); \
2467
0
      ir_live_pos _start = _ival->range.start; \
2468
0
      ir_live_pos _end = _ival->end; \
2469
0
      fprintf(stderr, action " R%d [%d.%d...%d.%d)" comment "\n", \
2470
0
        (_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
2471
0
        IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
2472
0
        IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end)); \
2473
0
    } \
2474
238k
  } while (0)
2475
236k
# define IR_LOG_LSRA_ASSIGN(action, ival, comment) do { \
2476
236k
    if (ctx->flags & IR_DEBUG_RA) { \
2477
0
      ir_live_interval *_ival = (ival); \
2478
0
      ir_live_pos _start = _ival->range.start; \
2479
0
      ir_live_pos _end = _ival->end; \
2480
0
      fprintf(stderr, action " R%d [%d.%d...%d.%d) to " IR_REG_NAME_FMT comment "\n", \
2481
0
        (_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
2482
0
        IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
2483
0
        IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
2484
0
        IR_REG_NAME_VAL(_ival)); \
2485
0
    } \
2486
236k
  } while (0)
2487
648
# define IR_LOG_LSRA_SPLIT(ival, pos) do { \
2488
648
    if (ctx->flags & IR_DEBUG_RA) { \
2489
0
      ir_live_interval *_ival = (ival); \
2490
0
      ir_live_pos _start = _ival->range.start; \
2491
0
      ir_live_pos _end = _ival->end; \
2492
0
      ir_live_pos _pos = (pos); \
2493
0
      fprintf(stderr, "      ---- Split R%d [%d.%d...%d.%d) at %d.%d\n", \
2494
0
        (_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
2495
0
        IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
2496
0
        IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
2497
0
        IR_LIVE_POS_TO_REF(_pos), IR_LIVE_POS_TO_SUB_REF(_pos)); \
2498
0
    } \
2499
648
  } while (0)
2500
0
# define IR_LOG_LSRA_CONFLICT(action, ival, pos) do { \
2501
0
    if (ctx->flags & IR_DEBUG_RA) { \
2502
0
      ir_live_interval *_ival = (ival); \
2503
0
      ir_live_pos _start = _ival->range.start; \
2504
0
      ir_live_pos _end = _ival->end; \
2505
0
      ir_live_pos _pos = (pos); \
2506
0
      fprintf(stderr, action " R%d [%d.%d...%d.%d) assigned to " IR_REG_NAME_FMT " at %d.%d\n", \
2507
0
        (_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
2508
0
        IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
2509
0
        IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
2510
0
        IR_REG_NAME_VAL(_ival), \
2511
0
        IR_LIVE_POS_TO_REF(_pos), IR_LIVE_POS_TO_SUB_REF(_pos)); \
2512
0
    } \
2513
0
  } while (0)
2514
#else
2515
# define IR_LOG_LSRA(action, ival, comment)
2516
# define IR_LOG_LSRA_ASSIGN(action, ival, comment)
2517
# define IR_LOG_LSRA_SPLIT(ival, pos)
2518
# define IR_LOG_LSRA_CONFLICT(action, ival, pos);
2519
#endif
2520
2521
static bool ir_ival_covers(ir_live_interval *ival, ir_live_pos position)
2522
968
{
2523
968
  ir_live_range *live_range = &ival->range;
2524
2525
968
  do {
2526
968
    if (position < live_range->end) {
2527
640
      return position >= live_range->start;
2528
640
    }
2529
328
    live_range = live_range->next;
2530
328
  } while (live_range);
2531
2532
328
  return 0;
2533
968
}
2534
2535
static bool ir_ival_has_hole_between(ir_live_interval *ival, ir_live_pos from, ir_live_pos to)
2536
640
{
2537
640
  ir_live_range *r = &ival->range;
2538
2539
640
  while (r) {
2540
640
    if (from < r->start) {
2541
0
      return 1;
2542
640
    } else if (to <= r->end) {
2543
640
      return 0;
2544
640
    }
2545
0
    r = r->next;
2546
0
  }
2547
0
  return 0;
2548
640
}
2549
2550
2551
static ir_live_pos ir_last_use_pos_before(ir_live_interval *ival, ir_live_pos pos, uint8_t flags)
2552
650
{
2553
650
  ir_live_pos ret = 0;
2554
650
  ir_use_pos *p = ival->use_pos;
2555
2556
1.62k
  while (p && p->pos <= pos) {
2557
974
    if (p->flags & flags) {
2558
970
      ret = p->pos;
2559
970
    }
2560
974
    p = p->next;
2561
974
  }
2562
650
  return ret;
2563
650
}
2564
2565
static ir_live_pos ir_first_use_pos_after(ir_live_interval *ival, ir_live_pos pos, uint8_t flags)
2566
0
{
2567
0
  ir_use_pos *p = ival->use_pos;
2568
2569
0
  while (p && p->pos < pos) {
2570
0
    p = p->next;
2571
0
  }
2572
0
  if (p && p->pos == pos && p->op_num != 0) {
2573
0
    p = p->next;
2574
0
  }
2575
0
  while (p && !(p->flags & flags)) {
2576
0
    p = p->next;
2577
0
  }
2578
0
  return p ? p->pos : 0x7fffffff;
2579
0
}
2580
2581
static ir_block *ir_block_from_live_pos(ir_ctx *ctx, ir_live_pos pos)
2582
1.29k
{
2583
1.29k
  ir_ref ref = IR_LIVE_POS_TO_REF(pos);
2584
1.29k
  uint32_t b = ctx->cfg_map[ref];
2585
2586
1.29k
  while (!b) {
2587
0
    ref--;
2588
0
    IR_ASSERT(ref > 0);
2589
0
    b = ctx->cfg_map[ref];
2590
0
  }
2591
1.29k
  IR_ASSERT(b <= ctx->cfg_blocks_count);
2592
1.29k
  return &ctx->cfg_blocks[b];
2593
1.29k
}
2594
2595
static ir_live_pos ir_find_optimal_split_position(ir_ctx *ctx, ir_live_interval *ival, ir_live_pos min_pos, ir_live_pos max_pos, bool prefer_max)
2596
648
{
2597
648
  ir_block *min_bb, *max_bb;
2598
2599
648
  if (min_pos == max_pos) {
2600
0
    return max_pos;
2601
0
  }
2602
2603
648
  IR_ASSERT(min_pos < max_pos);
2604
648
  IR_ASSERT(min_pos >= ival->range.start);
2605
648
  IR_ASSERT(max_pos < ival->end);
2606
2607
648
  min_bb = ir_block_from_live_pos(ctx, min_pos);
2608
648
  max_bb = ir_block_from_live_pos(ctx, max_pos);
2609
2610
648
  if (min_bb == max_bb
2611
640
   || ir_ival_has_hole_between(ival, min_pos, max_pos)) {  // TODO: ???
2612
8
    return (prefer_max) ? max_pos : min_pos;
2613
8
  }
2614
2615
640
  if (max_bb->loop_depth > 0) {
2616
    /* Split at the end of the loop entry */
2617
110
    do {
2618
110
      ir_block *bb;
2619
2620
110
      if (max_bb->flags & IR_BB_LOOP_HEADER) {
2621
0
        bb = max_bb;
2622
110
      } else {
2623
110
        IR_ASSERT(max_bb->loop_header);
2624
110
        bb = &ctx->cfg_blocks[max_bb->loop_header];
2625
110
      }
2626
110
      bb = &ctx->cfg_blocks[bb->idom];
2627
110
      if (IR_DEF_LIVE_POS_FROM_REF(bb->end) < min_pos) {
2628
110
        break;
2629
110
      }
2630
0
      max_bb = bb;
2631
0
    } while (max_bb->loop_depth > 0);
2632
2633
110
    if (IR_DEF_LIVE_POS_FROM_REF(max_bb->end) < max_pos) {
2634
0
      return IR_DEF_LIVE_POS_FROM_REF(max_bb->end);
2635
0
    }
2636
110
  }
2637
2638
640
  if (IR_LOAD_LIVE_POS_FROM_REF(max_bb->start) > min_pos) {
2639
640
    return IR_LOAD_LIVE_POS_FROM_REF(max_bb->start);
2640
640
  } else {
2641
    // TODO: "min_bb" is in a deeper loop than "max_bb" ???
2642
0
    return max_pos;
2643
0
  }
2644
640
}
2645
2646
static ir_live_interval *ir_split_interval_at(ir_ctx *ctx, ir_live_interval *ival, ir_live_pos pos)
2647
648
{
2648
648
  ir_live_interval *child;
2649
648
  ir_live_range *p, *prev;
2650
648
  ir_use_pos *use_pos, *prev_use_pos;
2651
2652
648
  IR_LOG_LSRA_SPLIT(ival, pos);
2653
648
  IR_ASSERT(pos > ival->range.start);
2654
648
  ctx->flags2 |= IR_RA_HAVE_SPLITS;
2655
2656
648
  p = &ival->range;
2657
648
  prev = NULL;
2658
648
  while (p && pos >= p->end) {
2659
0
    prev = p;
2660
0
    p = prev->next;
2661
0
  }
2662
648
  IR_ASSERT(p);
2663
2664
648
  if (pos < p->start) {
2665
    /* split between ranges */
2666
0
    pos = p->start;
2667
0
  }
2668
2669
648
  use_pos = ival->use_pos;
2670
648
  prev_use_pos = NULL;
2671
2672
648
  ival->flags &= ~(IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS);
2673
648
  if (p->start == pos) {
2674
0
    while (use_pos && pos > use_pos->pos) {
2675
0
      if (use_pos->hint != IR_REG_NONE) {
2676
0
        ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REGS;
2677
0
      }
2678
0
      if (use_pos->hint_ref > 0) {
2679
0
        ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REFS;
2680
0
      }
2681
0
      prev_use_pos = use_pos;
2682
0
      use_pos = use_pos->next;
2683
0
    }
2684
648
  } else {
2685
1.61k
    while (use_pos && pos >= use_pos->pos) {
2686
969
      if (use_pos->hint != IR_REG_NONE) {
2687
0
        ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REGS;
2688
0
      }
2689
969
      if (use_pos->hint_ref > 0) {
2690
0
        ival->flags |= IR_LIVE_INTERVAL_HAS_HINT_REFS;
2691
0
      }
2692
969
      prev_use_pos = use_pos;
2693
969
      use_pos = use_pos->next;
2694
969
    }
2695
648
  }
2696
2697
648
  child = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval));
2698
648
  child->type = ival->type;
2699
648
  child->reg = IR_REG_NONE;
2700
#if IR_X86_I64
2701
  child->reg_hi = IR_REG_NONE;
2702
  child->flags = (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) | IR_LIVE_INTERVAL_SPLIT_CHILD;
2703
#else
2704
648
  child->flags = IR_LIVE_INTERVAL_SPLIT_CHILD;
2705
648
#endif
2706
648
  child->vreg = ival->vreg;
2707
648
  child->stack_spill_pos = -1; // not allocated
2708
648
  child->range.start = pos;
2709
648
  child->range.end = p->end;
2710
648
  child->range.next = p->next;
2711
648
  child->end = ival->end;
2712
648
  child->use_pos = prev_use_pos ? prev_use_pos->next : use_pos;
2713
2714
648
  child->next = ival->next;
2715
648
  ival->next = child;
2716
2717
648
  if (pos == p->start) {
2718
0
    prev->next = NULL;
2719
0
    ival->end = prev->end;
2720
    /* Cache to reuse */
2721
0
    p->next = ctx->unused_ranges;
2722
0
    ctx->unused_ranges = p;
2723
648
  } else {
2724
648
    p->end = ival->end = pos;
2725
648
    p->next = NULL;
2726
648
  }
2727
648
  if (prev_use_pos) {
2728
327
    prev_use_pos->next = NULL;
2729
327
  } else {
2730
321
    ival->use_pos = NULL;
2731
321
  }
2732
2733
648
  use_pos = child->use_pos;
2734
1.30k
  while (use_pos) {
2735
652
    if (use_pos->hint != IR_REG_NONE) {
2736
0
      child->flags |= IR_LIVE_INTERVAL_HAS_HINT_REGS;
2737
0
    }
2738
652
    if (use_pos->hint_ref > 0) {
2739
0
      child->flags |= IR_LIVE_INTERVAL_HAS_HINT_REFS;
2740
0
    }
2741
652
    use_pos = use_pos->next;
2742
652
  }
2743
2744
648
  return child;
2745
648
}
2746
2747
static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size)
2748
325
{
2749
325
  ir_reg_alloc_data *data = ctx->data;
2750
325
  int32_t ret, n;
2751
2752
325
  if (size == 0) {
2753
0
    return IR_NULL;
2754
0
  }
2755
2756
325
  IR_ASSERT(size == 1 || size == 2 || size == 4 || size == 8);
2757
325
  n = IR_LOG2(size);
2758
325
  if (data->handled && data->handled[n]) {
2759
100
    ret = data->handled[n]->stack_spill_pos;
2760
100
    data->handled[n] = data->handled[n]->list_next;
2761
225
  } else if (size == 8) {
2762
225
    ret = ctx->stack_frame_size;
2763
225
    ctx->stack_frame_size += 8;
2764
225
  } else if (size == 4) {
2765
0
    if (data->unused_slot_4) {
2766
0
      ret = data->unused_slot_4;
2767
0
      data->unused_slot_4 = 0;
2768
0
      } else if (data->handled && data->handled[3]) {
2769
0
      ret = data->handled[3]->stack_spill_pos;
2770
0
      data->handled[3] = data->handled[3]->list_next;
2771
0
      data->unused_slot_4 = ret + 4;
2772
0
    } else {
2773
0
      ret = ctx->stack_frame_size;
2774
0
      if (sizeof(void*) == 8) {
2775
0
        data->unused_slot_4 = ctx->stack_frame_size + 4;
2776
0
        ctx->stack_frame_size += 8;
2777
0
      } else {
2778
0
        ctx->stack_frame_size += 4;
2779
0
      }
2780
0
    }
2781
0
  } else if (size == 2) {
2782
0
    if (data->unused_slot_2) {
2783
0
      ret = data->unused_slot_2;
2784
0
      data->unused_slot_2 = 0;
2785
0
    } else if (data->unused_slot_4) {
2786
0
      ret = data->unused_slot_4;
2787
0
      data->unused_slot_2 = data->unused_slot_4 + 2;
2788
0
      data->unused_slot_4 = 0;
2789
0
      } else if (data->handled && data->handled[2]) {
2790
0
      ret = data->handled[2]->stack_spill_pos;
2791
0
      data->handled[2] = data->handled[2]->list_next;
2792
0
      data->unused_slot_2 = ret + 2;
2793
0
      } else if (data->handled && data->handled[3]) {
2794
0
      ret = data->handled[3]->stack_spill_pos;
2795
0
      data->handled[3] = data->handled[3]->list_next;
2796
0
      data->unused_slot_2 = ret + 2;
2797
0
      data->unused_slot_4 = ret + 4;
2798
0
    } else {
2799
0
      ret = ctx->stack_frame_size;
2800
0
      data->unused_slot_2 = ctx->stack_frame_size + 2;
2801
0
      if (sizeof(void*) == 8) {
2802
0
        data->unused_slot_4 = ctx->stack_frame_size + 4;
2803
0
        ctx->stack_frame_size += 8;
2804
0
      } else {
2805
0
        ctx->stack_frame_size += 4;
2806
0
      }
2807
0
    }
2808
0
  } else if (size == 1) {
2809
0
    if (data->unused_slot_1) {
2810
0
      ret = data->unused_slot_1;
2811
0
      data->unused_slot_1 = 0;
2812
0
    } else if (data->unused_slot_2) {
2813
0
      ret = data->unused_slot_2;
2814
0
      data->unused_slot_1 = data->unused_slot_2 + 1;
2815
0
      data->unused_slot_2 = 0;
2816
0
    } else if (data->unused_slot_4) {
2817
0
      ret = data->unused_slot_4;
2818
0
      data->unused_slot_1 = data->unused_slot_4 + 1;
2819
0
      data->unused_slot_2 = data->unused_slot_4 + 2;
2820
0
      data->unused_slot_4 = 0;
2821
0
      } else if (data->handled && data->handled[1]) {
2822
0
      ret = data->handled[1]->stack_spill_pos;
2823
0
      data->handled[1] = data->handled[1]->list_next;
2824
0
      data->unused_slot_1 = ret + 1;
2825
0
      } else if (data->handled && data->handled[2]) {
2826
0
      ret = data->handled[2]->stack_spill_pos;
2827
0
      data->handled[2] = data->handled[2]->list_next;
2828
0
      data->unused_slot_1 = ret + 1;
2829
0
      data->unused_slot_2 = ret + 2;
2830
0
      } else if (data->handled && data->handled[3]) {
2831
0
      ret = data->handled[3]->stack_spill_pos;
2832
0
      data->handled[3] = data->handled[3]->list_next;
2833
0
      data->unused_slot_1 = ret + 1;
2834
0
      data->unused_slot_2 = ret + 2;
2835
0
      data->unused_slot_4 = ret + 4;
2836
0
    } else {
2837
0
      ret = ctx->stack_frame_size;
2838
0
      data->unused_slot_1 = ctx->stack_frame_size + 1;
2839
0
      data->unused_slot_2 = ctx->stack_frame_size + 2;
2840
0
      if (sizeof(void*) == 8) {
2841
0
        data->unused_slot_4 = ctx->stack_frame_size + 4;
2842
0
        ctx->stack_frame_size += 8;
2843
0
      } else {
2844
0
        ctx->stack_frame_size += 4;
2845
0
      }
2846
0
    }
2847
0
  } else {
2848
0
    ret = IR_NULL;
2849
0
  }
2850
325
  return ret;
2851
325
}
2852
2853
static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, size_t size, size_t align)
2854
0
{
2855
0
  int32_t ret;
2856
2857
0
  IR_ASSERT(size < 0xfffffff);
2858
0
  if (size <= 64 && (size & (size - 1)) == 0) {
2859
0
    uint32_t n = IR_LOG2(size);
2860
0
    ir_reg_alloc_data *data = ctx->data;
2861
2862
0
    if (data->handled && data->handled[n]) {
2863
0
      ret = data->handled[n]->stack_spill_pos;
2864
0
      data->handled[n] = data->handled[n]->list_next;
2865
0
      return ret;
2866
0
    }
2867
0
  }
2868
2869
  /* Align stack allocated data to 16 byte */
2870
  // TODO: support for alignment larger than 16 ???
2871
0
  ctx->flags2 |= IR_16B_FRAME_ALIGNMENT;
2872
0
  ret = IR_ALIGNED_SIZE(ctx->stack_frame_size, 16);
2873
0
  size = IR_ALIGNED_SIZE(size, 8);
2874
0
  ctx->stack_frame_size = ret + (int32_t)size;
2875
2876
0
  return ret;
2877
0
}
2878
2879
int32_t ir_allocate_spill_slot(ir_ctx *ctx, size_t size, size_t align)
2880
325
{
2881
325
  IR_ASSERT(align == 0 || (align & (align -1)) == 0); /* align must be a power of 2 */
2882
325
  if (size <= 8 && align < 16) {
2883
325
    if (align > size) {
2884
0
      size = align;
2885
325
    } else if ((size & (size - 1)) != 0) {
2886
0
      size = (size == 3) ? 4 : 8;
2887
0
    }
2888
325
    return ir_allocate_small_spill_slot(ctx, size);
2889
325
  } else {
2890
0
    return ir_allocate_big_spill_slot(ctx, size, align);
2891
0
  }
2892
325
}
2893
2894
2895
static ir_reg ir_get_first_reg_hint(ir_ctx *ctx, ir_live_interval *ival, ir_regset available)
2896
154
{
2897
154
  ir_use_pos *use_pos;
2898
154
  ir_reg reg;
2899
2900
154
  use_pos = ival->use_pos;
2901
490
  while (use_pos) {
2902
478
    reg = use_pos->hint;
2903
478
    if (reg >= 0) {
2904
#if IR_X86_I64
2905
      if (use_pos->flags & IR_HINT_TWO_REGS) {
2906
        ir_reg reg_hi = IR_REG_I64_HI(reg);
2907
        ir_reg reg_lo = IR_REG_I64_LO(reg);
2908
2909
        IR_ASSERT(ival->flags & IR_LIVE_INTERVAL_TWO_REGS);
2910
        if (IR_REGSET_IN(available, reg_lo) && IR_REGSET_IN(available, reg_hi)) {
2911
          return reg;
2912
        }
2913
      } else
2914
#endif
2915
154
      if (IR_REGSET_IN(available, reg)) {
2916
#if IR_X86_I64
2917
        if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
2918
          /* Use the same reg for reg_hi */
2919
          return IR_REG_I64_PAIR(reg, reg);
2920
        } else
2921
#endif
2922
142
        return reg;
2923
142
      }
2924
154
    }
2925
336
    use_pos = use_pos->next;
2926
336
  }
2927
2928
12
  return IR_REG_NONE;
2929
154
}
2930
2931
static ir_reg ir_try_allocate_preferred_reg(ir_ctx *ctx, ir_live_interval *ival, ir_regset available, ir_live_pos *freeUntilPos)
2932
107k
{
2933
107k
  ir_use_pos *use_pos;
2934
107k
  ir_reg reg;
2935
2936
107k
  if (ival->flags & IR_LIVE_INTERVAL_HAS_HINT_REGS) {
2937
65.6k
    use_pos = ival->use_pos;
2938
164k
    while (use_pos) {
2939
162k
      reg = use_pos->hint;
2940
162k
      if (reg >= 0) {
2941
#if IR_X86_I64
2942
        if (use_pos->flags & IR_HINT_TWO_REGS) {
2943
          ir_reg reg_hi = IR_REG_I64_HI(reg);
2944
          ir_reg reg_lo = IR_REG_I64_LO(reg);
2945
2946
          IR_ASSERT(ival->flags & IR_LIVE_INTERVAL_TWO_REGS);
2947
          if (IR_REGSET_IN(available, reg_hi) && IR_REGSET_IN(available, reg_lo)) {
2948
            if (ival->end <= freeUntilPos[reg_lo] && ival->end <= freeUntilPos[reg_hi]) {
2949
              return reg;
2950
            }
2951
          }
2952
        } else
2953
#endif
2954
66.9k
        if (IR_REGSET_IN(available, reg)) {
2955
63.4k
          if (ival->end <= freeUntilPos[reg]) {
2956
            /* register available for the whole interval */
2957
#if IR_X86_I64
2958
            if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
2959
              /* Use the same reg for reg_hi to perform arbitrary allocation */
2960
              return IR_REG_I64_PAIR(reg, reg);
2961
            } else
2962
#endif
2963
63.4k
            return reg;
2964
63.4k
          }
2965
63.4k
        }
2966
66.9k
      }
2967
98.8k
      use_pos = use_pos->next;
2968
98.8k
    }
2969
65.6k
  }
2970
2971
43.8k
  if (ival->flags & IR_LIVE_INTERVAL_HAS_HINT_REFS) {
2972
41.7k
    use_pos = ival->use_pos;
2973
104k
    while (use_pos) {
2974
86.7k
      if (use_pos->hint_ref > 0) {
2975
47.9k
        ir_live_interval *hint_ival = ctx->live_intervals[ctx->vregs[use_pos->hint_ref]];
2976
2977
47.9k
        reg = hint_ival->reg;
2978
47.9k
        if (reg >= 0) {
2979
#if IR_X86_I64
2980
          if ((hint_ival->flags & IR_LIVE_INTERVAL_TWO_REGS)
2981
           && (ival->flags & IR_LIVE_INTERVAL_TWO_REGS)) {
2982
              ir_reg reg_hi = hint_ival->reg_hi;
2983
2984
              if (IR_REGSET_IN(available, reg) && IR_REGSET_IN(available, reg_hi)) {
2985
                if (ival->end <= freeUntilPos[reg] && ival->end <= freeUntilPos[reg_hi]) {
2986
                  return IR_REG_I64_PAIR(reg, reg_hi);
2987
                }
2988
            }
2989
          } else
2990
#endif
2991
27.6k
          if (IR_REGSET_IN(available, reg)) {
2992
24.4k
            if (ival->end <= freeUntilPos[reg]) {
2993
              /* register available for the whole interval */
2994
#if IR_X86_I64
2995
              if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
2996
                /* Use the same reg for reg_hi to perform arbitrary allocation */
2997
                return IR_REG_I64_PAIR(reg, reg);
2998
              } else
2999
#endif
3000
24.4k
              return reg;
3001
24.4k
            }
3002
24.4k
          }
3003
27.6k
        }
3004
47.9k
      }
3005
62.3k
      use_pos = use_pos->next;
3006
62.3k
    }
3007
41.7k
  }
3008
3009
19.3k
  return IR_REG_NONE;
3010
43.8k
}
3011
3012
static ir_reg ir_get_preferred_reg(ir_ctx *ctx, ir_live_interval *ival, ir_regset available)
3013
0
{
3014
0
  ir_use_pos *use_pos;
3015
0
  ir_reg reg;
3016
3017
0
  use_pos = ival->use_pos;
3018
0
  while (use_pos) {
3019
0
    reg = use_pos->hint;
3020
0
    if (reg >= 0) {
3021
#if IR_X86_I64
3022
      if (use_pos->flags & IR_HINT_TWO_REGS) {
3023
        ir_reg reg_hi = IR_REG_I64_HI(reg);
3024
        ir_reg reg_lo = IR_REG_I64_LO(reg);
3025
3026
        IR_ASSERT(ival->flags & IR_LIVE_INTERVAL_TWO_REGS);
3027
        if (IR_REGSET_IN(available, reg_lo) && IR_REGSET_IN(available, reg_hi)) {
3028
          return reg;
3029
        }
3030
      } else
3031
#endif
3032
0
      if (IR_REGSET_IN(available, reg)) {
3033
#if IR_X86_I64
3034
        if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3035
          /* Use the same reg for reg_hi to perform arbitrary allocation */
3036
          return IR_REG_I64_PAIR(reg, reg);
3037
        } else
3038
#endif
3039
0
        return reg;
3040
0
      }
3041
0
    } else if (use_pos->hint_ref > 0) {
3042
0
      ir_live_interval *hint_ival = ctx->live_intervals[ctx->vregs[use_pos->hint_ref]];
3043
3044
0
      reg = hint_ival->reg;
3045
0
      if (reg >= 0) {
3046
#if IR_X86_I64
3047
        if ((hint_ival->flags & IR_LIVE_INTERVAL_TWO_REGS)
3048
         && (ival->flags & IR_LIVE_INTERVAL_TWO_REGS)) {
3049
          ir_reg reg_hi = hint_ival->reg_hi;
3050
3051
          IR_ASSERT(reg_hi >= 0);
3052
          if (IR_REGSET_IN(available, reg) && IR_REGSET_IN(available, reg_hi)) {
3053
            return IR_REG_I64_PAIR(reg, reg_hi);
3054
          }
3055
        } else
3056
#endif
3057
0
        if (IR_REGSET_IN(available, reg)) {
3058
#if IR_X86_I64
3059
          if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3060
            /* Use the same reg for reg_hi to perform arbitrary allocation */
3061
            return IR_REG_I64_PAIR(reg, reg);
3062
          } else
3063
#endif
3064
0
          return reg;
3065
0
        }
3066
0
      }
3067
0
    }
3068
0
    use_pos = use_pos->next;
3069
0
  }
3070
3071
0
  return IR_REG_NONE;
3072
0
}
3073
3074
static void ir_add_to_unhandled(ir_live_interval **unhandled, ir_live_interval *ival)
3075
141k
{
3076
141k
  ir_live_pos pos = ival->range.start;
3077
3078
141k
  if (*unhandled == NULL
3079
132k
   || pos < (*unhandled)->range.start
3080
2.39k
   || (pos == (*unhandled)->range.start
3081
0
    && (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS))
3082
0
    && !((*unhandled)->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)))
3083
2.39k
   || (pos == (*unhandled)->range.start
3084
138k
    && ival->vreg > (*unhandled)->vreg)) {
3085
138k
    ival->list_next = *unhandled;
3086
138k
    *unhandled = ival;
3087
138k
  } else {
3088
2.39k
    ir_live_interval *prev = *unhandled;
3089
3090
2.63k
    while (prev->list_next) {
3091
2.63k
      if (pos < prev->list_next->range.start
3092
239
       || (pos == prev->list_next->range.start
3093
0
        && (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS))
3094
0
        && !(prev->list_next->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)))
3095
239
       || (pos == prev->list_next->range.start
3096
2.39k
        && ival->vreg > prev->list_next->vreg)) {
3097
2.39k
        break;
3098
2.39k
      }
3099
239
      prev = prev->list_next;
3100
239
    }
3101
2.39k
    ival->list_next = prev->list_next;
3102
2.39k
    prev->list_next = ival;
3103
2.39k
  }
3104
141k
}
3105
3106
/* merge sorted lists */
3107
static void ir_merge_to_unhandled(ir_live_interval **unhandled, ir_live_interval *ival)
3108
9.54k
{
3109
9.54k
  ir_live_interval **prev;
3110
9.54k
  ir_live_pos pos;
3111
3112
9.54k
  if (*unhandled == NULL) {
3113
512
    *unhandled = ival;
3114
1.12k
    while (ival) {
3115
616
      ival = ival->list_next = ival->next;
3116
616
    }
3117
9.03k
  } else {
3118
9.03k
    prev = unhandled;
3119
104k
    while (ival) {
3120
95.3k
      pos = ival->range.start;
3121
234k
      while (*prev && pos >= (*prev)->range.start) {
3122
139k
        prev = &(*prev)->list_next;
3123
139k
      }
3124
95.3k
      ival->list_next = *prev;
3125
95.3k
      *prev = ival;
3126
95.3k
      prev = &ival->list_next;
3127
95.3k
      ival = ival->next;
3128
95.3k
    }
3129
9.03k
  }
3130
9.54k
#ifdef IR_DEBUG
3131
9.54k
  ival = *unhandled;
3132
9.54k
  pos = 0;
3133
3134
245k
  while (ival) {
3135
236k
    IR_ASSERT(ival->range.start >= pos);
3136
236k
    pos = ival->range.start;
3137
236k
    ival = ival->list_next;
3138
236k
  }
3139
9.54k
#endif
3140
9.54k
}
3141
3142
static void ir_add_to_unhandled_spill(ir_live_interval **unhandled, ir_live_interval *ival)
3143
325
{
3144
325
  ir_live_pos pos = ival->range.start;
3145
3146
325
  if (*unhandled == NULL
3147
325
   || pos <= (*unhandled)->range.start) {
3148
325
    ival->list_next = *unhandled;
3149
325
    *unhandled = ival;
3150
325
  } else {
3151
0
    ir_live_interval *prev = *unhandled;
3152
3153
0
    while (prev->list_next) {
3154
0
      if (pos <= prev->list_next->range.start) {
3155
0
        break;
3156
0
      }
3157
0
      prev = prev->list_next;
3158
0
    }
3159
0
    ival->list_next = prev->list_next;
3160
0
    prev->list_next = ival;
3161
0
  }
3162
325
}
3163
3164
static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_live_interval **active, ir_live_interval *inactive, ir_live_interval **unhandled)
3165
237k
{
3166
237k
  ir_live_pos freeUntilPos[IR_REG_NUM];
3167
237k
  int i, reg;
3168
237k
  ir_live_pos pos, next;
3169
237k
  ir_live_interval *other;
3170
237k
  ir_regset available, overlapped, scratch;
3171
3172
237k
  if (IR_IS_TYPE_FP(ival->type) || IR_IS_TYPE_VECTOR(ival->type)) {
3173
2.84k
    available = IR_REGSET_FP;
3174
    /* set freeUntilPos of all physical registers to maxInt */
3175
48.4k
    for (i = IR_REG_FP_FIRST; i <= IR_REG_FP_LAST; i++) {
3176
45.5k
      freeUntilPos[i] = 0x7fffffff;
3177
45.5k
    }
3178
234k
  } else {
3179
234k
    available = IR_REGSET_GP;
3180
234k
    if (ctx->flags & IR_USE_FRAME_POINTER) {
3181
0
      IR_REGSET_EXCL(available, IR_REG_FRAME_POINTER);
3182
0
    }
3183
#if defined(IR_TARGET_X86)
3184
    if (ir_type_size[ival->type] == 1) {
3185
      /* TODO: if no registers avialivle, we may use of one this register for already allocated interval ??? */
3186
      IR_REGSET_EXCL(available, IR_REG_RBP);
3187
      IR_REGSET_EXCL(available, IR_REG_RSI);
3188
      IR_REGSET_EXCL(available, IR_REG_RDI);
3189
    }
3190
#endif
3191
    /* set freeUntilPos of all physical registers to maxInt */
3192
3.98M
    for (i = IR_REG_GP_FIRST; i <= IR_REG_GP_LAST; i++) {
3193
3.75M
      freeUntilPos[i] = 0x7fffffff;
3194
3.75M
    }
3195
234k
  }
3196
3197
237k
  available = IR_REGSET_DIFFERENCE(available, (ir_regset)ctx->fixed_regset);
3198
3199
  /* for each interval it in active */
3200
237k
  other = *active;
3201
351k
  while (other) {
3202
    /* freeUntilPos[it.reg] = 0 */
3203
114k
    reg = other->reg;
3204
114k
    IR_ASSERT(reg >= 0);
3205
114k
    if (reg >= IR_REG_NUM) {
3206
5
      available = IR_REGSET_DIFFERENCE(available, ir_scratch_regset[reg - IR_REG_NUM]);
3207
114k
    } else {
3208
114k
      IR_REGSET_EXCL(available, reg);
3209
114k
    }
3210
#if IR_X86_I64
3211
    if (other->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3212
      reg = other->reg_hi;
3213
      IR_ASSERT(reg >= 0 && reg < IR_REG_NUM);
3214
      IR_REGSET_EXCL(available, reg);
3215
     }
3216
#endif
3217
114k
    other = other->list_next;
3218
114k
  }
3219
3220
  /* for each interval it in inactive intersecting with current
3221
   *
3222
   * This loop is not necessary for program in SSA form (see LSRA on SSA fig. 6),
3223
   * but it is still necessary after coalescing and splitting
3224
   */
3225
237k
  overlapped = IR_REGSET_EMPTY;
3226
237k
  other = inactive;
3227
237k
  pos = ival->end;
3228
976k
  while (other) {
3229
    /* freeUntilPos[it.reg] = next intersection of it with current */
3230
739k
    if (other->current_range->start < pos) {
3231
63.8k
      next = ir_ivals_overlap(&ival->range, other->current_range);
3232
63.8k
      if (next) {
3233
24.0k
        reg = other->reg;
3234
24.0k
        IR_ASSERT(reg >= 0);
3235
24.0k
        if (reg >= IR_REG_NUM) {
3236
8.81k
          ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
3237
8.81k
          overlapped = IR_REGSET_UNION(overlapped, regset);
3238
92.4k
          IR_REGSET_FOREACH(regset, reg) {
3239
92.4k
            if (next < freeUntilPos[reg]) {
3240
83.5k
              freeUntilPos[reg] = next;
3241
83.5k
            }
3242
92.4k
          } IR_REGSET_FOREACH_END();
3243
15.2k
        } else if (IR_REGSET_IN(available, reg)) {
3244
14.9k
          IR_REGSET_INCL(overlapped, reg);
3245
14.9k
          if (next < freeUntilPos[reg]) {
3246
11.9k
            freeUntilPos[reg] = next;
3247
11.9k
          }
3248
14.9k
        }
3249
#if IR_X86_I64
3250
        if (other->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3251
          reg = other->reg_hi;
3252
          IR_ASSERT(reg >= 0 && reg < IR_REG_NUM);
3253
          if (IR_REGSET_IN(available, reg)) {
3254
            IR_REGSET_INCL(overlapped, reg);
3255
            if (next < freeUntilPos[reg]) {
3256
              freeUntilPos[reg] = next;
3257
            }
3258
          }
3259
         }
3260
#endif
3261
24.0k
      }
3262
63.8k
    }
3263
739k
    other = other->list_next;
3264
739k
  }
3265
3266
237k
  available = IR_REGSET_DIFFERENCE(available, overlapped);
3267
237k
  if (available != IR_REGSET_EMPTY) {
3268
3269
236k
    if (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)) {
3270
      /* Try to use hint */
3271
107k
      reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
3272
107k
      if (reg != IR_REG_NONE) {
3273
#if IR_X86_I64
3274
        if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3275
          ir_reg reg_hi = IR_REG_I64_HI(reg);
3276
          reg = IR_REG_I64_LO(reg);
3277
          if (reg_hi == reg) {
3278
            IR_REGSET_EXCL(available, reg);
3279
            if (available == IR_REGSET_EMPTY) {
3280
              return IR_REG_NONE;
3281
            }
3282
            reg_hi = IR_REGSET_FIRST(available);
3283
            if (reg > reg_hi) {
3284
              int tmp = reg;
3285
              reg = reg_hi;
3286
              reg_hi = tmp;
3287
            }
3288
          }
3289
          IR_ASSERT(reg != reg_hi);
3290
          ival->reg = reg;
3291
          ival->reg_hi = reg_hi;
3292
          IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling)");
3293
          if (*unhandled && ival->end > (*unhandled)->range.start) {
3294
            ival->list_next = *active;
3295
            *active = ival;
3296
          }
3297
          return reg;
3298
        } else
3299
#endif
3300
87.9k
        {
3301
87.9k
          ival->reg = reg;
3302
87.9k
          IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (hint available without spilling)");
3303
87.9k
          if (*unhandled && ival->end > (*unhandled)->range.start) {
3304
25.6k
            ival->list_next = *active;
3305
25.6k
            *active = ival;
3306
25.6k
          }
3307
87.9k
          return reg;
3308
87.9k
        }
3309
87.9k
      }
3310
107k
    }
3311
3312
148k
    if (ival->flags & IR_LIVE_INTERVAL_SPLIT_CHILD) {
3313
      /* Try to reuse the register previously allocated for splited interval */
3314
323
      reg = ctx->live_intervals[ival->vreg]->reg;
3315
323
      if (reg >= 0 && IR_REGSET_IN(available, reg)) {
3316
#if IR_X86_I64
3317
        if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3318
          int8_t reg_hi = ctx->live_intervals[ival->vreg]->reg_hi;
3319
          if (reg_hi >= 0 && IR_REGSET_IN(available, reg_hi)) {
3320
            IR_ASSERT(reg < reg_hi);
3321
            ival->reg = reg;
3322
            ival->reg_hi = reg_hi;
3323
            IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling)");
3324
            if (*unhandled && ival->end > (*unhandled)->range.start) {
3325
              ival->list_next = *active;
3326
              *active = ival;
3327
            }
3328
            return reg;
3329
          }
3330
        } else
3331
#endif
3332
320
        {
3333
320
          ival->reg = reg;
3334
320
          IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling)");
3335
320
          if (*unhandled && ival->end > (*unhandled)->range.start) {
3336
0
            ival->list_next = *active;
3337
0
            *active = ival;
3338
0
          }
3339
320
          return reg;
3340
320
        }
3341
320
      }
3342
323
    }
3343
3344
    /* prefer caller-saved registers to avoid save/restore in prologue/epilogue */
3345
148k
    scratch = IR_REGSET_INTERSECTION(available,
3346
148k
      ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM]);
3347
148k
    if (scratch != IR_REGSET_EMPTY) {
3348
      /* prefer registers that don't conflict with the hints for the following unhandled intervals */
3349
140k
      if (1) {
3350
140k
        ir_regset non_conflicting = scratch;
3351
3352
140k
        other = *unhandled;
3353
148k
        while (other && other->range.start < ival->range.end) {
3354
8.26k
          if (other->flags & IR_LIVE_INTERVAL_HAS_HINT_REGS) {
3355
154
            reg = ir_get_first_reg_hint(ctx, other, non_conflicting);
3356
3357
154
            if (reg >= 0) {
3358
#if IR_X86_I64
3359
              if (other->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3360
                ir_reg reg_hi = IR_REG_I64_HI(reg);
3361
                ir_reg reg_lo = IR_REG_I64_LO(reg);
3362
3363
                IR_REGSET_EXCL(non_conflicting, reg_hi);
3364
                IR_REGSET_EXCL(non_conflicting, reg_lo);
3365
                if (non_conflicting == IR_REGSET_EMPTY) {
3366
                  break;
3367
                }
3368
              } else
3369
#endif
3370
142
              {
3371
142
                IR_REGSET_EXCL(non_conflicting, reg);
3372
142
                if (non_conflicting == IR_REGSET_EMPTY) {
3373
0
                  break;
3374
0
                }
3375
142
              }
3376
142
            }
3377
154
          }
3378
8.26k
          other = other->list_next;
3379
8.26k
        }
3380
140k
        if (non_conflicting != IR_REGSET_EMPTY) {
3381
140k
          reg = IR_REGSET_FIRST(non_conflicting);
3382
140k
        } else {
3383
0
          reg = IR_REGSET_FIRST(scratch);
3384
0
        }
3385
140k
      } else {
3386
0
        reg = IR_REGSET_FIRST(scratch);
3387
0
      }
3388
140k
    } else {
3389
8.16k
      reg = IR_REGSET_FIRST(available);
3390
8.16k
    }
3391
#if IR_X86_I64
3392
    if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3393
      IR_REGSET_EXCL(available, reg);
3394
      if (available != IR_REGSET_EMPTY) {
3395
        ir_reg reg_hi = IR_REGSET_FIRST(available);
3396
3397
        if (reg > reg_hi) {
3398
          int tmp = reg;
3399
          reg = reg_hi;
3400
          reg_hi = tmp;
3401
        }
3402
3403
        IR_ASSERT(reg != reg_hi);
3404
        ival->reg = reg;
3405
        ival->reg_hi = reg_hi;
3406
        IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling)");
3407
        if (*unhandled && ival->end > (*unhandled)->range.start) {
3408
          ival->list_next = *active;
3409
          *active = ival;
3410
        }
3411
        return reg;
3412
      }
3413
    } else
3414
#endif
3415
148k
    {
3416
148k
      ival->reg = reg;
3417
148k
      IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling)");
3418
148k
      if (*unhandled && ival->end > (*unhandled)->range.start) {
3419
21.4k
        ival->list_next = *active;
3420
21.4k
        *active = ival;
3421
21.4k
      }
3422
148k
      return reg;
3423
148k
    }
3424
148k
  }
3425
3426
#if IR_X86_I64
3427
  if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3428
    return IR_REG_NONE;
3429
  }
3430
#endif
3431
3432
  /* reg = register with highest freeUntilPos */
3433
650
  reg = IR_REG_NONE;
3434
650
  pos = 0;
3435
10.9k
  IR_REGSET_FOREACH(overlapped, i) {
3436
10.9k
    if (freeUntilPos[i] > pos) {
3437
645
      pos = freeUntilPos[i];
3438
645
      reg = i;
3439
9.67k
    } else if (freeUntilPos[i] == pos
3440
9.67k
        && !IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], reg)
3441
0
        && IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], i)) {
3442
      /* prefer caller-saved registers to avoid save/restore in prologue/epilogue */
3443
0
      pos = freeUntilPos[i];
3444
0
      reg = i;
3445
0
    }
3446
10.9k
  } IR_REGSET_FOREACH_END();
3447
3448
650
  if (pos > ival->range.start) {
3449
    /* register available for the first part of the interval */
3450
    /* split current before freeUntilPos[reg] */
3451
645
    ir_live_pos split_pos = ir_last_use_pos_before(ival, pos,
3452
645
      IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3453
645
    if (split_pos > ival->range.start) {
3454
320
      split_pos = ir_find_optimal_split_position(ctx, ival, split_pos, pos, 0);
3455
320
      other = ir_split_interval_at(ctx, ival, split_pos);
3456
320
      if (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)) {
3457
0
        ir_reg pref_reg = ir_try_allocate_preferred_reg(ctx, ival, IR_REGSET_UNION(available, overlapped), freeUntilPos);
3458
3459
0
        if (pref_reg != IR_REG_NONE) {
3460
0
          ival->reg = pref_reg;
3461
0
        } else {
3462
0
          ival->reg = reg;
3463
0
        }
3464
320
      } else {
3465
320
        ival->reg = reg;
3466
320
      }
3467
320
      IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (available without spilling for the first part)");
3468
320
      if (*unhandled && ival->end > (*unhandled)->range.start) {
3469
0
        ival->list_next = *active;
3470
0
        *active = ival;
3471
0
      }
3472
320
      ir_add_to_unhandled(unhandled, other);
3473
320
      IR_LOG_LSRA("      ---- Queue", other, "");
3474
320
      return reg;
3475
320
    }
3476
645
  }
3477
330
  return IR_REG_NONE;
3478
650
}
3479
3480
static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_live_interval **active, ir_live_interval **inactive, ir_live_interval **unhandled)
3481
330
{
3482
330
  ir_live_pos nextUsePos[IR_REG_NUM];
3483
330
  ir_live_pos blockPos[IR_REG_NUM];
3484
330
  int score, best_score, scores[IR_REG_NUM];
3485
330
  int i, reg;
3486
#if IR_X86_I64
3487
  int reg_hi = IR_REG_NONE;
3488
#endif
3489
330
  ir_live_pos pos, next_use_pos, block_pos;
3490
330
  ir_live_interval *other, *prev;
3491
330
  ir_use_pos *use_pos;
3492
330
  ir_regset available, tmp_regset;
3493
3494
330
  if (!(ival->flags & IR_LIVE_INTERVAL_TEMP)) {
3495
330
    use_pos = ival->use_pos;
3496
336
    while (use_pos && !(use_pos->flags & IR_USE_MUST_BE_IN_REG)) {
3497
6
      use_pos = use_pos->next;
3498
6
    }
3499
330
    if (!use_pos) {
3500
      /* spill */
3501
2
      IR_LOG_LSRA("    ---- Spill", ival, " (no use pos that must be in reg)");
3502
2
      ctx->flags2 |= IR_RA_HAVE_SPILLS;
3503
2
      return IR_REG_NONE;
3504
2
    }
3505
328
    next_use_pos = use_pos->pos;
3506
328
  } else {
3507
0
    next_use_pos = ival->range.end;
3508
0
  }
3509
3510
328
  if (IR_IS_TYPE_FP(ival->type) || IR_IS_TYPE_VECTOR(ival->type)) {
3511
328
    available = IR_REGSET_FP;
3512
    /* set nextUsePos of all physical registers to maxInt */
3513
5.57k
    for (i = IR_REG_FP_FIRST; i <= IR_REG_FP_LAST; i++) {
3514
5.24k
      nextUsePos[i] = 0x7fffffff;
3515
5.24k
      blockPos[i] = 0x7fffffff;
3516
5.24k
      scores[i] = 0;
3517
5.24k
    }
3518
328
  } else {
3519
0
    available = IR_REGSET_GP;
3520
0
    if (ctx->flags & IR_USE_FRAME_POINTER) {
3521
0
      IR_REGSET_EXCL(available, IR_REG_FRAME_POINTER);
3522
0
    }
3523
#if defined(IR_TARGET_X86)
3524
    if (ir_type_size[ival->type] == 1) {
3525
      /* TODO: if no registers avialivle, we may use of one this register for already allocated interval ??? */
3526
      IR_REGSET_EXCL(available, IR_REG_RBP);
3527
      IR_REGSET_EXCL(available, IR_REG_RSI);
3528
      IR_REGSET_EXCL(available, IR_REG_RDI);
3529
    }
3530
#endif
3531
    /* set nextUsePos of all physical registers to maxInt */
3532
0
    for (i = IR_REG_GP_FIRST; i <= IR_REG_GP_LAST; i++) {
3533
0
      nextUsePos[i] = 0x7fffffff;
3534
0
      blockPos[i] = 0x7fffffff;
3535
0
      scores[i] = 0;
3536
0
    }
3537
0
  }
3538
3539
328
  available = IR_REGSET_DIFFERENCE(available, (ir_regset)ctx->fixed_regset);
3540
3541
328
  if (IR_REGSET_IS_EMPTY(available)) {
3542
0
    fprintf(stderr, "LSRA Internal Error: No registers available. Allocation is not possible\n");
3543
0
    IR_ASSERT(0);
3544
0
    exit(-1);
3545
0
  }
3546
3547
  /* for each interval it in active */
3548
328
  other = *active;
3549
332
  while (other) {
3550
    /* nextUsePos[it.reg] = next use of it after start of current */
3551
4
    reg = other->reg;
3552
4
    IR_ASSERT(reg >= 0);
3553
4
    if (reg >= IR_REG_NUM) {
3554
3
      ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
3555
51
      IR_REGSET_FOREACH(regset, reg) {
3556
51
        blockPos[reg] = nextUsePos[reg] = 0;
3557
51
      } IR_REGSET_FOREACH_END();
3558
3
    } else if (IR_REGSET_IN(available, reg)) {
3559
0
      if (other->flags & (IR_LIVE_INTERVAL_FIXED|IR_LIVE_INTERVAL_TEMP)) {
3560
0
        blockPos[reg] = nextUsePos[reg] = 0;
3561
0
      } else {
3562
0
        pos = ir_first_use_pos_after(other, ival->range.start,
3563
0
          IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3564
0
        if (pos < nextUsePos[reg]) {
3565
0
          nextUsePos[reg] = pos;
3566
          /* Prefer splitting interval that was already splitted before */
3567
0
          scores[reg] = (other->flags & IR_LIVE_INTERVAL_SPLIT_CHILD) ? 1 : 0;
3568
0
        }
3569
0
      }
3570
0
    }
3571
#if IR_X86_I64
3572
    if (other->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3573
      reg = other->reg_hi;
3574
      IR_ASSERT(reg >= 0 && reg < IR_REG_NUM);
3575
      if (IR_REGSET_IN(available, reg)) {
3576
        pos = ir_first_use_pos_after(other, ival->range.start,
3577
          IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3578
        if (pos < nextUsePos[reg]) {
3579
          nextUsePos[reg] = pos;
3580
          /* Prefer splitting interval that was already splitted before */
3581
          scores[reg] = (other->flags & IR_LIVE_INTERVAL_SPLIT_CHILD) ? 1 : 0;
3582
        }
3583
      }
3584
     }
3585
#endif
3586
4
    other = other->list_next;
3587
4
  }
3588
3589
  /* for each interval it in inactive intersecting with current */
3590
328
  other = *inactive;
3591
1.44k
  while (other) {
3592
    /* freeUntilPos[it.reg] = next intersection of it with current */
3593
1.12k
    reg = other->reg;
3594
1.12k
    IR_ASSERT(reg >= 0);
3595
1.12k
    if (reg >= IR_REG_NUM) {
3596
325
      ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
3597
3598
325
      if (overlap) {
3599
325
        ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
3600
5.52k
        IR_REGSET_FOREACH(regset, reg) {
3601
5.52k
          if (overlap < nextUsePos[reg]) {
3602
5.20k
            nextUsePos[reg] = overlap;
3603
5.20k
            scores[reg] = 0;
3604
5.20k
          }
3605
5.52k
          if (overlap < blockPos[reg]) {
3606
5.20k
            blockPos[reg] = overlap;
3607
5.20k
          }
3608
5.52k
        } IR_REGSET_FOREACH_END();
3609
325
      }
3610
796
    } else if (IR_REGSET_IN(available, reg)) {
3611
0
      ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
3612
3613
0
      if (overlap) {
3614
0
        if (other->flags & (IR_LIVE_INTERVAL_FIXED|IR_LIVE_INTERVAL_TEMP)) {
3615
0
          if (overlap < nextUsePos[reg]) {
3616
0
            nextUsePos[reg] = overlap;
3617
0
            scores[reg] = 0;
3618
0
          }
3619
0
          if (overlap < blockPos[reg]) {
3620
0
            blockPos[reg] = overlap;
3621
0
          }
3622
0
        } else {
3623
0
          pos = ir_first_use_pos_after(other, ival->range.start,
3624
0
            IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3625
0
          if (pos < nextUsePos[reg]) {
3626
0
            nextUsePos[reg] = pos;
3627
            /* Prefer splitting interval that was already splitted before */
3628
0
            scores[reg] = (other->flags & IR_LIVE_INTERVAL_SPLIT_CHILD) ? 1 : 0;
3629
0
          }
3630
0
        }
3631
0
      }
3632
0
    }
3633
#if IR_X86_I64
3634
    if (other->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3635
      reg = other->reg_hi;
3636
      IR_ASSERT(reg >= 0 && reg < IR_REG_NUM);
3637
      if (IR_REGSET_IN(available, reg)) {
3638
        ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
3639
3640
        if (overlap) {
3641
          if (other->flags & (IR_LIVE_INTERVAL_FIXED|IR_LIVE_INTERVAL_TEMP)) {
3642
            if (overlap < nextUsePos[reg]) {
3643
              nextUsePos[reg] = overlap;
3644
              scores[reg] = 0;
3645
            }
3646
            if (overlap < blockPos[reg]) {
3647
              blockPos[reg] = overlap;
3648
            }
3649
          } else {
3650
            pos = ir_first_use_pos_after(other, ival->range.start,
3651
              IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3652
            if (pos < nextUsePos[reg]) {
3653
              nextUsePos[reg] = pos;
3654
              /* Prefer splitting interval that was already splitted before */
3655
              scores[reg] = (other->flags & IR_LIVE_INTERVAL_SPLIT_CHILD) ? 1 : 0;
3656
            }
3657
          }
3658
        }
3659
      }
3660
     }
3661
#endif
3662
1.12k
    other = other->list_next;
3663
1.12k
  }
3664
3665
  /* register hinting */
3666
328
  reg = IR_REG_NONE;
3667
328
  if (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)) {
3668
0
    reg = ir_get_preferred_reg(ctx, ival, available);
3669
#if IR_X86_I64
3670
    if (reg != IR_REG_NONE && ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3671
      reg_hi = IR_REG_I64_HI(reg);
3672
      reg = IR_REG_I64_LO(reg);
3673
      if (reg == reg_hi) {
3674
        reg_hi = IR_REG_NONE;
3675
      }
3676
    }
3677
#endif
3678
0
  }
3679
328
  if (reg == IR_REG_NONE) {
3680
328
select_register:
3681
328
    reg = IR_REGSET_FIRST(available);
3682
#if IR_X86_I64
3683
    reg_hi = IR_REG_NONE;
3684
#endif
3685
328
  }
3686
3687
  /* reg = register with highest nextUsePos */
3688
328
  pos = nextUsePos[reg];
3689
328
  best_score = (scores[reg] << 28) + nextUsePos[reg];
3690
328
  tmp_regset = available;
3691
328
  IR_REGSET_EXCL(tmp_regset, reg);
3692
5.24k
  IR_REGSET_FOREACH(tmp_regset, i) {
3693
5.24k
    if (nextUsePos[i] > pos) {
3694
0
      pos = nextUsePos[i];
3695
0
    }
3696
5.24k
    score = (scores[i] << 28) + nextUsePos[i];
3697
5.24k
    if (score > best_score) {
3698
0
      reg = i;
3699
0
      best_score = score;
3700
0
    }
3701
5.24k
  } IR_REGSET_FOREACH_END();
3702
3703
328
  block_pos = blockPos[reg];
3704
3705
#if IR_X86_I64
3706
  if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
3707
    ir_live_pos pos_hi;
3708
3709
    tmp_regset = available;
3710
    IR_REGSET_EXCL(tmp_regset, reg);
3711
3712
    if (IR_REGSET_IS_EMPTY(tmp_regset)) {
3713
      fprintf(stderr, "LSRA Internal Error: Unsolvable conflict. Allocation is not possible\n");
3714
      IR_ASSERT(0);
3715
      exit(-1);
3716
    }
3717
3718
    if (reg_hi == IR_REG_NONE || !IR_REGSET_IN(tmp_regset, reg_hi)) {
3719
      reg_hi = IR_REGSET_FIRST(tmp_regset);
3720
    }
3721
    pos_hi = nextUsePos[reg_hi];
3722
    best_score = (scores[reg_hi] << 28) + nextUsePos[reg_hi];
3723
    IR_REGSET_EXCL(tmp_regset, reg_hi);
3724
    IR_REGSET_FOREACH(tmp_regset, i) {
3725
      if (nextUsePos[i] > pos_hi) {
3726
        pos_hi = nextUsePos[i];
3727
      }
3728
      score = (scores[i] << 28) + nextUsePos[i];
3729
      if (score > best_score) {
3730
        reg_hi = i;
3731
        best_score = score;
3732
      }
3733
    } IR_REGSET_FOREACH_END();
3734
3735
    pos = IR_MIN(pos, pos_hi);
3736
    block_pos = IR_MIN(block_pos, blockPos[reg_hi]);
3737
    if (reg > reg_hi) {
3738
      int tmp = reg;
3739
      reg = reg_hi;
3740
      reg_hi = tmp;
3741
    }
3742
  }
3743
#endif
3744
3745
  /* if first usage of current is after nextUsePos[reg] then */
3746
328
  if (next_use_pos > pos && !(ival->flags & IR_LIVE_INTERVAL_TEMP)) {
3747
    /* all other intervals are used before current, so it is best to spill current itself */
3748
    /* assign spill slot to current */
3749
    /* split current before its first use position that requires a register */
3750
323
    ir_live_pos split_pos;
3751
3752
323
    if (next_use_pos == ival->range.start) {
3753
0
      IR_ASSERT(ival->use_pos && ival->use_pos->op_num == 0);
3754
      /* split right after definition */
3755
0
      split_pos = next_use_pos + 1;
3756
323
    } else {
3757
323
      split_pos = ir_find_optimal_split_position(ctx, ival, ival->range.start, next_use_pos - 1, 1);
3758
323
    }
3759
3760
323
    if (split_pos > ival->range.start) {
3761
323
      IR_LOG_LSRA("    ---- Conflict with others", ival, " (all others are used before)");
3762
323
      other = ir_split_interval_at(ctx, ival, split_pos);
3763
323
      IR_LOG_LSRA("    ---- Spill", ival, "");
3764
323
      ir_add_to_unhandled(unhandled, other);
3765
323
      IR_LOG_LSRA("    ---- Queue", other, "");
3766
323
      return IR_REG_NONE;
3767
323
    }
3768
323
  }
3769
3770
5
  if (ival->end > block_pos) {
3771
    /* spilling make a register free only for the first part of current */
3772
5
    IR_LOG_LSRA("    ---- Conflict with others", ival, " (spilling make a register free only for the first part)");
3773
    /* split current at optimal position before block_pos[reg] */
3774
5
    ir_live_pos split_pos = ir_last_use_pos_before(ival,  block_pos + 1,
3775
5
      IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3776
5
    if (split_pos == 0) {
3777
0
      split_pos = ir_first_use_pos_after(ival, block_pos,
3778
0
        IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG) - 1;
3779
0
      other = ir_split_interval_at(ctx, ival, split_pos);
3780
0
      ir_add_to_unhandled(unhandled, other);
3781
0
      IR_LOG_LSRA("      ---- Queue", other, "");
3782
0
      return IR_REG_NONE;
3783
0
    }
3784
5
    if (split_pos >= block_pos) {
3785
0
try_next_available_register:
3786
0
      IR_REGSET_EXCL(available, reg);
3787
#if IR_X86_I64
3788
      if (reg_hi != IR_REG_NONE) IR_REGSET_EXCL(available, reg_hi);
3789
#endif
3790
0
      if (IR_REGSET_IS_EMPTY(available)) {
3791
0
        fprintf(stderr, "LSRA Internal Error: Unsolvable conflict. Allocation is not possible\n");
3792
0
        IR_ASSERT(0);
3793
0
        exit(-1);
3794
0
      }
3795
0
      IR_LOG_LSRA("      ---- Restart", ival, "");
3796
0
      goto select_register;
3797
0
    }
3798
5
    split_pos = ir_find_optimal_split_position(ctx, ival, split_pos, block_pos, 1);
3799
5
    other = ir_split_interval_at(ctx, ival, split_pos);
3800
5
    ir_add_to_unhandled(unhandled, other);
3801
5
    IR_LOG_LSRA("      ---- Queue", other, "");
3802
5
  }
3803
3804
  /* spill intervals that currently block reg */
3805
5
  prev = NULL;
3806
5
  other = *active;
3807
5
  while (other) {
3808
0
    ir_live_pos split_pos;
3809
3810
#if IR_X86_I64
3811
    if (reg == other->reg || reg == other->reg_hi
3812
     || (reg_hi != IR_REG_NONE && (reg_hi == other->reg || reg_hi == other->reg_hi))) {
3813
#else
3814
0
    if (reg == other->reg) {
3815
0
#endif
3816
      /* split active interval for reg at position */
3817
0
      ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
3818
3819
0
      if (overlap) {
3820
0
        ir_live_interval *child, *child2;
3821
3822
0
        IR_ASSERT(other->type != IR_VOID);
3823
0
        IR_LOG_LSRA_CONFLICT("      ---- Conflict with active", other, overlap);
3824
3825
0
        split_pos = ir_last_use_pos_before(other, ival->range.start, IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
3826
0
        if (split_pos) {
3827
0
          split_pos = ir_find_optimal_split_position(ctx, other, split_pos, ival->range.start, 1);
3828
0
          if (split_pos > other->range.start) {
3829
0
            child = ir_split_interval_at(ctx, other, split_pos);
3830
0
            if (prev) {
3831
0
              prev->list_next = other->list_next;
3832
0
            } else {
3833
0
              *active = other->list_next;
3834
0
            }
3835
0
            IR_LOG_LSRA("      ---- Finish", other, "");
3836
0
          } else {
3837
0
            goto try_next_available_register;
3838
0
          }
3839
0
        } else {
3840
0
          child = other;
3841
0
        }
3842
3843
0
        split_pos = ir_first_use_pos_after(child, ival->range.start, IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG) - 1; // TODO: ???
3844
0
        if (split_pos > child->range.start && split_pos < child->end) {
3845
0
          if (child == other) {
3846
0
            other->reg = IR_REG_NONE;
3847
#if IR_X86_I64
3848
            other->reg_hi = IR_REG_NONE;
3849
#endif
3850
0
            if (prev) {
3851
0
              prev->list_next = other->list_next;
3852
0
            } else {
3853
0
              *active = other->list_next;
3854
0
            }
3855
0
          }
3856
0
          ir_live_pos opt_split_pos = ir_find_optimal_split_position(ctx, child, ival->range.start, split_pos, 1);
3857
0
          if (opt_split_pos > child->range.start) {
3858
0
            split_pos = opt_split_pos;
3859
0
          }
3860
0
          child2 = ir_split_interval_at(ctx, child, split_pos);
3861
0
          IR_LOG_LSRA("      ---- Spill", child, "");
3862
0
          ir_add_to_unhandled(unhandled, child2);
3863
0
          IR_LOG_LSRA("      ---- Queue", child2, "");
3864
0
        } else if (child != other) {
3865
          // TODO: this may cause endless loop
3866
0
          ir_add_to_unhandled(unhandled, child);
3867
0
          IR_LOG_LSRA("      ---- Queue", child, "");
3868
0
        } else {
3869
0
          goto try_next_available_register;
3870
0
        }
3871
0
      }
3872
#if IR_X86_I64
3873
      other = other->list_next;
3874
      continue;
3875
#else
3876
0
      break;
3877
0
#endif
3878
0
    }
3879
0
    prev = other;
3880
0
    other = other->list_next;
3881
0
  }
3882
3883
  /* split any inactive interval for reg at the end of its lifetime hole */
3884
5
  other = *inactive;
3885
24
  while (other) {
3886
    /* freeUntilPos[it.reg] = next intersection of it with current */
3887
#if IR_X86_I64
3888
    if (reg == other->reg || reg == other->reg_hi
3889
     || (reg_hi != IR_REG_NONE && (reg_hi == other->reg || reg_hi == other->reg_hi))) {
3890
#else
3891
19
    if (reg == other->reg) {
3892
0
#endif
3893
0
      ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
3894
3895
0
      if (overlap) {
3896
0
        ir_live_interval *child;
3897
3898
0
        IR_ASSERT(other->type != IR_VOID);
3899
0
        IR_LOG_LSRA_CONFLICT("      ---- Conflict with inactive", other, overlap);
3900
        // TODO: optimal split position (this case is not tested)
3901
0
        child = ir_split_interval_at(ctx, other, overlap);
3902
        /* reset range cache */
3903
0
        other->current_range = &other->range;
3904
0
        ir_add_to_unhandled(unhandled, child);
3905
0
        IR_LOG_LSRA("      ---- Queue", child, "");
3906
0
      }
3907
0
    }
3908
19
    other = other->list_next;
3909
19
  }
3910
3911
  /* current.reg = reg */
3912
5
  ival->reg = reg;
3913
#if IR_X86_I64
3914
  ival->reg_hi = reg_hi;
3915
#endif
3916
5
  IR_LOG_LSRA_ASSIGN("    ---- Assign", ival, " (after splitting others)");
3917
3918
5
  if (*unhandled && ival->end > (*unhandled)->range.start) {
3919
0
    ival->list_next = *active;
3920
0
    *active = ival;
3921
0
  }
3922
5
  return reg;
3923
5
}
3924
3925
static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival)
3926
0
{
3927
0
  ir_use_pos *use_pos = ival->use_pos;
3928
3929
0
  if (ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) {
3930
0
    IR_ASSERT(!ival->next && use_pos && use_pos->op_num == 0);
3931
0
#if IR_DEBUG
3932
0
    ir_insn *insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)];
3933
0
    IR_ASSERT(insn->op == IR_PARAM);
3934
0
#endif
3935
0
    use_pos = use_pos->next;
3936
0
    if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) {
3937
0
      return 0;
3938
0
    }
3939
3940
0
    if (use_pos) {
3941
0
      ir_block *bb = ir_block_from_live_pos(ctx, use_pos->pos);
3942
0
      if (bb->loop_depth) {
3943
0
        return 0;
3944
0
      }
3945
0
    }
3946
3947
0
    return 1;
3948
0
  }
3949
0
  return 0;
3950
0
}
3951
3952
static void ir_assign_bound_spill_slots(ir_ctx *ctx)
3953
0
{
3954
0
  ir_hashtab_bucket *b = ctx->binding->data;
3955
0
  uint32_t n = ctx->binding->count;
3956
0
  int32_t v;
3957
0
  ir_live_interval *ival;
3958
3959
0
  while (n > 0) {
3960
0
    v = ctx->vregs[b->key];
3961
0
    if (v > 0) {
3962
0
      ival = ctx->live_intervals[v];
3963
0
      if (ival
3964
0
       && ival->stack_spill_pos == -1
3965
0
       && (ival->next || ival->reg == IR_REG_NONE)) {
3966
0
        IR_ASSERT(b->val < 0);
3967
        /* special spill slot */
3968
0
        ival->stack_spill_pos = -b->val;
3969
0
        ival->flags |= IR_LIVE_INTERVAL_SPILLED | IR_LIVE_INTERVAL_SPILL_SPECIAL;
3970
0
      }
3971
0
    }
3972
0
    b++;
3973
0
    n--;
3974
0
  }
3975
0
}
3976
3977
static int ir_linear_scan(ir_ctx *ctx, ir_ref vars)
3978
9.93k
{
3979
9.93k
  uint32_t b;
3980
9.93k
  ir_block *bb;
3981
9.93k
  ir_live_interval *unhandled = NULL;
3982
9.93k
  ir_live_interval *active = NULL;
3983
9.93k
  ir_live_interval *inactive = NULL;
3984
9.93k
  ir_live_interval *ival, *other, *prev;
3985
9.93k
  int j;
3986
9.93k
  ir_live_pos position;
3987
9.93k
  ir_reg reg;
3988
3989
9.93k
  if (!ctx->live_intervals) {
3990
0
    return 0;
3991
0
  }
3992
3993
9.93k
  if (ctx->flags2 & IR_LR_HAVE_DESSA_MOVES) {
3994
    /* Add fixed intervals for temporary registers used for DESSA moves */
3995
75.1k
    for (b = ctx->cfg_blocks_count, bb = &ctx->cfg_blocks[b]; b > 0; b--, bb--) {
3996
73.8k
      IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
3997
73.8k
      if (bb->flags & IR_BB_DESSA_MOVES) {
3998
3.79k
        ir_tmp_reg tmp_reg;
3999
4000
3.79k
        if (bb->flags & IR_BB_DESSA_TMP_INT) {
4001
3.79k
          tmp_reg.num = 0;
4002
3.79k
          tmp_reg.type = IR_U32; // ???
4003
3.79k
          tmp_reg.start = IR_USE_SUB_REF;
4004
3.79k
          tmp_reg.end = IR_SAVE_SUB_REF;
4005
3.79k
          ir_add_tmp(ctx, bb->end, bb->end, tmp_reg.num, tmp_reg);
4006
3.79k
        }
4007
3.79k
        if (bb->flags & IR_BB_DESSA_TMP_FP) {
4008
0
          tmp_reg.num = 1;
4009
0
          tmp_reg.type = IR_DOUBLE; // ???
4010
0
          tmp_reg.start = IR_USE_SUB_REF;
4011
0
          tmp_reg.end = IR_SAVE_SUB_REF;
4012
0
          ir_add_tmp(ctx, bb->end, bb->end, tmp_reg.num, tmp_reg);
4013
0
        }
4014
3.79k
      }
4015
73.8k
    }
4016
1.36k
  }
4017
4018
9.93k
  while (vars) {
4019
0
    ir_ref var = vars;
4020
0
    ir_insn *insn = &ctx->ir_base[var];
4021
4022
0
    IR_ASSERT(insn->op == IR_VAR || insn->op == IR_ALLOCA);
4023
0
    vars = IR_VREG_TO_STACK_SLOT(ctx->vregs[var]); /* list next */
4024
4025
0
    if (insn->op == IR_VAR) {
4026
0
      ir_ref slot;
4027
0
      ir_use_list *use_list;
4028
0
      ir_ref n, *p;
4029
0
      size_t size = ir_get_type_size(insn->type);
4030
0
      size_t align = insn->op3;
4031
4032
0
#if IR_SIMD
4033
0
      if (IR_IS_TYPE_VECTOR(insn->type) && size < 4) {
4034
0
        size = 4;
4035
0
        align = IR_MAX(align, 4);
4036
0
      }
4037
0
#endif
4038
0
      slot = ir_allocate_spill_slot(ctx, size, align);
4039
0
      ctx->vregs[var] = IR_STACK_SLOT_TO_VREG(slot);
4040
0
      use_list = &ctx->use_lists[var];
4041
0
      n = use_list->count;
4042
0
      p = &ctx->use_edges[use_list->refs];
4043
0
      for (; n > 0; p++, n--) {
4044
0
        insn = &ctx->ir_base[*p];
4045
0
        if (insn->op == IR_VADDR) {
4046
0
          ctx->vregs[*p] = IR_STACK_SLOT_TO_VREG(slot);
4047
0
        }
4048
0
      }
4049
0
    } else {
4050
0
      ir_insn *val = &ctx->ir_base[insn->op2];
4051
0
      int32_t offset;
4052
4053
0
      IR_ASSERT(IR_IS_CONST_REF(insn->op2));
4054
0
      IR_ASSERT(IR_IS_TYPE_INT(val->type));
4055
0
      IR_ASSERT(!IR_IS_SYM_CONST(val->op));
4056
0
      IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 >= 0);
4057
0
      IR_ASSERT(val->val.i64 < 0x7fffffff);
4058
4059
0
      offset = ir_allocate_spill_slot(ctx, val->val.i32, insn->op3);
4060
0
      ctx->vregs[var] = IR_STACK_SLOT_TO_VREG(offset);
4061
0
    }
4062
0
  }
4063
4064
150k
  for (j = ctx->vregs_count; j != 0; j--) {
4065
140k
    ival = ctx->live_intervals[j];
4066
140k
    if (ival) {
4067
140k
      if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)
4068
140k
          || !ir_ival_spill_for_fuse_load(ctx, ival)) {
4069
140k
        ir_add_to_unhandled(&unhandled, ival);
4070
140k
      }
4071
140k
    }
4072
140k
  }
4073
4074
9.93k
  ival = ctx->live_intervals[0];
4075
9.93k
  if (ival) {
4076
9.54k
    ir_merge_to_unhandled(&unhandled, ival);
4077
9.54k
  }
4078
4079
  /* vregs + tmp + fixed + ALL + SCRATCH_N */
4080
367k
  for (j = ctx->vregs_count + 1; j <= ctx->vregs_count + IR_REG_SET_NUM; j++) {
4081
357k
    ival = ctx->live_intervals[j];
4082
357k
    if (ival) {
4083
31.6k
      ival->current_range = &ival->range;
4084
31.6k
      ival->list_next = inactive;
4085
31.6k
      inactive = ival;
4086
31.6k
    }
4087
357k
  }
4088
4089
9.93k
  ctx->flags2 &= ~(IR_RA_HAVE_SPLITS|IR_RA_HAVE_SPILLS);
4090
4091
9.93k
#ifdef IR_DEBUG
4092
9.93k
  if (ctx->flags & IR_DEBUG_RA) {
4093
0
    fprintf(stderr, "----\n");
4094
0
    ir_dump_live_ranges(ctx, stderr);
4095
0
    fprintf(stderr, "---- Start LSRA\n");
4096
0
  }
4097
9.93k
#endif
4098
4099
247k
  while (unhandled) {
4100
237k
    ival = unhandled;
4101
237k
    ival->current_range = &ival->range;
4102
237k
    unhandled = ival->list_next;
4103
237k
    position = ival->range.start;
4104
4105
237k
    IR_LOG_LSRA("  ---- Processing", ival, "...");
4106
4107
    /* for each interval i in active */
4108
237k
    other = active;
4109
237k
    prev = NULL;
4110
398k
    while (other) {
4111
161k
      ir_live_range *r = other->current_range;
4112
4113
161k
      IR_ASSERT(r);
4114
161k
      if (r->end <= position) {
4115
81.0k
        do {
4116
81.0k
          r = r->next;
4117
81.0k
        } while (r && r->end <= position);
4118
61.3k
        if (!r) {
4119
          /* move i from active to handled */
4120
41.2k
          other = other->list_next;
4121
41.2k
          if (prev) {
4122
10.7k
            prev->list_next = other;
4123
30.5k
          } else {
4124
30.5k
            active = other;
4125
30.5k
          }
4126
41.2k
          continue;
4127
41.2k
        }
4128
20.0k
        other->current_range = r;
4129
20.0k
      }
4130
120k
      if (position < r->start) {
4131
        /* move i from active to inactive */
4132
13.0k
        if (prev) {
4133
654
          prev->list_next = other->list_next;
4134
12.4k
        } else {
4135
12.4k
          active = other->list_next;
4136
12.4k
        }
4137
13.0k
        other->list_next = inactive;
4138
13.0k
        inactive = other;
4139
107k
      } else {
4140
107k
        prev = other;
4141
107k
      }
4142
120k
      other = prev ? prev->list_next : active;
4143
120k
    }
4144
4145
    /* for each interval i in inactive */
4146
237k
    other = inactive;
4147
237k
    prev = NULL;
4148
1.02M
    while (other) {
4149
783k
      ir_live_range *r = other->current_range;
4150
4151
783k
      IR_ASSERT(r);
4152
783k
      if (r->end <= position) {
4153
213k
        do {
4154
213k
          r = r->next;
4155
213k
        } while (r && r->end <= position);
4156
195k
        if (!r) {
4157
          /* move i from inactive to handled */
4158
37.1k
          other = other->list_next;
4159
37.1k
          if (prev) {
4160
8.06k
            prev->list_next = other;
4161
29.0k
          } else {
4162
29.0k
            inactive = other;
4163
29.0k
          }
4164
37.1k
          continue;
4165
37.1k
        }
4166
157k
        other->current_range = r;
4167
157k
      }
4168
746k
      if (position >= r->start) {
4169
        /* move i from inactive to active */
4170
7.40k
        if (prev) {
4171
1.19k
          prev->list_next = other->list_next;
4172
6.21k
        } else {
4173
6.21k
          inactive = other->list_next;
4174
6.21k
        }
4175
7.40k
        other->list_next = active;
4176
7.40k
        active = other;
4177
739k
      } else {
4178
739k
        prev = other;
4179
739k
      }
4180
746k
      other = prev ? prev->list_next : inactive;
4181
746k
    }
4182
4183
237k
    reg = ir_try_allocate_free_reg(ctx, ival, &active, inactive, &unhandled);
4184
237k
    if (reg == IR_REG_NONE) {
4185
330
      reg = ir_allocate_blocked_reg(ctx, ival, &active, &inactive, &unhandled);
4186
330
    }
4187
237k
  }
4188
4189
#if 0 //def IR_DEBUG
4190
  /* all intervals must be processed */
4191
  ival = active;
4192
  while (ival) {
4193
    IR_ASSERT(!ival->next);
4194
    ival = ival->list_next;
4195
  }
4196
  ival = inactive;
4197
  while (ival) {
4198
    IR_ASSERT(!ival->next);
4199
    ival = ival->list_next;
4200
  }
4201
#endif
4202
4203
9.93k
  if (ctx->flags2 & (IR_RA_HAVE_SPLITS|IR_RA_HAVE_SPILLS)) {
4204
4205
225
    if (ctx->binding) {
4206
0
      ir_assign_bound_spill_slots(ctx);
4207
0
    }
4208
4209
    /* Use simple linear-scan (without holes) to allocate and reuse spill slots */
4210
225
    unhandled = NULL;
4211
9.07k
    for (j = ctx->vregs_count; j != 0; j--) {
4212
8.85k
      ival = ctx->live_intervals[j];
4213
8.85k
      if (ival
4214
8.85k
       && (ival->next || ival->reg == IR_REG_NONE)
4215
325
       && ival->stack_spill_pos == -1) {
4216
325
        ival->flags |= IR_LIVE_INTERVAL_SPILLED;
4217
325
        if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) {
4218
325
          ir_live_range *r;
4219
4220
325
          other = ival;
4221
973
          while (other->next) {
4222
648
            other = other->next;
4223
648
          }
4224
325
          r = &other->range;
4225
325
          while (r->next) {
4226
0
            r = r->next;
4227
0
          }
4228
325
          ival->end = r->end;
4229
325
          ir_add_to_unhandled_spill(&unhandled, ival);
4230
325
        }
4231
325
      }
4232
8.85k
    }
4233
225
    if (unhandled) {
4234
225
      ir_live_interval *handled[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
4235
225
      ir_live_interval *old;
4236
4237
225
      ((ir_reg_alloc_data*)(ctx->data))->handled = handled;
4238
225
      active = NULL;
4239
550
      while (unhandled) {
4240
325
        ival = unhandled;
4241
325
        ival->current_range = &ival->range;
4242
325
        unhandled = ival->list_next;
4243
325
        position = ival->range.start;
4244
4245
        /* for each interval i in active */
4246
325
        other = active;
4247
325
        prev = NULL;
4248
325
        while (other) {
4249
0
          if (other->end <= position) {
4250
            /* move i from active to handled */
4251
0
            if (prev) {
4252
0
              prev->list_next = other->list_next;
4253
0
            } else {
4254
0
              active = other->list_next;
4255
0
            }
4256
4257
0
            uint8_t n, size = ir_get_type_size(other->type);
4258
4259
0
            IR_ASSERT(size == 1 || size == 2 || size == 4 || size == 8 || size == 16 || size == 32 || size == 64);
4260
0
            n = ir_ntz(size);
4261
0
            old = handled[n];
4262
0
            while (old) {
4263
0
              if (old->stack_spill_pos == other->stack_spill_pos) {
4264
0
                break;
4265
0
              }
4266
0
              old = old->list_next;
4267
0
            }
4268
0
            if (!old) {
4269
0
              other->list_next = handled[n];
4270
0
              handled[n] = other;
4271
0
            }
4272
0
          } else {
4273
0
            prev = other;
4274
0
          }
4275
0
          other = prev ? prev->list_next : active;
4276
0
        }
4277
4278
325
        size_t size = ir_get_type_size(ival->type);
4279
325
#if IR_SIMD
4280
325
        if (IR_IS_TYPE_VECTOR(ival->type) && size < 4) {
4281
0
          size = 4;
4282
0
        }
4283
325
#endif
4284
325
        ival->stack_spill_pos = ir_allocate_spill_slot(ctx, size, 0);
4285
325
        if (unhandled && ival->end > unhandled->range.start) {
4286
0
          ival->list_next = active;
4287
0
          active = ival;
4288
325
        } else {
4289
325
          uint32_t n, size = ir_get_type_size(ival->type);
4290
4291
325
          IR_ASSERT(size == 1 || size == 2 || size == 4 || size == 8 || size == 16 || size == 32 || size == 64);
4292
325
          n = ir_ntz(size);
4293
325
          old = handled[n];
4294
325
          while (old) {
4295
0
            if (old->stack_spill_pos == ival->stack_spill_pos) {
4296
0
              break;
4297
0
            }
4298
0
            old = old->list_next;
4299
0
          }
4300
325
          if (!old) {
4301
325
            ival->list_next = handled[n];
4302
325
            handled[n] = ival;
4303
325
          }
4304
325
        }
4305
325
      }
4306
225
      ((ir_reg_alloc_data*)(ctx->data))->handled = NULL;
4307
225
    }
4308
225
  }
4309
4310
#ifdef IR_TARGET_X86
4311
  if (ctx->flags2 & IR_HAS_FP_RET_SLOT) {
4312
    ctx->ret_slot = ir_allocate_spill_slot(ctx, ir_type_size[IR_DOUBLE], 0);
4313
  } else if ((ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE)
4314
      && ((ir_reg_alloc_data*)(ctx->data))->cc->fp_ret_reg == IR_REG_NONE) {
4315
    ctx->ret_slot = ir_allocate_spill_slot(ctx, ir_type_size[ctx->ret_type], 0);
4316
  } else {
4317
    ctx->ret_slot = -1;
4318
  }
4319
#endif
4320
4321
9.93k
#ifdef IR_DEBUG
4322
9.93k
  if (ctx->flags & IR_DEBUG_RA) {
4323
0
    fprintf(stderr, "---- Finish LSRA\n");
4324
0
    ir_dump_live_ranges(ctx, stderr);
4325
0
    fprintf(stderr, "----\n");
4326
0
  }
4327
9.93k
#endif
4328
4329
9.93k
  return 1;
4330
9.93k
}
4331
4332
static bool needs_spill_reload(ir_ctx *ctx, ir_live_interval *ival, uint32_t b0, ir_bitset available)
4333
323
{
4334
323
    ir_worklist worklist;
4335
323
  ir_block *bb;
4336
323
  uint32_t b, *p, n;
4337
4338
323
  ir_worklist_init(&worklist, ctx->cfg_blocks_count + 1);
4339
323
  ir_worklist_push(&worklist, b0);
4340
323
  while (ir_worklist_len(&worklist) != 0) {
4341
323
    b = ir_worklist_pop(&worklist);
4342
323
        bb = &ctx->cfg_blocks[b];
4343
323
    if (bb->flags & (IR_BB_ENTRY|IR_BB_START)) {
4344
3
      ir_worklist_free(&worklist);
4345
3
      return 1;
4346
3
    }
4347
320
    n = bb->predecessors_count;
4348
320
    for (p = &ctx->cfg_edges[bb->predecessors]; n > 0; p++, n--) {
4349
320
      b = *p;
4350
320
      bb = &ctx->cfg_blocks[b];
4351
4352
320
      if (!ir_ival_covers(ival, IR_SAVE_LIVE_POS_FROM_REF(bb->end))) {
4353
320
        ir_worklist_free(&worklist);
4354
320
        return 1;
4355
320
      } else if (!ir_bitset_in(available, b)) {
4356
0
        ir_worklist_push(&worklist, b);
4357
0
      }
4358
320
    }
4359
320
  }
4360
0
  ir_worklist_free(&worklist);
4361
0
  return 0;
4362
323
}
4363
4364
static bool needs_spill_load(ir_ctx *ctx, ir_live_interval *ival, ir_use_pos *use_pos)
4365
0
{
4366
0
  if (use_pos->next
4367
0
   && use_pos->op_num == 1
4368
0
   && use_pos->next->pos == use_pos->pos
4369
0
   && !(use_pos->next->flags & IR_USE_MUST_BE_IN_REG)) {
4370
    /* Support for R2 = ADD(R1, R1) */
4371
0
    use_pos = use_pos->next;
4372
0
  }
4373
0
  return use_pos->next && use_pos->next->op_num != 0;
4374
0
}
4375
4376
static void assign_regs(ir_ctx *ctx)
4377
9.93k
{
4378
9.93k
  ir_ref i;
4379
9.93k
  ir_live_interval *ival, *top_ival;
4380
9.93k
  ir_use_pos *use_pos;
4381
9.93k
  int8_t reg, old_reg;
4382
9.93k
  ir_ref ref;
4383
9.93k
  ir_regset used_regs = 0;
4384
4385
9.93k
  if (!ctx->regs) {
4386
0
    ctx->regs = ir_mem_malloc(sizeof(ir_regs) * ctx->insns_count);
4387
0
    memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count);
4388
0
  }
4389
4390
9.93k
  if (!(ctx->flags2 & (IR_RA_HAVE_SPLITS|IR_RA_HAVE_SPILLS))) {
4391
141k
    for (i = 1; i <= ctx->vregs_count; i++) {
4392
131k
      ival = ctx->live_intervals[i];
4393
131k
      if (ival) {
4394
131k
        do {
4395
131k
          if (ival->reg != IR_REG_NONE) {
4396
131k
            reg = ival->reg;
4397
131k
            IR_REGSET_INCL(used_regs, reg);
4398
#if IR_X86_I64
4399
            if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
4400
              IR_ASSERT(ival->reg_hi != IR_REG_NONE);
4401
              IR_REGSET_INCL(used_regs, ival->reg_hi);
4402
              reg = IR_REG_I64_PAIR(reg, ival->reg_hi);
4403
            }
4404
#endif
4405
131k
            use_pos = ival->use_pos;
4406
612k
            while (use_pos) {
4407
480k
              ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos);
4408
480k
              ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4409
480k
              use_pos = use_pos->next;
4410
480k
            }
4411
131k
          }
4412
131k
          ival = ival->next;
4413
131k
        } while (ival);
4414
131k
      }
4415
131k
    }
4416
9.71k
  } else {
4417
225
    ir_bitset available = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
4418
4419
9.07k
    for (i = 1; i <= ctx->vregs_count; i++) {
4420
8.85k
      top_ival = ival = ctx->live_intervals[i];
4421
8.85k
      if (ival) {
4422
8.85k
        if (!(ival->flags & IR_LIVE_INTERVAL_SPILLED)) {
4423
8.52k
          do {
4424
8.52k
            if (ival->reg != IR_REG_NONE) {
4425
8.52k
              reg = ival->reg;
4426
8.52k
              IR_REGSET_INCL(used_regs, reg);
4427
#if IR_X86_I64
4428
              if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
4429
                IR_ASSERT(ival->reg_hi != IR_REG_NONE);
4430
                IR_REGSET_INCL(used_regs, ival->reg_hi);
4431
                reg = IR_REG_I64_PAIR(reg, ival->reg_hi);
4432
              }
4433
#endif
4434
8.52k
              use_pos = ival->use_pos;
4435
37.7k
              while (use_pos) {
4436
29.1k
                ref = IR_LIVE_POS_TO_REF(use_pos->pos);
4437
29.1k
                if (use_pos->hint_ref < 0) {
4438
7.27k
                  ref = -use_pos->hint_ref;
4439
7.27k
                }
4440
29.1k
                ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4441
4442
29.1k
                use_pos = use_pos->next;
4443
29.1k
              }
4444
8.52k
            }
4445
8.52k
            ival = ival->next;
4446
8.52k
          } while (ival);
4447
8.52k
        } else {
4448
973
          do {
4449
973
            if (ival->reg != IR_REG_NONE) {
4450
648
              ir_ref prev_use_ref = IR_UNUSED;
4451
648
              int8_t reg0;
4452
4453
648
              ir_bitset_clear(available, ir_bitset_len(ctx->cfg_blocks_count + 1));
4454
648
              reg0 = ival->reg;
4455
648
              IR_REGSET_INCL(used_regs, reg0);
4456
#if IR_X86_I64
4457
              if (ival->flags & IR_LIVE_INTERVAL_TWO_REGS) {
4458
                IR_ASSERT(ival->reg_hi != IR_REG_NONE);
4459
                IR_REGSET_INCL(used_regs, ival->reg_hi);
4460
                reg0 = IR_REG_I64_PAIR(reg0, ival->reg_hi);
4461
              }
4462
#endif
4463
648
              use_pos = ival->use_pos;
4464
1.93k
              while (use_pos) {
4465
1.29k
                reg = reg0;
4466
1.29k
                ref = IR_LIVE_POS_TO_REF(use_pos->pos);
4467
                // TODO: Insert spill loads and stores in optimal positions (resolution)
4468
1.29k
                if (use_pos->op_num == 0) {
4469
325
                  if ((ctx->ir_base[ref].op == IR_COPY
4470
325
                    || ctx->ir_base[ref].op == IR_BITCAST
4471
325
                    || ctx->ir_base[ref].op == IR_TRUNC)
4472
0
                   && !IR_IS_CONST_REF(ctx->ir_base[ref].op1)
4473
0
                   && ctx->vregs[ctx->ir_base[ref].op1] == i) {
4474
                    /* register reuse */
4475
0
                    ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4476
0
                    prev_use_ref = ref;
4477
0
                    use_pos = use_pos->next;
4478
0
                    continue;
4479
0
                  }
4480
325
                  ir_bitset_clear(available, ir_bitset_len(ctx->cfg_blocks_count + 1));
4481
325
                  if (ctx->ir_base[ref].op == IR_PHI) {
4482
                    /* Spilled PHI var is passed through memory */
4483
0
                    reg = IR_REG_NONE;
4484
0
                    prev_use_ref = IR_UNUSED;
4485
325
                  } else if (ctx->ir_base[ref].op == IR_PARAM
4486
0
                   && (ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) {
4487
                    /* Stack PARAM var is passed through memory */
4488
0
                    reg = IR_REG_NONE;
4489
325
                  } else {
4490
325
                    uint32_t use_b = ctx->cfg_map[ref];
4491
4492
325
                    if (ir_ival_covers(ival, IR_SAVE_LIVE_POS_FROM_REF(ctx->cfg_blocks[use_b].end))) {
4493
320
                      ir_bitset_incl(available, use_b);
4494
320
                    }
4495
325
                    if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) {
4496
0
                      reg |= IR_REG_SPILL_SPECIAL;
4497
325
                    } else {
4498
325
                      reg |= IR_REG_SPILL_STORE;
4499
325
                    }
4500
325
                    prev_use_ref = ref;
4501
325
                  }
4502
965
                } else {
4503
965
                  if ((!prev_use_ref || ctx->cfg_map[prev_use_ref] != ctx->cfg_map[ref])
4504
323
                   && needs_spill_reload(ctx, ival, ctx->cfg_map[ref], available)) {
4505
323
                    if (!(use_pos->flags & IR_USE_MUST_BE_IN_REG)
4506
//                     && ctx->ir_base[ref].op != IR_CALL
4507
//                     && ctx->ir_base[ref].op != IR_TAILCALL) {
4508
0
                     && ctx->ir_base[ref].op != IR_SNAPSHOT
4509
0
                     && !needs_spill_load(ctx, ival, use_pos)) {
4510
                      /* fuse spill load (valid only when register is not reused) */
4511
0
                      reg = IR_REG_NONE;
4512
0
                      if (use_pos->next
4513
0
                       && use_pos->op_num == 1
4514
0
                       && use_pos->next->pos == use_pos->pos
4515
0
                       && !(use_pos->next->flags & IR_USE_MUST_BE_IN_REG)) {
4516
                        /* Support for R2 = BINOP(R1, R1) */
4517
0
                        if (use_pos->hint_ref < 0) {
4518
0
                          ref = -use_pos->hint_ref;
4519
0
                        }
4520
0
                        ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4521
0
                        use_pos = use_pos->next;
4522
0
                      }
4523
323
                    } else {
4524
323
                      if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) {
4525
0
                        reg |= IR_REG_SPILL_SPECIAL;
4526
323
                      } else {
4527
323
                        reg |= IR_REG_SPILL_LOAD;
4528
323
                      }
4529
323
                      if (ctx->ir_base[ref].op != IR_SNAPSHOT && !(use_pos->flags & IR_PHI_USE)) {
4530
323
                        uint32_t use_b = ctx->cfg_map[ref];
4531
4532
323
                        if (ir_ival_covers(ival, IR_SAVE_LIVE_POS_FROM_REF(ctx->cfg_blocks[use_b].end))) {
4533
0
                          ir_bitset_incl(available, use_b);
4534
0
                        }
4535
323
                        prev_use_ref = ref;
4536
323
                      }
4537
323
                    }
4538
642
                  } else {
4539
                    /* reuse register without spill load */
4540
642
                  }
4541
4542
965
                  if (use_pos->hint_ref < 0) {
4543
820
                    if (use_pos->flags & IR_PHI_USE) {
4544
0
                      IR_ASSERT(use_pos->hint_ref < 0);
4545
0
                      IR_ASSERT(ctx->vregs[-use_pos->hint_ref] > 0);
4546
0
                      IR_ASSERT(ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]);
4547
0
                      if (ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]->flags & IR_LIVE_INTERVAL_SPILLED) {
4548
                        /* Spilled PHI var is passed through memory */
4549
0
                        reg = IR_REG_NONE;
4550
0
                      }
4551
820
                    } else {
4552
820
                      IR_ASSERT(ctx->rules[-use_pos->hint_ref] & IR_FUSED);
4553
820
                      old_reg = ir_get_alocated_reg(ctx, -use_pos->hint_ref, use_pos->op_num);
4554
820
                      if ((old_reg != IR_REG_NONE && reg != old_reg) || reg == IR_REG_NONE) {
4555
0
                        ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG;
4556
0
                        ir_set_fused_reg(ctx, ref, -use_pos->hint_ref, use_pos->op_num, reg);
4557
0
                        use_pos = use_pos->next;
4558
0
                        continue;
4559
0
                      }
4560
820
                    }
4561
820
                    ref = -use_pos->hint_ref;
4562
820
                  }
4563
965
                }
4564
4565
1.29k
                ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4566
4567
1.29k
                use_pos = use_pos->next;
4568
1.29k
              }
4569
648
            } else {
4570
325
              use_pos = ival->use_pos;
4571
331
              while (use_pos) {
4572
6
                ref = IR_LIVE_POS_TO_REF(use_pos->pos);
4573
6
                if (ctx->ir_base[ref].op == IR_SNAPSHOT
4574
4
                 && !(top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL)) {
4575
4
                  IR_ASSERT(use_pos->hint_ref >= 0);
4576
                  /* A reference to a CPU spill slot */
4577
4
                  reg = IR_REG_SPILL_STORE | IR_REG_STACK_POINTER;
4578
4
                  ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
4579
4
                } else if (use_pos->hint_ref < 0 && !(use_pos->flags & IR_PHI_USE)) {
4580
0
                  IR_ASSERT(ctx->rules[-use_pos->hint_ref] & IR_FUSED);
4581
0
                  ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG;
4582
0
                  ir_set_fused_reg(ctx, ref, -use_pos->hint_ref, use_pos->op_num, IR_REG_NONE);
4583
0
                }
4584
6
                use_pos = use_pos->next;
4585
6
              }
4586
325
            }
4587
973
            ival = ival->next;
4588
973
          } while (ival);
4589
325
        }
4590
8.85k
      }
4591
8.85k
    }
4592
225
    ir_mem_free(available);
4593
225
  }
4594
4595
  /* Temporary registers */
4596
9.93k
  ival = ctx->live_intervals[0];
4597
9.93k
  if (ival) {
4598
95.9k
    do {
4599
95.9k
      IR_ASSERT(ival->reg != IR_REG_NONE);
4600
95.9k
      IR_REGSET_INCL(used_regs, ival->reg);
4601
95.9k
      reg = ival->reg;
4602
95.9k
      if (ival->tmp_op_num > 0) {
4603
92.1k
        ir_insn *insn = &ctx->ir_base[ival->tmp_ref];
4604
4605
92.1k
        if (ival->tmp_op_num <= insn->inputs_count) {
4606
91.0k
          ir_ref *ops = insn->ops;
4607
4608
91.0k
          if (IR_IS_CONST_REF(ops[ival->tmp_op_num])) {
4609
            /* constant rematerialization */
4610
90.9k
            reg |= IR_REG_SPILL_LOAD;
4611
90.9k
          } else if (ctx->rules[ops[ival->tmp_op_num]] == IR_STATIC_ALLOCA
4612
0
              && IR_OPND_KIND(ir_op_flags[insn->op], ival->tmp_op_num) == IR_OPND_DATA) {
4613
            /* local address rematerialization */
4614
0
            reg |= IR_REG_SPILL_LOAD;
4615
0
          }
4616
91.0k
        }
4617
92.1k
      }
4618
95.9k
      ir_set_alocated_tmp_reg(ctx, ival->tmp_ref, ival->tmp_op_num, reg);
4619
95.9k
      ival = ival->next;
4620
95.9k
    } while (ival);
4621
9.54k
  }
4622
4623
9.93k
  const ir_call_conv_dsc *cc = ((ir_reg_alloc_data*)(ctx->data))->cc;
4624
9.93k
  if (ctx->fixed_stack_frame_size != -1) {
4625
9.90k
    ctx->used_preserved_regs = (ir_regset)ctx->fixed_save_regset;
4626
9.90k
    if (IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs),
4627
9.90k
      ctx->used_preserved_regs)) {
4628
      // TODO: Preserved reg and fixed frame conflict ???
4629
      // IR_ASSERT(0 && "Preserved reg and fixed frame conflict");
4630
4.13k
    }
4631
9.90k
  } else {
4632
36
    ctx->used_preserved_regs = IR_REGSET_UNION((ir_regset)ctx->fixed_save_regset,
4633
36
      IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs),
4634
36
        (ctx->flags & IR_FUNCTION) ? (ir_regset)ctx->fixed_regset : cc->preserved_regs));
4635
36
  }
4636
4637
9.93k
  ir_fix_stack_frame(ctx);
4638
9.93k
}
4639
4640
int ir_reg_alloc(ir_ctx *ctx)
4641
9.93k
{
4642
9.93k
  ir_reg_alloc_data data;
4643
9.93k
  ir_ref vars = ctx->vars;
4644
4645
9.93k
  data.cc = ir_get_call_conv_dsc(ctx->flags);
4646
9.93k
  data.unused_slot_4 = 0;
4647
9.93k
  data.unused_slot_2 = 0;
4648
9.93k
  data.unused_slot_1 = 0;
4649
9.93k
  data.handled = NULL;
4650
4651
9.93k
  ctx->data = &data;
4652
9.93k
  ctx->stack_frame_size = 0;
4653
4654
9.93k
  if (ir_linear_scan(ctx, vars)) {
4655
9.93k
    assign_regs(ctx);
4656
9.93k
    ctx->data = NULL;
4657
9.93k
    return 1;
4658
9.93k
  }
4659
4660
0
  ctx->data = NULL;
4661
0
  return 0;
4662
9.93k
}