// File: /workspace/github_c_makefile_star2_O1/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 $0xb8, %rsp
movq %rsi, %rbx
xorpd %xmm0, %xmm0
movapd %xmm0, 0x50(%rsp)
movb $0x1, %al
movl %eax, 0x8(%rsp)
leaq 0x70(%rsp), %r14
movl $0x0, 0x4(%rsp)
xorl %r12d, %r12d
movl $0x0, 0x6c(%rsp)
movl $0x1, 0x34(%rsp)
movl $0x0, 0x38(%rsp)
movq %rsi, 0x28(%rsp)
cmpl $0x0, 0x3d45(%rip)      # 0x50cc
jne 0x139a
movl $0x1, %eax
movl %eax, 0x3d38(%rip)      # 0x50cc
movl %eax, 0x3d2e(%rip)      # 0x50c8
movslq 0x3d2b(%rip), %r15      # 0x50cc
movq (%rbx,%r15,8), %rbp
movl $0xffffffff, %r13d      # imm = 0xFFFFFFFF
testq %rbp, %rbp
je 0x1463
movq %rbp, %rdi
leaq 0x1d51(%rip), %rsi      # 0x310f
callq 0x10b0
testl %eax, %eax
je 0x142d
cmpb $0x2d, (%rbp)
jne 0x1463
callq 0x1160
movq (%rax), %rax
movsbq 0x1(%rbp), %rcx
testb $0x8, (%rax,%rcx,2)
je 0x1463
movslq 0x3cdd(%rip), %rbx      # 0x50c8
movsbl (%rbp,%rbx), %r13d
movl $0xa, %edx
leaq 0x1c43(%rip), %rdi      # 0x3040
movl %r13d, %esi
callq 0x10a0
testq %rax, %rax
je 0x168d
cmpb $0x3a, 0x1(%rax)
jne 0x1439
addq %rbx, %rbp
cmpb $0x0, 0x1(%rbp)
je 0x165d
incq %rbp
movq %rbp, 0x3cad(%rip)      # 0x50d8
jmp 0x144a
incl %r15d
movl %r15d, 0x3c95(%rip)     # 0x50cc
jmp 0x1463
leaq 0x1(%rbx), %rax
movl %eax, 0x3c85(%rip)      # 0x50c8
cmpb $0x0, 0x1(%rbp,%rbx)
jne 0x145e
incl %r15d
movl %r15d, 0x3c78(%rip)     # 0x50cc
movl $0x1, 0x3c6a(%rip)      # 0x50c8
movq 0x28(%rsp), %rbx
cmpl $0x78, %r13d
jne 0x14ed
xorpd %xmm0, %xmm0
movapd %xmm0, 0x80(%rsp)
movapd %xmm0, 0x70(%rsp)
movq 0x3c51(%rip), %r13      # 0x50d8
movq %r13, %rdi
callq 0x1060
cmpq $0x21, %rax
jae 0x1aaa
movq %r14, %rdi
movq %r13, %rsi
movq %rax, %rdx
callq 0x10e0
movq 0x70(%rsp), %rax
movq %rax, 0x90(%rsp)
movupd 0x78(%rsp), %xmm0
movupd %xmm0, 0x98(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0xa8(%rsp)
leaq 0x90(%rsp), %rdi
callq 0x1ce1
movl $0x1, 0x38(%rsp)
jmp 0x1380
cmpl $0x67, %r13d
jle 0x151a
cmpl $0x70, %r13d
jle 0x1545
cmpl $0x71, %r13d
je 0x1648
cmpl $0x73, %r13d
jne 0x1aaf
movl $0x1, 0x6c(%rsp)
jmp 0x1380
cmpl $-0x1, %r13d
je 0x16d1
cmpl $0x45, %r13d
je 0x1650
cmpl $0x49, %r13d
jne 0x1aaf
movl $0x1, 0x4(%rsp)
jmp 0x1380
jne 0x1a8e
movq 0x3b86(%rip), %r15      # 0x50d8
cmpb $0x5b, (%r15)
jne 0x1a84
incq %r15
movq $-0x3, %r13
cmpq $-0x3, %r13
movl $0x0, %edi
cmoveq %r15, %rdi
leaq 0x1b82(%rip), %rsi      # 0x30fc
callq 0x1110
movq %rax, %rdi
movq %r14, %rsi
movl $0xa, %edx
callq 0x10d0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x1a84
movq 0x70(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x1a84
movb %al, 0x4f(%rsp,%r13)
xorl %edi, %edi
leaq 0x1b40(%rip), %rsi      # 0x30fc
callq 0x1110
movq %rax, %rdi
movq %r14, %rsi
movl $0x10, %edx
callq 0x1120
movq %rax, %rcx
shrq $0x20, %rcx
jne 0x1a84
movq 0x70(%rsp), %rcx
movzbl (%rcx), %ecx
testb $-0x21, %cl
jne 0x1a84
movl %eax, 0x4c(%rsp,%r13,4)
incq %r13
jne 0x1566
xorl %edi, %edi
leaq 0x1cbf(%rip), %rsi      # 0x32c5
callq 0x1110
movq %rax, %rdi
movq %r14, %rsi
movl $0xa, %edx
callq 0x10d0
leaq -0x20(%rax), %rcx
cmpq $-0x1f, %rcx
jb 0x1a84
movq 0x70(%rsp), %rcx
cmpb $0x0, (%rcx)
jne 0x1a84
movb %al, 0x4f(%rsp)
movl $0x0, 0x34(%rsp)
jmp 0x1380
incl %r12d
jmp 0x1380
movl $0x0, 0x8(%rsp)
jmp 0x1380
movq 0x28(%rsp), %rbx
movq 0x8(%rbx,%r15,8), %rax
testq %rax, %rax
je 0x16bb
movq %rax, 0x3a65(%rip)      # 0x50d8
addl $0x2, %r15d
movl %r15d, 0x3a4e(%rip)     # 0x50cc
movl $0x1, 0x3a40(%rip)      # 0x50c8
jmp 0x1463
movq 0x3964(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq 0x28(%rsp), %rbx
movq (%rbx), %rdx
leaq 0x1a6c(%rip), %rsi      # 0x3112
movl %r13d, %ecx
xorl %eax, %eax
callq 0x10c0
movl $0x3f, %r13d
jmp 0x1463
movq 0x3936(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq (%rbx), %rdx
leaq 0x1a5b(%rip), %rsi      # 0x312a
jmp 0x16a6
cmpl $0x0, 0x4(%rsp)
jne 0x1ac8
testb $0x1, 0x8(%rsp)
je 0x1bdb
cmpl $0x0, 0x38(%rsp)
jne 0x16fb
leaq 0x90(%rsp), %rdi
callq 0x21ba
cmpl $0x0, 0x34(%rsp)
je 0x1714
leaq 0x40(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x221a
movsd 0x18ec(%rip), %xmm0     # 0x3008
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x1732
leaq 0x40(%rsp), %rdi
callq 0x1fb8
xorpd %xmm0, %xmm0
ucomisd 0x8(%rsp), %xmm0
jbe 0x174e
leaq 0x40(%rsp), %rdi
callq 0x2018
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, %r12d
jg 0x1768
leaq 0x1996(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movupd 0x40(%rsp), %xmm0
movapd %xmm0, 0x70(%rsp)
movl 0x50(%rsp), %ebx
movb 0x5f(%rsp), %al
movb %al, 0x4(%rsp)
xorl %r15d, %r15d
movb 0x5c(%rsp), %r14b
movsd 0x8(%rsp), %xmm1
xorl %ebp, %ebp
movl $0xffffffff, %r13d      # imm = 0xFFFFFFFF
testl %r13d, %r13d
je 0x186c
movupd 0x40(%rsp), %xmm0
movapd %xmm0, 0x10(%rsp)
addb %r13b, 0x1c(%rsp,%r15)
cmpl %ebx, 0x10(%rsp)
jne 0x1801
cmpb %r14b, 0x1c(%rsp)
jne 0x17f1
movq $-0x2, %rcx
testq %rcx, %rcx
je 0x17f7
movq %rcx, %rax
movl 0x1c(%rsp,%rcx,4), %ecx
cmpl 0x5c(%rsp,%rax,4), %ecx
jne 0x17e4
movb 0x1f(%rsp,%rax), %dl
leaq 0x1(%rax), %rcx
cmpb 0x5f(%rsp,%rax), %dl
je 0x17c4
addq $0x2, %rax
cmpq $0x2, %rax
setae %al
jmp 0x17f3
xorl %eax, %eax
testb %al, %al
je 0x1801
movb 0x4(%rsp), %al
cmpb %al, 0x1f(%rsp)
je 0x186c
movsd %xmm1, 0x38(%rsp)
testl %r12d, %r12d
jg 0x1824
leaq 0x18e8(%rip), %rdi      # 0x30fb
xorl %eax, %eax
callq 0x1070
leaq 0x10(%rsp), %rdi
callq 0x1fb8
leaq 0x10(%rsp), %rdi
callq 0x2018
testl %r12d, %r12d
jg 0x184d
leaq 0x18b7(%rip), %rdi      # 0x30f1
movb $0x1, %al
movsd %xmm0, 0x28(%rsp)
callq 0x1070
movsd 0x28(%rsp), %xmm0
movsd 0x38(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x186c
movaps 0x10(%rsp), %xmm1
movaps %xmm1, 0x70(%rsp)
movl $0x1, %ebp
movapd %xmm0, %xmm1
incl %r13d
cmpl $0x2, %r13d
jne 0x1796
incq %r15
cmpq $0x4, %r15
jne 0x1790
movl 0x50(%rsp), %ebx
movb 0x5f(%rsp), %al
movb %al, 0x4(%rsp)
movb 0x5c(%rsp), %r15b
xorl %r14d, %r14d
movl $0xfffffffe, %r13d      # imm = 0xFFFFFFFE
testl %r13d, %r13d
je 0x1976
movupd 0x40(%rsp), %xmm0
movapd %xmm0, 0x10(%rsp)
addl %r13d, 0x10(%rsp,%r14,4)
cmpl %ebx, 0x10(%rsp)
jne 0x190b
cmpb %r15b, 0x1c(%rsp)
jne 0x18fb
movq $-0x2, %rcx
testq %rcx, %rcx
je 0x1901
movq %rcx, %rax
movl 0x1c(%rsp,%rcx,4), %ecx
cmpl 0x5c(%rsp,%rax,4), %ecx
jne 0x18ee
movb 0x1f(%rsp,%rax), %dl
leaq 0x1(%rax), %rcx
cmpb 0x5f(%rsp,%rax), %dl
je 0x18ce
addq $0x2, %rax
cmpq $0x2, %rax
setae %al
jmp 0x18fd
xorl %eax, %eax
testb %al, %al
je 0x190b
movb 0x4(%rsp), %al
cmpb %al, 0x1f(%rsp)
je 0x1976
movsd %xmm1, 0x38(%rsp)
testl %r12d, %r12d
jg 0x192e
leaq 0x17de(%rip), %rdi      # 0x30fb
xorl %eax, %eax
callq 0x1070
leaq 0x10(%rsp), %rdi
callq 0x1fb8
leaq 0x10(%rsp), %rdi
callq 0x2018
testl %r12d, %r12d
jg 0x1957
leaq 0x17ad(%rip), %rdi      # 0x30f1
movb $0x1, %al
movsd %xmm0, 0x28(%rsp)
callq 0x1070
movsd 0x28(%rsp), %xmm0
movsd 0x38(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x1976
movaps 0x10(%rsp), %xmm1
movaps %xmm1, 0x70(%rsp)
movl $0x1, %ebp
movapd %xmm0, %xmm1
leal 0x2(%r13), %eax
testl %r13d, %r13d
movl %eax, %r13d
jle 0x18a0
incq %r14
cmpq $0x3, %r14
jne 0x189a
testl %ebp, %ebp
je 0x19d1
testl %r12d, %r12d
jg 0x19b4
leaq 0x175b(%rip), %rdi      # 0x30fe
movsd %xmm1, 0x38(%rsp)
callq 0x1050
movsd 0x38(%rsp), %xmm1
movaps 0x40(%rsp), %xmm0
movaps %xmm0, 0x50(%rsp)
movapd 0x70(%rsp), %xmm0
movapd %xmm0, 0x40(%rsp)
movb $0x1, %bl
jmp 0x1a62
cmpl $0x0, 0x6c(%rsp)
je 0x1a11
testl %r12d, %r12d
jg 0x19e9
leaq 0x1720(%rip), %rdi      # 0x3104
callq 0x1050
leaq 0x40(%rsp), %rdi
callq 0x1fb8
leaq 0x16f7(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
xorl %ebx, %ebx
movsd 0x8(%rsp), %xmm1
jmp 0x1a62
testl %r12d, %r12d
jg 0x1a22
leaq 0x16ec(%rip), %rdi      # 0x3109
callq 0x1050
leaq 0x40(%rsp), %r14
movq %r14, %rdi
callq 0x1fb8
movb $0x1, %bl
leaq 0x16b9(%rip), %rdi      # 0x30f1
movsd 0x8(%rsp), %xmm0
movb $0x1, %al
callq 0x1070
movb $0x0, 0x5c(%rsp)
movq %r14, %rdi
leaq 0x90(%rsp), %rsi
callq 0x221a
movsd 0x15a6(%rip), %xmm1     # 0x3008
movsd %xmm1, 0x8(%rsp)
testb %bl, %bl
jne 0x1722
xorl %eax, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x70(%rsp), %rdi
callq 0x11a5
cmpl $0x68, %r13d
jne 0x1aaf
movq 0x353d(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
callq 0x1c14
xorl %edi, %edi
callq 0x1130
callq 0x1180
movq 0x3542(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
callq 0x1c14
movl $0x1, %edi
callq 0x1130
cmpl $0x0, 0x34(%rsp)
jne 0x1c0a
leaq 0x17ed(%rip), %rdi      # 0x32c7
callq 0x1050
leaq 0x16bf(%rip), %rbx      # 0x31a5
leaq 0x15d3(%rip), %r14      # 0x30c0
leaq 0x15c1(%rip), %r15      # 0x30b5
xorl %ebp, %ebp
testb $0x1, %bpl
je 0x1b65
leal 0x1(%rbp), %eax
shrl %eax
movl $0x3, %ecx
subl %eax, %ecx
movl 0x40(%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 0x1567(%rip), %rdi      # 0x30c3
xorl %eax, %eax
callq 0x1070
jmp 0x1bbf
movl %ebp, %eax
shrl %eax
leaq 0x40(%rsp), %r12
subq %rax, %r12
leaq 0x1534(%rip), %rdi      # 0x30ac
xorl %eax, %eax
callq 0x1070
movsbl 0xf(%r12), %r12d
cmpl $0x1f, %r12d
jg 0x1bb3
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 0x1b8d
leaq 0x173b(%rip), %rdi      # 0x32f5
callq 0x1050
incl %ebp
cmpl $0x7, %ebp
jne 0x1af6
leaq 0x1714(%rip), %rdi      # 0x32e5
callq 0x1050
jmp 0x1aa3
cmpl $0x0, 0x34(%rsp)
jne 0x1c0f
leaq 0x40(%rsp), %rbx
movq %rbx, %rdi
callq 0x1fb8
movq %rbx, %rdi
callq 0x2018
leaq 0x14f3(%rip), %rdi      # 0x30f1
movb $0x1, %al
callq 0x1070
jmp 0x1aa3
callq 0x11cd
callq 0x11f2