// File: patmorin[P]rotate/jain.cpp
// Function: void prime_inshuffle_pf<unsigned int, unsigned long>(unsigned int*, unsigned long)
void prime_inshuffle_pf(Data *a, Index n) {
	while (n > 1) {
		// Compute appropriate value of m
 		int i = 0;
 		while (sprimes[i+1] <= n) i++;
 		Index m = sprimes[i];

		// Move correct m elements to front of the array
		std::rotate(a+m/2, a+n/2, a+n/2+m/2);

		// Now use Jain's trick to shuffle a[0,...,m-1];
		Index cur = 1;
		Data t = a[cur];

		const Index readahead = 35;
		Index buf[readahead];
		buf[0] = cur;
		for (Index i = 1; i < readahead; i++) {
			buf[i] = inshuffle_perm3(buf[i-1], m);
			__builtin_prefetch(a+buf[i]);
		}

		Index bicur = 0;
		do {
			Index biprv = bicur == 0 ? readahead-1 : bicur-1;
			Index binxt = bicur+1 == readahead ? 0 : bicur+1;

			buf[bicur] = inshuffle_perm3(buf[biprv], m);
			__builtin_prefetch(a+buf[bicur], 1);

			Data t2 = a[buf[binxt]];
			a[buf[binxt]] = t;
			t = t2;
			bicur = binxt;
		} while (buf[bicur] != 1);

		// Recurse on a[m,...n-1]
		a += m;
		n -= m;
	}
}

// Assembly:
subq $0x198, %rsp            # imm = 0x198
movq %rdi, 0x190(%rsp)
movq %rsi, 0x188(%rsp)
cmpq $0x1, 0x188(%rsp)
jbe 0x2dc6
movl $0x0, 0x184(%rsp)
movl 0x184(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rcx
leaq 0x658b(%rip), %rax      # 0x90d0
movq (%rax,%rcx,8), %rax
cmpq 0x188(%rsp), %rax
ja 0x2b66
movl 0x184(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x184(%rsp)
jmp 0x2b31
movslq 0x184(%rsp), %rcx
leaq 0x655b(%rip), %rax      # 0x90d0
movq (%rax,%rcx,8), %rax
movq %rax, 0x178(%rsp)
movq 0x190(%rsp), %rdi
movq 0x178(%rsp), %rax
shrq %rax
shlq $0x2, %rax
addq %rax, %rdi
movq 0x190(%rsp), %rsi
movq 0x188(%rsp), %rax
shrq %rax
shlq $0x2, %rax
addq %rax, %rsi
movq 0x190(%rsp), %rdx
movq 0x188(%rsp), %rax
shrq %rax
shlq $0x2, %rax
addq %rax, %rdx
movq 0x178(%rsp), %rax
shrq %rax
shlq $0x2, %rax
addq %rax, %rdx
callq 0x3610
movq $0x1, 0x170(%rsp)
movq 0x190(%rsp), %rax
movq 0x170(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x16c(%rsp)
movq $0x23, 0x160(%rsp)
movq 0x170(%rsp), %rax
movq %rax, 0x40(%rsp)
movq $0x1, 0x38(%rsp)
cmpq $0x23, 0x38(%rsp)
jae 0x2c8a
movq 0x38(%rsp), %rax
subq $0x1, %rax
movq 0x40(%rsp,%rax,8), %rdi
movq 0x178(%rsp), %rsi
callq 0x3670
movq %rax, %rcx
movq 0x38(%rsp), %rax
movq %rcx, 0x40(%rsp,%rax,8)
movq 0x190(%rsp), %rax
movq 0x38(%rsp), %rcx
movq 0x40(%rsp,%rcx,8), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
prefetcht0 (%rax)
movq 0x38(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x38(%rsp)
jmp 0x2c2e
movq $0x0, 0x30(%rsp)
cmpq $0x0, 0x30(%rsp)
jne 0x2ca7
movl $0x22, %eax
movq %rax, 0x10(%rsp)
jmp 0x2cb5
movq 0x30(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x30(%rsp), %rax
addq $0x1, %rax
cmpq $0x23, %rax
jne 0x2cd7
xorl %eax, %eax
movq %rax, 0x8(%rsp)
jmp 0x2ce5
movq 0x30(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x28(%rsp), %rax
movq 0x40(%rsp,%rax,8), %rdi
movq 0x178(%rsp), %rsi
callq 0x3670
movq %rax, %rcx
movq 0x30(%rsp), %rax
movq %rcx, 0x40(%rsp,%rax,8)
movq 0x190(%rsp), %rax
movq 0x30(%rsp), %rcx
movq 0x40(%rsp,%rcx,8), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
prefetchw (%rax)
movq 0x190(%rsp), %rax
movq 0x20(%rsp), %rcx
movq 0x40(%rsp,%rcx,8), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x1c(%rsp)
movl 0x16c(%rsp), %edx
movq 0x190(%rsp), %rax
movq 0x20(%rsp), %rcx
movq 0x40(%rsp,%rcx,8), %rcx
movl %edx, (%rax,%rcx,4)
movl 0x1c(%rsp), %eax
movl %eax, 0x16c(%rsp)
movq 0x20(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rax
cmpq $0x1, 0x40(%rsp,%rax,8)
jne 0x2c93
movq 0x178(%rsp), %rax
shlq $0x2, %rax
addq 0x190(%rsp), %rax
movq %rax, 0x190(%rsp)
movq 0x178(%rsp), %rcx
movq 0x188(%rsp), %rax
subq %rcx, %rax
movq %rax, 0x188(%rsp)
jmp 0x2b17
addq $0x198, %rsp            # imm = 0x198
retq
nop