// File: /workspace/github_c_makefile_star2_O1/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 $0x58, %rsp
movq (%rdi), %rax
movq %rax, 0x50(%rsp)
movq 0x8(%rdi), %r8
movq 0x10(%rdi), %rcx
movq 0x18(%rdi), %r9
movq 0x28(%rdi), %r15
movq 0x20(%rdi), %rax
movq %rsi, 0x10(%rsp)
imulq %rsi, %rax
shlq $0x3, %rax
addq 0x38(%rdi), %rax
movq %rax, 0x48(%rsp)
movq %r8, %rax
xorl %edx, %edx
divq %r9
movq %rax, %r13
movq %r9, 0x28(%rsp)
movq %r9, %rax
xorl %edx, %edx
divq %rcx
movq %rax, %rbx
movq %r8, 0x8(%rsp)
movq %r8, %rax
xorl %edx, %edx
divq %rcx
movq %rax, %r12
movq %rcx, 0x40(%rsp)
movq %rcx, %rax
xorl %edx, %edx
movq %rdi, 0x18(%rsp)
divq 0x30(%rdi)
movq %rax, 0x38(%rsp)
movq $0x50b310, %rax         # imm = 0x50B310
cmpl $0x2, (%rax)
jl 0x407e63
leaq 0xcb242(%rip), %rdi     # 0x4d3098
movq %r12, %rsi
movq %r13, %rdx
xorl %eax, %eax
callq 0x413340
leaq (,%r13,8), %rdi
callq 0x435520
movq %rax, %r14
movq %rax, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq *%r15
movq %r12, 0x30(%rsp)
leaq (,%r12,8), %rdi
movq %rdi, 0x20(%rsp)
callq 0x435520
movq %rax, %rbp
movq 0x28(%rsp), %rax
cmpq 0x8(%rsp), %rax
ja 0x407ed5
movq %r13, %r12
movq %r15, %r13
xorl %r15d, %r15d
movq %r15, %rax
imulq %rbx, %rax
leaq (,%rax,8), %rdi
addq %rbp, %rdi
movq (%r14,%r15,8), %rdx
imulq %rbx, %rdx
movq %rbx, %rsi
callq *%r13
incq %r15
cmpq %r12, %r15
jb 0x407ead
movq %r14, %rdi
callq 0x435860
movq $0x50b310, %rax         # imm = 0x50B310
cmpl $0x2, (%rax)
jl 0x407ef5
leaq 0xcb2df(%rip), %rdi     # 0x4d31cf
callq 0x4225c0
movq 0x20(%rsp), %rdi
callq 0x435520
movq %rax, %r13
movq 0x40(%rsp), %r15
cmpq 0x8(%rsp), %r15
movq 0x50(%rsp), %rbx
movq 0x48(%rsp), %r14
movq 0x30(%rsp), %r12
ja 0x407f31
xorl %eax, %eax
movq (%rbp,%rax,8), %rcx
movq %rax, (%r13,%rcx,8)
incq %rax
cmpq %r12, %rax
jb 0x407f1f
movq $0x50b310, %rax         # imm = 0x50B310
cmpl $0x2, (%rax)
jl 0x407f50
leaq 0xcb190(%rip), %rdi     # 0x4d30d4
movq 0x10(%rsp), %rsi
xorl %eax, %eax
callq 0x413340
cmpq 0x8(%rsp), %r15
movq 0x38(%rsp), %r8
ja 0x407fbf
movq 0x18(%rsp), %rax
movq 0x20(%rax), %rax
decq %rax
xorl %ecx, %ecx
movq (%r13,%rcx,8), %rdx
incq %rdx
cmpq %r12, %rdx
movl $0x0, %esi
cmovneq %rdx, %rsi
movq (%rbp,%rsi,8), %rdx
movq %rax, %rsi
andq %rdx, %rsi
imulq %r15, %rdx
movq (%r14,%rsi,8), %rsi
imulq %r8, %rsi
addq %rbx, %rdx
addq %rsi, %rdx
movq %rcx, %rsi
imulq %r15, %rsi
movq %rax, %rdi
andq %rcx, %rdi
movq (%r14,%rdi,8), %rdi
imulq %r8, %rdi
addq %rbx, %rsi
movq %rdx, (%rdi,%rsi)
incq %rcx
cmpq %r12, %rcx
jb 0x407f6a
movq %rbp, %rdi
movq %r8, %r15
callq 0x435860
movq %r13, %rdi
callq 0x435860
imulq (%r14), %r15
addq %r15, %rbx
movq %rbx, %rax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq