// File: /workspace/github_c_makefile_star2_O0/skeeto[P]hash-prospector/prospector.c
// Function: main
int
main(int argc, char **argv)
{
    int nops = 0;
    int min = 3;
    int max = 6;
    int flags = 0;
    int use_exact = 0;
    double best = 100.0;
    char *dynamic = 0;
    char *template = 0;
    struct hf_op ops[32];
    void *buf = execbuf_alloc();
    uint64_t rng[2] = {0x2a2bc037b59ff989, 0x6d7db86fa2f632ca};

    enum {MODE_SEARCH, MODE_EVAL, MODE_LIST} mode = MODE_SEARCH;

    int option;
    while ((option = getopt(argc, argv, "48EehLl:q:r:st:p:")) != -1) {
        switch (option) {
            case '4':
                flags &= ~F_U64;
                break;
            case '8':
                flags |= F_U64;
                break;
            case 'E':
                mode = MODE_EVAL;
                break;
            case 'e':
                use_exact = 1;
                break;
            case 'h': usage(stdout);
                exit(EXIT_SUCCESS);
                break;
            case 'L':
                mode = MODE_LIST;
                break;
            case 'l':
                dynamic = optarg;
                break;
            case 'p':
                template = optarg;
                break;
            case 'r':
                if (sscanf(optarg, "%d:%d", &min, &max) != 2 ||
                    min < 1 || max > countof(ops) || min > max) {
                    fprintf(stderr, "prospector: invalid range (-r): %s\n",
                            optarg);
                    exit(EXIT_FAILURE);
                }
                break;
            case 'q':
                score_quality = atoi(optarg);
                if (score_quality < 12 || score_quality > 30) {
                    fprintf(stderr, "prospector: invalid quality: %s\n",
                            optarg);
                    exit(EXIT_FAILURE);
                }
                break;
            case 'S':
                mode = MODE_SEARCH;
                break;
            case 's':
                flags |= F_TINY;
                break;
            case 't':
                best = strtod(optarg, 0);
                break;
            default:
                usage(stderr);
                exit(EXIT_FAILURE);
        }
    }

    /* Get a unique seed */
    FILE *urandom = fopen("/dev/urandom", "rb");
    if (urandom) {
        if (!fread(rng, sizeof(rng), 1, urandom)) {
            fputs("prospector: failed to read /dev/urandom\n", stderr);
            exit(EXIT_FAILURE);
        }
        fclose(urandom);
    }

    if (template) {
        nops = parse_template(ops, countof(ops), template, flags);
        if (!nops) {
            fprintf(stderr, "prospector: invalid template\n");
            exit(EXIT_FAILURE);
        }
    }

    if (mode == MODE_EVAL) {
        double bias;
        void *hashptr = 0;
        if (template) {
            hf_randfunc(ops, nops, rng);
            hf_compile(ops, nops, buf);
            execbuf_lock(buf);
            hashptr = buf;
        } else if (dynamic) {
            hashptr = load_function(dynamic);
        } else {
            fprintf(stderr, "prospector: must supply -p or -l\n");
            exit(EXIT_FAILURE);
        }

        uint64_t nhash;
        uint64_t beg = uepoch();
        if (flags & F_U64) {
            uint64_t ABI (*hash)(uint64_t) = hashptr;
            if (use_exact)
                fputs("warning: no exact bias for 64-bit\n", stderr);
            bias = estimate_bias64(hash, rng);
            nhash = (1L << score_quality) * 33;
        } else {
            uint32_t ABI (*hash)(uint32_t) = hashptr;
            if (use_exact) {
                bias = exact_bias32(hash);
                nhash = (1LL << 32) * 33;
            } else {
                bias = estimate_bias32(hash, rng);
                nhash = (1L << score_quality) * 65;
            }
        }
        uint64_t end = uepoch();
        printf("bias      = %.17g\n", bias);
        printf("speed     = %.3f nsec / hash\n", (end - beg) * 1000.0 / nhash);
        return 0;
    }

    if (mode == MODE_LIST) {
        void *hashptr = 0;
        if (template) {
            hf_randfunc(ops, nops, rng);
            hf_compile(ops, nops, buf);
            execbuf_lock(buf);
            hashptr = buf;
        } else if (dynamic) {
            hashptr = load_function(dynamic);
        } else {
            fprintf(stderr, "prospector: must supply -p or -l\n");
            exit(EXIT_FAILURE);
        }

        if (flags & F_U64) {
            uint64_t ABI (*hash)(uint64_t) = hashptr;
            uint64_t i = 0;
            do
                printf("%016llx %016llx\n",
                        (unsigned long long)i,
                        (unsigned long long)hash(i));
            while (++i);
        } else {
            uint32_t ABI (*hash)(uint32_t) = hashptr;
            uint32_t i = 0;
            do
                printf("%08lx %08lx\n",
                        (unsigned long)i,
                        (unsigned long)hash(i));
            while (++i);
        }
        return 0;
    }

    for (;;) {
        /* Generate */
        if (template) {
            hf_randfunc(ops, nops, rng);
        } else {
            nops = min + xoroshiro128plus(rng) % (max - min + 1);
            hf_genfunc(ops, nops, flags, rng);
        }

        /* Evaluate */
        double score;
        hf_compile(ops, nops, buf);
        execbuf_lock(buf);
        if (flags & F_U64) {
            uint64_t ABI (*hash)(uint64_t) = (void *)buf;
            score = estimate_bias64(hash, rng);
        } else {
            uint32_t ABI (*hash)(uint32_t) = (void *)buf;
            score = estimate_bias32(hash, rng);
        }
        execbuf_unlock(buf);

        /* Compare */
        if (score < best) {
            printf("// score = %.17g\n", score);
            hf_printfunc(ops, nops, stdout);
            fflush(stdout);
            best = score;
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x410, %rsp            # imm = 0x410
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x14(%rbp)
movl $0x3, -0x18(%rbp)
movl $0x6, -0x1c(%rbp)
movl $0x0, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movsd 0x2ce4(%rip), %xmm0     # 0x4008
movsd %xmm0, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
callq 0x1b30
movq %rax, -0x348(%rbp)
movq 0x2d14(%rip), %rax      # 0x4060
movq %rax, -0x360(%rbp)
movq 0x2d0e(%rip), %rax      # 0x4068
movq %rax, -0x358(%rbp)
movl $0x0, -0x364(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0x2f9f(%rip), %rdx      # 0x4318
callq 0x1170
movl %eax, -0x368(%rbp)
cmpl $-0x1, %eax
je 0x154f
movl -0x368(%rbp), %eax
addl $-0x34, %eax
movl %eax, %ecx
movq %rcx, -0x3f0(%rbp)
subl $0x40, %eax
ja 0x1531
movq -0x3f0(%rbp), %rax
leaq 0x2cba(%rip), %rcx      # 0x4070
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl -0x20(%rbp), %eax
andl $-0x2, %eax
movl %eax, -0x20(%rbp)
jmp 0x154a
movl -0x20(%rbp), %eax
orl $0x1, %eax
movl %eax, -0x20(%rbp)
jmp 0x154a
movl $0x1, -0x364(%rbp)
jmp 0x154a
movl $0x1, -0x24(%rbp)
jmp 0x154a
movq 0x4bd3(%rip), %rax      # 0x5fd0
movq (%rax), %rdi
callq 0x1bc0
xorl %edi, %edi
callq 0x11b0
movl $0x2, -0x364(%rbp)
jmp 0x154a
movq 0x4bb6(%rip), %rax      # 0x5fd8
movq (%rax), %rax
movq %rax, -0x38(%rbp)
jmp 0x154a
movq 0x4ba3(%rip), %rax      # 0x5fd8
movq (%rax), %rax
movq %rax, -0x40(%rbp)
jmp 0x154a
movq 0x4b90(%rip), %rax      # 0x5fd8
movq (%rax), %rdi
leaq 0x2ed8(%rip), %rsi      # 0x432a
leaq -0x18(%rbp), %rdx
leaq -0x1c(%rbp), %rcx
movb $0x0, %al
callq 0x1130
cmpl $0x2, %eax
jne 0x147a
cmpl $0x1, -0x18(%rbp)
jl 0x147a
cmpl $0x20, -0x1c(%rbp)
jg 0x147a
movl -0x18(%rbp), %eax
cmpl -0x1c(%rbp), %eax
jle 0x14a6
movq 0x4b77(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x4b4d(%rip), %rax      # 0x5fd8
movq (%rax), %rdx
leaq 0x2e9b(%rip), %rsi      # 0x4330
movb $0x0, %al
callq 0x1110
movl $0x1, %edi
callq 0x11b0
jmp 0x154a
movq 0x4b26(%rip), %rax      # 0x5fd8
movq (%rax), %rdi
callq 0x1190
movl %eax, 0x4c40(%rip)      # 0x6100
cmpl $0xc, 0x4c39(%rip)      # 0x6100
jl 0x14d2
cmpl $0x1e, 0x4c30(%rip)     # 0x6100
jle 0x14fe
movq 0x4b1f(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x4af5(%rip), %rax      # 0x5fd8
movq (%rax), %rdx
leaq 0x2e67(%rip), %rsi      # 0x4354
movb $0x0, %al
callq 0x1110
movl $0x1, %edi
callq 0x11b0
jmp 0x154a
movl $0x0, -0x364(%rbp)
jmp 0x154a
movl -0x20(%rbp), %eax
orl $0x2, %eax
movl %eax, -0x20(%rbp)
jmp 0x154a
movq 0x4aba(%rip), %rax      # 0x5fd8
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1060
movsd %xmm0, -0x30(%rbp)
jmp 0x154a
movq 0x4ac0(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
callq 0x1bc0
movl $0x1, %edi
callq 0x11b0
jmp 0x136b
leaq 0x2e1f(%rip), %rdi      # 0x4375
leaq 0x2e25(%rip), %rsi      # 0x4382
callq 0x1150
movq %rax, -0x370(%rbp)
cmpq $0x0, -0x370(%rbp)
je 0x15c2
leaq -0x360(%rbp), %rdi
movq -0x370(%rbp), %rcx
movl $0x10, %esi
movl $0x1, %edx
callq 0x1050
cmpq $0x0, %rax
jne 0x15b6
movq 0x4a5b(%rip), %rax      # 0x5ff8
movq (%rax), %rsi
leaq 0x2dde(%rip), %rdi      # 0x4385
callq 0x10b0
movl $0x1, %edi
callq 0x11b0
movq -0x370(%rbp), %rdi
callq 0x1070
cmpq $0x0, -0x40(%rbp)
je 0x160e
leaq -0x340(%rbp), %rdi
movq -0x40(%rbp), %rdx
movl -0x20(%rbp), %ecx
movl $0x20, %esi
callq 0x1cd0
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x14(%rbp)
jne 0x160c
movq 0x4a07(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
leaq 0x2db3(%rip), %rsi      # 0x43ae
movb $0x0, %al
callq 0x1110
movl $0x1, %edi
callq 0x11b0
jmp 0x160e
cmpl $0x1, -0x364(%rbp)
jne 0x183d
movq $0x0, -0x380(%rbp)
cmpq $0x0, -0x40(%rbp)
je 0x1675
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
leaq -0x360(%rbp), %rdx
callq 0x1e60
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x348(%rbp), %rdx
callq 0x1ed0
movq -0x348(%rbp), %rdi
callq 0x2e30
movq -0x348(%rbp), %rax
movq %rax, -0x380(%rbp)
jmp 0x16b2
cmpq $0x0, -0x38(%rbp)
je 0x168e
movq -0x38(%rbp), %rdi
callq 0x2ef0
movq %rax, -0x380(%rbp)
jmp 0x16b0
movq 0x4963(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
leaq 0x2d2d(%rip), %rsi      # 0x43cc
movb $0x0, %al
callq 0x1110
movl $0x1, %edi
callq 0x11b0
jmp 0x16b2
callq 0x2f90
movq %rax, -0x390(%rbp)
movl -0x20(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x172b
movq -0x380(%rbp), %rax
movq %rax, -0x398(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x16f3
movq 0x4914(%rip), %rax      # 0x5ff8
movq (%rax), %rsi
leaq 0x2d00(%rip), %rdi      # 0x43ee
callq 0x10b0
movq -0x398(%rbp), %rdi
leaq -0x360(%rbp), %rsi
callq 0x2fc0
movsd %xmm0, -0x378(%rbp)
movl 0x49ec(%rip), %eax      # 0x6100
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
imulq $0x21, %rax, %rax
movq %rax, -0x388(%rbp)
jmp 0x179e
movq -0x380(%rbp), %rax
movq %rax, -0x3a0(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x1766
movq -0x3a0(%rbp), %rdi
callq 0x3240
movsd %xmm0, -0x378(%rbp)
movabsq $0x2100000000, %rax     # imm = 0x2100000000
movq %rax, -0x388(%rbp)
jmp 0x179c
movq -0x3a0(%rbp), %rdi
leaq -0x360(%rbp), %rsi
callq 0x3560
movsd %xmm0, -0x378(%rbp)
movl 0x4979(%rip), %eax      # 0x6100
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
imulq $0x41, %rax, %rax
movq %rax, -0x388(%rbp)
jmp 0x179e
callq 0x2f90
movq %rax, -0x3a8(%rbp)
movsd -0x378(%rbp), %xmm0
leaq 0x2c58(%rip), %rdi      # 0x4411
movb $0x1, %al
callq 0x1090
movq -0x3a8(%rbp), %rax
movq -0x390(%rbp), %rcx
subq %rcx, %rax
movq %rax, %xmm0
movaps 0x2863(%rip), %xmm3     # 0x4040
punpckldq %xmm3, %xmm0    # xmm0 = xmm0[0],xmm3[0],xmm0[1],xmm3[1]
movapd 0x2867(%rip), %xmm2     # 0x4050
subpd %xmm2, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd 0x2810(%rip), %xmm1     # 0x4010
mulsd %xmm1, %xmm0
movq -0x388(%rbp), %xmm1
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
subpd %xmm2, %xmm1
movaps %xmm1, %xmm2
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm2, %xmm1
divsd %xmm1, %xmm0
leaq 0x2bfa(%rip), %rdi      # 0x4424
movb $0x1, %al
callq 0x1090
movl $0x0, -0x4(%rbp)
jmp 0x1b23
cmpl $0x2, -0x364(%rbp)
jne 0x19c4
movq $0x0, -0x3b0(%rbp)
cmpq $0x0, -0x40(%rbp)
je 0x18a4
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
leaq -0x360(%rbp), %rdx
callq 0x1e60
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x348(%rbp), %rdx
callq 0x1ed0
movq -0x348(%rbp), %rdi
callq 0x2e30
movq -0x348(%rbp), %rax
movq %rax, -0x3b0(%rbp)
jmp 0x18e1
cmpq $0x0, -0x38(%rbp)
je 0x18bd
movq -0x38(%rbp), %rdi
callq 0x2ef0
movq %rax, -0x3b0(%rbp)
jmp 0x18df
movq 0x4734(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
leaq 0x2afe(%rip), %rsi      # 0x43cc
movb $0x0, %al
callq 0x1110
movl $0x1, %edi
callq 0x11b0
jmp 0x18e1
movl -0x20(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x1955
movq -0x3b0(%rbp), %rax
movq %rax, -0x3b8(%rbp)
movq $0x0, -0x3c0(%rbp)
movq -0x3c0(%rbp), %rax
movq %rax, -0x3f8(%rbp)
movq -0x3b8(%rbp), %rax
movq -0x3c0(%rbp), %rdi
callq *%rax
movq -0x3f8(%rbp), %rsi
movq %rax, %rdx
leaq 0x2b0e(%rip), %rdi      # 0x4442
movb $0x0, %al
callq 0x1090
movq -0x3c0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x3c0(%rbp)
cmpq $0x0, %rax
jne 0x1905
jmp 0x19b8
movq -0x3b0(%rbp), %rax
movq %rax, -0x3c8(%rbp)
movl $0x0, -0x3cc(%rbp)
movl -0x3cc(%rbp), %eax
movq %rax, -0x400(%rbp)
movq -0x3c8(%rbp), %rax
movl -0x3cc(%rbp), %edi
callq *%rax
movq -0x400(%rbp), %rsi
movl %eax, %eax
movl %eax, %edx
leaq 0x2ab8(%rip), %rdi      # 0x4453
movb $0x0, %al
callq 0x1090
movl -0x3cc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3cc(%rbp)
cmpl $0x0, %eax
jne 0x196d
jmp 0x19b8
movl $0x0, -0x4(%rbp)
jmp 0x1b23
jmp 0x19c6
cmpq $0x0, -0x40(%rbp)
je 0x19e5
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
leaq -0x360(%rbp), %rdx
callq 0x1e60
jmp 0x1a33
movslq -0x18(%rbp), %rax
movq %rax, -0x408(%rbp)
leaq -0x360(%rbp), %rdi
callq 0x37d0
movl -0x1c(%rbp), %ecx
subl -0x18(%rbp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
xorl %edx, %edx
divq %rcx
movq -0x408(%rbp), %rax
addq %rdx, %rax
movl %eax, -0x14(%rbp)
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
movl -0x20(%rbp), %edx
leaq -0x360(%rbp), %rcx
callq 0x3860
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x348(%rbp), %rdx
callq 0x1ed0
movq -0x348(%rbp), %rdi
callq 0x2e30
movl -0x20(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x1a8b
movq -0x348(%rbp), %rax
movq %rax, -0x3e0(%rbp)
movq -0x3e0(%rbp), %rdi
leaq -0x360(%rbp), %rsi
callq 0x2fc0
movsd %xmm0, -0x3d8(%rbp)
jmp 0x1ab4
movq -0x348(%rbp), %rax
movq %rax, -0x3e8(%rbp)
movq -0x3e8(%rbp), %rdi
leaq -0x360(%rbp), %rsi
callq 0x3560
movsd %xmm0, -0x3d8(%rbp)
movq -0x348(%rbp), %rdi
callq 0x3900
movsd -0x3d8(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1b1e
movsd -0x3d8(%rbp), %xmm0
leaq 0x297e(%rip), %rdi      # 0x4460
movb $0x1, %al
callq 0x1090
leaq -0x340(%rbp), %rdi
movl -0x14(%rbp), %esi
movq 0x44d6(%rip), %rax      # 0x5fd0
movq (%rax), %rdx
callq 0x3960
movq 0x44c7(%rip), %rax      # 0x5fd0
movq (%rax), %rdi
callq 0x1120
movsd -0x3d8(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
jmp 0x19c6
movl -0x4(%rbp), %eax
addq $0x410, %rsp            # imm = 0x410
popq %rbp
retq
nop