// File: /workspace/github_c_makefile_star2_O2/google[P]multichase/permutation.c
// Function: generate_chase
void *generate_chase(const struct generate_chase_common_args *args,
                     size_t mixer_idx) {
  char *arena = args->arena;
  size_t total_memory = args->total_memory;
  size_t stride = args->stride;
  size_t tlb_locality = args->tlb_locality;
  void (*gen_permutation)(perm_t *, size_t, size_t) = args->gen_permutation;
  const perm_t *mixer = args->mixer + mixer_idx * args->nr_mixers;
  size_t nr_mixer_indices = args->nr_mixer_indices;

  size_t nr_tlb_groups = total_memory / tlb_locality;
  size_t nr_elts_per_tlb = tlb_locality / stride;
  size_t nr_elts = total_memory / stride;
  perm_t *tlb_perm;
  perm_t *perm;
  size_t i;
  perm_t *perm_inverse;
  size_t mixer_scale = stride / nr_mixer_indices;

  if (verbosity > 1)
    printf("generating permutation of %zu elements (in %zu TLB groups)\n",
           nr_elts, nr_tlb_groups);
  tlb_perm = malloc(nr_tlb_groups * sizeof(*tlb_perm));
  gen_permutation(tlb_perm, nr_tlb_groups, 0);
  perm = malloc(nr_elts * sizeof(*perm));
  for (i = 0; i < nr_tlb_groups; ++i) {
    gen_permutation(&perm[i * nr_elts_per_tlb], nr_elts_per_tlb,
                    tlb_perm[i] * nr_elts_per_tlb);
  }
  free(tlb_perm);

  dassert(is_a_permutation(perm, nr_elts));

  if (verbosity > 1) printf("generating inverse permtuation\n");
  perm_inverse = malloc(nr_elts * sizeof(*perm));
  for (i = 0; i < nr_elts; ++i) {
    perm_inverse[perm[i]] = i;
  }

  dassert(is_a_permutation(perm_inverse, nr_elts));

#define MIXED(x) ((x)*stride + mixer[(x) & (args->nr_mixers - 1)] * mixer_scale)

  if (verbosity > 1)
    printf("threading the chase (mixer_idx = %zu)\n", mixer_idx);
  for (i = 0; i < nr_elts; ++i) {
    size_t next;
    dassert(perm[perm_inverse[i]] == i);
    next = perm_inverse[i] + 1;
    next = (next == nr_elts) ? 0 : next;
    *(void **)(arena + MIXED(i)) = (void *)(arena + MIXED(perm[next]));
  }

  free(perm);
  free(perm_inverse);

  return arena + MIXED(0);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq (%rdi), %rax
movq %rax, 0x40(%rsp)
movq 0x8(%rdi), %rcx
movq 0x10(%rdi), %r8
movq 0x18(%rdi), %r9
movq 0x28(%rdi), %rax
movq %rax, 0x18(%rsp)
movq 0x20(%rdi), %rax
movq %rsi, 0x20(%rsp)
imulq %rsi, %rax
shlq $0x3, %rax
addq 0x38(%rdi), %rax
movq %rax, 0x38(%rsp)
movq %rcx, %rax
xorl %edx, %edx
divq %r9
movq %rax, %rbp
movq %r9, %rax
xorl %edx, %edx
divq %r8
movq %rax, %rbx
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rax, %r13
movq %r8, 0x8(%rsp)
movq %r8, %rax
xorl %edx, %edx
movq %rdi, 0x10(%rsp)
divq 0x30(%rdi)
movq %rax, 0x30(%rsp)
movq $0x50a310, %rax         # imm = 0x50A310
cmpl $0x2, (%rax)
jl 0x407986
leaq 0xca71f(%rip), %rdi     # 0x4d2098
movq %r13, %rsi
movq %rbp, %rdx
xorl %eax, %eax
callq 0x412ec0
leaq (,%rbp,8), %rdi
callq 0x4350a0
movq %rax, %r15
xorl %r14d, %r14d
movq %rax, %rdi
movq %rbp, %r12
movq %rbp, %rsi
xorl %edx, %edx
callq *0x18(%rsp)
leaq (,%r13,8), %rdi
movq %rdi, 0x28(%rsp)
callq 0x4350a0
movq %rax, %rbp
cmpq %r12, %r14
jae 0x4079e8
movq %r14, %rax
imulq %rbx, %rax
leaq (,%rax,8), %rdi
addq %rbp, %rdi
movq (%r15,%r14,8), %rdx
imulq %rbx, %rdx
movq %rbx, %rsi
callq *0x18(%rsp)
incq %r14
jmp 0x4079bd
movq %r15, %rdi
callq 0x4353e0
movq $0x50a310, %rax         # imm = 0x50A310
cmpl $0x2, (%rax)
jl 0x407a08
leaq 0xca7cc(%rip), %rdi     # 0x4d21cf
callq 0x422140
movq 0x28(%rsp), %rdi
callq 0x4350a0
movq %rax, %r14
xorl %eax, %eax
movq 0x40(%rsp), %rbx
movq 0x38(%rsp), %r15
movq 0x10(%rsp), %rdi
movq 0x8(%rsp), %r8
movq 0x30(%rsp), %r12
cmpq %r13, %rax
jae 0x407a43
movq (%rbp,%rax,8), %rcx
movq %rax, (%r14,%rcx,8)
incq %rax
jmp 0x407a30
movq $0x50a310, %rax         # imm = 0x50A310
cmpl $0x2, (%rax)
jl 0x407a6c
leaq 0xca67e(%rip), %rdi     # 0x4d20d4
movq 0x20(%rsp), %rsi
xorl %eax, %eax
callq 0x412ec0
movq 0x8(%rsp), %r8
movq 0x10(%rsp), %rdi
xorl %eax, %eax
cmpq %r13, %rax
jae 0x407ac8
movq (%r14,%rax,8), %rcx
incq %rcx
cmpq %r13, %rcx
movl $0x0, %edx
cmovneq %rcx, %rdx
movq (%rbp,%rdx,8), %rcx
movq 0x20(%rdi), %rdx
decq %rdx
movq %rdx, %rsi
andq %rcx, %rsi
imulq %r8, %rcx
movq (%r15,%rsi,8), %rsi
imulq %r12, %rsi
addq %rbx, %rcx
addq %rsi, %rcx
movq %rax, %rsi
imulq %r8, %rsi
andq %rax, %rdx
movq (%r15,%rdx,8), %rdx
imulq %r12, %rdx
addq %rbx, %rsi
movq %rcx, (%rdx,%rsi)
incq %rax
jmp 0x407a6e
movq %rbp, %rdi
callq 0x4353e0
movq %r14, %rdi
callq 0x4353e0
imulq (%r15), %r12
addq %r12, %rbx
movq %rbx, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq