// File: 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
andq $-0x20, %rsp
subq $0x1700, %rsp           # imm = 0x1700
movl %edi, 0x15f8(%rsp)
leaq 0x270(%rsp), %rdi
movq %rdi, 0x108(%rsp)
callq 0x3440
movq 0x108(%rsp), %rdi
callq 0x34e0
movq %rax, 0x110(%rsp)
jmp 0x25e2
movq 0x110(%rsp), %rax
movq %rax, 0x268(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0x100(%rsp)
jmp 0x2609
movq 0x100(%rsp), %rax
movq %rax, 0x250(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xf8(%rsp)
jmp 0x2630
movq 0xf8(%rsp), %rax
movq %rax, 0x248(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xf0(%rsp)
jmp 0x2657
movq 0xf0(%rsp), %rax
movq %rax, 0x240(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xe8(%rsp)
jmp 0x267e
movq 0xe8(%rsp), %rax
movq %rax, 0x238(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xe0(%rsp)
jmp 0x26a5
movq 0xe0(%rsp), %rax
movq %rax, 0x230(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xd8(%rsp)
jmp 0x26cc
movq 0xd8(%rsp), %rax
movq %rax, 0x228(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x34e0
movq %rax, 0xd0(%rsp)
jmp 0x26f3
movq 0xd0(%rsp), %rax
movq %rax, 0x220(%rsp)
movq 0x268(%rsp), %rsi
movq 0x248(%rsp), %rdx
movq 0x238(%rsp), %rcx
movq 0x228(%rsp), %rax
movq %rsi, 0x1638(%rsp)
movq %rdx, 0x1630(%rsp)
movq %rcx, 0x1628(%rsp)
movq %rax, 0x1620(%rsp)
movq 0x1620(%rsp), %rsi
movq 0x1628(%rsp), %rdx
movq 0x1630(%rsp), %rcx
movq 0x1638(%rsp), %rax
movq %rsi, 0x1678(%rsp)
movq %rdx, 0x1670(%rsp)
movq %rcx, 0x1668(%rsp)
movq %rax, 0x1660(%rsp)
vmovq 0x1678(%rsp), %xmm1
vmovq 0x1670(%rsp), %xmm0
vpunpcklqdq %xmm1, %xmm0, %xmm1 # xmm1 = xmm0[0],xmm1[0]
vmovq 0x1668(%rsp), %xmm2
vmovq 0x1660(%rsp), %xmm0
vpunpcklqdq %xmm2, %xmm0, %xmm2 # xmm2 = xmm0[0],xmm2[0]
vmovaps %xmm2, %xmm0
vinserti128 $0x1, %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x1640(%rsp)
vmovdqa 0x1640(%rsp), %ymm0
vmovaps %ymm0, 0xa0(%rsp)
movq 0x250(%rsp), %rsi
movq 0x240(%rsp), %rdx
movq 0x230(%rsp), %rcx
movq 0x220(%rsp), %rax
movq %rsi, 0x1618(%rsp)
movq %rdx, 0x1610(%rsp)
movq %rcx, 0x1608(%rsp)
movq %rax, 0x1600(%rsp)
movq 0x1600(%rsp), %rsi
movq 0x1608(%rsp), %rdx
movq 0x1610(%rsp), %rcx
movq 0x1618(%rsp), %rax
movq %rsi, 0x16b8(%rsp)
movq %rdx, 0x16b0(%rsp)
movq %rcx, 0x16a8(%rsp)
movq %rax, 0x16a0(%rsp)
vmovq 0x16b8(%rsp), %xmm1
vmovq 0x16b0(%rsp), %xmm0
vpunpcklqdq %xmm1, %xmm0, %xmm1 # xmm1 = xmm0[0],xmm1[0]
vmovq 0x16a8(%rsp), %xmm2
vmovq 0x16a0(%rsp), %xmm0
vpunpcklqdq %xmm2, %xmm0, %xmm2 # xmm2 = xmm0[0],xmm2[0]
vmovaps %xmm2, %xmm0
vinserti128 $0x1, %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x1680(%rsp)
vmovdqa 0x1680(%rsp), %ymm0
vmovaps %ymm0, 0x80(%rsp)
vmovaps 0x80(%rsp), %ymm1
vmovaps 0xa0(%rsp), %ymm0
leaq 0x1e0(%rsp), %rdi
callq 0x3560
jmp 0x28c6
movq 0x268(%rsp), %rsi
movq 0x250(%rsp), %rdx
movq 0x248(%rsp), %rcx
movq 0x240(%rsp), %r8
movq 0x238(%rsp), %r9
movq 0x230(%rsp), %rdi
movq 0x228(%rsp), %r10
movq 0x220(%rsp), %r11
movq %rsp, %rax
movq %r11, 0x10(%rax)
movq %r10, 0x8(%rax)
movq %rdi, (%rax)
leaq 0x1a8(%rsp), %rdi
vzeroupper
callq 0x3640
jmp 0x2926
movl $0x0, 0x17c(%rsp)
movl 0x17c(%rsp), %eax
cmpl 0x15f8(%rsp), %eax
jge 0x2b2d
leaq 0x1e0(%rsp), %rdi
callq 0x3770
vmovaps %ymm0, 0x60(%rsp)
jmp 0x295a
vmovaps 0x60(%rsp), %ymm0
vmovaps %ymm0, 0x140(%rsp)
leaq 0x1c0(%rsp), %rax
vmovaps 0x140(%rsp), %ymm0
movq %rax, 0x16e8(%rsp)
vmovaps %ymm0, 0x16c0(%rsp)
vmovaps 0x16c0(%rsp), %ymm0
movq 0x16e8(%rsp), %rax
vmovups %ymm0, (%rax)
leaq 0x1a8(%rsp), %rdi
leaq 0x180(%rsp), %rsi
vzeroupper
callq 0x38a0
jmp 0x29ba
movl $0x0, 0x13c(%rsp)
cmpl $0x8, 0x13c(%rsp)
jge 0x2b15
movslq 0x13c(%rsp), %rax
vmovss 0x180(%rsp,%rax,4), %xmm0
movslq 0x13c(%rsp), %rax
vucomiss 0x1c0(%rsp,%rax,4), %xmm0
jne 0x29fe
jp 0x29fe
jmp 0x2afd
movq 0x55cb(%rip), %rdi      # 0x7fd0
leaq 0x26e2(%rip), %rsi      # 0x50ee
callq 0x2110
jmp 0x2a13
leaq 0x180(%rsp), %rdi
callq 0x3a20
jmp 0x2a22
movq 0x55a7(%rip), %rdi      # 0x7fd0
leaq 0x26cf(%rip), %rsi      # 0x50ff
callq 0x2110
jmp 0x2a37
leaq 0x1c0(%rsp), %rdi
callq 0x3a20
jmp 0x2a46
movq 0x5583(%rip), %rdi      # 0x7fd0
leaq 0x26bc(%rip), %rsi      # 0x5110
callq 0x2110
movq %rax, 0x58(%rsp)
jmp 0x2a60
movq 0x58(%rsp), %rdi
movl 0x13c(%rsp), %esi
callq 0x21d0
movq %rax, 0x50(%rsp)
jmp 0x2a78
movq 0x50(%rsp), %rdi
leaq 0x2814(%rip), %rsi      # 0x5298
callq 0x2110
movq %rax, 0x48(%rsp)
jmp 0x2a90
movq 0x48(%rsp), %rdi
movq 0x551c(%rip), %rsi      # 0x7fb8
callq 0x2130
jmp 0x2aa3
movb $0x0, 0x15ff(%rsp)
movl $0x1, 0x138(%rsp)
jmp 0x2dcb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x260(%rsp)
movl %eax, 0x25c(%rsp)
jmp 0x2df3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x260(%rsp)
movl %eax, 0x25c(%rsp)
leaq 0x1a8(%rsp), %rdi
vzeroupper
callq 0x3ba0
jmp 0x2df3
jmp 0x2aff
movl 0x13c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x13c(%rsp)
jmp 0x29c5
jmp 0x2b17
movl 0x17c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x17c(%rsp)
jmp 0x2931
movl $0x2710, 0x134(%rsp) # imm = 0x2710
movslq 0x134(%rsp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x2030
movq %rax, 0x40(%rsp)
jmp 0x2b62
movq 0x40(%rsp), %rax
movq %rax, 0x128(%rsp)
movslq 0x134(%rsp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x2030
movq %rax, 0x38(%rsp)
jmp 0x2b99
movq 0x38(%rsp), %rax
movq %rax, 0x120(%rsp)
movq 0x120(%rsp), %rsi
movl 0x134(%rsp), %edx
leaq 0x1e0(%rsp), %rdi
callq 0x3a90
jmp 0x2bc4
movl $0x0, 0x11c(%rsp)
movl 0x11c(%rsp), %eax
cmpl 0x134(%rsp), %eax
jge 0x2c17
movq 0x128(%rsp), %rax
movslq 0x11c(%rsp), %rcx
leaq (%rax,%rcx,4), %rsi
leaq 0x1a8(%rsp), %rdi
callq 0x38a0
jmp 0x2c02
jmp 0x2c04
movl 0x11c(%rsp), %eax
addl $0x8, %eax
movl %eax, 0x11c(%rsp)
jmp 0x2bcf
movl $0x0, 0x118(%rsp)
movl 0x118(%rsp), %eax
cmpl 0x134(%rsp), %eax
jge 0x2d8b
movq 0x128(%rsp), %rax
movslq 0x118(%rsp), %rcx
vmovss 0x23e2(%rip), %xmm0     # 0x5030
vucomiss (%rax,%rcx,4), %xmm0
ja 0x2cba
movq 0x128(%rsp), %rax
movslq 0x118(%rsp), %rcx
vmovss (%rax,%rcx,4), %xmm0
vmovss 0x23c2(%rip), %xmm1     # 0x5034
vucomiss %xmm1, %xmm0
ja 0x2cba
movq 0x120(%rsp), %rax
movslq 0x118(%rsp), %rcx
vmovss 0x23a0(%rip), %xmm0     # 0x5030
vucomiss (%rax,%rcx,4), %xmm0
ja 0x2cba
movq 0x120(%rsp), %rax
movslq 0x118(%rsp), %rcx
vmovss (%rax,%rcx,4), %xmm0
vmovss 0x2380(%rip), %xmm1     # 0x5034
vucomiss %xmm1, %xmm0
jbe 0x2ce9
movq 0x530f(%rip), %rdi      # 0x7fd0
leaq 0x248e(%rip), %rsi      # 0x5156
callq 0x2110
movq %rax, 0x30(%rsp)
jmp 0x2cd4
movq 0x30(%rsp), %rdi
movq 0x52d8(%rip), %rsi      # 0x7fb8
callq 0x2130
jmp 0x2ce7
jmp 0x2ce9
movq 0x128(%rsp), %rax
movslq 0x118(%rsp), %rcx
vmovss (%rax,%rcx,4), %xmm0
movq 0x120(%rsp), %rax
movslq 0x118(%rsp), %rcx
vucomiss (%rax,%rcx,4), %xmm0
jne 0x2d19
jp 0x2d19
jmp 0x2d73
movq 0x52b0(%rip), %rdi      # 0x7fd0
leaq 0x248c(%rip), %rsi      # 0x51b3
callq 0x2110
movq %rax, 0x28(%rsp)
jmp 0x2d33
movq 0x28(%rsp), %rdi
movl 0x118(%rsp), %esi
callq 0x21d0
movq %rax, 0x20(%rsp)
jmp 0x2d4b
movq 0x20(%rsp), %rdi
movq 0x5261(%rip), %rsi      # 0x7fb8
callq 0x2130
jmp 0x2d5e
movb $0x0, 0x15ff(%rsp)
movl $0x1, 0x138(%rsp)
jmp 0x2dcb
jmp 0x2d75
movl 0x118(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x118(%rsp)
jmp 0x2c22
movq 0x523e(%rip), %rdi      # 0x7fd0
leaq 0x2479(%rip), %rsi      # 0x5212
callq 0x2110
movq %rax, 0x18(%rsp)
jmp 0x2da5
movq 0x18(%rsp), %rdi
movq 0x5207(%rip), %rsi      # 0x7fb8
callq 0x2130
jmp 0x2db8
movb $0x1, 0x15ff(%rsp)
movl $0x1, 0x138(%rsp)
leaq 0x1a8(%rsp), %rdi
callq 0x3ba0
leaq 0x270(%rsp), %rdi
callq 0x3520
movb 0x15ff(%rsp), %al
andb $0x1, %al
movq %rbp, %rsp
popq %rbp
retq
leaq 0x270(%rsp), %rdi
vzeroupper
callq 0x3520
movq 0x260(%rsp), %rdi
callq 0x21e0