// File: /workspace/github_c_makefile_star2_O3/skeeto[P]hash-prospector/hillclimb.c
// Function: main
int
main(int argc, char **argv)
{
    int seeded = 0;
    uint64_t rng[4];
    struct hash cur, last = {0};
    int generate = 1;
    int one_shot = 0;
    int quiet = 0;
    int invert = 0;
    int evaluate = 0;
    double cur_score = -1;

    int option;
    while ((option = getopt(argc, argv, "EhIp:qsx:")) != -1) {
        switch (option) {
            case 'E': {
                evaluate = 1;
            } break;
            case 'h': {
                usage(stdout);
                exit(EXIT_SUCCESS);
            } break;
            case 'I': {
                invert = 1;
            } break;
            case 'p': {
                if (!hash_parse(&cur, optarg)) {
                    fprintf(stderr, "hillclimb: invalid pattern: %s\n", optarg);
                    exit(EXIT_FAILURE);
                }
                generate = 0;
            } break;
            case 'q': {
                quiet++;
            } break;
            case 's': {
                one_shot = 1;
            } break;
            case 'x': {
                unsigned char buf[32] = {0};
                size_t len = strlen(optarg);
                if (len > sizeof(buf)) {
                    fprintf(stderr, "hillclimb: seed too long (> 32 bytes)\n");
                    exit(EXIT_FAILURE);
                }
                memcpy(buf, optarg, len);
                rng[0] = load64(buf +  0);
                rng[1] = load64(buf +  8);
                rng[2] = load64(buf + 16);
                rng[3] = load64(buf + 24);
                mix64x4(rng);
                seeded = 1;
            } break;
            default:
                usage(stderr);
                exit(EXIT_FAILURE);
        }
    }

    if (invert) {
        if (generate) {
            fprintf(stderr, "hillclimb: -I requires -p\n");
            exit(EXIT_FAILURE);
        }
        printf("uint32_t\nhash_r(uint32_t x)\n{\n");
        for (int i = 0; i < HASHN * 2 + 1; i++) {
            switch (i & 1) {
                case 0: {
                    int s = HASHN - i / 2;
                    printf("    x ^=");
                    for (int i = cur.s[s]; i < 32; i += cur.s[s])
                        printf(" %sx >> %d", i == cur.s[s] ? "" : "^ ", i);
                    printf(";\n");
                } break;
                case 1: {
                    int c = HASHN - (i + 1) / 2;
                    unsigned long inv = modinv32(cur.c[c]);
                    printf("    x *= 0x%08lx;\n", inv);
                } break;
            }
        }
        printf("    return x;\n}\n");
        exit(EXIT_SUCCESS);
    }

    if (evaluate) {
        if (generate) {
            fprintf(stderr, "hillclimb: -E requires -p\n");
            exit(EXIT_FAILURE);
        }
        hash_print(&cur);
        printf(" = %.17g\n", exact_bias32(&cur));
        exit(EXIT_SUCCESS);
    }

    if (!seeded)
        rng_init(rng);

    if (generate)
        hash_gen_strict(&cur, rng);

    for (;;) {
        int found = 0;
        struct hash best;
        double best_score;

        if (quiet < 2)
            hash_print(&cur);
        if (cur_score < 0)
            cur_score = exact_bias32(&cur);
        if (quiet < 2)
            printf(" = %.17g\n", cur_score);

        best = cur;
        best_score = cur_score;

        /* Explore around shifts */
        for (int i = 0; i <= HASHN; i++) {
            /* In theory the shift could drift above 31 or below 1, but
             * in practice it would never get this far since these would
             * be terrible hashes.
             */
            for (int d = -SHIFT_RANGE; d <= +SHIFT_RANGE; d++) {
                if (d == 0) continue;
                struct hash tmp = cur;
                tmp.s[i] += d;
                if (hash_equal(&tmp, &last)) continue;
                if (quiet <= 0) {
                    printf("  ");
                    hash_print(&tmp);
                }
                double score = exact_bias32(&tmp);
                if (quiet <= 0)
                    printf(" = %.17g\n", score);
                if (score < best_score) {
                    best_score = score;
                    best = tmp;
                    found = 1;
                }
            }
        }

        /* Explore around constants */
        for (int i = 0; i < HASHN; i++) {
            for (int d = -CONST_RANGE; d <= +CONST_RANGE; d += 2) {
                if (d == 0) continue;
                struct hash tmp = cur;
                tmp.c[i] += d;
                if (hash_equal(&tmp, &last)) continue;
                if (quiet <= 0) {
                    printf("  ");
                    hash_print(&tmp);
                }
                double score = exact_bias32(&tmp);
                if (quiet <= 0)
                    printf(" = %.17g\n", score);
                if (score < best_score) {
                    best_score = score;
                    best = tmp;
                    found = 1;
                }
            }
        }

        if (found) {
            /* Move to the lowest item found */
            if (quiet < 1)
                puts("CLIMB");
            last = cur;
            cur = best;
            cur_score = best_score;
        } else if (one_shot) {
            /* Hit local minima, exit */
            if (quiet < 1)
                puts("DONE");
            hash_print(&cur);
            printf(" = %.17g\n", cur_score);
            break;
        } else {
            /* Hit local minima, reset */
            if (quiet < 1)
                puts("RESET");
            hash_print(&cur);
            printf(" = %.17g\n", cur_score);
            last.s[0] = 0; // set to invalid
            hash_gen_strict(&cur, rng);
            cur_score = -1;
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rsi, 0x38(%rsp)
xorps %xmm0, %xmm0
movaps %xmm0, 0x60(%rsp)
movl $0x1, 0x14(%rsp)
movq $0x0, 0x98(%rsp)
movb $0x1, %al
movl %eax, 0x58(%rsp)
movl 0x3d67(%rip), %ebx      # 0x50c4
xorl %r12d, %r12d
movl $0x0, 0x5c(%rsp)
movl $0x0, 0x8(%rsp)
movl 0x3d49(%rip), %r13d     # 0x50c0
movq 0x3d52(%rip), %r14      # 0x50d0
movq %r14, 0x18(%rsp)
testl %ebx, %ebx
jne 0x13a0
movl $0x1, %r13d
movl %r13d, 0x3d30(%rip)     # 0x50c4
movl %r13d, 0x3d25(%rip)     # 0x50c0
movl $0x1, %ebx
movslq %ebx, %rbp
movq 0x38(%rsp), %rax
movq (%rax,%rbp,8), %r14
testq %r14, %r14
je 0x1694
cmpb $0x2d, (%r14)
jne 0x1694
movl %ebx, %r15d
movsbq 0x1(%r14), %rbx
cmpq $0x2d, %rbx
jne 0x13d8
cmpb $0x0, 0x2(%r14)
je 0x168a
callq 0x1150
movq (%rax), %rax
testb $0x8, (%rax,%rbx,2)
je 0x1694
movslq %r13d, %rbx
movsbl (%r14,%rbx), %r13d
movl $0xa, %edx
leaq 0x1c42(%rip), %rdi      # 0x3040
movl %r13d, %esi
callq 0x10a0
testq %rax, %rax
je 0x19be
cmpb $0x3a, 0x1(%rax)
jne 0x142c
addq %rbx, %r14
cmpb $0x0, 0x1(%r14)
je 0x144b
incq %r14
movl $0x1, %eax
movl %r15d, %ebx
jmp 0x1466
leaq 0x1(%rbx), %rax
movl %eax, 0x3c8a(%rip)      # 0x50c0
cmpb $0x0, 0x1(%r14,%rbx)
je 0x146f
movq %rax, %rbp
movl %r15d, %ebx
movq 0x18(%rsp), %r14
jmp 0x1493
movq 0x38(%rsp), %rax
movq 0x8(%rax,%rbp,8), %r14
movl $0x2, %eax
testq %r14, %r14
movl %r15d, %ebx
je 0x19fa
movq %r14, 0x3c63(%rip)      # 0x50d0
jmp 0x147c
movl $0x1, %eax
movl %r15d, %ebx
movq 0x18(%rsp), %r14
addl %eax, %ebx
movl %ebx, 0x3c40(%rip)      # 0x50c4
movl $0x1, 0x3c32(%rip)      # 0x50c0
movl $0x1, %ebp
cmpb $0x78, %r13b
jne 0x1507
xorps %xmm0, %xmm0
movaps %xmm0, 0x80(%rsp)
movaps %xmm0, 0x70(%rsp)
movq %r14, %rdi
callq 0x1060
cmpq $0x21, %rax
jae 0x1a28
leaq 0x70(%rsp), %rdi
movq %r14, %rsi
movq %rax, %rdx
callq 0x10d0
movaps 0x70(%rsp), %xmm0
movapd 0x80(%rsp), %xmm1
movaps %xmm0, 0xa0(%rsp)
movapd %xmm1, 0xb0(%rsp)
leaq 0xa0(%rsp), %rdi
callq 0x1c47
movl $0x1, 0x8(%rsp)
movq %rbp, %r13
jmp 0x137e
movzbl %r13b, %eax
cmpl $0x70, %eax
jg 0x1539
cmpl $0x67, %eax
jg 0x1558
cmpl $0x45, %eax
je 0x1669
cmpl $0x49, %eax
jne 0x19e1
movl $0x1, %eax
movq %rax, 0x98(%rsp)
jmp 0x1370
cmpl $0x71, %eax
je 0x1676
cmpl $0x73, %eax
jne 0x167e
movl $0x1, 0x5c(%rsp)
jmp 0x1370
cmpl $0x70, %eax
leaq 0x70(%rsp), %rbx
jne 0x1a0d
movq 0x3b63(%rip), %r14      # 0x50d0
cmpb $0x5b, (%r14)
jne 0x1a03
incq %r14
movq $-0x3, %r15
cmpq $-0x3, %r15
movl $0x0, %edi
cmoveq %r14, %rdi
leaq 0x1b67(%rip), %rsi      # 0x30fc
callq 0x1100
movq %rax, %rdi
movq %rbx, %rsi
movl $0xa, %edx
callq 0x10c0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x1a03
movq 0x70(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x1a03
movb %al, 0x2f(%rsp,%r15)
xorl %edi, %edi
leaq 0x1b25(%rip), %rsi      # 0x30fc
callq 0x1100
movq %rax, %rdi
movq %rbx, %rsi
movl $0x10, %edx
callq 0x1110
movq %rax, %rcx
shrq $0x20, %rcx
jne 0x1a03
movq 0x70(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x1a03
movl %eax, 0x2c(%rsp,%r15,4)
incq %r15
jne 0x1581
xorl %edi, %edi
leaq 0x1ca1(%rip), %rsi      # 0x32c2
callq 0x1100
movq %rax, %rdi
movq %rbx, %rsi
movl $0xa, %edx
callq 0x10c0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x1a03
movq 0x70(%rsp), %rcx
cmpb $0x0, (%rcx)
jne 0x1a03
movl 0x3a6c(%rip), %ebx      # 0x50c4
movb %al, 0x2f(%rsp)
movl $0x0, 0x14(%rsp)
jmp 0x1370
movl $0x0, 0x58(%rsp)
jmp 0x1370
incl %r12d
jmp 0x1370
cmpl $0xff, %eax
je 0x1694
jmp 0x19e1
incl %r15d
movl %r15d, 0x3a30(%rip)     # 0x50c4
cmpl $0x0, 0x98(%rsp)
jne 0x1a2d
testb $0x1, 0x58(%rsp)
je 0x1b41
cmpl $0x0, 0x8(%rsp)
jne 0x16c1
leaq 0xa0(%rsp), %rdi
callq 0x2128
cmpl $0x0, 0x14(%rsp)
je 0x16da
leaq 0x20(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x2188
movsd 0x1926(%rip), %xmm0     # 0x3008
leaq 0x40(%rsp), %r15
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x16fd
leaq 0x20(%rsp), %rdi
callq 0x1f1e
xorpd %xmm0, %xmm0
ucomisd 0x8(%rsp), %xmm0
jbe 0x1719
leaq 0x20(%rsp), %rdi
callq 0x1f7e
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x1733
leaq 0x19cb(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movups 0x20(%rsp), %xmm0
movaps %xmm0, 0x70(%rsp)
xorl %r14d, %r14d
movb 0x6f(%rsp), %r13b
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
xorl %ebx, %ebx
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
testl %ebp, %ebp
je 0x1805
movupd 0x20(%rsp), %xmm0
movapd %xmm0, 0x40(%rsp)
addb %bpl, 0x4c(%rsp,%r14)
xorl %eax, %eax
movl 0x40(%rsp,%rax,4), %ecx
cmpl 0x60(%rsp,%rax,4), %ecx
jne 0x1797
movb 0x4c(%rsp,%rax), %cl
cmpb 0x6c(%rsp,%rax), %cl
jne 0x1797
incq %rax
cmpq $0x3, %rax
jne 0x1773
cmpb %r13b, 0x4f(%rsp)
je 0x1805
testl %r12d, %r12d
jle 0x17aa
movq %r15, %rdi
callq 0x1f7e
movapd %xmm0, %xmm1
jmp 0x17e2
leaq 0x194a(%rip), %rdi      # 0x30fb
xorl %eax, %eax
callq 0x1070
movq %r15, %rdi
callq 0x1f1e
movq %r15, %rdi
callq 0x1f7e
movsd %xmm0, 0x38(%rsp)
leaq 0x191c(%rip), %rdi      # 0x30f1
movb $0x1, %al
callq 0x1070
movsd 0x38(%rsp), %xmm1
movsd 0x18(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1805
movapd 0x40(%rsp), %xmm0
movapd %xmm0, 0x70(%rsp)
movl $0x1, %ebx
movsd %xmm1, 0x18(%rsp)
incl %ebp
cmpl $0x2, %ebp
jne 0x1758
incq %r14
cmpq $0x4, %r14
jne 0x1753
xorl %r14d, %r14d
movl $0xfffffffe, %ebp       # imm = 0xFFFFFFFE
testl %ebp, %ebp
je 0x18d2
movupd 0x20(%rsp), %xmm0
movapd %xmm0, 0x40(%rsp)
addl %ebp, 0x40(%rsp,%r14,4)
xorl %eax, %eax
movl 0x40(%rsp,%rax,4), %ecx
cmpl 0x60(%rsp,%rax,4), %ecx
jne 0x1864
movb 0x4c(%rsp,%rax), %cl
cmpb 0x6c(%rsp,%rax), %cl
jne 0x1864
incq %rax
cmpq $0x3, %rax
jne 0x1840
cmpb %r13b, 0x4f(%rsp)
je 0x18d2
testl %r12d, %r12d
jle 0x1877
movq %r15, %rdi
callq 0x1f7e
movapd %xmm0, %xmm1
jmp 0x18af
leaq 0x187d(%rip), %rdi      # 0x30fb
xorl %eax, %eax
callq 0x1070
movq %r15, %rdi
callq 0x1f1e
movq %r15, %rdi
callq 0x1f7e
movsd %xmm0, 0x38(%rsp)
leaq 0x184f(%rip), %rdi      # 0x30f1
movb $0x1, %al
callq 0x1070
movsd 0x38(%rsp), %xmm1
movsd 0x18(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x18d2
movapd 0x40(%rsp), %xmm0
movapd %xmm0, 0x70(%rsp)
movl $0x1, %ebx
movsd %xmm1, 0x18(%rsp)
leal 0x2(%rbp), %eax
testl %ebp, %ebp
movl %eax, %ebp
jle 0x1825
incq %r14
cmpq $0x3, %r14
jne 0x1820
testl %ebx, %ebx
je 0x1920
testl %r12d, %r12d
jg 0x1901
leaq 0x1802(%rip), %rdi      # 0x30fe
callq 0x1050
movaps 0x20(%rsp), %xmm0
movaps %xmm0, 0x60(%rsp)
movaps 0x70(%rsp), %xmm0
movaps %xmm0, 0x20(%rsp)
movsd 0x18(%rsp), %xmm0
jmp 0x16e7
cmpl $0x0, 0x5c(%rsp)
jne 0x197b
testl %r12d, %r12d
jg 0x1938
leaq 0x17d6(%rip), %rdi      # 0x3109
callq 0x1050
leaq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x1f1e
leaq 0x17a5(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movb $0x0, 0x6c(%rsp)
movq %rbx, %rdi
leaq 0xa0(%rsp), %rsi
callq 0x2188
movsd 0x1692(%rip), %xmm0     # 0x3008
jmp 0x16e7
testl %r12d, %r12d
jg 0x198c
leaq 0x177d(%rip), %rdi      # 0x3104
callq 0x1050
leaq 0x20(%rsp), %rdi
callq 0x1f1e
leaq 0x1754(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x174a(%rip), %rsi      # 0x310f
movq 0x362c(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq 0x38(%rsp), %rax
movq (%rax), %rdx
movl %r13d, %ecx
xorl %eax, %eax
callq 0x10b0
movq 0x3610(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
callq 0x1b7a
movl $0x1, %edi
callq 0x1120
leaq 0x1726(%rip), %rsi      # 0x3127
jmp 0x19c5
leaq 0x70(%rsp), %rdi
callq 0x1195
cmpl $0x68, %eax
jne 0x19e1
movq 0x35bf(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
callq 0x1b7a
xorl %edi, %edi
callq 0x1120
callq 0x1170
cmpl $0x0, 0x14(%rsp)
jne 0x1b70
leaq 0x1885(%rip), %rdi      # 0x32c4
callq 0x1050
leaq 0x1757(%rip), %rbx      # 0x31a2
leaq 0x166e(%rip), %r14      # 0x30c0
leaq 0x165c(%rip), %r15      # 0x30b5
xorl %ebp, %ebp
testb $0x1, %bpl
je 0x1acb
incl %ebp
movl %ebp, %eax
shrl %eax
movl $0x3, %ecx
subl %eax, %ecx
movl 0x20(%rsp,%rcx,4), %eax
movl %eax, %ecx
imull %eax, %ecx
movl $0x2, %edx
subl %ecx, %edx
imull %eax, %edx
movl %edx, %ecx
imull %eax, %ecx
movl $0x2, %esi
subl %ecx, %esi
imull %edx, %esi
movl %esi, %ecx
imull %eax, %ecx
movl $0x2, %edx
subl %ecx, %edx
imull %esi, %edx
movl %edx, %ecx
imull %eax, %ecx
movl $0x2, %edi
subl %ecx, %edi
imull %edx, %edi
imull %edi, %eax
movl $0x2, %esi
subl %eax, %esi
imull %edi, %esi
leaq 0x1601(%rip), %rdi      # 0x30c3
xorl %eax, %eax
callq 0x1070
jmp 0x1b27
movl %ebp, %eax
shrl %eax
leaq 0x20(%rsp), %r12
subq %rax, %r12
leaq 0x15ce(%rip), %rdi      # 0x30ac
xorl %eax, %eax
callq 0x1070
movsbl 0xf(%r12), %r12d
cmpl $0x1f, %r12d
jg 0x1b19
xorl %eax, %eax
leal (%r12,%rax), %r13d
testl %eax, %eax
movq %r14, %rsi
cmoveq %rbx, %rsi
movq %r15, %rdi
movl %r13d, %edx
xorl %eax, %eax
callq 0x1070
leal (%r12,%r13), %ecx
movl %r13d, %eax
cmpl $0x20, %ecx
jl 0x1af3
leaq 0x17d2(%rip), %rdi      # 0x32f2
callq 0x1050
incl %ebp
cmpl $0x7, %ebp
jne 0x1a5b
leaq 0x17ab(%rip), %rdi      # 0x32e2
callq 0x1050
jmp 0x1a21
cmpl $0x0, 0x14(%rsp)
jne 0x1b75
leaq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x1f1e
movq %rbx, %rdi
callq 0x1f7e
leaq 0x158d(%rip), %rdi      # 0x30f1
movb $0x1, %al
callq 0x1070
jmp 0x1a21
callq 0x11bd
callq 0x11e2