// File: /workspace/github_c_makefile_star2_O0/cogbee[P]vmir-latest/src/vmir_transform.c
// Function: coalesce
static void
coalesce(ir_unit_t *iu,
         int setwords, int temp_values,
         int ffv, ir_function_t *f)
{
  // Interference Matrix
  uint32_t *mtx = tribitmtx_alloc(temp_values);
  ir_bb_t *ib;
  ir_instr_t *ii, *iin;

  /*
   * Any non-move instruction that defines variable 'a' add
   * interference edges for (a,{liveout})
   *
   * Any move instruction a <- b add interference for (a, {liveout} - b)
   *
   */
  TAILQ_FOREACH(ib, &f->if_bbs, ib_link) {
    TAILQ_FOREACH(ii, &ib->ib_instrs, ii_link) {
      if(ii->ii_ret.value == -1)
        continue;

      int num_ret_values;
      const ir_valuetype_t *ret_values;
      if(ii->ii_ret.value < -1) {
        ret_values = ii->ii_rets;
        num_ret_values = -ii->ii_ret.value;
      } else {
        ret_values = &ii->ii_ret;
        num_ret_values = 1;
      }
      int v = -1;

      if(ii->ii_class == IR_IC_MOVE)
        v = ((ir_instr_move_t *)ii)->value.value - ffv;

      const uint32_t *out = ii->ii_liveness;

      for(int a = 0; a < num_ret_values; a++) {
        int x = ret_values[a].value;
        ir_value_t *xval = value_get(iu, x);
        x-= ffv;
        int edges = 0;
        for(int j = 0; j < setwords; j++) {
          uint32_t w = out[j];
          while(w) {
            int b = ffs(w) - 1;
            int y = (j << 5) + b;
            w &= ~(1 << b);
            if(y != x && y != v) {
              if(!tribitmtx_get(mtx, x, y)) {
                tribitmtx_set(mtx, x, y);
                edges++;
                iu->iu_values.vh_p[y + ffv]->iv_edges++;
              }
            }
          }
        }
        xval->iv_edges += edges;
      }
    }
  }

  /*
   * Find values that can be coalesced.
   * Search for moves between two registers that do not interfere with
   * each other. For such cases we can say the registers are basically
   * the same, so we merge then. This process is called coalescing
   */

  TAILQ_FOREACH(ib, &f->if_bbs, ib_link) {
    for(ii = TAILQ_FIRST(&ib->ib_instrs); ii != NULL; ii = iin) {
      iin = TAILQ_NEXT(ii, ii_link);

      if(ii->ii_class == IR_IC_MOVE) {
        unsigned int v = ((ir_instr_move_t *)ii)->value.value;
        if(v < ffv)
          continue;
        ir_value_t *src = VECTOR_ITEM(&iu->iu_values, v);
        if(src->iv_class != IR_VC_TEMPORARY)
          continue;
        if(ii->ii_ret.value < -1)
          continue;

        ir_value_t *dst = VECTOR_ITEM(&iu->iu_values, ii->ii_ret.value);

        if(dst == src) {
          /*
           * Move from -> to same register
           * This happens when we coalesce two registers that are used
           * by a move different than the one that initiated the merge.
           * We could detect that when this happens but destroying
           * any instruction other than the current one will break
           * the TAILQ traversal
           */
          instr_destroy(ii);
          iu->iu_stats.moves_killed++;
          continue;
        }

        assert(dst->iv_class == IR_VC_TEMPORARY);

        if(dst->iv_precolored != -1 && src->iv_precolored != -1)
          continue;

        if(!tribitmtx_get(mtx, ii->ii_ret.value - ffv, v - ffv)) {
          ir_value_t *killed, *saved;

          if(src->iv_precolored != -1) {
            killed = dst;
            saved = src;
          } else {
            killed = src;
            saved = dst;
          }

          if(iu->iu_debug_flags_func & VMIR_DBG_DUMP_REGALLOC) {
            printf("Merging value %s -> %s based on instr: %s\n",
                   value_str(iu, killed),  value_str(iu, saved),
                   instr_str(iu, ii, 1));
          }

          ir_value_instr_t *ivi, *ivin;
          for(ivi = LIST_FIRST(&killed->iv_instructions); ivi != NULL;
              ivi = ivin) {
            ivin = LIST_NEXT(ivi, ivi_value_link);

            if(iu->iu_debug_flags_func & VMIR_DBG_DUMP_REGALLOC) {
              printf("\t Pre altering instruction %s\n",
                     instr_str(iu, ivi->ivi_instr, 1));
            }

            instr_replace_values(ivi->ivi_instr, iu, killed->iv_id,
                                 saved->iv_id);
            LIST_REMOVE(ivi, ivi_value_link);
            ivi->ivi_value = saved;
            LIST_INSERT_HEAD(&saved->iv_instructions, ivi, ivi_value_link);
#ifdef VMIR_VM_JIT
            if(!(iu->iu_debug_flags_func & VMIR_DBG_DISABLE_JIT)) {
              memset(ivi->ivi_instr->ii_liveness,
                     0, setwords * sizeof(uint32_t) * 3);
              liveness_set_gen(ivi->ivi_instr, iu,
                               ivi->ivi_instr->ii_liveness + setwords);
            }
#endif
            if(iu->iu_debug_flags_func & VMIR_DBG_DUMP_REGALLOC) {
              printf("\tPost altering instruction %s\n",
                     instr_str(iu, ivi->ivi_instr, 1));
            }
          }

          // Merge nodes in interference matrix
          for(int i = 0; i < temp_values; i++) {
            if(tribitmtx_get(mtx, killed->iv_id - ffv, i)) {
              tribitmtx_clr(mtx, killed->iv_id - ffv, i);

              if(!tribitmtx_get(mtx, saved->iv_id - ffv, i)) {
                tribitmtx_set(mtx, saved->iv_id - ffv, i);
                saved->iv_edges++;
              } else {
                iu->iu_values.vh_p[i + ffv]->iv_edges--;
              }
            }
          }

          killed->iv_edges = 0;
          killed->iv_class = IR_VC_DEAD;
          iu->iu_stats.moves_killed++;
          instr_destroy(ii);
        }
      }
    }
  }

  remove_empty_bb(iu, f);

#ifdef VMIR_VM_JIT
  if(!(iu->iu_debug_flags_func & VMIR_DBG_DISABLE_JIT)) {
    liveness_update(f, setwords, ffv);
    jit_analyze(iu, f, setwords, ffv);
  }
#endif

  reg_alloc(iu, mtx, temp_values, ffv, f);
  free(mtx);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movl %ecx, -0x14(%rbp)
movq %r8, -0x20(%rbp)
movl -0x10(%rbp), %edi
callq 0x2a5d0
movq %rax, -0x28(%rbp)
movq -0x20(%rbp), %rax
movq 0x48(%rax), %rax
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0x29e16
movq -0x30(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
je 0x29e04
movq -0x38(%rbp), %rax
cmpl $-0x1, 0x2c(%rax)
jne 0x29c55
jmp 0x29df4
movq -0x38(%rbp), %rax
cmpl $-0x1, 0x2c(%rax)
jge 0x29c79
movq -0x38(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x38(%rbp), %rcx
xorl %eax, %eax
subl 0x2c(%rcx), %eax
movl %eax, -0x44(%rbp)
jmp 0x29c8c
movq -0x38(%rbp), %rax
addq $0x2c, %rax
movq %rax, -0x50(%rbp)
movl $0x1, -0x44(%rbp)
movl $0xffffffff, -0x54(%rbp) # imm = 0xFFFFFFFF
movq -0x38(%rbp), %rax
cmpl $0x15, 0x28(%rax)
jne 0x29caa
movq -0x38(%rbp), %rax
movl 0x58(%rax), %eax
subl -0x14(%rbp), %eax
movl %eax, -0x54(%rbp)
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movq %rax, -0x60(%rbp)
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x44(%rbp), %eax
jge 0x29df2
movq -0x50(%rbp), %rax
movslq -0x64(%rbp), %rcx
movl (%rax,%rcx,8), %eax
movl %eax, -0x68(%rbp)
movq -0x8(%rbp), %rdi
movl -0x68(%rbp), %esi
callq 0x20ee0
movq %rax, -0x70(%rbp)
movl -0x14(%rbp), %ecx
movl -0x68(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x68(%rbp)
movl $0x0, -0x74(%rbp)
movl $0x0, -0x78(%rbp)
movl -0x78(%rbp), %eax
cmpl -0xc(%rbp), %eax
jge 0x29dd7
movq -0x60(%rbp), %rax
movslq -0x78(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x7c(%rbp)
cmpl $0x0, -0x7c(%rbp)
je 0x29dc7
movl -0x7c(%rbp), %edi
callq 0x3340
subl $0x1, %eax
movl %eax, -0x80(%rbp)
movl -0x78(%rbp), %eax
shll $0x5, %eax
addl -0x80(%rbp), %eax
movl %eax, -0x84(%rbp)
movl -0x80(%rbp), %ecx
movl $0x1, %eax
shll %cl, %eax
xorl $-0x1, %eax
andl -0x7c(%rbp), %eax
movl %eax, -0x7c(%rbp)
movl -0x84(%rbp), %eax
cmpl -0x68(%rbp), %eax
je 0x29dc2
movl -0x84(%rbp), %eax
cmpl -0x54(%rbp), %eax
je 0x29dc2
movq -0x28(%rbp), %rdi
movl -0x68(%rbp), %esi
movl -0x84(%rbp), %edx
callq 0x2a640
cmpl $0x0, %eax
jne 0x29dc0
movq -0x28(%rbp), %rdi
movl -0x68(%rbp), %esi
movl -0x84(%rbp), %edx
callq 0x2a680
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
movq -0x8(%rbp), %rax
movq 0x180(%rax), %rax
movl -0x84(%rbp), %ecx
addl -0x14(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movl 0x28(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x28(%rax)
jmp 0x29dc2
jmp 0x29d1a
jmp 0x29dc9
movl -0x78(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x78(%rbp)
jmp 0x29d00
movl -0x74(%rbp), %ecx
movq -0x70(%rbp), %rax
addl 0x28(%rax), %ecx
movl %ecx, 0x28(%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x29cbd
jmp 0x29df4
movq -0x38(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x38(%rbp)
jmp 0x29c3b
jmp 0x29e06
movq -0x30(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x29c24
movq -0x20(%rbp), %rax
movq 0x48(%rax), %rax
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0x2a2fc
movq -0x30(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
je 0x2a2ea
movq -0x38(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x40(%rbp)
movq -0x38(%rbp), %rax
cmpl $0x15, 0x28(%rax)
jne 0x2a2db
movq -0x38(%rbp), %rax
movl 0x58(%rax), %eax
movl %eax, -0x88(%rbp)
movl -0x88(%rbp), %eax
cmpl -0x14(%rbp), %eax
jae 0x29e7a
jmp 0x2a2dd
movq -0x8(%rbp), %rax
movq 0x180(%rax), %rax
movl -0x88(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
cmpl $0x4, (%rax)
je 0x29ea7
jmp 0x2a2dd
movq -0x38(%rbp), %rax
cmpl $-0x1, 0x2c(%rax)
jge 0x29eb6
jmp 0x2a2dd
movq -0x8(%rbp), %rax
movq 0x180(%rax), %rax
movq -0x38(%rbp), %rcx
movslq 0x2c(%rcx), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rax
cmpq -0x90(%rbp), %rax
jne 0x29f05
movq -0x38(%rbp), %rdi
callq 0x1cad0
movq -0x8(%rbp), %rax
movl 0x61c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x61c(%rax)
jmp 0x2a2dd
movq -0x98(%rbp), %rax
cmpl $0x4, (%rax)
jne 0x29f13
jmp 0x29f32
leaq 0x15e81(%rip), %rdi     # 0x3fd9b
leaq 0x154cc(%rip), %rsi     # 0x3f3ed
movl $0x7f4, %edx            # imm = 0x7F4
leaq 0x15e8f(%rip), %rcx     # 0x3fdbc
callq 0x31c0
movq -0x98(%rbp), %rax
cmpl $-0x1, 0x38(%rax)
je 0x29f51
movq -0x90(%rbp), %rax
cmpl $-0x1, 0x38(%rax)
je 0x29f51
jmp 0x2a2dd
movq -0x28(%rbp), %rdi
movq -0x38(%rbp), %rax
movl 0x2c(%rax), %esi
subl -0x14(%rbp), %esi
movl -0x88(%rbp), %edx
subl -0x14(%rbp), %edx
callq 0x2a640
cmpl $0x0, %eax
jne 0x2a2d9
movq -0x90(%rbp), %rax
cmpl $-0x1, 0x38(%rax)
je 0x29fa1
movq -0x98(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0xa8(%rbp)
jmp 0x29fbd
movq -0x90(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0x8(%rbp), %rax
movl 0x104(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x2a02e
movq -0x8(%rbp), %rdi
movq -0xa0(%rbp), %rsi
callq 0x264e0
movq %rax, -0xd0(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x264e0
movq %rax, -0xc8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x38(%rbp), %rsi
movl $0x1, %edx
callq 0x225c0
movq -0xd0(%rbp), %rsi
movq -0xc8(%rbp), %rdx
movq %rax, %rcx
leaq 0x15dd0(%rip), %rdi     # 0x3fdf7
movb $0x0, %al
callq 0x3170
movq -0xa0(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0xb0(%rbp)
cmpq $0x0, -0xb0(%rbp)
je 0x2a1bd
movq -0xb0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xb8(%rbp)
movq -0x8(%rbp), %rax
movl 0x104(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x2a09b
movq -0x8(%rbp), %rdi
movq -0xb0(%rbp), %rax
movq 0x28(%rax), %rsi
movl $0x1, %edx
callq 0x225c0
movq %rax, %rsi
leaq 0x15d8e(%rip), %rdi     # 0x3fe22
movb $0x0, %al
callq 0x3170
movq -0xb0(%rbp), %rax
movq 0x28(%rax), %rdi
movq -0x8(%rbp), %rsi
movq -0xa0(%rbp), %rax
movl 0x20(%rax), %edx
movq -0xa8(%rbp), %rax
movl 0x20(%rax), %ecx
callq 0x2a6c0
movq -0xb0(%rbp), %rax
cmpq $0x0, (%rax)
je 0x2a0e9
movq -0xb0(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0xb0(%rbp), %rax
movq (%rax), %rax
movq %rcx, 0x8(%rax)
movq -0xb0(%rbp), %rax
movq (%rax), %rcx
movq -0xb0(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, (%rax)
movq -0xa8(%rbp), %rcx
movq -0xb0(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0xa8(%rbp), %rax
movq 0x8(%rax), %rax
movq -0xb0(%rbp), %rcx
movq %rax, (%rcx)
cmpq $0x0, %rax
je 0x2a144
movq -0xb0(%rbp), %rcx
movq -0xa8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x8(%rax)
movq -0xb0(%rbp), %rcx
movq -0xa8(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0xa8(%rbp), %rcx
addq $0x8, %rcx
movq -0xb0(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x8(%rbp), %rax
movl 0x104(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x2a1a8
movq -0x8(%rbp), %rdi
movq -0xb0(%rbp), %rax
movq 0x28(%rax), %rsi
movl $0x1, %edx
callq 0x225c0
movq %rax, %rsi
leaq 0x15ca0(%rip), %rdi     # 0x3fe41
movb $0x0, %al
callq 0x3170
jmp 0x2a1aa
movq -0xb8(%rbp), %rax
movq %rax, -0xb0(%rbp)
jmp 0x2a040
movl $0x0, -0xbc(%rbp)
movl -0xbc(%rbp), %eax
cmpl -0x10(%rbp), %eax
jge 0x2a2a2
movq -0x28(%rbp), %rdi
movq -0xa0(%rbp), %rax
movl 0x20(%rax), %esi
subl -0x14(%rbp), %esi
movl -0xbc(%rbp), %edx
callq 0x2a640
cmpl $0x0, %eax
je 0x2a28c
movq -0x28(%rbp), %rdi
movq -0xa0(%rbp), %rax
movl 0x20(%rax), %esi
subl -0x14(%rbp), %esi
movl -0xbc(%rbp), %edx
callq 0x2aaf0
movq -0x28(%rbp), %rdi
movq -0xa8(%rbp), %rax
movl 0x20(%rax), %esi
subl -0x14(%rbp), %esi
movl -0xbc(%rbp), %edx
callq 0x2a640
cmpl $0x0, %eax
jne 0x2a266
movq -0x28(%rbp), %rdi
movq -0xa8(%rbp), %rax
movl 0x20(%rax), %esi
subl -0x14(%rbp), %esi
movl -0xbc(%rbp), %edx
callq 0x2a680
movq -0xa8(%rbp), %rax
movl 0x28(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x28(%rax)
jmp 0x2a28a
movq -0x8(%rbp), %rax
movq 0x180(%rax), %rax
movl -0xbc(%rbp), %ecx
addl -0x14(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movl 0x28(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x28(%rax)
jmp 0x2a28c
jmp 0x2a28e
movl -0xbc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xbc(%rbp)
jmp 0x2a1c7
movq -0xa0(%rbp), %rax
movl $0x0, 0x28(%rax)
movq -0xa0(%rbp), %rax
movl $0xc, (%rax)
movq -0x8(%rbp), %rax
movl 0x61c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x61c(%rax)
movq -0x38(%rbp), %rdi
callq 0x1cad0
jmp 0x2a2db
jmp 0x2a2dd
movq -0x40(%rbp), %rax
movq %rax, -0x38(%rbp)
jmp 0x29e39
jmp 0x2a2ec
movq -0x30(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x29e22
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x2ab30
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
movl -0x10(%rbp), %edx
movl -0x14(%rbp), %ecx
movq -0x20(%rbp), %r8
callq 0x2acd0
movq -0x28(%rbp), %rdi
callq 0x3030
addq $0xd0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)