// File: bitwiseshiftleft[P]crandom/test_random.cpp
// Function: main
int main(int argc, char **argv) {
  (void) argc; (void) argv;
  
  crandom_features = crandom_detect_features();
  
  unsigned int chacha_features = SSE2 | SSSE3 | XOP, aes_features = AESNI;
  
  prg_generator<chacha> *ch = new prg_generator<chacha>(true);
  prg_generator<aes> *ae = new prg_generator<aes>(true);
  printf("****** Generators and processor features ******\n\n");
  
  printf("chacha, direct, u_int32_t");
  test<prg_generator<chacha>, u_int32_t, false>(100000000, SSE2 | SSSE3 | XOP, chacha_features, ch);
  printf("chacha, direct, u_int32_t");
  test<prg_generator<chacha>, u_int32_t, false>(100000000, SSE2 | SSSE3, chacha_features, ch);
  printf("chacha, direct, u_int32_t");
  test<prg_generator<chacha>, u_int32_t, false>(100000000, SSE2, chacha_features, ch);
  printf("chacha, direct, u_int32_t");
  test<prg_generator<chacha>, u_int32_t, false>(10000000, 0, chacha_features, ch);
  
  printf("aes, direct, u_int32_t");
  test<prg_generator<aes>, u_int32_t, false>(100000000, AESNI, aes_features, ae);
  printf("aes, direct, u_int32_t");
  test<prg_generator<aes>, u_int32_t, false>(10000000, 0, aes_features, ae);
  
  printf("rand, int\n");
  test_rand(100000000);
  
  printf("random, int\n");
  test_random(100000000);
  
  #ifdef __MAC_10_0
    printf("arc4random, int\n");
    test_arc4random(10000000);
  #endif
  
  printf("drand48, int\n");
  test_drand48(10000000);
  
  printf("****** Data sizes ******\n\n");
  
  printf("chacha, direct, u_int128_t");
  test<prg_generator<chacha>, u_int128_t, false>(100000000, 0, 0, ch);
  printf("chacha, direct, u_int8_t");
  test<prg_generator<chacha>, u_int8_t, false>(100000000, 0, 0, ch);
  printf("chacha, direct, float");
  test<prg_generator<chacha>, float, false>(100000000, 0, 0, ch);
  printf("chacha, direct, double");
  test<prg_generator<chacha>, double, false>(100000000, 0, 0, ch);
  printf("aes, direct, u_int128_t");
  test<prg_generator<aes>, u_int128_t, false>(100000000, AESNI, aes_features, ae);
  printf("aes, direct, u_int8_t");
  test<prg_generator<aes>, u_int8_t, false>(100000000, 0, 0, ae);
  
  printf("****** Indirection ******\n\n");
  
  printf("aes, indirect, u_int32_t");
  test<generator_base, u_int32_t, false>(100000000, 0, 0,
    opacify(1) ? static_cast<generator_base *>(ae) : static_cast<generator_base *>(ch));
  printf("chacha, indirect, u_int32_t");
  test<generator_base, u_int32_t, false>(100000000, 0, 0,
    opacify(1) ? static_cast<generator_base *>(ch) : static_cast<generator_base *>(ae));
  printf("chacha, indirect, u_int32_t, slow case");
  test<generator_base, u_int32_t, true>(100000000, 0, 0,
    opacify(1) ? static_cast<generator_base *>(ch) : static_cast<generator_base *>(ae));
  
  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl $0x0, -0x1c(%rbp)
movl %edi, -0x20(%rbp)
movq %rsi, -0x28(%rbp)
callq 0x6890
movl %eax, %ecx
leaq 0x8f29(%rip), %rax      # 0xa4e0
movl %ecx, (%rax)
movl $0x16, -0x2c(%rbp)
movl $0x8, -0x30(%rbp)
movl $0x28, %edi
callq 0x10e0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x58(%rbp)
movl $0x1, %esi
callq 0x19d0
jmp 0x15e7
movq -0x58(%rbp), %rax
movq %rax, -0x38(%rbp)
movl $0x28, %edi
callq 0x10e0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x60(%rbp)
movl $0x1, %esi
callq 0x1a30
jmp 0x160f
movq -0x60(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq 0x5a82(%rip), %rdi      # 0x70a0
movb $0x0, %al
callq 0x1030
leaq 0x5aa6(%rip), %rdi      # 0x70d2
movb $0x0, %al
callq 0x1030
movl -0x2c(%rbp), %edx
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
movl $0x16, %esi
callq 0x1a90
leaq 0x5a82(%rip), %rdi      # 0x70d2
movb $0x0, %al
callq 0x1030
movl -0x2c(%rbp), %edx
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
movl $0x6, %esi
callq 0x1a90
leaq 0x5a5e(%rip), %rdi      # 0x70d2
movb $0x0, %al
callq 0x1030
movl -0x2c(%rbp), %edx
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
movl $0x2, %esi
callq 0x1a90
leaq 0x5a3a(%rip), %rdi      # 0x70d2
movb $0x0, %al
callq 0x1030
movl -0x2c(%rbp), %edx
movq -0x38(%rbp), %rcx
movl $0x989680, %edi         # imm = 0x989680
xorl %esi, %esi
callq 0x1a90
leaq 0x5a33(%rip), %rdi      # 0x70ec
movb $0x0, %al
callq 0x1030
movl -0x30(%rbp), %edx
movq -0x50(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
movl $0x8, %esi
callq 0x1c20
leaq 0x5a0f(%rip), %rdi      # 0x70ec
movb $0x0, %al
callq 0x1030
movl -0x30(%rbp), %edx
movq -0x50(%rbp), %rcx
movl $0x989680, %edi         # imm = 0x989680
xorl %esi, %esi
callq 0x1c20
leaq 0x5a05(%rip), %rdi      # 0x7103
movb $0x0, %al
callq 0x1030
movl $0x5f5e100, %edi        # imm = 0x5F5E100
callq 0x1300
leaq 0x59f8(%rip), %rdi      # 0x710e
movb $0x0, %al
callq 0x1030
movl $0x5f5e100, %edi        # imm = 0x5F5E100
callq 0x1410
leaq 0x59ed(%rip), %rdi      # 0x711b
movb $0x0, %al
callq 0x1030
movl $0x989680, %edi         # imm = 0x989680
callq 0x14e0
leaq 0x59e3(%rip), %rdi      # 0x7129
movb $0x0, %al
callq 0x1030
leaq 0x59f0(%rip), %rdi      # 0x7144
movb $0x0, %al
callq 0x1030
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x1db0
leaq 0x59eb(%rip), %rdi      # 0x715f
movb $0x0, %al
callq 0x1030
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x1f60
leaq 0x59e4(%rip), %rdi      # 0x7178
movb $0x0, %al
callq 0x1030
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x20f0
leaq 0x59da(%rip), %rdi      # 0x718e
movb $0x0, %al
callq 0x1030
movq -0x38(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x22b0
leaq 0x59d1(%rip), %rdi      # 0x71a5
movb $0x0, %al
callq 0x1030
movl -0x30(%rbp), %edx
movq -0x50(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
movl $0x8, %esi
callq 0x2470
leaq 0x59c5(%rip), %rdi      # 0x71bd
movb $0x0, %al
callq 0x1030
movq -0x50(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x2620
leaq 0x59bb(%rip), %rdi      # 0x71d3
movb $0x0, %al
callq 0x1030
leaq 0x59c9(%rip), %rdi      # 0x71ef
movb $0x0, %al
callq 0x1030
movq $0x1, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, %rax
movq %rax, -0x8(%rbp)
cmpq $0x0, -0x8(%rbp)
je 0x1851
movq -0x50(%rbp), %rax
movq %rax, -0x68(%rbp)
jmp 0x1859
movq -0x38(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x27b0
leaq 0x5996(%rip), %rdi      # 0x7208
movb $0x0, %al
callq 0x1030
movq $0x1, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq %rax, %rax
movq %rax, -0x10(%rbp)
cmpq $0x0, -0x10(%rbp)
je 0x189d
movq -0x38(%rbp), %rax
movq %rax, -0x70(%rbp)
jmp 0x18a5
movq -0x50(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x27b0
leaq 0x5966(%rip), %rdi      # 0x7224
movb $0x0, %al
callq 0x1030
movq $0x1, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq %rax, %rax
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x18e9
movq -0x38(%rbp), %rax
movq %rax, -0x78(%rbp)
jmp 0x18f1
movq -0x50(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rcx
movl $0x5f5e100, %edi        # imm = 0x5F5E100
xorl %edx, %edx
movl %edx, %esi
callq 0x2940
xorl %eax, %eax
addq $0x80, %rsp
popq %rbp
retq
movq -0x58(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
movl $0x28, %esi
callq 0x10f0
jmp 0x1944
movq -0x60(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
movl $0x28, %esi
callq 0x10f0
movq -0x40(%rbp), %rdi
callq 0x1130
nopl (%rax)