// File: /workspace/github_cpp_makefile_star2_O2/patmorin[P]rotate/jain.cpp
// Function: main
int main(int argc, char *argv[]) {
	std::uint64_t n;
    if (argc != 2) usage(argv[0]);
	{
	    std::istringstream is_n(argv[1]);
	    is_n >> n;
	}

	const unsigned BLOCK=96;

	std::cout << "Building and filling...";
	std::cout.flush();
	auto *a = new std::uint32_t[n];

	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using jain_inshuffle()...";
	std::cout.flush();
	print_array(a, n);
	auto start = std::chrono::high_resolution_clock::now();
	jain_inshuffle(a, n);
	auto stop =  std::chrono::high_resolution_clock::now();
	std::chrono::duration<double> elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_inshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using prime_inshuffle()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	prime_inshuffle(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_inshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using jain_inshuffle_pf()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	jain_inshuffle_pf(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_inshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using prime_inshuffle_pf()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	prime_inshuffle_pf(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_inshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using prime_outshuffle()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	prime_outshuffle(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_outshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using blocked_outshuffle()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	blocked_outshuffle<BLOCK>(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_outshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using blocked_outshuffle_pf()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	blocked_outshuffle<BLOCK,true>(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_outshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using jain_outshuffle()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	jain_outshuffle(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	check_outshuffle_output(a, n);

	std::cout << "Refilling...";
	std::cout.flush();
	std::iota(a, a+n, 0);
	std::cout << "done" << std::endl;

	std::cout << "Permuting using blocked_eytzinger()...";
	std::cout.flush();
	print_array(a, n);
	start = std::chrono::high_resolution_clock::now();
	blocked_eytzinger<BLOCK,true>(a, n);
	stop =  std::chrono::high_resolution_clock::now();
	elapsed = stop - start;
	std::cout << "done (" << elapsed.count() << "s)" << std::endl;
	print_array(a, n);
	// TODO: Check correctness of Eytzinger permutation

}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
subq $0x1c0, %rsp            # imm = 0x1C0
cmpl $0x2, %edi
jne 0x1bc6
movq 0x8(%rsi), %rsi
leaq 0x20(%rsp), %rdi
leaq 0x1f(%rsp), %rdx
callq 0x1050
leaq 0x40(%rsp), %rdi
leaq 0x20(%rsp), %rsi
pushq $0x8
popq %rdx
callq 0x1130
leaq 0x20(%rsp), %rdi
callq 0x1060
leaq 0x40(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x1090
leaq 0x40(%rsp), %rdi
callq 0x1070
movq 0x3caf(%rip), %rbx      # 0x4fd0
leaq 0x1cf5(%rip), %rsi      # 0x301d
movq %rbx, %rdi
callq 0x10e0
movq %rbx, %rdi
callq 0x10b0
movq 0x8(%rsp), %r14
movq %r14, %rax
shrq $0x3e, %rax
shlq $0x2, %r14
negq %rax
sbbq %rdi, %rdi
orq %r14, %rdi
callq 0x1030
movq %rax, %rbx
xorl %eax, %eax
testq %r14, %r14
je 0x136c
movl %eax, (%rbx,%rax,4)
incq %rax
addq $-0x4, %r14
jmp 0x135b
movq 0x3c5d(%rip), %r14      # 0x4fd0
leaq 0x1cbb(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x1ca9(%rip), %rsi      # 0x303a
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x1c6b
callq 0x1040
subq %r15, %rax
leaq 0x1c8c(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm0, %xmm0
vdivsd 0x1c26(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x1c63(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1d20
leaq 0x1c35(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x145f
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x144e
movq 0x3b6a(%rip), %r14      # 0x4fd0
leaq 0x1bc8(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x1bf1(%rip), %rsi      # 0x3075
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x1d73
callq 0x1040
subq %r15, %rax
leaq 0x1b99(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x1b33(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x1b70(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1d20
leaq 0x1b42(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x1552
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x1541
movq 0x3a77(%rip), %r14      # 0x4fd0
leaq 0x1ad5(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x1b23(%rip), %rsi      # 0x309a
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x1e12
callq 0x1040
subq %r15, %rax
leaq 0x1aa6(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x1a40(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x1a7d(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1d20
leaq 0x1a4f(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x1645
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x1634
movq 0x3984(%rip), %r14      # 0x4fd0
leaq 0x19e2(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x1a57(%rip), %rsi      # 0x30c1
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x1f3d
callq 0x1040
subq %r15, %rax
leaq 0x19b3(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x194d(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x198a(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1d20
leaq 0x195c(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x1738
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x1727
movq 0x3891(%rip), %r14      # 0x4fd0
leaq 0x18ef(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x198c(%rip), %rsi      # 0x30e9
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x2059
callq 0x1040
subq %r15, %rax
leaq 0x18c0(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x185a(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x1897(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x20e2
leaq 0x1869(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x182b
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x181a
movq 0x379e(%rip), %r14      # 0x4fd0
leaq 0x17fc(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x18bf(%rip), %rsi      # 0x310f
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x2138
callq 0x1040
subq %r15, %rax
leaq 0x17cd(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x1767(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x17a4(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x20e2
leaq 0x1776(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x191e
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x190d
movq 0x36ab(%rip), %r14      # 0x4fd0
leaq 0x1709(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x17f4(%rip), %rsi      # 0x3137
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x21c2
callq 0x1040
subq %r15, %rax
leaq 0x16da(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x1674(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x16b1(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x20e2
leaq 0x1683(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x1a11
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x1a00
movq 0x35b8(%rip), %r14      # 0x4fd0
leaq 0x1616(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x172c(%rip), %rsi      # 0x3162
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x224c
callq 0x1040
subq %r15, %rax
leaq 0x15e7(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x1581(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x15be(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x20e2
leaq 0x1590(%rip), %rsi      # 0x3068
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rax
xorl %ecx, %ecx
shlq $0x2, %rax
testq %rax, %rax
je 0x1b04
movl %ecx, (%rbx,%rcx,4)
incq %rcx
addq $-0x4, %rax
jmp 0x1af3
movq 0x34c5(%rip), %r14      # 0x4fd0
leaq 0x1523(%rip), %rsi      # 0x3035
movq %r14, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x165e(%rip), %rsi      # 0x3187
movq %r14, %rdi
callq 0x10e0
movq %r14, %rdi
callq 0x10b0
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
callq 0x1040
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
movq %rax, %r15
callq 0x22ea
callq 0x1040
subq %r15, %rax
leaq 0x14f4(%rip), %rsi      # 0x305e
movq %r14, %rdi
vcvtsi2sd %rax, %xmm1, %xmm0
vdivsd 0x148e(%rip), %xmm0, %xmm0 # 0x3008
vmovsd %xmm0, 0x10(%rsp)
callq 0x10e0
vmovsd 0x10(%rsp), %xmm0
movq %rax, %rdi
callq 0x1110
leaq 0x14cb(%rip), %rsi      # 0x3065
movq %rax, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x1bf7
xorl %eax, %eax
addq $0x1c0, %rsp            # imm = 0x1C0
popq %rbx
popq %r14
popq %r15
retq
movq (%rsi), %rdi
callq 0x127c
leaq 0x40(%rsp), %rdi
movq %rax, %rbx
callq 0x1070
jmp 0x1bef
leaq 0x20(%rsp), %rdi
movq %rax, %rbx
callq 0x1060
jmp 0x1bef
movq %rax, %rbx
movq %rbx, %rdi
callq 0x1140