Problem 550

Divisor Game - nimber XOR convolution via FWHT.

Answer328104836
Output328104836
StatusPASS
Native helperno
Runtime70 ms
Peak memory52592 KB
Time complexityO(n^3) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^3)O(n log log n)
Space complexityO(n^2)O(n)
ApproachFlow solutionSieve-based divisor sums
VerdictSuboptimal

Flow source

# Project Euler 550
# Divisor Game - nimber XOR convolution via FWHT.

extern {
    function calloc(n: i64, size: i64) -> ptr<void>
    function free(p: ptr<void>) -> void
}

const MOD: i64 = 987654321

function mod_pow(a0: i64, e0: i64, mod: i64) -> i64 {
    let mut r: i64 = 1 % mod
    let mut a: i64 = a0 % mod
    if a < 0 { a = a + mod }
    let mut e: i64 = e0
    while e > 0 {
        if (e & 1) != 0 {
            r = ((r as i128) * (a as i128) % (mod as i128)) as i64
        }
        a = ((a as i128) * (a as i128) % (mod as i128)) as i64
        e = e >> 1
    }
    return r
}

function mod_inv(a0: i64, mod: i64) -> i64 {
    let mut old_r: i64 = a0 % mod
    let mut r: i64 = mod
    let mut old_s: i64 = 1
    let mut s: i64 = 0
    if old_r < 0 { old_r = old_r + mod }
    while r != 0 {
        let q: i64 = old_r / r
        let t: i64 = old_r - q * r
        old_r = r
        r = t
        let t2: i64 = old_s - q * s
        old_s = s
        s = t2
    }
    if old_s < 0 { old_s = old_s + mod }
    return old_s % mod
}

function fwht_xor(a: ptr<i64>, n: i64, mod: i64) -> void {
    let mut h: i64 = 1
    while h < n {
        let step: i64 = h << 1
        let mut i: i64 = 0
        while i < n {
            let mut j: i64 = i
            while j < i + h {
                let x: i64 = a[j]
                let y: i64 = a[j + h]
                let mut s: i64 = x + y
                if s >= mod { s = s - mod }
                let mut d: i64 = x - y
                if d < 0 { d = d + mod }
                a[j] = s
                a[j + h] = d
                j = j + 1
            }
            i = i + step
        }
        h = h << 1
    }
}

function omega_counts_up_to(n: i64, counts: ptr<i64>) -> i64 {
    let spf: ptr<i32> = calloc(n + 1, 4)
    let omega: ptr<i8> = calloc(n + 1, 1)
    let primes: ptr<i32> = calloc(700000, 4)
    if spf == null || omega == null || primes == null {
        free(spf); free(omega); free(primes)
        return -1
    }
    let mut z: i64 = 0
    while z < 32 {
        counts[z] = 0
        z = z + 1
    }

    let mut np: i64 = 0
    let mut max_om: i64 = 0

    let mut i: i64 = 2
    while i <= n {
        let si: i32 = spf[i]
        let oi: i64
        if si == 0 {
            spf[i] = i as i32
            primes[np] = i as i32
            np = np + 1
            omega[i] = 1
            oi = 1
        } else {
            oi = omega[i] as i64
        }
        counts[oi] = counts[oi] + 1
        if oi > max_om { max_om = oi }

        let mut j: i64 = 0
        while j < np {
            let p: i64 = primes[j] as i64
            let ip: i64 = i * p
            if ip > n { break }
            spf[ip] = p as i32
            omega[ip] = (oi + 1) as i8
            if p == (si as i64) { break }
            j = j + 1
        }
        i = i + 1
    }

    free(spf)
    free(omega)
    free(primes)
    return max_om
}

function compute_h_sequence(tmax: i64, h: ptr<i64>) -> i64 {
    if tmax <= 0 { return 0 }
    h[1] = 0
    let mut max_g: i64 = 0
    let reachable: ptr<i64> = calloc(64, 8)
    let mut t: i64 = 2
    while t <= tmax {
        let mut z: i64 = 0
        while z < 64 {
            reachable[z] = 0
            z = z + 1
        }
        let mut i: i64 = 1
        while i < t {
            let mut j: i64 = 1
            while j < t {
                let v: i64 = h[i] ^ h[j]
                let idx: i64 = (v >> 6) & 63
                let bit: i64 = (1 as i64) << (v & 63)
                reachable[idx] = reachable[idx] | bit
                j = j + 1
            }
            i = i + 1
        }
        let mut mex: i64 = 0
        while mex < 4096 {
            let idx: i64 = (mex >> 6) & 63
            let bit: i64 = (1 as i64) << (mex & 63)
            if (reachable[idx] & bit) != 0 {
                mex = mex + 1
            } else {
                break
            }
        }
        h[t] = mex
        if mex > max_g { max_g = mex }
        t = t + 1
    }
    free(reachable)
    return max_g
}

function f(n: i64, k: i64) -> i64 {
    let counts: ptr<i64> = calloc(32, 8)
    let max_om: i64 = omega_counts_up_to(n, counts)
    if max_om < 0 { free(counts); return 0 }

    let h: ptr<i64> = calloc(32, 8)
    let max_g: i64 = compute_h_sequence(max_om, h)

    let mut size: i64 = 1
    while size <= max_g { size = size << 1 }

    let arr: ptr<i64> = calloc(size, 8)
    if arr == null { free(counts); free(h); return 0 }

    let mut t: i64 = 1
    while t <= max_om {
        arr[h[t]] = (arr[h[t]] + counts[t]) % MOD
        t = t + 1
    }

    fwht_xor(arr, size, MOD)

    let mut s: i64 = 0
    let mut i: i64 = 0
    while i < size {
        s = (s + mod_pow(arr[i], k, MOD)) % MOD
        i = i + 1
    }

    let losing: i64 = ((s as i128) * (mod_inv(size, MOD) as i128) % (MOD as i128)) as i64
    let total: i64 = mod_pow(n - 1, k, MOD)
    let mut ans: i64 = (total - losing) % MOD
    if ans < 0 { ans = ans + MOD }

    free(arr)
    free(counts)
    free(h)
    return ans
}

function main() -> i32 {
    printf("%lld\n", f(10000000, 1000000000000))
    return 0
}

Generated C

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Flow runtime helpers */
typedef struct flow_temp_node { struct flow_temp_node* next; } flow_temp_node;
static flow_temp_node* flow_temp_head = NULL;
static int flow_temp_atexit_set = 0;
__attribute__((unused)) static void flow_temp_free_all(void) {
    while (flow_temp_head) {
        flow_temp_node* n = flow_temp_head;
        flow_temp_head = n->next;
        free(n);
    }
}
__attribute__((unused)) static void* flow_temp_alloc(size_t nbytes) {
    flow_temp_node* node = (flow_temp_node*)malloc(sizeof(flow_temp_node) + nbytes);
    if (!node) return NULL;
    node->next = flow_temp_head;
    flow_temp_head = node;
    if (!flow_temp_atexit_set) {
        flow_temp_atexit_set = 1;
        atexit(flow_temp_free_all);
    }
    return (void*)(node + 1);
}
#ifndef FLOW_DIAG
#define FLOW_DIAG(msg) fprintf(stderr, "%s", (msg))
#endif
#ifndef FLOW_LOG
#define FLOW_LOG(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
#ifndef FLOW_LOG_EMPTY
#define FLOW_LOG_EMPTY(fmt) printf(fmt)
#endif
static char* flow_strcat(const char* a, const char* b) {
    size_t la = strlen(a ? a : ""), lb = strlen(b ? b : "");
    char* r = (char*)flow_temp_alloc(la + lb + 1);
    if (!r) return NULL;
    if (la) memcpy(r, a, la);
    if (lb) memcpy(r + la, b, lb);
    r[la + lb] = '\0';
    return r;
}

#define __flow_in_arr(arr, val) __extension__ ({ \
    int _found = 0; \
    size_t _n = sizeof(arr)/sizeof((arr)[0]); \
    for (size_t _i = 0; _i < _n; _i++) { \
        if ((arr)[_i] == (val)) { _found = 1; break; } \
    } _found; })

/* Unified fault handler (MISRA #279) — override with -DFLOW_FAULT_HANDLER=fn */
#ifndef FLOW_FAULT_HANDLER
__attribute__((unused)) static inline void flow_fault_handler(const char* msg) {
    fprintf(stderr, "flow: %s\n", msg ? msg : "fault");
    abort();
#if defined(__GNUC__) || defined(__clang__)
    __builtin_unreachable();
#endif
}
#else
#define flow_fault_handler FLOW_FAULT_HANDLER
#endif
#define flow_div_by_zero_handler() flow_fault_handler("division by zero")
#define flow_shift_ub_handler() flow_fault_handler("invalid shift (amount out of range or left-shift of negative)")

#ifndef FLOW_CHECKED_DIV
#define FLOW_CHECKED_DIV(L, R) (((R) != 0) ? ((L) / (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_MOD
#define FLOW_CHECKED_MOD(L, R) (((R) != 0) ? ((L) % (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHL
#define FLOW_CHECKED_SHL(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull)) && ((L) >= 0)) ? ((L) << (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHR
#define FLOW_CHECKED_SHR(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull))) ? ((L) >> (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif

#include <math.h>

void* _ui_state = NULL;

static inline float i32_to_f32(int32_t v) { return (float)v; }

/* Host stub for @gpu kernels (device codegen replaces this). */
static inline int32_t gpu_thread_id(void) { return 0; }

int64_t mod_pow_i64_i64_i64(int64_t a0, int64_t e0, int64_t mod);
int64_t mod_inv_i64_i64(int64_t a0, int64_t mod);
void fwht_xor_ptr_i64_i64_i64(int64_t* a, int64_t n, int64_t mod);
int64_t omega_counts_up_to_i64_ptr_i64(int64_t n, int64_t* counts);
int64_t compute_h_sequence_i64_ptr_i64(int64_t tmax, int64_t* h);
int64_t f_i64_i64(int64_t n, int64_t k);
int32_t main(void);

static const int64_t MOD = 987654321;



int64_t mod_pow_i64_i64_i64(int64_t a0, int64_t e0, int64_t mod) {
    int64_t r = FLOW_CHECKED_MOD((1), (mod));
    int64_t a = FLOW_CHECKED_MOD((a0), (mod));
    if (a < 0) {
        a = (a + mod);
    }
    int64_t e = e0;
    while (e > 0) {
        if ((e & 1) != 0) {
            r = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(r)) * ((__int128)(a)))), (((__int128)(mod))))));
        }
        a = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(a)) * ((__int128)(a)))), (((__int128)(mod))))));
        e = FLOW_CHECKED_SHR((e), (1));
    }
    return r;
}

int64_t mod_inv_i64_i64(int64_t a0, int64_t mod) {
    int64_t old_r = FLOW_CHECKED_MOD((a0), (mod));
    int64_t r = mod;
    int64_t old_s = 1;
    int64_t s = 0;
    if (old_r < 0) {
        old_r = (old_r + mod);
    }
    while (r != 0) {
        int64_t q = FLOW_CHECKED_DIV((old_r), (r));
        int64_t t = (old_r - (q * r));
        old_r = r;
        r = t;
        int64_t t2 = (old_s - (q * s));
        old_s = s;
        s = t2;
    }
    if (old_s < 0) {
        old_s = (old_s + mod);
    }
    return FLOW_CHECKED_MOD((old_s), (mod));
}

void fwht_xor_ptr_i64_i64_i64(int64_t* a, int64_t n, int64_t mod) {
    int64_t h = 1;
    while (h < n) {
        int64_t step = FLOW_CHECKED_SHL((h), (1));
        int64_t i = 0;
        while (i < n) {
            int64_t j = i;
            while (j < (i + h)) {
                int64_t x = a[j];
                int64_t y = a[(j + h)];
                int64_t s = (x + y);
                if (s >= mod) {
                    s = (s - mod);
                }
                int64_t d = (x - y);
                if (d < 0) {
                    d = (d + mod);
                }
                a[j] = s;
                a[(j + h)] = d;
                j = (j + 1);
            }
            i = (i + step);
        }
        h = FLOW_CHECKED_SHL((h), (1));
    }
}

int64_t omega_counts_up_to_i64_ptr_i64(int64_t n, int64_t* counts) {
    int32_t* spf = (int32_t*)(calloc((n + 1), 4));
    int8_t* omega = (int8_t*)(calloc((n + 1), 1));
    int32_t* primes = (int32_t*)(calloc(700000, 4));
    if (((spf == NULL || omega == NULL) || primes == NULL)) {
        free(spf);
        free(omega);
        free(primes);
        return (-1);
    }
    int64_t z = 0;
    while (z < 32) {
        counts[z] = 0;
        z = (z + 1);
    }
    int64_t np = 0;
    int64_t max_om = 0;
    int64_t i = 2;
    while (i <= n) {
        int32_t si = spf[i];
        int64_t oi;
        if (si == 0) {
            spf[i] = ((int32_t)(i));
            primes[np] = ((int32_t)(i));
            np = (np + 1);
            omega[i] = 1;
            oi = 1;
        } else {
            oi = ((int64_t)(omega[i]));
        }
        counts[oi] = (counts[oi] + 1);
        if (oi > max_om) {
            max_om = oi;
        }
        int64_t j = 0;
        while (j < np) {
            int64_t p = ((int64_t)(primes[j]));
            int64_t ip = (i * p);
            if (ip > n) {
                break;
            }
            spf[ip] = ((int32_t)(p));
            omega[ip] = ((int8_t)((oi + 1)));
            if (p == ((int64_t)(si))) {
                break;
            }
            j = (j + 1);
        }
        i = (i + 1);
    }
    free(spf);
    free(omega);
    free(primes);
    return max_om;
}

int64_t compute_h_sequence_i64_ptr_i64(int64_t tmax, int64_t* h) {
    if (tmax <= 0) {
        return 0;
    }
    h[1] = 0;
    int64_t max_g = 0;
    int64_t* reachable = (int64_t*)(calloc(64, 8));
    int64_t t = 2;
    while (t <= tmax) {
        int64_t z = 0;
        while (z < 64) {
            reachable[z] = 0;
            z = (z + 1);
        }
        int64_t i = 1;
        while (i < t) {
            int64_t j = 1;
            while (j < t) {
                int64_t v = (h[i] ^ h[j]);
                int64_t idx = (FLOW_CHECKED_SHR((v), (6)) & 63);
                int64_t bit = FLOW_CHECKED_SHL((((int64_t)(1))), ((v & 63)));
                reachable[idx] = (reachable[idx] | bit);
                j = (j + 1);
            }
            i = (i + 1);
        }
        int64_t mex = 0;
        while (mex < 4096) {
            int64_t idx = (FLOW_CHECKED_SHR((mex), (6)) & 63);
            int64_t bit = FLOW_CHECKED_SHL((((int64_t)(1))), ((mex & 63)));
            if ((reachable[idx] & bit) != 0) {
                mex = (mex + 1);
            } else {
                break;
            }
        }
        h[t] = mex;
        if (mex > max_g) {
            max_g = mex;
        }
        t = (t + 1);
    }
    free(reachable);
    return max_g;
}

int64_t f_i64_i64(int64_t n, int64_t k) {
    int64_t* counts = (int64_t*)(calloc(32, 8));
    int64_t max_om = omega_counts_up_to_i64_ptr_i64(n, counts);
    if (max_om < 0) {
        free(counts);
        return 0;
    }
    int64_t* h = (int64_t*)(calloc(32, 8));
    int64_t max_g = compute_h_sequence_i64_ptr_i64(max_om, h);
    int64_t size = 1;
    while (size <= max_g) {
        size = FLOW_CHECKED_SHL((size), (1));
    }
    int64_t* arr = (int64_t*)(calloc(size, 8));
    if (arr == NULL) {
        free(counts);
        free(h);
        return 0;
    }
    int64_t t = 1;
    while (t <= max_om) {
        arr[h[t]] = FLOW_CHECKED_MOD(((arr[h[t]] + counts[t])), (MOD));
        t = (t + 1);
    }
    fwht_xor_ptr_i64_i64_i64(arr, size, MOD);
    int64_t s = 0;
    int64_t i = 0;
    while (i < size) {
        s = FLOW_CHECKED_MOD(((s + mod_pow_i64_i64_i64(arr[i], k, MOD))), (MOD));
        i = (i + 1);
    }
    int64_t losing = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(s)) * ((__int128)(mod_inv_i64_i64(size, MOD))))), (((__int128)(MOD))))));
    int64_t total = mod_pow_i64_i64_i64((n - 1), k, MOD);
    int64_t ans = FLOW_CHECKED_MOD(((total - losing)), (MOD));
    if (ans < 0) {
        ans = (ans + MOD);
    }
    free(arr);
    free(counts);
    free(h);
    return ans;
}

int32_t main(void) {
    printf("%lld\n", f_i64_i64(10000000, 1000000000000));
    return 0;
}

Generated MLIR

module {
  llvm.func @printf(!llvm.ptr, ...) -> i32
  llvm.mlir.global internal constant @str_0("%lld\n\00") {addr_space = 0 : i32} : !llvm.array<6 x i8>
  func.func private @calloc(i64, i64) -> !llvm.ptr
  func.func private @free(!llvm.ptr) -> ()
  // Constant: MOD
  llvm.mlir.global internal constant @MOD(987654321 : i64) : i64
  func.func @mod_pow(%arg0: i64, %arg1: i64, %arg2: i64) -> i64 {
    %0 = arith.constant 1 : i32
    %2 = arith.extsi %0 : i32 to i64
    %1 = arith.remsi %2, %arg2 : i64
    %3 = llvm.mlir.constant(1 : i64) : i64
    %4 = llvm.alloca %3 x i64 : (i64) -> !llvm.ptr
    llvm.store %1, %4 : i64, !llvm.ptr
    %5 = arith.remsi %arg0, %arg2 : i64
    %6 = llvm.mlir.constant(1 : i64) : i64
    %7 = llvm.alloca %6 x i64 : (i64) -> !llvm.ptr
    llvm.store %5, %7 : i64, !llvm.ptr
    %8 = llvm.load %7 : !llvm.ptr -> i64
    %9 = arith.constant 0 : i32
    %11 = arith.extsi %9 : i32 to i64
    %10 = arith.cmpi slt, %8, %11 : i64
    cf.cond_br %10, ^bb0, ^bb1
    ^bb0:
      %12 = llvm.load %7 : !llvm.ptr -> i64
      %13 = arith.addi %12, %arg2 : i64
      llvm.store %13, %7 : i64, !llvm.ptr
      cf.br ^bb2
    ^bb1:
      cf.br ^bb2
    ^bb2:
    %14 = llvm.mlir.constant(1 : i64) : i64
    %15 = llvm.alloca %14 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %15 : i64, !llvm.ptr
    cf.br ^bb3
    ^bb3:
    %16 = llvm.load %15 : !llvm.ptr -> i64
    %17 = arith.constant 0 : i32
    %19 = arith.extsi %17 : i32 to i64
    %18 = arith.cmpi sgt, %16, %19 : i64
    cf.cond_br %18, ^bb4, ^bb5
    ^bb4:
      %20 = llvm.load %15 : !llvm.ptr -> i64
      %21 = arith.constant 1 : i32
      %23 = arith.extsi %21 : i32 to i64
      %22 = arith.andi %20, %23 : i64
      %24 = arith.constant 0 : i32
      %26 = arith.extsi %24 : i32 to i64
      %25 = arith.cmpi ne, %22, %26 : i64
      cf.cond_br %25, ^bb6, ^bb7
      ^bb6:
        %27 = llvm.load %4 : !llvm.ptr -> i64
        %28 = arith.extsi %27 : i64 to i128
        %29 = llvm.load %7 : !llvm.ptr -> i64
        %30 = arith.extsi %29 : i64 to i128
        %32 = arith.trunci %28 : i128 to i64
        %33 = arith.trunci %30 : i128 to i64
        %31 = arith.muli %32, %33 : i64
        %34 = arith.extsi %arg2 : i64 to i128
        %36 = arith.trunci %34 : i128 to i64
        %35 = arith.remsi %31, %36 : i64
        llvm.store %35, %4 : i64, !llvm.ptr
        cf.br ^bb8
      ^bb7:
        cf.br ^bb8
      ^bb8:
      %37 = llvm.load %7 : !llvm.ptr -> i64
      %38 = arith.extsi %37 : i64 to i128
      %39 = llvm.load %7 : !llvm.ptr -> i64
      %40 = arith.extsi %39 : i64 to i128
      %42 = arith.trunci %38 : i128 to i64
      %43 = arith.trunci %40 : i128 to i64
      %41 = arith.muli %42, %43 : i64
      %44 = arith.extsi %arg2 : i64 to i128
      %46 = arith.trunci %44 : i128 to i64
      %45 = arith.remsi %41, %46 : i64
      llvm.store %45, %7 : i64, !llvm.ptr
      %47 = llvm.load %15 : !llvm.ptr -> i64
      %48 = arith.constant 1 : i32
      %50 = arith.extsi %48 : i32 to i64
      %49 = arith.shrsi %47, %50 : i64
      llvm.store %49, %15 : i64, !llvm.ptr
      cf.br ^bb3
    ^bb5:
    %51 = llvm.load %4 : !llvm.ptr -> i64
    func.return %51 : i64
  }
  func.func @mod_inv(%arg0: i64, %arg1: i64) -> i64 {
    %52 = arith.remsi %arg0, %arg1 : i64
    %53 = llvm.mlir.constant(1 : i64) : i64
    %54 = llvm.alloca %53 x i64 : (i64) -> !llvm.ptr
    llvm.store %52, %54 : i64, !llvm.ptr
    %55 = llvm.mlir.constant(1 : i64) : i64
    %56 = llvm.alloca %55 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %56 : i64, !llvm.ptr
    %57 = arith.constant 1 : i32
    %58 = arith.extsi %57 : i32 to i64
    %59 = llvm.mlir.constant(1 : i64) : i64
    %60 = llvm.alloca %59 x i64 : (i64) -> !llvm.ptr
    llvm.store %58, %60 : i64, !llvm.ptr
    %61 = arith.constant 0 : i32
    %62 = arith.extsi %61 : i32 to i64
    %63 = llvm.mlir.constant(1 : i64) : i64
    %64 = llvm.alloca %63 x i64 : (i64) -> !llvm.ptr
    llvm.store %62, %64 : i64, !llvm.ptr
    %65 = llvm.load %54 : !llvm.ptr -> i64
    %66 = arith.constant 0 : i32
    %68 = arith.extsi %66 : i32 to i64
    %67 = arith.cmpi slt, %65, %68 : i64
    cf.cond_br %67, ^bb9, ^bb10
    ^bb9:
      %69 = llvm.load %54 : !llvm.ptr -> i64
      %70 = arith.addi %69, %arg1 : i64
      llvm.store %70, %54 : i64, !llvm.ptr
      cf.br ^bb11
    ^bb10:
      cf.br ^bb11
    ^bb11:
    cf.br ^bb12
    ^bb12:
    %71 = llvm.load %56 : !llvm.ptr -> i64
    %72 = arith.constant 0 : i32
    %74 = arith.extsi %72 : i32 to i64
    %73 = arith.cmpi ne, %71, %74 : i64
    cf.cond_br %73, ^bb13, ^bb14
    ^bb13:
      %75 = llvm.load %54 : !llvm.ptr -> i64
      %76 = llvm.load %56 : !llvm.ptr -> i64
      %77 = arith.divsi %75, %76 : i64
      %78 = llvm.load %54 : !llvm.ptr -> i64
      %79 = llvm.load %56 : !llvm.ptr -> i64
      %80 = arith.muli %77, %79 : i64
      %81 = arith.subi %78, %80 : i64
      %82 = llvm.load %56 : !llvm.ptr -> i64
      llvm.store %82, %54 : i64, !llvm.ptr
      llvm.store %81, %56 : i64, !llvm.ptr
      %83 = llvm.load %60 : !llvm.ptr -> i64
      %84 = llvm.load %64 : !llvm.ptr -> i64
      %85 = arith.muli %77, %84 : i64
      %86 = arith.subi %83, %85 : i64
      %87 = llvm.load %64 : !llvm.ptr -> i64
      llvm.store %87, %60 : i64, !llvm.ptr
      llvm.store %86, %64 : i64, !llvm.ptr
      cf.br ^bb12
    ^bb14:
    %88 = llvm.load %60 : !llvm.ptr -> i64
    %89 = arith.constant 0 : i32
    %91 = arith.extsi %89 : i32 to i64
    %90 = arith.cmpi slt, %88, %91 : i64
    cf.cond_br %90, ^bb15, ^bb16
    ^bb15:
      %92 = llvm.load %60 : !llvm.ptr -> i64
      %93 = arith.addi %92, %arg1 : i64
      llvm.store %93, %60 : i64, !llvm.ptr
      cf.br ^bb17
    ^bb16:
      cf.br ^bb17
    ^bb17:
    %94 = llvm.load %60 : !llvm.ptr -> i64
    %95 = arith.remsi %94, %arg1 : i64
    func.return %95 : i64
  }
  func.func @fwht_xor(%arg0: !llvm.ptr, %arg1: i64, %arg2: i64) -> () {
    %96 = arith.constant 1 : i32
    %97 = arith.extsi %96 : i32 to i64
    %98 = llvm.mlir.constant(1 : i64) : i64
    %99 = llvm.alloca %98 x i64 : (i64) -> !llvm.ptr
    llvm.store %97, %99 : i64, !llvm.ptr
    cf.br ^bb18
    ^bb18:
    %100 = llvm.load %99 : !llvm.ptr -> i64
    %101 = arith.cmpi slt, %100, %arg1 : i64
    cf.cond_br %101, ^bb19, ^bb20
    ^bb19:
      %102 = llvm.load %99 : !llvm.ptr -> i64
      %103 = arith.constant 1 : i32
      %105 = arith.extsi %103 : i32 to i64
      %104 = arith.shli %102, %105 : i64
      %106 = arith.constant 0 : i32
      %107 = arith.extsi %106 : i32 to i64
      %108 = llvm.mlir.constant(1 : i64) : i64
      %109 = llvm.alloca %108 x i64 : (i64) -> !llvm.ptr
      llvm.store %107, %109 : i64, !llvm.ptr
      cf.br ^bb21
      ^bb21:
      %110 = llvm.load %109 : !llvm.ptr -> i64
      %111 = arith.cmpi slt, %110, %arg1 : i64
      cf.cond_br %111, ^bb22, ^bb23
      ^bb22:
        %112 = llvm.load %109 : !llvm.ptr -> i64
        %113 = llvm.mlir.constant(1 : i64) : i64
        %114 = llvm.alloca %113 x i64 : (i64) -> !llvm.ptr
        llvm.store %112, %114 : i64, !llvm.ptr
        cf.br ^bb24
        ^bb24:
        %115 = llvm.load %114 : !llvm.ptr -> i64
        %116 = llvm.load %109 : !llvm.ptr -> i64
        %117 = llvm.load %99 : !llvm.ptr -> i64
        %118 = arith.addi %116, %117 : i64
        %119 = arith.cmpi slt, %115, %118 : i64
        cf.cond_br %119, ^bb25, ^bb26
        ^bb25:
          %121 = llvm.load %114 : !llvm.ptr -> i64
          %122 = llvm.getelementptr %arg0[%121] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %120 = llvm.load %122 : !llvm.ptr -> i64
          %124 = llvm.load %114 : !llvm.ptr -> i64
          %125 = llvm.load %99 : !llvm.ptr -> i64
          %126 = arith.addi %124, %125 : i64
          %127 = llvm.getelementptr %arg0[%126] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %123 = llvm.load %127 : !llvm.ptr -> i64
          %128 = arith.addi %120, %123 : i64
          %129 = llvm.mlir.constant(1 : i64) : i64
          %130 = llvm.alloca %129 x i64 : (i64) -> !llvm.ptr
          llvm.store %128, %130 : i64, !llvm.ptr
          %131 = llvm.load %130 : !llvm.ptr -> i64
          %132 = arith.cmpi sge, %131, %arg2 : i64
          cf.cond_br %132, ^bb27, ^bb28
          ^bb27:
            %133 = llvm.load %130 : !llvm.ptr -> i64
            %134 = arith.subi %133, %arg2 : i64
            llvm.store %134, %130 : i64, !llvm.ptr
            cf.br ^bb29
          ^bb28:
            cf.br ^bb29
          ^bb29:
          %135 = arith.subi %120, %123 : i64
          %136 = llvm.mlir.constant(1 : i64) : i64
          %137 = llvm.alloca %136 x i64 : (i64) -> !llvm.ptr
          llvm.store %135, %137 : i64, !llvm.ptr
          %138 = llvm.load %137 : !llvm.ptr -> i64
          %139 = arith.constant 0 : i32
          %141 = arith.extsi %139 : i32 to i64
          %140 = arith.cmpi slt, %138, %141 : i64
          cf.cond_br %140, ^bb30, ^bb31
          ^bb30:
            %142 = llvm.load %137 : !llvm.ptr -> i64
            %143 = arith.addi %142, %arg2 : i64
            llvm.store %143, %137 : i64, !llvm.ptr
            cf.br ^bb32
          ^bb31:
            cf.br ^bb32
          ^bb32:
          %144 = llvm.load %130 : !llvm.ptr -> i64
          %145 = llvm.load %114 : !llvm.ptr -> i64
          %146 = llvm.getelementptr %arg0[%145] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          llvm.store %144, %146 : i64, !llvm.ptr
          %147 = llvm.load %137 : !llvm.ptr -> i64
          %148 = llvm.load %114 : !llvm.ptr -> i64
          %149 = llvm.load %99 : !llvm.ptr -> i64
          %150 = arith.addi %148, %149 : i64
          %151 = llvm.getelementptr %arg0[%150] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          llvm.store %147, %151 : i64, !llvm.ptr
          %152 = llvm.load %114 : !llvm.ptr -> i64
          %153 = arith.constant 1 : i32
          %155 = arith.extsi %153 : i32 to i64
          %154 = arith.addi %152, %155 : i64
          llvm.store %154, %114 : i64, !llvm.ptr
          cf.br ^bb24
        ^bb26:
        %156 = llvm.load %109 : !llvm.ptr -> i64
        %157 = arith.addi %156, %104 : i64
        llvm.store %157, %109 : i64, !llvm.ptr
        cf.br ^bb21
      ^bb23:
      %158 = llvm.load %99 : !llvm.ptr -> i64
      %159 = arith.constant 1 : i32
      %161 = arith.extsi %159 : i32 to i64
      %160 = arith.shli %158, %161 : i64
      llvm.store %160, %99 : i64, !llvm.ptr
      cf.br ^bb18
    ^bb20:
    func.return
  }
  func.func @omega_counts_up_to(%arg0: i64, %arg1: !llvm.ptr) -> i64 {
    %163 = arith.constant 1 : i32
    %165 = arith.extsi %163 : i32 to i64
    %164 = arith.addi %arg0, %165 : i64
    %166 = arith.constant 4 : i32
    %167 = arith.extsi %166 : i32 to i64
    %162 = func.call @calloc(%164, %167) : (i64, i64) -> !llvm.ptr
    %169 = arith.constant 1 : i32
    %171 = arith.extsi %169 : i32 to i64
    %170 = arith.addi %arg0, %171 : i64
    %172 = arith.constant 1 : i32
    %173 = arith.extsi %172 : i32 to i64
    %168 = func.call @calloc(%170, %173) : (i64, i64) -> !llvm.ptr
    %175 = arith.constant 700000 : i32
    %176 = arith.constant 4 : i32
    %177 = arith.extsi %175 : i32 to i64
    %178 = arith.extsi %176 : i32 to i64
    %174 = func.call @calloc(%177, %178) : (i64, i64) -> !llvm.ptr
    %179 = llvm.mlir.zero : !llvm.ptr
    %180 = llvm.icmp "eq" %162, %179 : !llvm.ptr
    %181 = scf.if %180 -> (i1) {
      %182 = arith.constant true
      scf.yield %182 : i1
    } else {
      %183 = llvm.mlir.zero : !llvm.ptr
      %184 = llvm.icmp "eq" %168, %183 : !llvm.ptr
      scf.yield %184 : i1
    }
    %185 = scf.if %181 -> (i1) {
      %186 = arith.constant true
      scf.yield %186 : i1
    } else {
      %187 = llvm.mlir.zero : !llvm.ptr
      %188 = llvm.icmp "eq" %174, %187 : !llvm.ptr
      scf.yield %188 : i1
    }
    cf.cond_br %185, ^bb33, ^bb34
    ^bb33:
      func.call @free(%162) : (!llvm.ptr) -> ()
      func.call @free(%168) : (!llvm.ptr) -> ()
      func.call @free(%174) : (!llvm.ptr) -> ()
      %192 = arith.constant 1 : i32
      %194 = arith.constant 0 : i32
      %193 = arith.subi %194, %192 : i32
      %195 = arith.extsi %193 : i32 to i64
      func.return %195 : i64
    ^bb34:
      cf.br ^bb35
    ^bb35:
    %196 = arith.constant 0 : i32
    %197 = arith.extsi %196 : i32 to i64
    %198 = llvm.mlir.constant(1 : i64) : i64
    %199 = llvm.alloca %198 x i64 : (i64) -> !llvm.ptr
    llvm.store %197, %199 : i64, !llvm.ptr
    cf.br ^bb36
    ^bb36:
    %200 = llvm.load %199 : !llvm.ptr -> i64
    %201 = arith.constant 32 : i32
    %203 = arith.extsi %201 : i32 to i64
    %202 = arith.cmpi slt, %200, %203 : i64
    cf.cond_br %202, ^bb37, ^bb38
    ^bb37:
      %204 = arith.constant 0 : i32
      %205 = llvm.load %199 : !llvm.ptr -> i64
      %206 = arith.extsi %204 : i32 to i64
      %207 = llvm.getelementptr %arg1[%205] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %206, %207 : i64, !llvm.ptr
      %208 = llvm.load %199 : !llvm.ptr -> i64
      %209 = arith.constant 1 : i32
      %211 = arith.extsi %209 : i32 to i64
      %210 = arith.addi %208, %211 : i64
      llvm.store %210, %199 : i64, !llvm.ptr
      cf.br ^bb36
    ^bb38:
    %212 = arith.constant 0 : i32
    %213 = arith.extsi %212 : i32 to i64
    %214 = llvm.mlir.constant(1 : i64) : i64
    %215 = llvm.alloca %214 x i64 : (i64) -> !llvm.ptr
    llvm.store %213, %215 : i64, !llvm.ptr
    %216 = arith.constant 0 : i32
    %217 = arith.extsi %216 : i32 to i64
    %218 = llvm.mlir.constant(1 : i64) : i64
    %219 = llvm.alloca %218 x i64 : (i64) -> !llvm.ptr
    llvm.store %217, %219 : i64, !llvm.ptr
    %220 = arith.constant 2 : i32
    %221 = arith.extsi %220 : i32 to i64
    %222 = llvm.mlir.constant(1 : i64) : i64
    %223 = llvm.alloca %222 x i64 : (i64) -> !llvm.ptr
    llvm.store %221, %223 : i64, !llvm.ptr
    cf.br ^bb39
    ^bb39:
    %224 = llvm.load %223 : !llvm.ptr -> i64
    %225 = arith.cmpi sle, %224, %arg0 : i64
    cf.cond_br %225, ^bb40, ^bb41
    ^bb40:
      %227 = llvm.load %223 : !llvm.ptr -> i64
      %228 = llvm.getelementptr %162[%227] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %226 = llvm.load %228 : !llvm.ptr -> i32
      %229 = llvm.mlir.undef : i64
      %230 = arith.constant 0 : i32
      %231 = arith.cmpi eq, %226, %230 : i32
      %232 = scf.if %231 -> (i64) {
        %233 = llvm.load %223 : !llvm.ptr -> i64
        %234 = arith.trunci %233 : i64 to i32
        %235 = llvm.load %223 : !llvm.ptr -> i64
        %236 = llvm.getelementptr %162[%235] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        llvm.store %234, %236 : i32, !llvm.ptr
        %237 = llvm.load %223 : !llvm.ptr -> i64
        %238 = arith.trunci %237 : i64 to i32
        %239 = llvm.load %215 : !llvm.ptr -> i64
        %240 = llvm.getelementptr %174[%239] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        llvm.store %238, %240 : i32, !llvm.ptr
        %241 = llvm.load %215 : !llvm.ptr -> i64
        %242 = arith.constant 1 : i32
        %244 = arith.extsi %242 : i32 to i64
        %243 = arith.addi %241, %244 : i64
        llvm.store %243, %215 : i64, !llvm.ptr
        %245 = arith.constant 1 : i32
        %246 = llvm.load %223 : !llvm.ptr -> i64
        %247 = arith.trunci %245 : i32 to i8
        %248 = llvm.getelementptr %168[%246] : (!llvm.ptr, i64) -> !llvm.ptr, i8
        llvm.store %247, %248 : i8, !llvm.ptr
        %249 = arith.constant 1 : i32
        %250 = arith.extsi %249 : i32 to i64
        scf.yield %250 : i64
      } else {
        %252 = llvm.load %223 : !llvm.ptr -> i64
        %253 = llvm.getelementptr %168[%252] : (!llvm.ptr, i64) -> !llvm.ptr, i8
        %251 = llvm.load %253 : !llvm.ptr -> i8
        %254 = arith.extsi %251 : i8 to i64
        scf.yield %254 : i64
      }
      %256 = llvm.getelementptr %arg1[%232] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %255 = llvm.load %256 : !llvm.ptr -> i64
      %257 = arith.constant 1 : i32
      %259 = arith.extsi %257 : i32 to i64
      %258 = arith.addi %255, %259 : i64
      %260 = llvm.getelementptr %arg1[%232] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %258, %260 : i64, !llvm.ptr
      %261 = llvm.load %219 : !llvm.ptr -> i64
      %262 = arith.cmpi sgt, %232, %261 : i64
      cf.cond_br %262, ^bb42, ^bb43
      ^bb42:
        llvm.store %232, %219 : i64, !llvm.ptr
        cf.br ^bb44
      ^bb43:
        cf.br ^bb44
      ^bb44:
      %263 = arith.constant 0 : i32
      %264 = arith.extsi %263 : i32 to i64
      %265 = llvm.mlir.constant(1 : i64) : i64
      %266 = llvm.alloca %265 x i64 : (i64) -> !llvm.ptr
      llvm.store %264, %266 : i64, !llvm.ptr
      cf.br ^bb45
      ^bb45:
      %267 = llvm.load %266 : !llvm.ptr -> i64
      %268 = llvm.load %215 : !llvm.ptr -> i64
      %269 = arith.cmpi slt, %267, %268 : i64
      cf.cond_br %269, ^bb46, ^bb47
      ^bb46:
        %271 = llvm.load %266 : !llvm.ptr -> i64
        %272 = llvm.getelementptr %174[%271] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %270 = llvm.load %272 : !llvm.ptr -> i32
        %273 = arith.extsi %270 : i32 to i64
        %274 = llvm.load %223 : !llvm.ptr -> i64
        %275 = arith.muli %274, %273 : i64
        %276 = arith.cmpi sgt, %275, %arg0 : i64
        cf.cond_br %276, ^bb48, ^bb49
        ^bb48:
          cf.br ^bb47
        ^bb49:
          cf.br ^bb50
        ^bb50:
        %277 = arith.trunci %273 : i64 to i32
        %278 = llvm.getelementptr %162[%275] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        llvm.store %277, %278 : i32, !llvm.ptr
        %279 = arith.constant 1 : i32
        %281 = arith.extsi %279 : i32 to i64
        %280 = arith.addi %232, %281 : i64
        %282 = arith.trunci %280 : i64 to i8
        %283 = llvm.getelementptr %168[%275] : (!llvm.ptr, i64) -> !llvm.ptr, i8
        llvm.store %282, %283 : i8, !llvm.ptr
        %284 = arith.extsi %226 : i32 to i64
        %285 = arith.cmpi eq, %273, %284 : i64
        cf.cond_br %285, ^bb51, ^bb52
        ^bb51:
          cf.br ^bb47
        ^bb52:
          cf.br ^bb53
        ^bb53:
        %286 = llvm.load %266 : !llvm.ptr -> i64
        %287 = arith.constant 1 : i32
        %289 = arith.extsi %287 : i32 to i64
        %288 = arith.addi %286, %289 : i64
        llvm.store %288, %266 : i64, !llvm.ptr
        cf.br ^bb45
      ^bb47:
      %290 = llvm.load %223 : !llvm.ptr -> i64
      %291 = arith.constant 1 : i32
      %293 = arith.extsi %291 : i32 to i64
      %292 = arith.addi %290, %293 : i64
      llvm.store %292, %223 : i64, !llvm.ptr
      cf.br ^bb39
    ^bb41:
    func.call @free(%162) : (!llvm.ptr) -> ()
    func.call @free(%168) : (!llvm.ptr) -> ()
    func.call @free(%174) : (!llvm.ptr) -> ()
    %297 = llvm.load %219 : !llvm.ptr -> i64
    func.return %297 : i64
  }
  func.func @compute_h_sequence(%arg0: i64, %arg1: !llvm.ptr) -> i64 {
    %298 = arith.constant 0 : i32
    %300 = arith.extsi %298 : i32 to i64
    %299 = arith.cmpi sle, %arg0, %300 : i64
    cf.cond_br %299, ^bb54, ^bb55
    ^bb54:
      %301 = arith.constant 0 : i32
      %302 = arith.extsi %301 : i32 to i64
      func.return %302 : i64
    ^bb55:
      cf.br ^bb56
    ^bb56:
    %303 = arith.constant 0 : i32
    %304 = arith.constant 1 : i32
    %305 = arith.extsi %303 : i32 to i64
    %306 = arith.extsi %304 : i32 to i64
    %307 = llvm.getelementptr %arg1[%306] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %305, %307 : i64, !llvm.ptr
    %308 = arith.constant 0 : i32
    %309 = arith.extsi %308 : i32 to i64
    %310 = llvm.mlir.constant(1 : i64) : i64
    %311 = llvm.alloca %310 x i64 : (i64) -> !llvm.ptr
    llvm.store %309, %311 : i64, !llvm.ptr
    %313 = arith.constant 64 : i32
    %314 = arith.constant 8 : i32
    %315 = arith.extsi %313 : i32 to i64
    %316 = arith.extsi %314 : i32 to i64
    %312 = func.call @calloc(%315, %316) : (i64, i64) -> !llvm.ptr
    %317 = arith.constant 2 : i32
    %318 = arith.extsi %317 : i32 to i64
    %319 = llvm.mlir.constant(1 : i64) : i64
    %320 = llvm.alloca %319 x i64 : (i64) -> !llvm.ptr
    llvm.store %318, %320 : i64, !llvm.ptr
    cf.br ^bb57
    ^bb57:
    %321 = llvm.load %320 : !llvm.ptr -> i64
    %322 = arith.cmpi sle, %321, %arg0 : i64
    cf.cond_br %322, ^bb58, ^bb59
    ^bb58:
      %323 = arith.constant 0 : i32
      %324 = arith.extsi %323 : i32 to i64
      %325 = llvm.mlir.constant(1 : i64) : i64
      %326 = llvm.alloca %325 x i64 : (i64) -> !llvm.ptr
      llvm.store %324, %326 : i64, !llvm.ptr
      cf.br ^bb60
      ^bb60:
      %327 = llvm.load %326 : !llvm.ptr -> i64
      %328 = arith.constant 64 : i32
      %330 = arith.extsi %328 : i32 to i64
      %329 = arith.cmpi slt, %327, %330 : i64
      cf.cond_br %329, ^bb61, ^bb62
      ^bb61:
        %331 = arith.constant 0 : i32
        %332 = llvm.load %326 : !llvm.ptr -> i64
        %333 = arith.extsi %331 : i32 to i64
        %334 = llvm.getelementptr %312[%332] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %333, %334 : i64, !llvm.ptr
        %335 = llvm.load %326 : !llvm.ptr -> i64
        %336 = arith.constant 1 : i32
        %338 = arith.extsi %336 : i32 to i64
        %337 = arith.addi %335, %338 : i64
        llvm.store %337, %326 : i64, !llvm.ptr
        cf.br ^bb60
      ^bb62:
      %339 = arith.constant 1 : i32
      %340 = arith.extsi %339 : i32 to i64
      %341 = llvm.mlir.constant(1 : i64) : i64
      %342 = llvm.alloca %341 x i64 : (i64) -> !llvm.ptr
      llvm.store %340, %342 : i64, !llvm.ptr
      cf.br ^bb63
      ^bb63:
      %343 = llvm.load %342 : !llvm.ptr -> i64
      %344 = llvm.load %320 : !llvm.ptr -> i64
      %345 = arith.cmpi slt, %343, %344 : i64
      cf.cond_br %345, ^bb64, ^bb65
      ^bb64:
        %346 = arith.constant 1 : i32
        %347 = arith.extsi %346 : i32 to i64
        %348 = llvm.mlir.constant(1 : i64) : i64
        %349 = llvm.alloca %348 x i64 : (i64) -> !llvm.ptr
        llvm.store %347, %349 : i64, !llvm.ptr
        cf.br ^bb66
        ^bb66:
        %350 = llvm.load %349 : !llvm.ptr -> i64
        %351 = llvm.load %320 : !llvm.ptr -> i64
        %352 = arith.cmpi slt, %350, %351 : i64
        cf.cond_br %352, ^bb67, ^bb68
        ^bb67:
          %354 = llvm.load %342 : !llvm.ptr -> i64
          %355 = llvm.getelementptr %arg1[%354] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %353 = llvm.load %355 : !llvm.ptr -> i64
          %357 = llvm.load %349 : !llvm.ptr -> i64
          %358 = llvm.getelementptr %arg1[%357] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %356 = llvm.load %358 : !llvm.ptr -> i64
          %359 = arith.xori %353, %356 : i64
          %360 = arith.constant 6 : i32
          %362 = arith.extsi %360 : i32 to i64
          %361 = arith.shrsi %359, %362 : i64
          %363 = arith.constant 63 : i32
          %365 = arith.extsi %363 : i32 to i64
          %364 = arith.andi %361, %365 : i64
          %366 = arith.constant 1 : i32
          %367 = arith.extsi %366 : i32 to i64
          %368 = arith.constant 63 : i32
          %370 = arith.extsi %368 : i32 to i64
          %369 = arith.andi %359, %370 : i64
          %371 = arith.shli %367, %369 : i64
          %373 = llvm.getelementptr %312[%364] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %372 = llvm.load %373 : !llvm.ptr -> i64
          %374 = arith.ori %372, %371 : i64
          %375 = llvm.getelementptr %312[%364] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          llvm.store %374, %375 : i64, !llvm.ptr
          %376 = llvm.load %349 : !llvm.ptr -> i64
          %377 = arith.constant 1 : i32
          %379 = arith.extsi %377 : i32 to i64
          %378 = arith.addi %376, %379 : i64
          llvm.store %378, %349 : i64, !llvm.ptr
          cf.br ^bb66
        ^bb68:
        %380 = llvm.load %342 : !llvm.ptr -> i64
        %381 = arith.constant 1 : i32
        %383 = arith.extsi %381 : i32 to i64
        %382 = arith.addi %380, %383 : i64
        llvm.store %382, %342 : i64, !llvm.ptr
        cf.br ^bb63
      ^bb65:
      %384 = arith.constant 0 : i32
      %385 = arith.extsi %384 : i32 to i64
      %386 = llvm.mlir.constant(1 : i64) : i64
      %387 = llvm.alloca %386 x i64 : (i64) -> !llvm.ptr
      llvm.store %385, %387 : i64, !llvm.ptr
      cf.br ^bb69
      ^bb69:
      %388 = llvm.load %387 : !llvm.ptr -> i64
      %389 = arith.constant 4096 : i32
      %391 = arith.extsi %389 : i32 to i64
      %390 = arith.cmpi slt, %388, %391 : i64
      cf.cond_br %390, ^bb70, ^bb71
      ^bb70:
        %392 = llvm.load %387 : !llvm.ptr -> i64
        %393 = arith.constant 6 : i32
        %395 = arith.extsi %393 : i32 to i64
        %394 = arith.shrsi %392, %395 : i64
        %396 = arith.constant 63 : i32
        %398 = arith.extsi %396 : i32 to i64
        %397 = arith.andi %394, %398 : i64
        %399 = arith.constant 1 : i32
        %400 = arith.extsi %399 : i32 to i64
        %401 = llvm.load %387 : !llvm.ptr -> i64
        %402 = arith.constant 63 : i32
        %404 = arith.extsi %402 : i32 to i64
        %403 = arith.andi %401, %404 : i64
        %405 = arith.shli %400, %403 : i64
        %407 = llvm.getelementptr %312[%397] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %406 = llvm.load %407 : !llvm.ptr -> i64
        %408 = arith.andi %406, %405 : i64
        %409 = arith.constant 0 : i32
        %411 = arith.extsi %409 : i32 to i64
        %410 = arith.cmpi ne, %408, %411 : i64
        cf.cond_br %410, ^bb72, ^bb73
        ^bb72:
          %412 = llvm.load %387 : !llvm.ptr -> i64
          %413 = arith.constant 1 : i32
          %415 = arith.extsi %413 : i32 to i64
          %414 = arith.addi %412, %415 : i64
          llvm.store %414, %387 : i64, !llvm.ptr
          cf.br ^bb74
        ^bb73:
          cf.br ^bb71
        ^bb74:
        cf.br ^bb69
      ^bb71:
      %416 = llvm.load %387 : !llvm.ptr -> i64
      %417 = llvm.load %320 : !llvm.ptr -> i64
      %418 = llvm.getelementptr %arg1[%417] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %416, %418 : i64, !llvm.ptr
      %419 = llvm.load %387 : !llvm.ptr -> i64
      %420 = llvm.load %311 : !llvm.ptr -> i64
      %421 = arith.cmpi sgt, %419, %420 : i64
      cf.cond_br %421, ^bb75, ^bb76
      ^bb75:
        %422 = llvm.load %387 : !llvm.ptr -> i64
        llvm.store %422, %311 : i64, !llvm.ptr
        cf.br ^bb77
      ^bb76:
        cf.br ^bb77
      ^bb77:
      %423 = llvm.load %320 : !llvm.ptr -> i64
      %424 = arith.constant 1 : i32
      %426 = arith.extsi %424 : i32 to i64
      %425 = arith.addi %423, %426 : i64
      llvm.store %425, %320 : i64, !llvm.ptr
      cf.br ^bb57
    ^bb59:
    func.call @free(%312) : (!llvm.ptr) -> ()
    %428 = llvm.load %311 : !llvm.ptr -> i64
    func.return %428 : i64
  }
  func.func @f(%arg0: i64, %arg1: i64) -> i64 {
    %430 = arith.constant 32 : i32
    %431 = arith.constant 8 : i32
    %432 = arith.extsi %430 : i32 to i64
    %433 = arith.extsi %431 : i32 to i64
    %429 = func.call @calloc(%432, %433) : (i64, i64) -> !llvm.ptr
    %434 = func.call @omega_counts_up_to(%arg0, %429) : (i64, !llvm.ptr) -> i64
    %435 = arith.constant 0 : i32
    %437 = arith.extsi %435 : i32 to i64
    %436 = arith.cmpi slt, %434, %437 : i64
    cf.cond_br %436, ^bb78, ^bb79
    ^bb78:
      func.call @free(%429) : (!llvm.ptr) -> ()
      %439 = arith.constant 0 : i32
      %440 = arith.extsi %439 : i32 to i64
      func.return %440 : i64
    ^bb79:
      cf.br ^bb80
    ^bb80:
    %442 = arith.constant 32 : i32
    %443 = arith.constant 8 : i32
    %444 = arith.extsi %442 : i32 to i64
    %445 = arith.extsi %443 : i32 to i64
    %441 = func.call @calloc(%444, %445) : (i64, i64) -> !llvm.ptr
    %446 = func.call @compute_h_sequence(%434, %441) : (i64, !llvm.ptr) -> i64
    %447 = arith.constant 1 : i32
    %448 = arith.extsi %447 : i32 to i64
    %449 = llvm.mlir.constant(1 : i64) : i64
    %450 = llvm.alloca %449 x i64 : (i64) -> !llvm.ptr
    llvm.store %448, %450 : i64, !llvm.ptr
    cf.br ^bb81
    ^bb81:
    %451 = llvm.load %450 : !llvm.ptr -> i64
    %452 = arith.cmpi sle, %451, %446 : i64
    cf.cond_br %452, ^bb82, ^bb83
    ^bb82:
      %453 = llvm.load %450 : !llvm.ptr -> i64
      %454 = arith.constant 1 : i32
      %456 = arith.extsi %454 : i32 to i64
      %455 = arith.shli %453, %456 : i64
      llvm.store %455, %450 : i64, !llvm.ptr
      cf.br ^bb81
    ^bb83:
    %458 = llvm.load %450 : !llvm.ptr -> i64
    %459 = arith.constant 8 : i32
    %460 = arith.extsi %459 : i32 to i64
    %457 = func.call @calloc(%458, %460) : (i64, i64) -> !llvm.ptr
    %461 = llvm.mlir.zero : !llvm.ptr
    %462 = llvm.icmp "eq" %457, %461 : !llvm.ptr
    cf.cond_br %462, ^bb84, ^bb85
    ^bb84:
      func.call @free(%429) : (!llvm.ptr) -> ()
      func.call @free(%441) : (!llvm.ptr) -> ()
      %465 = arith.constant 0 : i32
      %466 = arith.extsi %465 : i32 to i64
      func.return %466 : i64
    ^bb85:
      cf.br ^bb86
    ^bb86:
    %467 = arith.constant 1 : i32
    %468 = arith.extsi %467 : i32 to i64
    %469 = llvm.mlir.constant(1 : i64) : i64
    %470 = llvm.alloca %469 x i64 : (i64) -> !llvm.ptr
    llvm.store %468, %470 : i64, !llvm.ptr
    cf.br ^bb87
    ^bb87:
    %471 = llvm.load %470 : !llvm.ptr -> i64
    %472 = arith.cmpi sle, %471, %434 : i64
    cf.cond_br %472, ^bb88, ^bb89
    ^bb88:
      %475 = llvm.load %470 : !llvm.ptr -> i64
      %476 = llvm.getelementptr %441[%475] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %474 = llvm.load %476 : !llvm.ptr -> i64
      %477 = llvm.getelementptr %457[%474] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %473 = llvm.load %477 : !llvm.ptr -> i64
      %479 = llvm.load %470 : !llvm.ptr -> i64
      %480 = llvm.getelementptr %429[%479] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %478 = llvm.load %480 : !llvm.ptr -> i64
      %481 = arith.addi %473, %478 : i64
      %482 = llvm.mlir.addressof @MOD : !llvm.ptr
      %483 = llvm.load %482 : !llvm.ptr -> i64
      %484 = arith.remsi %481, %483 : i64
      %486 = llvm.load %470 : !llvm.ptr -> i64
      %487 = llvm.getelementptr %441[%486] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %485 = llvm.load %487 : !llvm.ptr -> i64
      %488 = llvm.getelementptr %457[%485] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %484, %488 : i64, !llvm.ptr
      %489 = llvm.load %470 : !llvm.ptr -> i64
      %490 = arith.constant 1 : i32
      %492 = arith.extsi %490 : i32 to i64
      %491 = arith.addi %489, %492 : i64
      llvm.store %491, %470 : i64, !llvm.ptr
      cf.br ^bb87
    ^bb89:
    %494 = llvm.load %450 : !llvm.ptr -> i64
    %495 = llvm.mlir.addressof @MOD : !llvm.ptr
    %496 = llvm.load %495 : !llvm.ptr -> i64
    func.call @fwht_xor(%457, %494, %496) : (!llvm.ptr, i64, i64) -> ()
    %497 = arith.constant 0 : i32
    %498 = arith.extsi %497 : i32 to i64
    %499 = llvm.mlir.constant(1 : i64) : i64
    %500 = llvm.alloca %499 x i64 : (i64) -> !llvm.ptr
    llvm.store %498, %500 : i64, !llvm.ptr
    %501 = arith.constant 0 : i32
    %502 = arith.extsi %501 : i32 to i64
    %503 = llvm.mlir.constant(1 : i64) : i64
    %504 = llvm.alloca %503 x i64 : (i64) -> !llvm.ptr
    llvm.store %502, %504 : i64, !llvm.ptr
    cf.br ^bb90
    ^bb90:
    %505 = llvm.load %504 : !llvm.ptr -> i64
    %506 = llvm.load %450 : !llvm.ptr -> i64
    %507 = arith.cmpi slt, %505, %506 : i64
    cf.cond_br %507, ^bb91, ^bb92
    ^bb91:
      %508 = llvm.load %500 : !llvm.ptr -> i64
      %511 = llvm.load %504 : !llvm.ptr -> i64
      %512 = llvm.getelementptr %457[%511] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %510 = llvm.load %512 : !llvm.ptr -> i64
      %513 = llvm.mlir.addressof @MOD : !llvm.ptr
      %514 = llvm.load %513 : !llvm.ptr -> i64
      %509 = func.call @mod_pow(%510, %arg1, %514) : (i64, i64, i64) -> i64
      %515 = arith.addi %508, %509 : i64
      %516 = llvm.mlir.addressof @MOD : !llvm.ptr
      %517 = llvm.load %516 : !llvm.ptr -> i64
      %518 = arith.remsi %515, %517 : i64
      llvm.store %518, %500 : i64, !llvm.ptr
      %519 = llvm.load %504 : !llvm.ptr -> i64
      %520 = arith.constant 1 : i32
      %522 = arith.extsi %520 : i32 to i64
      %521 = arith.addi %519, %522 : i64
      llvm.store %521, %504 : i64, !llvm.ptr
      cf.br ^bb90
    ^bb92:
    %523 = llvm.load %500 : !llvm.ptr -> i64
    %524 = arith.extsi %523 : i64 to i128
    %526 = llvm.load %450 : !llvm.ptr -> i64
    %527 = llvm.mlir.addressof @MOD : !llvm.ptr
    %528 = llvm.load %527 : !llvm.ptr -> i64
    %525 = func.call @mod_inv(%526, %528) : (i64, i64) -> i64
    %529 = arith.extsi %525 : i64 to i128
    %531 = arith.trunci %524 : i128 to i64
    %532 = arith.trunci %529 : i128 to i64
    %530 = arith.muli %531, %532 : i64
    %533 = llvm.mlir.addressof @MOD : !llvm.ptr
    %534 = llvm.load %533 : !llvm.ptr -> i64
    %535 = arith.extsi %534 : i64 to i128
    %537 = arith.trunci %535 : i128 to i64
    %536 = arith.remsi %530, %537 : i64
    %539 = arith.constant 1 : i32
    %541 = arith.extsi %539 : i32 to i64
    %540 = arith.subi %arg0, %541 : i64
    %542 = llvm.mlir.addressof @MOD : !llvm.ptr
    %543 = llvm.load %542 : !llvm.ptr -> i64
    %538 = func.call @mod_pow(%540, %arg1, %543) : (i64, i64, i64) -> i64
    %544 = arith.subi %538, %536 : i64
    %545 = llvm.mlir.addressof @MOD : !llvm.ptr
    %546 = llvm.load %545 : !llvm.ptr -> i64
    %547 = arith.remsi %544, %546 : i64
    %548 = llvm.mlir.constant(1 : i64) : i64
    %549 = llvm.alloca %548 x i64 : (i64) -> !llvm.ptr
    llvm.store %547, %549 : i64, !llvm.ptr
    %550 = llvm.load %549 : !llvm.ptr -> i64
    %551 = arith.constant 0 : i32
    %553 = arith.extsi %551 : i32 to i64
    %552 = arith.cmpi slt, %550, %553 : i64
    cf.cond_br %552, ^bb93, ^bb94
    ^bb93:
      %554 = llvm.load %549 : !llvm.ptr -> i64
      %555 = llvm.mlir.addressof @MOD : !llvm.ptr
      %556 = llvm.load %555 : !llvm.ptr -> i64
      %557 = arith.addi %554, %556 : i64
      llvm.store %557, %549 : i64, !llvm.ptr
      cf.br ^bb95
    ^bb94:
      cf.br ^bb95
    ^bb95:
    func.call @free(%457) : (!llvm.ptr) -> ()
    func.call @free(%429) : (!llvm.ptr) -> ()
    func.call @free(%441) : (!llvm.ptr) -> ()
    %561 = llvm.load %549 : !llvm.ptr -> i64
    func.return %561 : i64
  }
  func.func @main() -> i32 {
    %562 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %564 = arith.constant 10000000 : i32
    %565 = arith.constant 995705032704 : i32
    %566 = arith.extsi %564 : i32 to i64
    %567 = arith.extsi %565 : i32 to i64
    %563 = func.call @f(%566, %567) : (i64, i64) -> i64
    %568 = llvm.call @printf(%562, %563) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    %569 = arith.constant 0 : i32
    func.return %569 : i32
  }
}