// File: patmorin[P]rotate/jain.cpp
// Function: void prime_outshuffle_pf<4u, void blocked_outshuffle<96u, true, unsigned int, unsigned long>(unsigned int*, unsigned long)::block, unsigned long>(void blocked_outshuffle<96u, true, unsigned int, unsigned long>(unsigned int*, unsigned long)::block*, unsigned int)
void prime_outshuffle_pf(Data *a, Index n) {
	if (n <= 1) return;

	// Compute appropriate value of m
	int i = 0;
	while (sprimes[i+1] <= n) i++;
	Index m = sprimes[i];

	Index cur = 0;
	Index pf = cur;
	for (unsigned i = 0; i < R; i++)
		__builtin_prefetch(a+(pf = outshuffle_perm3(pf, m)), 1);
	Data t[2];
	int flipflop = 0;
	t[flipflop] = a[cur];
	do {
		__builtin_prefetch(a+(pf = outshuffle_perm3(pf, m)), 1);
		Index nxt = outshuffle_perm3(cur, m);
		t[!flipflop] = a[nxt];
		a[nxt] = t[flipflop];
		flipflop = !flipflop;
		cur = nxt;
	} while (cur != 0);

	// Recurse on a[m,...n-1]
	prime_outshuffle(a+m, n-m);

	// Regroup odds and evens
	std::rotate(a+m/2, a+m, a+m+(n-m)/2);
}

// Assembly:
subq $0x358, %rsp            # imm = 0x358
movq %rdi, 0x350(%rsp)
movq %rsi, 0x348(%rsp)
cmpq $0x1, 0x348(%rsp)
ja 0x4b77
jmp 0x4e1f
movl $0x0, 0x344(%rsp)
movl 0x344(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rcx
leaq 0x453a(%rip), %rax      # 0x90d0
movq (%rax,%rcx,8), %rax
cmpq 0x348(%rsp), %rax
ja 0x4bb7
movl 0x344(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x344(%rsp)
jmp 0x4b82
movslq 0x344(%rsp), %rcx
leaq 0x450a(%rip), %rax      # 0x90d0
movq (%rax,%rcx,8), %rax
movq %rax, 0x338(%rsp)
movq $0x0, 0x330(%rsp)
movq 0x330(%rsp), %rax
movq %rax, 0x328(%rsp)
movl $0x0, 0x324(%rsp)
cmpl $0x4, 0x324(%rsp)
jae 0x4c55
movq 0x350(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x328(%rsp), %rdi
movq 0x338(%rsp), %rsi
callq 0x3e50
movq %rax, %rcx
movq 0x8(%rsp), %rax
movq %rcx, 0x328(%rsp)
imulq $0x180, %rcx, %rcx      # imm = 0x180
addq %rcx, %rax
prefetchw (%rax)
movl 0x324(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x324(%rsp)
jmp 0x4bf9
movl $0x0, 0x1c(%rsp)
movq 0x350(%rsp), %rsi
imulq $0x180, 0x330(%rsp), %rax # imm = 0x180
addq %rax, %rsi
movslq 0x1c(%rsp), %rax
leaq 0x20(%rsp), %rdi
imulq $0x180, %rax, %rax      # imm = 0x180
addq %rax, %rdi
movl $0x180, %edx            # imm = 0x180
callq 0x1080
movq 0x350(%rsp), %rax
movq %rax, (%rsp)
movq 0x328(%rsp), %rdi
movq 0x338(%rsp), %rsi
callq 0x3e50
movq %rax, %rcx
movq (%rsp), %rax
movq %rcx, 0x328(%rsp)
imulq $0x180, %rcx, %rcx      # imm = 0x180
addq %rcx, %rax
prefetchw (%rax)
movq 0x330(%rsp), %rdi
movq 0x338(%rsp), %rsi
callq 0x3e50
movq %rax, 0x10(%rsp)
movq 0x350(%rsp), %rsi
imulq $0x180, 0x10(%rsp), %rax # imm = 0x180
addq %rax, %rsi
cmpl $0x0, 0x1c(%rsp)
setne %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %eax
leaq 0x20(%rsp), %rdi
imulq $0x180, %rax, %rax      # imm = 0x180
addq %rax, %rdi
movl $0x180, %edx            # imm = 0x180
callq 0x1080
movslq 0x1c(%rsp), %rax
leaq 0x20(%rsp), %rsi
imulq $0x180, %rax, %rax      # imm = 0x180
addq %rax, %rsi
movq 0x350(%rsp), %rdi
imulq $0x180, 0x10(%rsp), %rax # imm = 0x180
addq %rax, %rdi
movl $0x180, %edx            # imm = 0x180
callq 0x1080
cmpl $0x0, 0x1c(%rsp)
setne %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x1c(%rsp)
movq 0x10(%rsp), %rax
movq %rax, 0x330(%rsp)
cmpq $0x0, 0x330(%rsp)
jne 0x4c92
movq 0x350(%rsp), %rdi
imulq $0x180, 0x338(%rsp), %rax # imm = 0x180
addq %rax, %rdi
movq 0x348(%rsp), %rsi
subq 0x338(%rsp), %rsi
callq 0x4e30
movq 0x350(%rsp), %rdi
movq 0x338(%rsp), %rax
shrq %rax
imulq $0x180, %rax, %rax      # imm = 0x180
addq %rax, %rdi
movq 0x350(%rsp), %rsi
imulq $0x180, 0x338(%rsp), %rax # imm = 0x180
addq %rax, %rsi
movq 0x350(%rsp), %rdx
imulq $0x180, 0x338(%rsp), %rax # imm = 0x180
addq %rax, %rdx
movq 0x348(%rsp), %rax
subq 0x338(%rsp), %rax
shrq %rax
imulq $0x180, %rax, %rax      # imm = 0x180
addq %rax, %rdx
callq 0x5050
addq $0x358, %rsp            # imm = 0x358
retq
nopw (%rax,%rax)