// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x140, %rsp            # imm = 0x140
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x14(%rbp)
leaq -0x60(%rbp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x10a0
movl $0x1, -0x64(%rbp)
movl $0x0, -0x68(%rbp)
movl $0x0, -0x6c(%rbp)
movl $0x0, -0x70(%rbp)
movl $0x0, -0x74(%rbp)
movsd 0x1d1d(%rip), %xmm0     # 0x3008
movsd %xmm0, -0x80(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0x1e12(%rip), %rdx      # 0x3110
callq 0x1ad0
movl %eax, -0x84(%rbp)
cmpl $-0x1, %eax
je 0x14be
movl -0x84(%rbp), %eax
addl $-0x45, %eax
movl %eax, %ecx
movq %rcx, -0x138(%rbp)
subl $0x33, %eax
ja 0x14a0
movq -0x138(%rbp), %rax
leaq 0x1cfd(%rip), %rcx      # 0x3038
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x1, -0x74(%rbp)
jmp 0x14b9
movq 0x3c81(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
callq 0x1d70
xorl %edi, %edi
callq 0x1130
movl $0x1, -0x70(%rbp)
jmp 0x14b9
movq 0x3d5f(%rip), %rsi      # 0x50d8
leaq -0x50(%rbp), %rdi
callq 0x1e20
cmpl $0x0, %eax
jne 0x13b0
movq 0x3c6a(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
movq 0x3d40(%rip), %rdx      # 0x50d8
leaq 0x1d7b(%rip), %rsi      # 0x311a
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1130
movl $0x0, -0x64(%rbp)
jmp 0x14b9
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x14b9
movl $0x1, -0x68(%rbp)
jmp 0x14b9
leaq -0xb0(%rbp), %rdi
xorl %esi, %esi
movl $0x20, %edx
callq 0x10a0
movq 0x3ce8(%rip), %rdi      # 0x50d8
callq 0x1060
movq %rax, -0xb8(%rbp)
cmpq $0x20, -0xb8(%rbp)
jbe 0x1428
movq 0x3beb(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
leaq 0x1d23(%rip), %rsi      # 0x313a
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1130
leaq -0xb0(%rbp), %rdi
movq 0x3ca2(%rip), %rsi      # 0x50d8
movq -0xb8(%rbp), %rdx
callq 0x10e0
leaq -0xb0(%rbp), %rdi
callq 0x1fd0
movq %rax, -0x40(%rbp)
leaq -0xb0(%rbp), %rdi
addq $0x8, %rdi
callq 0x1fd0
movq %rax, -0x38(%rbp)
leaq -0xb0(%rbp), %rdi
addq $0x10, %rdi
callq 0x1fd0
movq %rax, -0x30(%rbp)
leaq -0xb0(%rbp), %rdi
addq $0x18, %rdi
callq 0x1fd0
movq %rax, -0x28(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x2060
movl $0x1, -0x14(%rbp)
jmp 0x14b9
movq 0x3b51(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
callq 0x1d70
movl $0x1, %edi
callq 0x1130
jmp 0x12f0
cmpl $0x0, -0x70(%rbp)
je 0x165f
cmpl $0x0, -0x64(%rbp)
je 0x14f0
movq 0x3b23(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
leaq 0x1c82(%rip), %rsi      # 0x3161
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1130
leaq 0x1c85(%rip), %rdi      # 0x317c
movb $0x0, %al
callq 0x1080
movl $0x0, -0xbc(%rbp)
cmpl $0x7, -0xbc(%rbp)
jge 0x164a
movl -0xbc(%rbp), %eax
andl $0x1, %eax
movl %eax, -0x13c(%rbp)
je 0x153c
jmp 0x1528
movl -0x13c(%rbp), %eax
subl $0x1, %eax
je 0x15e6
jmp 0x1634
movl -0xbc(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl $0x3, %eax
subl %ecx, %eax
movl %eax, -0xc0(%rbp)
leaq 0x1c3b(%rip), %rdi      # 0x319b
movb $0x0, %al
callq 0x1080
movslq -0xc0(%rbp), %rax
movsbl -0x44(%rbp,%rax), %eax
movl %eax, -0xc4(%rbp)
cmpl $0x20, -0xc4(%rbp)
jge 0x15d6
movl -0xc4(%rbp), %ecx
movslq -0xc0(%rbp), %rax
movsbl -0x44(%rbp,%rax), %edx
leaq 0x1c14(%rip), %rsi      # 0x31af
leaq 0x1d03(%rip), %rax      # 0x32a5
cmpl %edx, %ecx
cmoveq %rax, %rsi
movl -0xc4(%rbp), %edx
leaq 0x1bef(%rip), %rdi      # 0x31a4
movb $0x0, %al
callq 0x1080
movslq -0xc0(%rbp), %rax
movsbl -0x44(%rbp,%rax), %eax
addl -0xc4(%rbp), %eax
movl %eax, -0xc4(%rbp)
jmp 0x1579
leaq 0x1be5(%rip), %rdi      # 0x31c2
movb $0x0, %al
callq 0x1080
jmp 0x1634
movl -0xbc(%rbp), %eax
addl $0x1, %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl $0x3, %eax
subl %ecx, %eax
movl %eax, -0xc8(%rbp)
movslq -0xc8(%rbp), %rax
movl -0x50(%rbp,%rax,4), %edi
callq 0x23b0
movl %eax, %eax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rsi
leaq 0x1b85(%rip), %rdi      # 0x31b2
movb $0x0, %al
callq 0x1080
jmp 0x1636
movl -0xbc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xbc(%rbp)
jmp 0x1508
leaq 0x1b74(%rip), %rdi      # 0x31c5
movb $0x0, %al
callq 0x1080
xorl %edi, %edi
callq 0x1130
cmpl $0x0, -0x74(%rbp)
je 0x16b4
cmpl $0x0, -0x64(%rbp)
je 0x168d
movq 0x3986(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
leaq 0x1b5a(%rip), %rsi      # 0x31d6
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1130
leaq -0x50(%rbp), %rdi
callq 0x2430
leaq -0x50(%rbp), %rdi
callq 0x24c0
leaq 0x1b4b(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
xorl %edi, %edi
callq 0x1130
cmpl $0x0, -0x14(%rbp)
jne 0x16c3
leaq -0x40(%rbp), %rdi
callq 0x27d0
cmpl $0x0, -0x64(%rbp)
je 0x16d6
leaq -0x40(%rbp), %rsi
leaq -0x50(%rbp), %rdi
callq 0x2840
jmp 0x16d8
movl $0x0, -0xd4(%rbp)
cmpl $0x2, -0x6c(%rbp)
jge 0x16f1
leaq -0x50(%rbp), %rdi
callq 0x2430
xorps %xmm0, %xmm0
ucomisd -0x80(%rbp), %xmm0
jbe 0x1709
leaq -0x50(%rbp), %rdi
callq 0x24c0
movsd %xmm0, -0x80(%rbp)
cmpl $0x2, -0x6c(%rbp)
jge 0x1722
movsd -0x80(%rbp), %xmm0
leaq 0x1ad6(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
movq -0x50(%rbp), %rax
movq %rax, -0xe4(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0xdc(%rbp)
movsd -0x80(%rbp), %xmm0
movsd %xmm0, -0xf0(%rbp)
movl $0x0, -0xf4(%rbp)
cmpl $0x3, -0xf4(%rbp)
jg 0x1897
movl $0xffffffff, -0xf8(%rbp) # imm = 0xFFFFFFFF
cmpl $0x1, -0xf8(%rbp)
jg 0x1881
cmpl $0x0, -0xf8(%rbp)
jne 0x1781
jmp 0x186d
movq -0x50(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x100(%rbp)
movl -0xf8(%rbp), %edx
movslq -0xf4(%rbp), %rax
movsbl -0xfc(%rbp,%rax), %ecx
addl %edx, %ecx
movb %cl, -0xfc(%rbp,%rax)
leaq -0x108(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x2880
cmpl $0x0, %eax
je 0x17cf
jmp 0x186d
cmpl $0x0, -0x6c(%rbp)
jg 0x17ef
leaq 0x1a1f(%rip), %rdi      # 0x31fb
movb $0x0, %al
callq 0x1080
leaq -0x108(%rbp), %rdi
callq 0x2430
leaq -0x108(%rbp), %rdi
callq 0x24c0
movsd %xmm0, -0x110(%rbp)
cmpl $0x0, -0x6c(%rbp)
jg 0x181f
movsd -0x110(%rbp), %xmm0
leaq 0x19d9(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
movsd -0x110(%rbp), %xmm1
movsd -0xf0(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x186b
movsd -0x110(%rbp), %xmm0
movsd %xmm0, -0xf0(%rbp)
movq -0x108(%rbp), %rax
movq %rax, -0xe4(%rbp)
movq -0x100(%rbp), %rax
movq %rax, -0xdc(%rbp)
movl $0x1, -0xd4(%rbp)
jmp 0x186d
movl -0xf8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xf8(%rbp)
jmp 0x1766
jmp 0x1883
movl -0xf4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xf4(%rbp)
jmp 0x174f
movl $0x0, -0x114(%rbp)
cmpl $0x3, -0x114(%rbp)
jge 0x19e6
movl $0xfffffffe, -0x118(%rbp) # imm = 0xFFFFFFFE
cmpl $0x2, -0x118(%rbp)
jg 0x19d0
cmpl $0x0, -0x118(%rbp)
jne 0x18d3
jmp 0x19bc
movq -0x50(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x120(%rbp)
movl -0x118(%rbp), %ecx
movslq -0x114(%rbp), %rax
addl -0x128(%rbp,%rax,4), %ecx
movl %ecx, -0x128(%rbp,%rax,4)
leaq -0x128(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x2880
cmpl $0x0, %eax
je 0x191e
jmp 0x19bc
cmpl $0x0, -0x6c(%rbp)
jg 0x193e
leaq 0x18d0(%rip), %rdi      # 0x31fb
movb $0x0, %al
callq 0x1080
leaq -0x128(%rbp), %rdi
callq 0x2430
leaq -0x128(%rbp), %rdi
callq 0x24c0
movsd %xmm0, -0x130(%rbp)
cmpl $0x0, -0x6c(%rbp)
jg 0x196e
movsd -0x130(%rbp), %xmm0
leaq 0x188a(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
movsd -0x130(%rbp), %xmm1
movsd -0xf0(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x19ba
movsd -0x130(%rbp), %xmm0
movsd %xmm0, -0xf0(%rbp)
movq -0x128(%rbp), %rax
movq %rax, -0xe4(%rbp)
movq -0x120(%rbp), %rax
movq %rax, -0xdc(%rbp)
movl $0x1, -0xd4(%rbp)
jmp 0x19bc
movl -0x118(%rbp), %eax
addl $0x2, %eax
movl %eax, -0x118(%rbp)
jmp 0x18b8
jmp 0x19d2
movl -0x114(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x114(%rbp)
jmp 0x18a1
cmpl $0x0, -0xd4(%rbp)
je 0x1a39
cmpl $0x1, -0x6c(%rbp)
jge 0x1a01
leaq 0x1802(%rip), %rdi      # 0x31fe
callq 0x1050
movq -0x50(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0xe4(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0xdc(%rbp), %rax
movq %rax, -0x48(%rbp)
movsd -0xf0(%rbp), %xmm0
movsd %xmm0, -0x80(%rbp)
jmp 0x1abd
cmpl $0x0, -0x68(%rbp)
je 0x1a6f
cmpl $0x1, -0x6c(%rbp)
jge 0x1a51
leaq 0x17b8(%rip), %rdi      # 0x3204
callq 0x1050
leaq -0x50(%rbp), %rdi
callq 0x2430
movsd -0x80(%rbp), %xmm0
leaq 0x178b(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
jmp 0x1ac2
cmpl $0x1, -0x6c(%rbp)
jge 0x1a81
leaq 0x178d(%rip), %rdi      # 0x3209
callq 0x1050
leaq -0x50(%rbp), %rdi
callq 0x2430
movsd -0x80(%rbp), %xmm0
leaq 0x175b(%rip), %rdi      # 0x31f1
movb $0x1, %al
callq 0x1080
movb $0x0, -0x54(%rbp)
leaq -0x40(%rbp), %rsi
leaq -0x50(%rbp), %rdi
callq 0x2840
movsd 0x1552(%rip), %xmm0     # 0x3008
movsd %xmm0, -0x80(%rbp)
jmp 0x1abd
jmp 0x16d8
movl -0x4(%rbp), %eax
addq $0x140, %rsp            # imm = 0x140
popq %rbp
retq
nop