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

		// 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];
		for (Index g = 1; g < m; g *= 3) {
			Index cur = g-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] != g-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 0x2af5
movq $0x1, 0x180(%rsp)
imulq $0x3, 0x180(%rsp), %rax
subq $0x1, %rax
cmpq 0x188(%rsp), %rax
ja 0x284c
imulq $0x3, 0x180(%rsp), %rax
movq %rax, 0x180(%rsp)
jmp 0x2822
movq 0x180(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x180(%rsp)
movq 0x190(%rsp), %rdi
movq 0x180(%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 0x180(%rsp), %rax
shrq %rax
shlq $0x2, %rax
addq %rax, %rdx
callq 0x3610
movq $0x1, 0x178(%rsp)
movq 0x178(%rsp), %rax
cmpq 0x180(%rsp), %rax
jae 0x2ab9
movq 0x178(%rsp), %rax
subq $0x1, %rax
movq %rax, 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 0x2993
movq 0x38(%rsp), %rax
subq $0x1, %rax
movq 0x40(%rsp,%rax,8), %rdi
movq 0x180(%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 0x2937
movq $0x0, 0x30(%rsp)
cmpq $0x0, 0x30(%rsp)
jne 0x29b0
movl $0x22, %eax
movq %rax, 0x10(%rsp)
jmp 0x29be
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 0x29e0
xorl %eax, %eax
movq %rax, 0x8(%rsp)
jmp 0x29ee
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 0x180(%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
movq 0x40(%rsp,%rax,8), %rax
movq 0x178(%rsp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jne 0x299c
jmp 0x2aa3
imulq $0x3, 0x178(%rsp), %rax
movq %rax, 0x178(%rsp)
jmp 0x28d1
movq 0x180(%rsp), %rax
shlq $0x2, %rax
addq 0x190(%rsp), %rax
movq %rax, 0x190(%rsp)
movq 0x180(%rsp), %rcx
movq 0x188(%rsp), %rax
subq %rcx, %rax
movq %rax, 0x188(%rsp)
jmp 0x2807
addq $0x198, %rsp            # imm = 0x198
retq
nopl (%rax)