// File: /workspace/github_cpp_makefile_star2_O2/mburhanpurkar[P]fast_xorshift_plus/test_rng.cpp
// Function: test_xorshift(int)
inline bool test_xorshift(int niter=10000)
{
    random_device rd;
    uint64_t rn1 = rng_helpers::rd64(rd);
    uint64_t rn2 = rng_helpers::rd64(rd);
    uint64_t rn3 = rng_helpers::rd64(rd);
    uint64_t rn4 = rng_helpers::rd64(rd);
    uint64_t rn5 = rng_helpers::rd64(rd);
    uint64_t rn6 = rng_helpers::rd64(rd);
    uint64_t rn7 = rng_helpers::rd64(rd);
    uint64_t rn8 = rng_helpers::rd64(rd);
          
    fast_rng::vec_xorshift_plus a(_mm256_setr_epi64x(rn1, rn3, rn5, rn7), _mm256_setr_epi64x(rn2, rn4, rn6, rn8));
    float vrn_vec[8];
    rng_helpers::xorshift_plus b(rn1, rn2, rn3, rn4, rn5, rn6, rn7, rn8);
    float srn_vec[8];

    for (int iter=0; iter < niter; iter++)
    {
        __m256 vrn = a.gen_floats();
	_mm256_storeu_ps(&vrn_vec[0], vrn);
	b.gen_floats(srn_vec);
	
	for (int i=0; i<8; i++)
	{
	    if (srn_vec[i] != vrn_vec[i])
	    {
	        cout << "S code outputs: ";
		print_vec(srn_vec);
		cout << "V code outputs: ";
		print_vec(vrn_vec);
		cout << "rng test failed: scalar and vectorized prngs are out of sync on iter " << i << "!" << endl;
		return false;
	    }
	}
    }

    // Check that array generation is working
    int n = 10000;
    float *big_scalar = new float[n];
    float *big_vector = new float[n];

    a.gen_arr(big_vector, n);

    for (int i = 0; i < n; i += 8)
        b.gen_floats(big_scalar + i);
	  
    for (int i = 0; i < n; i++)
    {
        if (big_scalar[i] < -1 || big_scalar[i] > 1 || big_vector[i] < -1 || big_vector[i] > 1)
	{
	    cout << "Oh no, something isn't outputting a floating point number between (-1, 1). This is very bad!" << endl;
	}
        if (big_scalar[i] != big_vector[i])
	{
	    cout << "The output of vec_xorshift_plus: gen_arr diverged from the scalar implementation at iteration " << i << endl;
	    return false;
	}
    }
	  
    cout << "All rng tests passed." << endl;
    return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
andq $-0x20, %rsp
subq $0x1460, %rsp           # imm = 0x1460
movl %edi, 0x14(%rsp)
leaq 0xc0(%rsp), %rbx
movq %rbx, %rdi
callq 0x29a6
movq %rbx, %rdi
callq 0x29fb
movq %rax, 0x20(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, 0x18(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, %r12
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, %r13
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, %r14
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq %rax, %r15
leaq 0xc0(%rsp), %rdi
callq 0x29fb
movq 0x20(%rsp), %rsi
movq 0x18(%rsp), %rdx
vmovq %r12, %xmm0
vmovq %rbx, %xmm2
vmovq %r14, %xmm4
vmovq %rsi, %xmm1
vmovq %rdx, %xmm3
vpunpcklqdq %xmm0, %xmm1, %xmm0 # xmm0 = xmm1[0],xmm0[0]
vmovq %r15, %xmm1
vpunpcklqdq %xmm1, %xmm2, %xmm1 # xmm1 = xmm2[0],xmm1[0]
vmovq %r13, %xmm2
vmovdqa %xmm0, 0x40(%rsp)
vpunpcklqdq %xmm2, %xmm3, %xmm2 # xmm2 = xmm3[0],xmm2[0]
vmovq %rax, %xmm3
vmovdqa %xmm1, 0x50(%rsp)
vpunpcklqdq %xmm3, %xmm4, %xmm3 # xmm3 = xmm4[0],xmm3[0]
vmovdqa %xmm2, 0x60(%rsp)
vmovdqa %xmm3, 0x70(%rsp)
subq $0x8, %rsp
leaq 0x30(%rsp), %rdi
movq %r12, %rcx
movq %r13, %r8
movq %rbx, %r9
pushq %rax
pushq %r15
pushq %r14
callq 0x2a3c
addq $0x20, %rsp
movl 0x14(%rsp), %ecx
leaq 0x40(%rsp), %rdi
leaq 0x28(%rsp), %rbx
xorl %r14d, %r14d
movl %ecx, %eax
sarl $0x1f, %eax
andnl %ecx, %eax, %r13d
cmpl %r13d, %r14d
je 0x26bf
movq %rdi, %r15
callq 0x2a82
vmovdqu %ymm0, 0xa0(%rsp)
leaq 0x80(%rsp), %rsi
movq %rbx, %rdi
movq %rbx, %r12
vzeroupper
callq 0x2a98
xorl %ebx, %ebx
cmpq $0x8, %rbx
je 0x2616
vmovss 0x80(%rsp,%rbx,4), %xmm0
vucomiss 0xa0(%rsp,%rbx,4), %xmm0
jne 0x2621
jp 0x2621
incq %rbx
jmp 0x25f5
incl %r14d
movq %r15, %rdi
movq %r12, %rbx
jmp 0x25c3
movq 0x29a8(%rip), %rdi      # 0x4fd0
leaq 0xa7f(%rip), %rsi       # 0x30ae
callq 0x2130
leaq 0x80(%rsp), %rdi
callq 0x2aff
movq 0x2988(%rip), %rdi      # 0x4fd0
leaq 0xa70(%rip), %rsi       # 0x30bf
callq 0x2130
leaq 0xa0(%rsp), %rdi
callq 0x2aff
movq 0x2968(%rip), %rdi      # 0x4fd0
leaq 0xa61(%rip), %rsi       # 0x30d0
callq 0x2130
movq %rax, %rdi
movl %ebx, %esi
callq 0x21d0
leaq 0xbd3(%rip), %rsi       # 0x3258
movq %rax, %rdi
callq 0x2130
movq %rax, %rdi
callq 0x20a0
xorl %ebx, %ebx
leaq 0x28(%rsp), %rdi
callq 0x2c7a
leaq 0xc0(%rsp), %rdi
callq 0x2a20
movl %ebx, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x9c40, %edi           # imm = 0x9C40
callq 0x2030
movq %rax, %rbx
movl $0x9c40, %edi           # imm = 0x9C40
callq 0x2030
movq %rax, %r14
leaq 0x40(%rsp), %rdi
movl $0x2710, %edx           # imm = 0x2710
movq %rax, %rsi
callq 0x2b5e
leaq 0x28(%rsp), %r15
xorl %r13d, %r13d
movq %rbx, %r12
cmpq $0x2710, %r13           # imm = 0x2710
jae 0x2714
movq %r15, %rdi
movq %r12, %rsi
callq 0x2a98
addq $0x8, %r13
addq $0x20, %r12
jmp 0x26f6
movq 0x28b5(%rip), %r12      # 0x4fd0
leaq 0x9f4(%rip), %r13       # 0x3116
xorl %r15d, %r15d
cmpq $0x2710, %r15           # imm = 0x2710
je 0x278e
vmovss (%rbx,%r15,4), %xmm0
vandps 0x8f2(%rip){1to4}, %xmm0, %xmm1 # 0x3030
vucomiss 0x8ee(%rip), %xmm1      # 0x3034
ja 0x2762
vmovss (%r14,%r15,4), %xmm1
vandps 0x8d8(%rip){1to4}, %xmm1, %xmm2 # 0x3030
vucomiss 0x8d4(%rip), %xmm2      # 0x3034
jbe 0x2781
movq %r12, %rdi
movq %r13, %rsi
callq 0x2130
movq %rax, %rdi
callq 0x20a0
vmovss (%rbx,%r15,4), %xmm0
vmovss (%r14,%r15,4), %xmm1
vucomiss %xmm1, %xmm0
jne 0x27b0
jp 0x27b0
incq %r15
jmp 0x2725
movq 0x283b(%rip), %rdi      # 0x4fd0
leaq 0xa36(%rip), %rsi       # 0x31d2
callq 0x2130
movb $0x1, %bl
movq %rax, %rdi
callq 0x20a0
jmp 0x2697
movq 0x2819(%rip), %rdi      # 0x4fd0
leaq 0x9b5(%rip), %rsi       # 0x3173
callq 0x2130
movq %rax, %rdi
movl %r15d, %esi
callq 0x21d0
movq %rax, %rdi
callq 0x20a0
jmp 0x2695
jmp 0x27fa
jmp 0x27fa
jmp 0x27fa
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
jmp 0x27f1
movq %rax, %rbx
jmp 0x280a
jmp 0x27fa
jmp 0x27fa
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
vzeroupper
callq 0x2c7a
leaq 0xc0(%rsp), %rdi
callq 0x2a20
movq %rbx, %rdi
callq 0x21e0
nop