// File: /workspace/github_c_makefile_star2_O2/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, 0x90(%rsp)
pushq $0x1
popq %rbp
movq $0x0, 0x88(%rsp)
movb $0x1, %al
movl %eax, 0x44(%rsp)
movl 0x3e09(%rip), %ebx      # 0x50c4
xorl %r12d, %r12d
movl $0x0, 0x4c(%rsp)
movl %ebp, 0x1c(%rsp)
movl $0x0, 0x48(%rsp)
movl 0x3de7(%rip), %r14d     # 0x50c0
movq 0x3df0(%rip), %r13      # 0x50d0
movq %r13, 0x10(%rsp)
testl %ebx, %ebx
jne 0x12fa
movl %ebp, 0x3dd5(%rip)      # 0x50c4
movl %ebp, 0x3dcb(%rip)      # 0x50c0
movl %ebp, %r14d
movl %ebp, %ebx
movslq %ebx, %rcx
movq 0x38(%rsp), %rax
movq %rcx, 0x8(%rsp)
movq (%rax,%rcx,8), %r13
testq %r13, %r13
je 0x15da
cmpb $0x2d, (%r13)
jne 0x15da
movsbq 0x1(%r13), %r15
cmpq $0x2d, %r15
jne 0x1335
cmpb $0x0, 0x2(%r13)
je 0x15d2
callq 0x1150
movq (%rax), %rax
testb $0x8, (%rax,%r15,2)
je 0x15da
movl %ebx, %r15d
movl %ebp, %ebx
movslq %r14d, %rbp
movsbl (%r13,%rbp), %r14d
leaq 0x1d07(%rip), %rdi      # 0x3064
movl %r14d, %esi
pushq $0xa
popq %rdx
callq 0x10a0
testq %rax, %rax
je 0x18f9
cmpb $0x3a, 0x1(%rax)
jne 0x138a
addq %rbp, %r13
cmpb $0x0, 0x1(%r13)
je 0x13ae
incq %r13
movl %ebx, %ebp
movl %ebx, %eax
jmp 0x13cb
movl %r14d, %ecx
leaq 0x1(%rbp), %r14
movl %r14d, 0x3d28(%rip)     # 0x50c0
cmpb $0x0, 0x1(%r13,%rbp)
movl %ebx, %ebp
movl %ebx, %eax
movq 0x10(%rsp), %r13
je 0x13d5
movl %r15d, %ebx
jmp 0x13ed
movq 0x38(%rsp), %rax
movq 0x8(%rsp), %rcx
movq 0x8(%rax,%rcx,8), %r13
pushq $0x2
popq %rax
testq %r13, %r13
movl %ebx, %ebp
je 0x1933
movl %r14d, %ecx
movq %r13, 0x3cfb(%rip)      # 0x50d0
movl %r15d, %ebx
addl %eax, %ebx
movl %ebx, 0x3ce4(%rip)      # 0x50c4
movl $0x1, 0x3cd6(%rip)      # 0x50c0
movl %ebp, %r14d
movzbl %cl, %eax
leal -0x70(%rax), %ecx
cmpl $0x8, %ecx
ja 0x146c
leaq 0x1c41(%rip), %rdx      # 0x3040
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
leaq 0x60(%rsp), %r15
jmpq *%rax
xorps %xmm0, %xmm0
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movq %r13, %rdi
callq 0x1060
cmpq $0x21, %rax
jae 0x195d
movq %r15, %rdi
movq %r13, %rsi
movq %rax, %rdx
callq 0x10d0
movaps 0x60(%rsp), %xmm0
movapd 0x70(%rsp), %xmm1
movaps %xmm0, 0xa0(%rsp)
movapd %xmm1, 0xb0(%rsp)
leaq 0xa0(%rsp), %rdi
callq 0x1ba7
movl %ebp, 0x48(%rsp)
jmp 0x12e0
cmpl $0x45, %eax
je 0x1550
cmpl $0x49, %eax
jne 0x15ac
movl %ebp, %eax
movq %rax, 0x88(%rsp)
jmp 0x12d2
movq 0x3c3c(%rip), %rbx      # 0x50d0
cmpb $0x5b, (%rbx)
jne 0x193c
incq %rbx
pushq $-0x3
popq %r14
testq %r14, %r14
je 0x155d
cmpq $-0x3, %r14
movl $0x0, %edi
cmoveq %rbx, %rdi
leaq 0x1c5f(%rip), %rsi      # 0x3120
callq 0x1100
movq %rax, %rdi
movq %r15, %rsi
pushq $0xa
popq %rdx
callq 0x10c0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x193c
movq 0x60(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x193c
movb %al, 0x2f(%rsp,%r14)
xorl %edi, %edi
leaq 0x1c1f(%rip), %rsi      # 0x3120
callq 0x1100
movq %rax, %rdi
movq %r15, %rsi
pushq $0x10
popq %rdx
callq 0x1110
movq %rax, %rcx
shrq $0x20, %rcx
jne 0x193c
movq 0x60(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x193c
movl %eax, 0x2c(%rsp,%r14,4)
incq %r14
jmp 0x14a4
incl %r12d
jmp 0x12d2
movl %ebp, 0x4c(%rsp)
jmp 0x12d2
movl $0x0, 0x44(%rsp)
jmp 0x12d2
xorl %edi, %edi
leaq 0x1d80(%rip), %rsi      # 0x32e6
callq 0x1100
movq %rax, %rdi
movq %r15, %rsi
pushq $0xa
popq %rdx
callq 0x10c0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x193c
movq 0x60(%rsp), %rcx
cmpb $0x0, (%rcx)
jne 0x193c
movl 0x3b29(%rip), %ebx      # 0x50c4
movb %al, 0x2f(%rsp)
movl $0x0, 0x1c(%rsp)
jmp 0x12d2
cmpl $0xff, %eax
je 0x15da
cmpl $0x68, %eax
jne 0x191c
movq 0x3a15(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
callq 0x1ae6
xorl %edi, %edi
callq 0x1120
incl %ebx
movl %ebx, 0x3aea(%rip)      # 0x50c4
cmpl $0x0, 0x88(%rsp)
jne 0x197b
testb $0x1, 0x44(%rsp)
je 0x1a7b
cmpl $0x0, 0x48(%rsp)
jne 0x1607
leaq 0xa0(%rsp), %rdi
callq 0x2060
cmpl $0x0, 0x1c(%rsp)
je 0x1620
leaq 0x20(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x20a6
movsd 0x19e0(%rip), %xmm0     # 0x3008
leaq 0x50(%rsp), %rbp
leaq 0x90(%rsp), %r15
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x164b
leaq 0x20(%rsp), %rdi
callq 0x1e7e
xorpd %xmm0, %xmm0
ucomisd 0x8(%rsp), %xmm0
jbe 0x1667
leaq 0x20(%rsp), %rdi
callq 0x1ede
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x1681
leaq 0x1aa1(%rip), %rdi      # 0x3115
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movups 0x20(%rsp), %xmm0
movaps %xmm0, 0x60(%rsp)
xorl %r13d, %r13d
xorl %ebx, %ebx
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
cmpq $0x4, %r13
je 0x1761
pushq $-0x1
popq %r14
testl %r14d, %r14d
je 0x1751
cmpl $0x2, %r14d
je 0x1759
movupd 0x20(%rsp), %xmm0
movapd %xmm0, 0x50(%rsp)
movzbl 0x5c(%rsp,%r13), %eax
addl %r14d, %eax
movb %al, 0x5c(%rsp,%r13)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x2213
testl %eax, %eax
jne 0x1751
testl %r12d, %r12d
jg 0x1701
leaq 0x1a2d(%rip), %rdi      # 0x311f
xorl %eax, %eax
callq 0x1070
movq %rbp, %rdi
callq 0x1e7e
movq %rbp, %rdi
callq 0x1ede
movapd %xmm0, %xmm1
testl %r12d, %r12d
jg 0x1730
leaq 0x19fc(%rip), %rdi      # 0x3115
movapd %xmm1, %xmm0
movb $0x1, %al
movsd %xmm1, 0x38(%rsp)
callq 0x1070
movsd 0x38(%rsp), %xmm1
movsd 0x10(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1751
movapd 0x50(%rsp), %xmm0
movapd %xmm0, 0x60(%rsp)
pushq $0x1
popq %rbx
movsd %xmm1, 0x10(%rsp)
incl %r14d
jmp 0x16aa
incq %r13
jmp 0x169c
xorl %r13d, %r13d
cmpq $0x3, %r13
je 0x1821
pushq $-0x2
popq %r14
cmpl $0x3, %r14d
jge 0x1819
testl %r14d, %r14d
je 0x1810
movupd 0x20(%rsp), %xmm0
movapd %xmm0, 0x50(%rsp)
addl %r14d, 0x50(%rsp,%r13,4)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x2213
testl %eax, %eax
jne 0x1810
testl %r12d, %r12d
jg 0x17c0
leaq 0x196e(%rip), %rdi      # 0x311f
xorl %eax, %eax
callq 0x1070
movq %rbp, %rdi
callq 0x1e7e
movq %rbp, %rdi
callq 0x1ede
movapd %xmm0, %xmm1
testl %r12d, %r12d
jg 0x17ef
leaq 0x193d(%rip), %rdi      # 0x3115
movapd %xmm1, %xmm0
movb $0x1, %al
movsd %xmm1, 0x38(%rsp)
callq 0x1070
movsd 0x38(%rsp), %xmm1
movsd 0x10(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1810
movapd 0x50(%rsp), %xmm0
movapd %xmm0, 0x60(%rsp)
pushq $0x1
popq %rbx
movsd %xmm1, 0x10(%rsp)
addl $0x2, %r14d
jmp 0x1772
incq %r13
jmp 0x1764
testl %ebx, %ebx
je 0x1858
testl %r12d, %r12d
jg 0x1836
leaq 0x18f1(%rip), %rdi      # 0x3122
callq 0x1050
movaps 0x20(%rsp), %xmm0
movaps %xmm0, 0x90(%rsp)
movaps 0x60(%rsp), %xmm0
movaps %xmm0, 0x20(%rsp)
movsd 0x10(%rsp), %xmm0
jmp 0x1635
cmpl $0x0, 0x4c(%rsp)
jne 0x18b6
testl %r12d, %r12d
jg 0x1870
leaq 0x18c2(%rip), %rdi      # 0x312d
callq 0x1050
leaq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x1e7e
leaq 0x1891(%rip), %rdi      # 0x3115
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movb $0x0, 0x9c(%rsp)
movq %rbx, %rdi
leaq 0xa0(%rsp), %rsi
callq 0x20a6
movsd 0x1757(%rip), %xmm0     # 0x3008
jmp 0x1635
testl %r12d, %r12d
jg 0x18c7
leaq 0x1866(%rip), %rdi      # 0x3128
callq 0x1050
leaq 0x20(%rsp), %rdi
callq 0x1e7e
leaq 0x183d(%rip), %rdi      # 0x3115
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 0x1833(%rip), %rsi      # 0x3133
movq 0x36f1(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq 0x38(%rsp), %rax
movq (%rax), %rdx
movl %r14d, %ecx
xorl %eax, %eax
callq 0x10b0
movq 0x36d5(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
callq 0x1ae6
pushq $0x1
popq %rdi
callq 0x1120
leaq 0x1811(%rip), %rsi      # 0x314b
jmp 0x1900
movq 0x36b5(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq 0x3783(%rip), %rdx      # 0x50d0
leaq 0x171a(%rip), %rsi      # 0x306e
xorl %eax, %eax
callq 0x10b0
jmp 0x192b
movq 0x3694(%rip), %rax      # 0x4ff8
movq (%rax), %rcx
leaq 0x1720(%rip), %rdi      # 0x308e
pushq $0x26
popq %rsi
pushq $0x1
popq %rdx
callq 0x1130
jmp 0x192b
cmpl $0x0, 0x1c(%rsp)
jne 0x1aaa
leaq 0x195b(%rip), %rdi      # 0x32e8
callq 0x1050
leaq 0x182d(%rip), %r14      # 0x31c6
leaq 0x1744(%rip), %rbx      # 0x30e4
leaq 0x1732(%rip), %r15      # 0x30d9
xorl %ebp, %ebp
cmpl $0x7, %ebp
je 0x1abd
testb $0x1, %bpl
je 0x1a1a
incl %ebp
movl %ebp, %eax
shrl %eax
pushq $0x3
popq %rcx
subl %eax, %ecx
movl 0x20(%rsp,%rcx,4), %eax
movl %eax, %ecx
imull %eax, %ecx
pushq $0x2
popq %r8
movl %r8d, %edx
subl %ecx, %edx
imull %eax, %edx
movl %edx, %ecx
imull %eax, %ecx
movl %r8d, %esi
subl %ecx, %esi
imull %edx, %esi
movl %esi, %ecx
imull %eax, %ecx
movl %r8d, %edx
subl %ecx, %edx
imull %esi, %edx
movl %edx, %ecx
imull %eax, %ecx
movl %r8d, %edi
subl %ecx, %edi
imull %edx, %edi
imull %edi, %eax
movl %r8d, %esi
subl %eax, %esi
imull %edi, %esi
leaq 0x16d6(%rip), %rdi      # 0x30e7
xorl %eax, %eax
callq 0x1070
jmp 0x19a9
movl %ebp, 0x10(%rsp)
movl %ebp, %eax
shrl %eax
leaq 0x20(%rsp), %r13
subq %rax, %r13
xorl %r12d, %r12d
leaq 0x169c(%rip), %rdi      # 0x30d0
xorl %eax, %eax
callq 0x1070
movsbl 0xf(%r13), %r13d
leal (%r12,%r13), %ebp
cmpl $0x20, %ebp
jge 0x1a64
testl %r12d, %r12d
movq %rbx, %rsi
cmoveq %r14, %rsi
movq %r15, %rdi
movl %ebp, %edx
xorl %eax, %eax
callq 0x1070
movl %ebp, %r12d
jmp 0x1a40
leaq 0x18ab(%rip), %rdi      # 0x3316
callq 0x1050
movl 0x10(%rsp), %ebp
incl %ebp
jmp 0x19a9
cmpl $0x0, 0x1c(%rsp)
jne 0x1ace
leaq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x1e7e
movq %rbx, %rdi
callq 0x1ede
leaq 0x1677(%rip), %rdi      # 0x3115
movb $0x1, %al
callq 0x1070
jmp 0x15cb
movq 0x3547(%rip), %rax      # 0x4ff8
movq (%rax), %rcx
leaq 0x15fa(%rip), %rdi      # 0x30b5
jmp 0x1adf
leaq 0x1842(%rip), %rdi      # 0x3306
callq 0x1050
jmp 0x15cb
movq 0x3523(%rip), %rax      # 0x4ff8
movq (%rax), %rcx
leaq 0x161b(%rip), %rdi      # 0x30fa
pushq $0x1a
jmp 0x1970