Problem 459

Flipping Cards — tartan theorem + 1D Grundy prefixes + nim-product matching.

Answer3996390106631
Output3996390106631
StatusPASS
Native helperno
Runtime6360 ms
Peak memory55456 KB
Time complexityO(2^n) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(2^n)O(n)
Space complexityO(n^2)O(1)
ApproachFlow solutionDirect hand evaluation or enumeration
VerdictSuboptimal

Flow source

# Project Euler 459
# Flipping Cards — tartan theorem + 1D Grundy prefixes + nim-product matching.

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

const N: i64 = 1000000
const M: i64 = 1024
const MEMO_CAP: i64 = 2097152

let mut G_mk1: ptr<i64> = null
let mut G_mk2: ptr<i64> = null
let mut G_mv: ptr<i64> = null
let mut G_mu: ptr<i8> = null

function memo_get(a: i64, b: i64) -> i64 {
    # returns -1 if miss
    let mut h: i64 = (a * 1315423911 + b) % MEMO_CAP
    if h < 0 { h = h + MEMO_CAP }
    while G_mu[h] != 0 {
        if G_mk1[h] == a && G_mk2[h] == b {
            return G_mv[h]
        }
        h = h + 1
        if h == MEMO_CAP { h = 0 }
    }
    return -1
}

function memo_put(a: i64, b: i64, v: i64) -> void {
    let mut h: i64 = (a * 1315423911 + b) % MEMO_CAP
    if h < 0 { h = h + MEMO_CAP }
    while G_mu[h] != 0 {
        if G_mk1[h] == a && G_mk2[h] == b {
            G_mv[h] = v
            return
        }
        h = h + 1
        if h == MEMO_CAP { h = 0 }
    }
    G_mu[h] = 1
    G_mk1[h] = a
    G_mk2[h] = b
    G_mv[h] = v
}

function fermat(i: i64) -> i64 {
    # F_i = 2^(2^i)
    return 1 << (1 << i)
}

function fermat_index(x: i64) -> i64 {
    let mut i: i64 = 0
    while i + 1 < 7 && fermat(i + 1) <= x {
        i = i + 1
    }
    return i
}

function nim_mul(a0: i64, b0: i64) -> i64 {
    let mut a: i64 = a0
    let mut b: i64 = b0
    if a == 0 || b == 0 { return 0 }
    if a == 1 { return b }
    if b == 1 { return a }
    if a < b {
        let t: i64 = a
        a = b
        b = t
    }
    let cached: i64 = memo_get(a, b)
    if cached >= 0 { return cached }
    let m: i64 = fermat_index(a)
    let n: i64 = fermat_index(b)
    let mut r: i64 = 0
    if m != n {
        if m > n {
            let Fm: i64 = fermat(m)
            let shift: i64 = 1 << m
            let a1: i64 = a / Fm
            let a2: i64 = a % Fm
            r = (nim_mul(a1, b) << shift) ^ nim_mul(a2, b)
        } else {
            let Fn: i64 = fermat(n)
            let shift: i64 = 1 << n
            let b1: i64 = b / Fn
            let b2: i64 = b % Fn
            r = (nim_mul(a, b1) << shift) ^ nim_mul(a, b2)
        }
    } else {
        let Fn: i64 = fermat(n)
        let shift: i64 = 1 << n
        let a1: i64 = a / Fn
        let a2: i64 = a % Fn
        let b1: i64 = b / Fn
        let b2: i64 = b % Fn
        let p1: i64 = nim_mul(a1, b1)
        let p2: i64 = nim_mul(a2, b2)
        let p3: i64 = nim_mul(a1 ^ a2, b1 ^ b2)
        let p4: i64 = nim_mul(p1, Fn / 2)
        let p5: i64 = p3 ^ p2
        r = (p5 << shift) ^ p2 ^ p4
    }
    memo_put(a, b, r)
    return r
}

function nim_pow(a0: i64, e0: i64) -> i64 {
    let mut res: i64 = 1
    let mut base: i64 = a0
    let mut e: i64 = e0
    while e > 0 {
        if (e & 1) == 1 {
            res = nim_mul(res, base)
        }
        e = e / 2
        if e > 0 {
            base = nim_mul(base, base)
        }
    }
    return res
}

function nim_inv(a: i64) -> i64 {
    return nim_pow(a, 65534)
}

function compute_1d(n: i64, L: ptr<i64>, Llen: i64, freq: ptr<i64>) -> i64 {
    # returns C[n]; fills freq[0..M)
    let C: ptr<i32> = calloc(n + 1, 4)
    let mark: ptr<i32> = calloc(M, 4)
    let cnt: ptr<i32> = calloc(M, 4)
    let touched: ptr<i32> = calloc(M, 4)
    if C == null || mark == null || cnt == null || touched == null { return 0 }
    let mut mi: i64 = 0
    let mut x: i64 = 1
    while x <= n {
        while mi < Llen && L[mi] <= x {
            mi = mi + 1
        }
        let cx_prev: i64 = C[x - 1] as i64
        let mut tlen: i64 = 0
        let mut j: i64 = 0
        while j < mi {
            let v: i64 = cx_prev ^ (C[x - L[j]] as i64)
            if (mark[v] as i64) != x {
                mark[v] = x as i32
                cnt[v] = 1
                touched[tlen] = v as i32
                tlen = tlen + 1
            } else {
                cnt[v] = cnt[v] + 1
            }
            j = j + 1
        }
        let mut t: i64 = 0
        while (mark[t] as i64) == x {
            t = t + 1
        }
        let cx: i64 = cx_prev ^ t
        C[x] = cx as i32
        let mut i2: i64 = 0
        while i2 < tlen {
            let v2: i64 = touched[i2] as i64
            freq[v2 ^ t] = freq[v2 ^ t] + (cnt[v2] as i64)
            i2 = i2 + 1
        }
        x = x + 1
    }
    let cn: i64 = C[n] as i64
    free(touched)
    free(cnt)
    free(mark)
    free(C)
    return cn
}

function main() -> i32 {
    G_mk1 = calloc(MEMO_CAP, 8)
    G_mk2 = calloc(MEMO_CAP, 8)
    G_mv = calloc(MEMO_CAP, 8)
    G_mu = calloc(MEMO_CAP, 1)
    let squares: ptr<i64> = calloc(1024, 8)
    let tris: ptr<i64> = calloc(2048, 8)
    let freq_sq: ptr<i64> = calloc(M, 8)
    let freq_tr: ptr<i64> = calloc(M, 8)
    if G_mk1 == null || G_mk2 == null || G_mv == null || G_mu == null { return 1 }
    if squares == null || tris == null || freq_sq == null || freq_tr == null { return 1 }

    let mut ns: i64 = 0
    let mut k: i64 = 1
    while k * k <= N {
        squares[ns] = k * k
        ns = ns + 1
        k = k + 1
    }
    let mut nt: i64 = 0
    k = 1
    while true {
        let t: i64 = k * (k + 1) / 2
        if t > N { break }
        tris[nt] = t
        nt = nt + 1
        k = k + 1
    }

    let Csq: i64 = compute_1d(N, squares, ns, freq_sq)
    let Ctr: i64 = compute_1d(N, tris, nt, freq_tr)
    let board: i64 = nim_mul(Csq, Ctr)

    let mut sum_sq: i64 = 0
    let mut sum_tr: i64 = 0
    let mut a: i64 = 0
    while a < M {
        sum_sq = sum_sq + freq_sq[a]
        sum_tr = sum_tr + freq_tr[a]
        a = a + 1
    }

    let mut total: i64 = 0
    if board == 0 {
        let a0: i64 = freq_sq[0]
        let b0: i64 = freq_tr[0]
        total = a0 * sum_tr + (sum_sq - a0) * b0
    } else {
        a = 1
        while a < M {
            let fa: i64 = freq_sq[a]
            if fa != 0 {
                let inva: i64 = nim_inv(a)
                let b: i64 = nim_mul(board, inva)
                if b < M {
                    total = total + fa * freq_tr[b]
                }
            }
            a = a + 1
        }
    }

    printf("%lld\n", total)
    free(freq_tr)
    free(freq_sq)
    free(tris)
    free(squares)
    free(G_mu)
    free(G_mv)
    free(G_mk2)
    free(G_mk1)
    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 memo_get_i64_i64(int64_t a, int64_t b);
void memo_put_i64_i64_i64(int64_t a, int64_t b, int64_t v);
int64_t fermat_i64(int64_t i);
int64_t fermat_index_i64(int64_t x);
int64_t nim_mul_i64_i64(int64_t a0, int64_t b0);
int64_t nim_pow_i64_i64(int64_t a0, int64_t e0);
int64_t nim_inv_i64(int64_t a);
int64_t compute_1d_i64_ptr_i64_i64_ptr_i64(int64_t n, int64_t* L, int64_t Llen, int64_t* freq);
int32_t main(void);

static const int64_t N = 1000000;
static const int64_t M = 1024;
static const int64_t MEMO_CAP = 2097152;

/* Module statics */
static int64_t* G_mk1 = NULL;
static int64_t* G_mk2 = NULL;
static int64_t* G_mv = NULL;
static int8_t* G_mu = NULL;



int64_t memo_get_i64_i64(int64_t a, int64_t b) {
    int64_t h = FLOW_CHECKED_MOD((((a * 1315423911) + b)), (MEMO_CAP));
    if (h < 0) {
        h = (h + MEMO_CAP);
    }
    while (G_mu[h] != 0) {
        if ((G_mk1[h] == a && G_mk2[h] == b)) {
            return G_mv[h];
        }
        h = (h + 1);
        if (h == MEMO_CAP) {
            h = 0;
        }
    }
    return (-1);
}

void memo_put_i64_i64_i64(int64_t a, int64_t b, int64_t v) {
    int64_t h = FLOW_CHECKED_MOD((((a * 1315423911) + b)), (MEMO_CAP));
    if (h < 0) {
        h = (h + MEMO_CAP);
    }
    while (G_mu[h] != 0) {
        if ((G_mk1[h] == a && G_mk2[h] == b)) {
            G_mv[h] = v;
            return;
        }
        h = (h + 1);
        if (h == MEMO_CAP) {
            h = 0;
        }
    }
    G_mu[h] = 1;
    G_mk1[h] = a;
    G_mk2[h] = b;
    G_mv[h] = v;
}

int64_t fermat_i64(int64_t i) {
    return FLOW_CHECKED_SHL((1), (FLOW_CHECKED_SHL((1), (i))));
}

int64_t fermat_index_i64(int64_t x) {
    int64_t i = 0;
    while (((i + 1) < 7 && fermat_i64((i + 1)) <= x)) {
        i = (i + 1);
    }
    return i;
}

int64_t nim_mul_i64_i64(int64_t a0, int64_t b0) {
    int64_t a = a0;
    int64_t b = b0;
    if ((a == 0 || b == 0)) {
        return 0;
    }
    if (a == 1) {
        return b;
    }
    if (b == 1) {
        return a;
    }
    if (a < b) {
        int64_t t = a;
        a = b;
        b = t;
    }
    int64_t cached = memo_get_i64_i64(a, b);
    if (cached >= 0) {
        return cached;
    }
    int64_t m = fermat_index_i64(a);
    int64_t n = fermat_index_i64(b);
    int64_t r = 0;
    if (m != n) {
        if (m > n) {
            int64_t Fm = fermat_i64(m);
            int64_t shift = FLOW_CHECKED_SHL((1), (m));
            int64_t a1 = FLOW_CHECKED_DIV((a), (Fm));
            int64_t a2 = FLOW_CHECKED_MOD((a), (Fm));
            r = (FLOW_CHECKED_SHL((nim_mul_i64_i64(a1, b)), (shift)) ^ nim_mul_i64_i64(a2, b));
        } else {
            int64_t Fn = fermat_i64(n);
            int64_t shift = FLOW_CHECKED_SHL((1), (n));
            int64_t b1 = FLOW_CHECKED_DIV((b), (Fn));
            int64_t b2 = FLOW_CHECKED_MOD((b), (Fn));
            r = (FLOW_CHECKED_SHL((nim_mul_i64_i64(a, b1)), (shift)) ^ nim_mul_i64_i64(a, b2));
        }
    } else {
        int64_t Fn = fermat_i64(n);
        int64_t shift = FLOW_CHECKED_SHL((1), (n));
        int64_t a1 = FLOW_CHECKED_DIV((a), (Fn));
        int64_t a2 = FLOW_CHECKED_MOD((a), (Fn));
        int64_t b1 = FLOW_CHECKED_DIV((b), (Fn));
        int64_t b2 = FLOW_CHECKED_MOD((b), (Fn));
        int64_t p1 = nim_mul_i64_i64(a1, b1);
        int64_t p2 = nim_mul_i64_i64(a2, b2);
        int64_t p3 = nim_mul_i64_i64((a1 ^ a2), (b1 ^ b2));
        int64_t p4 = nim_mul_i64_i64(p1, FLOW_CHECKED_DIV((Fn), (2)));
        int64_t p5 = (p3 ^ p2);
        r = ((FLOW_CHECKED_SHL((p5), (shift)) ^ p2) ^ p4);
    }
    memo_put_i64_i64_i64(a, b, r);
    return r;
}

int64_t nim_pow_i64_i64(int64_t a0, int64_t e0) {
    int64_t res = 1;
    int64_t base = a0;
    int64_t e = e0;
    while (e > 0) {
        if ((e & 1) == 1) {
            res = nim_mul_i64_i64(res, base);
        }
        e = FLOW_CHECKED_DIV((e), (2));
        if (e > 0) {
            base = nim_mul_i64_i64(base, base);
        }
    }
    return res;
}

int64_t nim_inv_i64(int64_t a) {
    return nim_pow_i64_i64(a, 65534);
}

int64_t compute_1d_i64_ptr_i64_i64_ptr_i64(int64_t n, int64_t* L, int64_t Llen, int64_t* freq) {
    int32_t* C = (int32_t*)(calloc((n + 1), 4));
    int32_t* mark = (int32_t*)(calloc(M, 4));
    int32_t* cnt = (int32_t*)(calloc(M, 4));
    int32_t* touched = (int32_t*)(calloc(M, 4));
    if ((((C == NULL || mark == NULL) || cnt == NULL) || touched == NULL)) {
        return 0;
    }
    int64_t mi = 0;
    int64_t x = 1;
    while (x <= n) {
        while ((mi < Llen && L[mi] <= x)) {
            mi = (mi + 1);
        }
        int64_t cx_prev = ((int64_t)(C[(x - 1)]));
        int64_t tlen = 0;
        int64_t j = 0;
        while (j < mi) {
            int64_t v = (cx_prev ^ ((int64_t)(C[(x - L[j])])));
            if (((int64_t)(mark[v])) != x) {
                mark[v] = ((int32_t)(x));
                cnt[v] = 1;
                touched[tlen] = ((int32_t)(v));
                tlen = (tlen + 1);
            } else {
                cnt[v] = (cnt[v] + 1);
            }
            j = (j + 1);
        }
        int64_t t = 0;
        while (((int64_t)(mark[t])) == x) {
            t = (t + 1);
        }
        int64_t cx = (cx_prev ^ t);
        C[x] = ((int32_t)(cx));
        int64_t i2 = 0;
        while (i2 < tlen) {
            int64_t v2 = ((int64_t)(touched[i2]));
            freq[(v2 ^ t)] = (freq[(v2 ^ t)] + ((int64_t)(cnt[v2])));
            i2 = (i2 + 1);
        }
        x = (x + 1);
    }
    int64_t cn = ((int64_t)(C[n]));
    free(touched);
    free(cnt);
    free(mark);
    free(C);
    return cn;
}

int32_t main(void) {
    G_mk1 = calloc(MEMO_CAP, 8);
    G_mk2 = calloc(MEMO_CAP, 8);
    G_mv = calloc(MEMO_CAP, 8);
    G_mu = calloc(MEMO_CAP, 1);
    int64_t* squares = (int64_t*)(calloc(1024, 8));
    int64_t* tris = (int64_t*)(calloc(2048, 8));
    int64_t* freq_sq = (int64_t*)(calloc(M, 8));
    int64_t* freq_tr = (int64_t*)(calloc(M, 8));
    if ((((G_mk1 == NULL || G_mk2 == NULL) || G_mv == NULL) || G_mu == NULL)) {
        return 1;
    }
    if ((((squares == NULL || tris == NULL) || freq_sq == NULL) || freq_tr == NULL)) {
        return 1;
    }
    int64_t ns = 0;
    int64_t k = 1;
    while ((k * k) <= N) {
        squares[ns] = (k * k);
        ns = (ns + 1);
        k = (k + 1);
    }
    int64_t nt = 0;
    k = 1;
    while (1) {
        int64_t t = FLOW_CHECKED_DIV(((k * (k + 1))), (2));
        if (t > N) {
            break;
        }
        tris[nt] = t;
        nt = (nt + 1);
        k = (k + 1);
    }
    int64_t Csq = compute_1d_i64_ptr_i64_i64_ptr_i64(N, squares, ns, freq_sq);
    int64_t Ctr = compute_1d_i64_ptr_i64_i64_ptr_i64(N, tris, nt, freq_tr);
    int64_t board = nim_mul_i64_i64(Csq, Ctr);
    int64_t sum_sq = 0;
    int64_t sum_tr = 0;
    int64_t a = 0;
    while (a < M) {
        sum_sq = (sum_sq + freq_sq[a]);
        sum_tr = (sum_tr + freq_tr[a]);
        a = (a + 1);
    }
    int64_t total = 0;
    if (board == 0) {
        int64_t a0 = freq_sq[0];
        int64_t b0 = freq_tr[0];
        total = ((a0 * sum_tr) + ((sum_sq - a0) * b0));
    } else {
        a = 1;
        while (a < M) {
            int64_t fa = freq_sq[a];
            if (fa != 0) {
                int64_t inva = nim_inv_i64(a);
                int64_t b = nim_mul_i64_i64(board, inva);
                if (b < M) {
                    total = (total + (fa * freq_tr[b]));
                }
            }
            a = (a + 1);
        }
    }
    printf("%lld\n", total);
    free(freq_tr);
    free(freq_sq);
    free(tris);
    free(squares);
    free(G_mu);
    free(G_mv);
    free(G_mk2);
    free(G_mk1);
    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: N
  llvm.mlir.global internal constant @N(1000000 : i64) : i64
  // Constant: M
  llvm.mlir.global internal constant @M(1024 : i64) : i64
  // Constant: MEMO_CAP
  llvm.mlir.global internal constant @MEMO_CAP(2097152 : i64) : i64
  // Module static: G_mk1
  llvm.mlir.global internal @G_mk1() {addr_space = 0 : i32} : !llvm.ptr {
    %0 = llvm.mlir.zero : !llvm.ptr
    llvm.return %0 : !llvm.ptr
  }
  // Module static: G_mk2
  llvm.mlir.global internal @G_mk2() {addr_space = 0 : i32} : !llvm.ptr {
    %1 = llvm.mlir.zero : !llvm.ptr
    llvm.return %1 : !llvm.ptr
  }
  // Module static: G_mv
  llvm.mlir.global internal @G_mv() {addr_space = 0 : i32} : !llvm.ptr {
    %2 = llvm.mlir.zero : !llvm.ptr
    llvm.return %2 : !llvm.ptr
  }
  // Module static: G_mu
  llvm.mlir.global internal @G_mu() {addr_space = 0 : i32} : !llvm.ptr {
    %3 = llvm.mlir.zero : !llvm.ptr
    llvm.return %3 : !llvm.ptr
  }
  func.func @memo_get(%arg0: i64, %arg1: i64) -> i64 {
    %4 = arith.constant 1315423911 : i32
    %6 = arith.extsi %4 : i32 to i64
    %5 = arith.muli %arg0, %6 : i64
    %7 = arith.addi %5, %arg1 : i64
    %8 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %9 = llvm.load %8 : !llvm.ptr -> i64
    %10 = arith.remsi %7, %9 : i64
    %11 = llvm.mlir.constant(1 : i64) : i64
    %12 = llvm.alloca %11 x i64 : (i64) -> !llvm.ptr
    llvm.store %10, %12 : i64, !llvm.ptr
    %13 = llvm.load %12 : !llvm.ptr -> i64
    %14 = arith.constant 0 : i32
    %16 = arith.extsi %14 : i32 to i64
    %15 = arith.cmpi slt, %13, %16 : i64
    cf.cond_br %15, ^bb0, ^bb1
    ^bb0:
      %17 = llvm.load %12 : !llvm.ptr -> i64
      %18 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
      %19 = llvm.load %18 : !llvm.ptr -> i64
      %20 = arith.addi %17, %19 : i64
      llvm.store %20, %12 : i64, !llvm.ptr
      cf.br ^bb2
    ^bb1:
      cf.br ^bb2
    ^bb2:
    cf.br ^bb3
    ^bb3:
    %22 = llvm.mlir.addressof @G_mu : !llvm.ptr
    %23 = llvm.load %22 : !llvm.ptr -> !llvm.ptr
    %24 = llvm.load %12 : !llvm.ptr -> i64
    %25 = llvm.getelementptr %23[%24] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    %21 = llvm.load %25 : !llvm.ptr -> i8
    %26 = arith.constant 0 : i32
    %28 = arith.extsi %21 : i8 to i32
    %27 = arith.cmpi ne, %28, %26 : i32
    cf.cond_br %27, ^bb4, ^bb5
    ^bb4:
      %30 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
      %31 = llvm.load %30 : !llvm.ptr -> !llvm.ptr
      %32 = llvm.load %12 : !llvm.ptr -> i64
      %33 = llvm.getelementptr %31[%32] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %29 = llvm.load %33 : !llvm.ptr -> i64
      %34 = arith.cmpi eq, %29, %arg0 : i64
      %35 = scf.if %34 -> (i1) {
        %37 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
        %38 = llvm.load %37 : !llvm.ptr -> !llvm.ptr
        %39 = llvm.load %12 : !llvm.ptr -> i64
        %40 = llvm.getelementptr %38[%39] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %36 = llvm.load %40 : !llvm.ptr -> i64
        %41 = arith.cmpi eq, %36, %arg1 : i64
        scf.yield %41 : i1
      } else {
        %42 = arith.constant false
        scf.yield %42 : i1
      }
      cf.cond_br %35, ^bb6, ^bb7
      ^bb6:
        %44 = llvm.mlir.addressof @G_mv : !llvm.ptr
        %45 = llvm.load %44 : !llvm.ptr -> !llvm.ptr
        %46 = llvm.load %12 : !llvm.ptr -> i64
        %47 = llvm.getelementptr %45[%46] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %43 = llvm.load %47 : !llvm.ptr -> i64
        func.return %43 : i64
      ^bb7:
        cf.br ^bb8
      ^bb8:
      %48 = llvm.load %12 : !llvm.ptr -> i64
      %49 = arith.constant 1 : i32
      %51 = arith.extsi %49 : i32 to i64
      %50 = arith.addi %48, %51 : i64
      llvm.store %50, %12 : i64, !llvm.ptr
      %52 = llvm.load %12 : !llvm.ptr -> i64
      %53 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
      %54 = llvm.load %53 : !llvm.ptr -> i64
      %55 = arith.cmpi eq, %52, %54 : i64
      cf.cond_br %55, ^bb9, ^bb10
      ^bb9:
        %56 = arith.constant 0 : i32
        %57 = arith.extsi %56 : i32 to i64
        llvm.store %57, %12 : i64, !llvm.ptr
        cf.br ^bb11
      ^bb10:
        cf.br ^bb11
      ^bb11:
      cf.br ^bb3
    ^bb5:
    %58 = arith.constant 1 : i32
    %60 = arith.constant 0 : i32
    %59 = arith.subi %60, %58 : i32
    %61 = arith.extsi %59 : i32 to i64
    func.return %61 : i64
  }
  func.func @memo_put(%arg0: i64, %arg1: i64, %arg2: i64) -> () {
    %62 = arith.constant 1315423911 : i32
    %64 = arith.extsi %62 : i32 to i64
    %63 = arith.muli %arg0, %64 : i64
    %65 = arith.addi %63, %arg1 : i64
    %66 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %67 = llvm.load %66 : !llvm.ptr -> i64
    %68 = arith.remsi %65, %67 : i64
    %69 = llvm.mlir.constant(1 : i64) : i64
    %70 = llvm.alloca %69 x i64 : (i64) -> !llvm.ptr
    llvm.store %68, %70 : i64, !llvm.ptr
    %71 = llvm.load %70 : !llvm.ptr -> i64
    %72 = arith.constant 0 : i32
    %74 = arith.extsi %72 : i32 to i64
    %73 = arith.cmpi slt, %71, %74 : i64
    cf.cond_br %73, ^bb12, ^bb13
    ^bb12:
      %75 = llvm.load %70 : !llvm.ptr -> i64
      %76 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
      %77 = llvm.load %76 : !llvm.ptr -> i64
      %78 = arith.addi %75, %77 : i64
      llvm.store %78, %70 : i64, !llvm.ptr
      cf.br ^bb14
    ^bb13:
      cf.br ^bb14
    ^bb14:
    cf.br ^bb15
    ^bb15:
    %80 = llvm.mlir.addressof @G_mu : !llvm.ptr
    %81 = llvm.load %80 : !llvm.ptr -> !llvm.ptr
    %82 = llvm.load %70 : !llvm.ptr -> i64
    %83 = llvm.getelementptr %81[%82] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    %79 = llvm.load %83 : !llvm.ptr -> i8
    %84 = arith.constant 0 : i32
    %86 = arith.extsi %79 : i8 to i32
    %85 = arith.cmpi ne, %86, %84 : i32
    cf.cond_br %85, ^bb16, ^bb17
    ^bb16:
      %88 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
      %89 = llvm.load %88 : !llvm.ptr -> !llvm.ptr
      %90 = llvm.load %70 : !llvm.ptr -> i64
      %91 = llvm.getelementptr %89[%90] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %87 = llvm.load %91 : !llvm.ptr -> i64
      %92 = arith.cmpi eq, %87, %arg0 : i64
      %93 = scf.if %92 -> (i1) {
        %95 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
        %96 = llvm.load %95 : !llvm.ptr -> !llvm.ptr
        %97 = llvm.load %70 : !llvm.ptr -> i64
        %98 = llvm.getelementptr %96[%97] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %94 = llvm.load %98 : !llvm.ptr -> i64
        %99 = arith.cmpi eq, %94, %arg1 : i64
        scf.yield %99 : i1
      } else {
        %100 = arith.constant false
        scf.yield %100 : i1
      }
      cf.cond_br %93, ^bb18, ^bb19
      ^bb18:
        %101 = llvm.mlir.addressof @G_mv : !llvm.ptr
        %102 = llvm.load %101 : !llvm.ptr -> !llvm.ptr
        %103 = llvm.load %70 : !llvm.ptr -> i64
        %104 = llvm.getelementptr %102[%103] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %arg2, %104 : i64, !llvm.ptr
        func.return
      ^bb19:
        cf.br ^bb20
      ^bb20:
      %105 = llvm.load %70 : !llvm.ptr -> i64
      %106 = arith.constant 1 : i32
      %108 = arith.extsi %106 : i32 to i64
      %107 = arith.addi %105, %108 : i64
      llvm.store %107, %70 : i64, !llvm.ptr
      %109 = llvm.load %70 : !llvm.ptr -> i64
      %110 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
      %111 = llvm.load %110 : !llvm.ptr -> i64
      %112 = arith.cmpi eq, %109, %111 : i64
      cf.cond_br %112, ^bb21, ^bb22
      ^bb21:
        %113 = arith.constant 0 : i32
        %114 = arith.extsi %113 : i32 to i64
        llvm.store %114, %70 : i64, !llvm.ptr
        cf.br ^bb23
      ^bb22:
        cf.br ^bb23
      ^bb23:
      cf.br ^bb15
    ^bb17:
    %115 = arith.constant 1 : i32
    %116 = llvm.mlir.addressof @G_mu : !llvm.ptr
    %117 = llvm.load %116 : !llvm.ptr -> !llvm.ptr
    %118 = llvm.load %70 : !llvm.ptr -> i64
    %119 = arith.trunci %115 : i32 to i8
    %120 = llvm.getelementptr %117[%118] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    llvm.store %119, %120 : i8, !llvm.ptr
    %121 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
    %122 = llvm.load %121 : !llvm.ptr -> !llvm.ptr
    %123 = llvm.load %70 : !llvm.ptr -> i64
    %124 = llvm.getelementptr %122[%123] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg0, %124 : i64, !llvm.ptr
    %125 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
    %126 = llvm.load %125 : !llvm.ptr -> !llvm.ptr
    %127 = llvm.load %70 : !llvm.ptr -> i64
    %128 = llvm.getelementptr %126[%127] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg1, %128 : i64, !llvm.ptr
    %129 = llvm.mlir.addressof @G_mv : !llvm.ptr
    %130 = llvm.load %129 : !llvm.ptr -> !llvm.ptr
    %131 = llvm.load %70 : !llvm.ptr -> i64
    %132 = llvm.getelementptr %130[%131] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg2, %132 : i64, !llvm.ptr
    func.return
  }
  func.func @fermat(%arg0: i64) -> i64 {
    %133 = arith.constant 1 : i32
    %134 = arith.constant 1 : i32
    %136 = arith.extsi %134 : i32 to i64
    %135 = arith.shli %136, %arg0 : i64
    %138 = arith.extsi %133 : i32 to i64
    %137 = arith.shli %138, %135 : i64
    func.return %137 : i64
  }
  func.func @fermat_index(%arg0: i64) -> i64 {
    %139 = arith.constant 0 : i32
    %140 = arith.extsi %139 : i32 to i64
    %141 = llvm.mlir.constant(1 : i64) : i64
    %142 = llvm.alloca %141 x i64 : (i64) -> !llvm.ptr
    llvm.store %140, %142 : i64, !llvm.ptr
    cf.br ^bb24
    ^bb24:
    %143 = llvm.load %142 : !llvm.ptr -> i64
    %144 = arith.constant 1 : i32
    %146 = arith.extsi %144 : i32 to i64
    %145 = arith.addi %143, %146 : i64
    %147 = arith.constant 7 : i32
    %149 = arith.extsi %147 : i32 to i64
    %148 = arith.cmpi slt, %145, %149 : i64
    %150 = scf.if %148 -> (i1) {
      %152 = llvm.load %142 : !llvm.ptr -> i64
      %153 = arith.constant 1 : i32
      %155 = arith.extsi %153 : i32 to i64
      %154 = arith.addi %152, %155 : i64
      %151 = func.call @fermat(%154) : (i64) -> i64
      %156 = arith.cmpi sle, %151, %arg0 : i64
      scf.yield %156 : i1
    } else {
      %157 = arith.constant false
      scf.yield %157 : i1
    }
    cf.cond_br %150, ^bb25, ^bb26
    ^bb25:
      %158 = llvm.load %142 : !llvm.ptr -> i64
      %159 = arith.constant 1 : i32
      %161 = arith.extsi %159 : i32 to i64
      %160 = arith.addi %158, %161 : i64
      llvm.store %160, %142 : i64, !llvm.ptr
      cf.br ^bb24
    ^bb26:
    %162 = llvm.load %142 : !llvm.ptr -> i64
    func.return %162 : i64
  }
  func.func @nim_mul(%arg0: i64, %arg1: i64) -> i64 {
    %163 = llvm.mlir.constant(1 : i64) : i64
    %164 = llvm.alloca %163 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg0, %164 : i64, !llvm.ptr
    %165 = llvm.mlir.constant(1 : i64) : i64
    %166 = llvm.alloca %165 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %166 : i64, !llvm.ptr
    %167 = llvm.load %164 : !llvm.ptr -> i64
    %168 = arith.constant 0 : i32
    %170 = arith.extsi %168 : i32 to i64
    %169 = arith.cmpi eq, %167, %170 : i64
    %171 = scf.if %169 -> (i1) {
      %172 = arith.constant true
      scf.yield %172 : i1
    } else {
      %173 = llvm.load %166 : !llvm.ptr -> i64
      %174 = arith.constant 0 : i32
      %176 = arith.extsi %174 : i32 to i64
      %175 = arith.cmpi eq, %173, %176 : i64
      scf.yield %175 : i1
    }
    cf.cond_br %171, ^bb27, ^bb28
    ^bb27:
      %177 = arith.constant 0 : i32
      %178 = arith.extsi %177 : i32 to i64
      func.return %178 : i64
    ^bb28:
      cf.br ^bb29
    ^bb29:
    %179 = llvm.load %164 : !llvm.ptr -> i64
    %180 = arith.constant 1 : i32
    %182 = arith.extsi %180 : i32 to i64
    %181 = arith.cmpi eq, %179, %182 : i64
    cf.cond_br %181, ^bb30, ^bb31
    ^bb30:
      %183 = llvm.load %166 : !llvm.ptr -> i64
      func.return %183 : i64
    ^bb31:
      cf.br ^bb32
    ^bb32:
    %184 = llvm.load %166 : !llvm.ptr -> i64
    %185 = arith.constant 1 : i32
    %187 = arith.extsi %185 : i32 to i64
    %186 = arith.cmpi eq, %184, %187 : i64
    cf.cond_br %186, ^bb33, ^bb34
    ^bb33:
      %188 = llvm.load %164 : !llvm.ptr -> i64
      func.return %188 : i64
    ^bb34:
      cf.br ^bb35
    ^bb35:
    %189 = llvm.load %164 : !llvm.ptr -> i64
    %190 = llvm.load %166 : !llvm.ptr -> i64
    %191 = arith.cmpi slt, %189, %190 : i64
    cf.cond_br %191, ^bb36, ^bb37
    ^bb36:
      %192 = llvm.load %164 : !llvm.ptr -> i64
      %193 = llvm.load %166 : !llvm.ptr -> i64
      llvm.store %193, %164 : i64, !llvm.ptr
      llvm.store %192, %166 : i64, !llvm.ptr
      cf.br ^bb38
    ^bb37:
      cf.br ^bb38
    ^bb38:
    %195 = llvm.load %164 : !llvm.ptr -> i64
    %196 = llvm.load %166 : !llvm.ptr -> i64
    %194 = func.call @memo_get(%195, %196) : (i64, i64) -> i64
    %197 = arith.constant 0 : i32
    %199 = arith.extsi %197 : i32 to i64
    %198 = arith.cmpi sge, %194, %199 : i64
    cf.cond_br %198, ^bb39, ^bb40
    ^bb39:
      func.return %194 : i64
    ^bb40:
      cf.br ^bb41
    ^bb41:
    %201 = llvm.load %164 : !llvm.ptr -> i64
    %200 = func.call @fermat_index(%201) : (i64) -> i64
    %203 = llvm.load %166 : !llvm.ptr -> i64
    %202 = func.call @fermat_index(%203) : (i64) -> i64
    %204 = arith.constant 0 : i32
    %205 = arith.extsi %204 : i32 to i64
    %206 = llvm.mlir.constant(1 : i64) : i64
    %207 = llvm.alloca %206 x i64 : (i64) -> !llvm.ptr
    llvm.store %205, %207 : i64, !llvm.ptr
    %208 = arith.cmpi ne, %200, %202 : i64
    cf.cond_br %208, ^bb42, ^bb43
    ^bb42:
      %209 = arith.cmpi sgt, %200, %202 : i64
      cf.cond_br %209, ^bb45, ^bb46
      ^bb45:
        %210 = func.call @fermat(%200) : (i64) -> i64
        %211 = arith.constant 1 : i32
        %213 = arith.extsi %211 : i32 to i64
        %212 = arith.shli %213, %200 : i64
        %214 = llvm.load %164 : !llvm.ptr -> i64
        %215 = arith.divsi %214, %210 : i64
        %216 = llvm.load %164 : !llvm.ptr -> i64
        %217 = arith.remsi %216, %210 : i64
        %219 = llvm.load %166 : !llvm.ptr -> i64
        %218 = func.call @nim_mul(%215, %219) : (i64, i64) -> i64
        %220 = arith.shli %218, %212 : i64
        %222 = llvm.load %166 : !llvm.ptr -> i64
        %221 = func.call @nim_mul(%217, %222) : (i64, i64) -> i64
        %223 = arith.xori %220, %221 : i64
        llvm.store %223, %207 : i64, !llvm.ptr
        cf.br ^bb47
      ^bb46:
        %224 = func.call @fermat(%202) : (i64) -> i64
        %225 = arith.constant 1 : i32
        %227 = arith.extsi %225 : i32 to i64
        %226 = arith.shli %227, %202 : i64
        %228 = llvm.load %166 : !llvm.ptr -> i64
        %229 = arith.divsi %228, %224 : i64
        %230 = llvm.load %166 : !llvm.ptr -> i64
        %231 = arith.remsi %230, %224 : i64
        %233 = llvm.load %164 : !llvm.ptr -> i64
        %232 = func.call @nim_mul(%233, %229) : (i64, i64) -> i64
        %234 = arith.shli %232, %226 : i64
        %236 = llvm.load %164 : !llvm.ptr -> i64
        %235 = func.call @nim_mul(%236, %231) : (i64, i64) -> i64
        %237 = arith.xori %234, %235 : i64
        llvm.store %237, %207 : i64, !llvm.ptr
        cf.br ^bb47
      ^bb47:
      cf.br ^bb44
    ^bb43:
      %238 = func.call @fermat(%202) : (i64) -> i64
      %239 = arith.constant 1 : i32
      %241 = arith.extsi %239 : i32 to i64
      %240 = arith.shli %241, %202 : i64
      %242 = llvm.load %164 : !llvm.ptr -> i64
      %243 = arith.divsi %242, %238 : i64
      %244 = llvm.load %164 : !llvm.ptr -> i64
      %245 = arith.remsi %244, %238 : i64
      %246 = llvm.load %166 : !llvm.ptr -> i64
      %247 = arith.divsi %246, %238 : i64
      %248 = llvm.load %166 : !llvm.ptr -> i64
      %249 = arith.remsi %248, %238 : i64
      %250 = func.call @nim_mul(%243, %247) : (i64, i64) -> i64
      %251 = func.call @nim_mul(%245, %249) : (i64, i64) -> i64
      %253 = arith.xori %243, %245 : i64
      %254 = arith.xori %247, %249 : i64
      %252 = func.call @nim_mul(%253, %254) : (i64, i64) -> i64
      %256 = arith.constant 2 : i32
      %258 = arith.extsi %256 : i32 to i64
      %257 = arith.divsi %238, %258 : i64
      %255 = func.call @nim_mul(%250, %257) : (i64, i64) -> i64
      %259 = arith.xori %252, %251 : i64
      %260 = arith.shli %259, %240 : i64
      %261 = arith.xori %260, %251 : i64
      %262 = arith.xori %261, %255 : i64
      llvm.store %262, %207 : i64, !llvm.ptr
      cf.br ^bb44
    ^bb44:
    %264 = llvm.load %164 : !llvm.ptr -> i64
    %265 = llvm.load %166 : !llvm.ptr -> i64
    %266 = llvm.load %207 : !llvm.ptr -> i64
    func.call @memo_put(%264, %265, %266) : (i64, i64, i64) -> ()
    %267 = llvm.load %207 : !llvm.ptr -> i64
    func.return %267 : i64
  }
  func.func @nim_pow(%arg0: i64, %arg1: i64) -> i64 {
    %268 = arith.constant 1 : i32
    %269 = arith.extsi %268 : i32 to i64
    %270 = llvm.mlir.constant(1 : i64) : i64
    %271 = llvm.alloca %270 x i64 : (i64) -> !llvm.ptr
    llvm.store %269, %271 : i64, !llvm.ptr
    %272 = llvm.mlir.constant(1 : i64) : i64
    %273 = llvm.alloca %272 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg0, %273 : i64, !llvm.ptr
    %274 = llvm.mlir.constant(1 : i64) : i64
    %275 = llvm.alloca %274 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %275 : i64, !llvm.ptr
    cf.br ^bb48
    ^bb48:
    %276 = llvm.load %275 : !llvm.ptr -> i64
    %277 = arith.constant 0 : i32
    %279 = arith.extsi %277 : i32 to i64
    %278 = arith.cmpi sgt, %276, %279 : i64
    cf.cond_br %278, ^bb49, ^bb50
    ^bb49:
      %280 = llvm.load %275 : !llvm.ptr -> i64
      %281 = arith.constant 1 : i32
      %283 = arith.extsi %281 : i32 to i64
      %282 = arith.andi %280, %283 : i64
      %284 = arith.constant 1 : i32
      %286 = arith.extsi %284 : i32 to i64
      %285 = arith.cmpi eq, %282, %286 : i64
      cf.cond_br %285, ^bb51, ^bb52
      ^bb51:
        %288 = llvm.load %271 : !llvm.ptr -> i64
        %289 = llvm.load %273 : !llvm.ptr -> i64
        %287 = func.call @nim_mul(%288, %289) : (i64, i64) -> i64
        llvm.store %287, %271 : i64, !llvm.ptr
        cf.br ^bb53
      ^bb52:
        cf.br ^bb53
      ^bb53:
      %290 = llvm.load %275 : !llvm.ptr -> i64
      %291 = arith.constant 2 : i32
      %293 = arith.extsi %291 : i32 to i64
      %292 = arith.divsi %290, %293 : i64
      llvm.store %292, %275 : i64, !llvm.ptr
      %294 = llvm.load %275 : !llvm.ptr -> i64
      %295 = arith.constant 0 : i32
      %297 = arith.extsi %295 : i32 to i64
      %296 = arith.cmpi sgt, %294, %297 : i64
      cf.cond_br %296, ^bb54, ^bb55
      ^bb54:
        %299 = llvm.load %273 : !llvm.ptr -> i64
        %300 = llvm.load %273 : !llvm.ptr -> i64
        %298 = func.call @nim_mul(%299, %300) : (i64, i64) -> i64
        llvm.store %298, %273 : i64, !llvm.ptr
        cf.br ^bb56
      ^bb55:
        cf.br ^bb56
      ^bb56:
      cf.br ^bb48
    ^bb50:
    %301 = llvm.load %271 : !llvm.ptr -> i64
    func.return %301 : i64
  }
  func.func @nim_inv(%arg0: i64) -> i64 {
    %303 = arith.constant 65534 : i32
    %304 = arith.extsi %303 : i32 to i64
    %302 = func.call @nim_pow(%arg0, %304) : (i64, i64) -> i64
    func.return %302 : i64
  }
  func.func @compute_1d(%arg0: i64, %arg1: !llvm.ptr, %arg2: i64, %arg3: !llvm.ptr) -> i64 {
    %306 = arith.constant 1 : i32
    %308 = arith.extsi %306 : i32 to i64
    %307 = arith.addi %arg0, %308 : i64
    %309 = arith.constant 4 : i32
    %310 = arith.extsi %309 : i32 to i64
    %305 = func.call @calloc(%307, %310) : (i64, i64) -> !llvm.ptr
    %312 = llvm.mlir.addressof @M : !llvm.ptr
    %313 = llvm.load %312 : !llvm.ptr -> i64
    %314 = arith.constant 4 : i32
    %315 = arith.extsi %314 : i32 to i64
    %311 = func.call @calloc(%313, %315) : (i64, i64) -> !llvm.ptr
    %317 = llvm.mlir.addressof @M : !llvm.ptr
    %318 = llvm.load %317 : !llvm.ptr -> i64
    %319 = arith.constant 4 : i32
    %320 = arith.extsi %319 : i32 to i64
    %316 = func.call @calloc(%318, %320) : (i64, i64) -> !llvm.ptr
    %322 = llvm.mlir.addressof @M : !llvm.ptr
    %323 = llvm.load %322 : !llvm.ptr -> i64
    %324 = arith.constant 4 : i32
    %325 = arith.extsi %324 : i32 to i64
    %321 = func.call @calloc(%323, %325) : (i64, i64) -> !llvm.ptr
    %326 = llvm.mlir.zero : !llvm.ptr
    %327 = llvm.icmp "eq" %305, %326 : !llvm.ptr
    %328 = scf.if %327 -> (i1) {
      %329 = arith.constant true
      scf.yield %329 : i1
    } else {
      %330 = llvm.mlir.zero : !llvm.ptr
      %331 = llvm.icmp "eq" %311, %330 : !llvm.ptr
      scf.yield %331 : i1
    }
    %332 = scf.if %328 -> (i1) {
      %333 = arith.constant true
      scf.yield %333 : i1
    } else {
      %334 = llvm.mlir.zero : !llvm.ptr
      %335 = llvm.icmp "eq" %316, %334 : !llvm.ptr
      scf.yield %335 : i1
    }
    %336 = scf.if %332 -> (i1) {
      %337 = arith.constant true
      scf.yield %337 : i1
    } else {
      %338 = llvm.mlir.zero : !llvm.ptr
      %339 = llvm.icmp "eq" %321, %338 : !llvm.ptr
      scf.yield %339 : i1
    }
    cf.cond_br %336, ^bb57, ^bb58
    ^bb57:
      %340 = arith.constant 0 : i32
      %341 = arith.extsi %340 : i32 to i64
      func.return %341 : i64
    ^bb58:
      cf.br ^bb59
    ^bb59:
    %342 = arith.constant 0 : i32
    %343 = arith.extsi %342 : i32 to i64
    %344 = llvm.mlir.constant(1 : i64) : i64
    %345 = llvm.alloca %344 x i64 : (i64) -> !llvm.ptr
    llvm.store %343, %345 : i64, !llvm.ptr
    %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 ^bb60
    ^bb60:
    %350 = llvm.load %349 : !llvm.ptr -> i64
    %351 = arith.cmpi sle, %350, %arg0 : i64
    cf.cond_br %351, ^bb61, ^bb62
    ^bb61:
      cf.br ^bb63
      ^bb63:
      %352 = llvm.load %345 : !llvm.ptr -> i64
      %353 = arith.cmpi slt, %352, %arg2 : i64
      %354 = scf.if %353 -> (i1) {
        %356 = llvm.load %345 : !llvm.ptr -> i64
        %357 = llvm.getelementptr %arg1[%356] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %355 = llvm.load %357 : !llvm.ptr -> i64
        %358 = llvm.load %349 : !llvm.ptr -> i64
        %359 = arith.cmpi sle, %355, %358 : i64
        scf.yield %359 : i1
      } else {
        %360 = arith.constant false
        scf.yield %360 : i1
      }
      cf.cond_br %354, ^bb64, ^bb65
      ^bb64:
        %361 = llvm.load %345 : !llvm.ptr -> i64
        %362 = arith.constant 1 : i32
        %364 = arith.extsi %362 : i32 to i64
        %363 = arith.addi %361, %364 : i64
        llvm.store %363, %345 : i64, !llvm.ptr
        cf.br ^bb63
      ^bb65:
      %366 = llvm.load %349 : !llvm.ptr -> i64
      %367 = arith.constant 1 : i32
      %369 = arith.extsi %367 : i32 to i64
      %368 = arith.subi %366, %369 : i64
      %370 = llvm.getelementptr %305[%368] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %365 = llvm.load %370 : !llvm.ptr -> i32
      %371 = arith.extsi %365 : i32 to i64
      %372 = arith.constant 0 : i32
      %373 = arith.extsi %372 : i32 to i64
      %374 = llvm.mlir.constant(1 : i64) : i64
      %375 = llvm.alloca %374 x i64 : (i64) -> !llvm.ptr
      llvm.store %373, %375 : i64, !llvm.ptr
      %376 = arith.constant 0 : i32
      %377 = arith.extsi %376 : i32 to i64
      %378 = llvm.mlir.constant(1 : i64) : i64
      %379 = llvm.alloca %378 x i64 : (i64) -> !llvm.ptr
      llvm.store %377, %379 : i64, !llvm.ptr
      cf.br ^bb66
      ^bb66:
      %380 = llvm.load %379 : !llvm.ptr -> i64
      %381 = llvm.load %345 : !llvm.ptr -> i64
      %382 = arith.cmpi slt, %380, %381 : i64
      cf.cond_br %382, ^bb67, ^bb68
      ^bb67:
        %384 = llvm.load %349 : !llvm.ptr -> i64
        %386 = llvm.load %379 : !llvm.ptr -> i64
        %387 = llvm.getelementptr %arg1[%386] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %385 = llvm.load %387 : !llvm.ptr -> i64
        %388 = arith.subi %384, %385 : i64
        %389 = llvm.getelementptr %305[%388] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %383 = llvm.load %389 : !llvm.ptr -> i32
        %390 = arith.extsi %383 : i32 to i64
        %391 = arith.xori %371, %390 : i64
        %393 = llvm.getelementptr %311[%391] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %392 = llvm.load %393 : !llvm.ptr -> i32
        %394 = arith.extsi %392 : i32 to i64
        %395 = llvm.load %349 : !llvm.ptr -> i64
        %396 = arith.cmpi ne, %394, %395 : i64
        cf.cond_br %396, ^bb69, ^bb70
        ^bb69:
          %397 = llvm.load %349 : !llvm.ptr -> i64
          %398 = arith.trunci %397 : i64 to i32
          %399 = llvm.getelementptr %311[%391] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %398, %399 : i32, !llvm.ptr
          %400 = arith.constant 1 : i32
          %401 = llvm.getelementptr %316[%391] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %400, %401 : i32, !llvm.ptr
          %402 = arith.trunci %391 : i64 to i32
          %403 = llvm.load %375 : !llvm.ptr -> i64
          %404 = llvm.getelementptr %321[%403] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %402, %404 : i32, !llvm.ptr
          %405 = llvm.load %375 : !llvm.ptr -> i64
          %406 = arith.constant 1 : i32
          %408 = arith.extsi %406 : i32 to i64
          %407 = arith.addi %405, %408 : i64
          llvm.store %407, %375 : i64, !llvm.ptr
          cf.br ^bb71
        ^bb70:
          %410 = llvm.getelementptr %316[%391] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          %409 = llvm.load %410 : !llvm.ptr -> i32
          %411 = arith.constant 1 : i32
          %412 = arith.addi %409, %411 : i32
          %413 = llvm.getelementptr %316[%391] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %412, %413 : i32, !llvm.ptr
          cf.br ^bb71
        ^bb71:
        %414 = llvm.load %379 : !llvm.ptr -> i64
        %415 = arith.constant 1 : i32
        %417 = arith.extsi %415 : i32 to i64
        %416 = arith.addi %414, %417 : i64
        llvm.store %416, %379 : i64, !llvm.ptr
        cf.br ^bb66
      ^bb68:
      %418 = arith.constant 0 : i32
      %419 = arith.extsi %418 : i32 to i64
      %420 = llvm.mlir.constant(1 : i64) : i64
      %421 = llvm.alloca %420 x i64 : (i64) -> !llvm.ptr
      llvm.store %419, %421 : i64, !llvm.ptr
      cf.br ^bb72
      ^bb72:
      %423 = llvm.load %421 : !llvm.ptr -> i64
      %424 = llvm.getelementptr %311[%423] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %422 = llvm.load %424 : !llvm.ptr -> i32
      %425 = arith.extsi %422 : i32 to i64
      %426 = llvm.load %349 : !llvm.ptr -> i64
      %427 = arith.cmpi eq, %425, %426 : i64
      cf.cond_br %427, ^bb73, ^bb74
      ^bb73:
        %428 = llvm.load %421 : !llvm.ptr -> i64
        %429 = arith.constant 1 : i32
        %431 = arith.extsi %429 : i32 to i64
        %430 = arith.addi %428, %431 : i64
        llvm.store %430, %421 : i64, !llvm.ptr
        cf.br ^bb72
      ^bb74:
      %432 = llvm.load %421 : !llvm.ptr -> i64
      %433 = arith.xori %371, %432 : i64
      %434 = arith.trunci %433 : i64 to i32
      %435 = llvm.load %349 : !llvm.ptr -> i64
      %436 = llvm.getelementptr %305[%435] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %434, %436 : i32, !llvm.ptr
      %437 = arith.constant 0 : i32
      %438 = arith.extsi %437 : i32 to i64
      %439 = llvm.mlir.constant(1 : i64) : i64
      %440 = llvm.alloca %439 x i64 : (i64) -> !llvm.ptr
      llvm.store %438, %440 : i64, !llvm.ptr
      cf.br ^bb75
      ^bb75:
      %441 = llvm.load %440 : !llvm.ptr -> i64
      %442 = llvm.load %375 : !llvm.ptr -> i64
      %443 = arith.cmpi slt, %441, %442 : i64
      cf.cond_br %443, ^bb76, ^bb77
      ^bb76:
        %445 = llvm.load %440 : !llvm.ptr -> i64
        %446 = llvm.getelementptr %321[%445] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %444 = llvm.load %446 : !llvm.ptr -> i32
        %447 = arith.extsi %444 : i32 to i64
        %449 = llvm.load %421 : !llvm.ptr -> i64
        %450 = arith.xori %447, %449 : i64
        %451 = llvm.getelementptr %arg3[%450] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %448 = llvm.load %451 : !llvm.ptr -> i64
        %453 = llvm.getelementptr %316[%447] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %452 = llvm.load %453 : !llvm.ptr -> i32
        %454 = arith.extsi %452 : i32 to i64
        %455 = arith.addi %448, %454 : i64
        %456 = llvm.load %421 : !llvm.ptr -> i64
        %457 = arith.xori %447, %456 : i64
        %458 = llvm.getelementptr %arg3[%457] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %455, %458 : i64, !llvm.ptr
        %459 = llvm.load %440 : !llvm.ptr -> i64
        %460 = arith.constant 1 : i32
        %462 = arith.extsi %460 : i32 to i64
        %461 = arith.addi %459, %462 : i64
        llvm.store %461, %440 : i64, !llvm.ptr
        cf.br ^bb75
      ^bb77:
      %463 = llvm.load %349 : !llvm.ptr -> i64
      %464 = arith.constant 1 : i32
      %466 = arith.extsi %464 : i32 to i64
      %465 = arith.addi %463, %466 : i64
      llvm.store %465, %349 : i64, !llvm.ptr
      cf.br ^bb60
    ^bb62:
    %468 = llvm.getelementptr %305[%arg0] : (!llvm.ptr, i64) -> !llvm.ptr, i32
    %467 = llvm.load %468 : !llvm.ptr -> i32
    %469 = arith.extsi %467 : i32 to i64
    func.call @free(%321) : (!llvm.ptr) -> ()
    func.call @free(%316) : (!llvm.ptr) -> ()
    func.call @free(%311) : (!llvm.ptr) -> ()
    func.call @free(%305) : (!llvm.ptr) -> ()
    func.return %469 : i64
  }
  func.func @main() -> i32 {
    %475 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %476 = llvm.load %475 : !llvm.ptr -> i64
    %477 = arith.constant 8 : i32
    %478 = arith.extsi %477 : i32 to i64
    %474 = func.call @calloc(%476, %478) : (i64, i64) -> !llvm.ptr
    %479 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
    llvm.store %474, %479 : !llvm.ptr, !llvm.ptr
    %481 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %482 = llvm.load %481 : !llvm.ptr -> i64
    %483 = arith.constant 8 : i32
    %484 = arith.extsi %483 : i32 to i64
    %480 = func.call @calloc(%482, %484) : (i64, i64) -> !llvm.ptr
    %485 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
    llvm.store %480, %485 : !llvm.ptr, !llvm.ptr
    %487 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %488 = llvm.load %487 : !llvm.ptr -> i64
    %489 = arith.constant 8 : i32
    %490 = arith.extsi %489 : i32 to i64
    %486 = func.call @calloc(%488, %490) : (i64, i64) -> !llvm.ptr
    %491 = llvm.mlir.addressof @G_mv : !llvm.ptr
    llvm.store %486, %491 : !llvm.ptr, !llvm.ptr
    %493 = llvm.mlir.addressof @MEMO_CAP : !llvm.ptr
    %494 = llvm.load %493 : !llvm.ptr -> i64
    %495 = arith.constant 1 : i32
    %496 = arith.extsi %495 : i32 to i64
    %492 = func.call @calloc(%494, %496) : (i64, i64) -> !llvm.ptr
    %497 = llvm.mlir.addressof @G_mu : !llvm.ptr
    llvm.store %492, %497 : !llvm.ptr, !llvm.ptr
    %499 = arith.constant 1024 : i32
    %500 = arith.constant 8 : i32
    %501 = arith.extsi %499 : i32 to i64
    %502 = arith.extsi %500 : i32 to i64
    %498 = func.call @calloc(%501, %502) : (i64, i64) -> !llvm.ptr
    %504 = arith.constant 2048 : i32
    %505 = arith.constant 8 : i32
    %506 = arith.extsi %504 : i32 to i64
    %507 = arith.extsi %505 : i32 to i64
    %503 = func.call @calloc(%506, %507) : (i64, i64) -> !llvm.ptr
    %509 = llvm.mlir.addressof @M : !llvm.ptr
    %510 = llvm.load %509 : !llvm.ptr -> i64
    %511 = arith.constant 8 : i32
    %512 = arith.extsi %511 : i32 to i64
    %508 = func.call @calloc(%510, %512) : (i64, i64) -> !llvm.ptr
    %514 = llvm.mlir.addressof @M : !llvm.ptr
    %515 = llvm.load %514 : !llvm.ptr -> i64
    %516 = arith.constant 8 : i32
    %517 = arith.extsi %516 : i32 to i64
    %513 = func.call @calloc(%515, %517) : (i64, i64) -> !llvm.ptr
    %518 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
    %519 = llvm.load %518 : !llvm.ptr -> !llvm.ptr
    %520 = llvm.mlir.zero : !llvm.ptr
    %521 = llvm.icmp "eq" %519, %520 : !llvm.ptr
    %522 = scf.if %521 -> (i1) {
      %523 = arith.constant true
      scf.yield %523 : i1
    } else {
      %524 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
      %525 = llvm.load %524 : !llvm.ptr -> !llvm.ptr
      %526 = llvm.mlir.zero : !llvm.ptr
      %527 = llvm.icmp "eq" %525, %526 : !llvm.ptr
      scf.yield %527 : i1
    }
    %528 = scf.if %522 -> (i1) {
      %529 = arith.constant true
      scf.yield %529 : i1
    } else {
      %530 = llvm.mlir.addressof @G_mv : !llvm.ptr
      %531 = llvm.load %530 : !llvm.ptr -> !llvm.ptr
      %532 = llvm.mlir.zero : !llvm.ptr
      %533 = llvm.icmp "eq" %531, %532 : !llvm.ptr
      scf.yield %533 : i1
    }
    %534 = scf.if %528 -> (i1) {
      %535 = arith.constant true
      scf.yield %535 : i1
    } else {
      %536 = llvm.mlir.addressof @G_mu : !llvm.ptr
      %537 = llvm.load %536 : !llvm.ptr -> !llvm.ptr
      %538 = llvm.mlir.zero : !llvm.ptr
      %539 = llvm.icmp "eq" %537, %538 : !llvm.ptr
      scf.yield %539 : i1
    }
    cf.cond_br %534, ^bb78, ^bb79
    ^bb78:
      %540 = arith.constant 1 : i32
      func.return %540 : i32
    ^bb79:
      cf.br ^bb80
    ^bb80:
    %541 = llvm.mlir.zero : !llvm.ptr
    %542 = llvm.icmp "eq" %498, %541 : !llvm.ptr
    %543 = scf.if %542 -> (i1) {
      %544 = arith.constant true
      scf.yield %544 : i1
    } else {
      %545 = llvm.mlir.zero : !llvm.ptr
      %546 = llvm.icmp "eq" %503, %545 : !llvm.ptr
      scf.yield %546 : i1
    }
    %547 = scf.if %543 -> (i1) {
      %548 = arith.constant true
      scf.yield %548 : i1
    } else {
      %549 = llvm.mlir.zero : !llvm.ptr
      %550 = llvm.icmp "eq" %508, %549 : !llvm.ptr
      scf.yield %550 : i1
    }
    %551 = scf.if %547 -> (i1) {
      %552 = arith.constant true
      scf.yield %552 : i1
    } else {
      %553 = llvm.mlir.zero : !llvm.ptr
      %554 = llvm.icmp "eq" %513, %553 : !llvm.ptr
      scf.yield %554 : i1
    }
    cf.cond_br %551, ^bb81, ^bb82
    ^bb81:
      %555 = arith.constant 1 : i32
      func.return %555 : i32
    ^bb82:
      cf.br ^bb83
    ^bb83:
    %556 = arith.constant 0 : i32
    %557 = arith.extsi %556 : i32 to i64
    %558 = llvm.mlir.constant(1 : i64) : i64
    %559 = llvm.alloca %558 x i64 : (i64) -> !llvm.ptr
    llvm.store %557, %559 : i64, !llvm.ptr
    %560 = arith.constant 1 : i32
    %561 = arith.extsi %560 : i32 to i64
    %562 = llvm.mlir.constant(1 : i64) : i64
    %563 = llvm.alloca %562 x i64 : (i64) -> !llvm.ptr
    llvm.store %561, %563 : i64, !llvm.ptr
    cf.br ^bb84
    ^bb84:
    %564 = llvm.load %563 : !llvm.ptr -> i64
    %565 = llvm.load %563 : !llvm.ptr -> i64
    %566 = arith.muli %564, %565 : i64
    %567 = llvm.mlir.addressof @N : !llvm.ptr
    %568 = llvm.load %567 : !llvm.ptr -> i64
    %569 = arith.cmpi sle, %566, %568 : i64
    cf.cond_br %569, ^bb85, ^bb86
    ^bb85:
      %570 = llvm.load %563 : !llvm.ptr -> i64
      %571 = llvm.load %563 : !llvm.ptr -> i64
      %572 = arith.muli %570, %571 : i64
      %573 = llvm.load %559 : !llvm.ptr -> i64
      %574 = llvm.getelementptr %498[%573] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %572, %574 : i64, !llvm.ptr
      %575 = llvm.load %559 : !llvm.ptr -> i64
      %576 = arith.constant 1 : i32
      %578 = arith.extsi %576 : i32 to i64
      %577 = arith.addi %575, %578 : i64
      llvm.store %577, %559 : i64, !llvm.ptr
      %579 = llvm.load %563 : !llvm.ptr -> i64
      %580 = arith.constant 1 : i32
      %582 = arith.extsi %580 : i32 to i64
      %581 = arith.addi %579, %582 : i64
      llvm.store %581, %563 : i64, !llvm.ptr
      cf.br ^bb84
    ^bb86:
    %583 = arith.constant 0 : i32
    %584 = arith.extsi %583 : i32 to i64
    %585 = llvm.mlir.constant(1 : i64) : i64
    %586 = llvm.alloca %585 x i64 : (i64) -> !llvm.ptr
    llvm.store %584, %586 : i64, !llvm.ptr
    %587 = arith.constant 1 : i32
    %588 = arith.extsi %587 : i32 to i64
    llvm.store %588, %563 : i64, !llvm.ptr
    cf.br ^bb87
    ^bb87:
    %589 = arith.constant 1 : i1
    cf.cond_br %589, ^bb88, ^bb89
    ^bb88:
      %590 = llvm.load %563 : !llvm.ptr -> i64
      %591 = llvm.load %563 : !llvm.ptr -> i64
      %592 = arith.constant 1 : i32
      %594 = arith.extsi %592 : i32 to i64
      %593 = arith.addi %591, %594 : i64
      %595 = arith.muli %590, %593 : i64
      %596 = arith.constant 2 : i32
      %598 = arith.extsi %596 : i32 to i64
      %597 = arith.divsi %595, %598 : i64
      %599 = llvm.mlir.addressof @N : !llvm.ptr
      %600 = llvm.load %599 : !llvm.ptr -> i64
      %601 = arith.cmpi sgt, %597, %600 : i64
      cf.cond_br %601, ^bb90, ^bb91
      ^bb90:
        cf.br ^bb89
      ^bb91:
        cf.br ^bb92
      ^bb92:
      %602 = llvm.load %586 : !llvm.ptr -> i64
      %603 = llvm.getelementptr %503[%602] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %597, %603 : i64, !llvm.ptr
      %604 = llvm.load %586 : !llvm.ptr -> i64
      %605 = arith.constant 1 : i32
      %607 = arith.extsi %605 : i32 to i64
      %606 = arith.addi %604, %607 : i64
      llvm.store %606, %586 : i64, !llvm.ptr
      %608 = llvm.load %563 : !llvm.ptr -> i64
      %609 = arith.constant 1 : i32
      %611 = arith.extsi %609 : i32 to i64
      %610 = arith.addi %608, %611 : i64
      llvm.store %610, %563 : i64, !llvm.ptr
      cf.br ^bb87
    ^bb89:
    %613 = llvm.mlir.addressof @N : !llvm.ptr
    %614 = llvm.load %613 : !llvm.ptr -> i64
    %615 = llvm.load %559 : !llvm.ptr -> i64
    %612 = func.call @compute_1d(%614, %498, %615, %508) : (i64, !llvm.ptr, i64, !llvm.ptr) -> i64
    %617 = llvm.mlir.addressof @N : !llvm.ptr
    %618 = llvm.load %617 : !llvm.ptr -> i64
    %619 = llvm.load %586 : !llvm.ptr -> i64
    %616 = func.call @compute_1d(%618, %503, %619, %513) : (i64, !llvm.ptr, i64, !llvm.ptr) -> i64
    %620 = func.call @nim_mul(%612, %616) : (i64, i64) -> i64
    %621 = arith.constant 0 : i32
    %622 = arith.extsi %621 : i32 to i64
    %623 = llvm.mlir.constant(1 : i64) : i64
    %624 = llvm.alloca %623 x i64 : (i64) -> !llvm.ptr
    llvm.store %622, %624 : i64, !llvm.ptr
    %625 = arith.constant 0 : i32
    %626 = arith.extsi %625 : i32 to i64
    %627 = llvm.mlir.constant(1 : i64) : i64
    %628 = llvm.alloca %627 x i64 : (i64) -> !llvm.ptr
    llvm.store %626, %628 : i64, !llvm.ptr
    %629 = arith.constant 0 : i32
    %630 = arith.extsi %629 : i32 to i64
    %631 = llvm.mlir.constant(1 : i64) : i64
    %632 = llvm.alloca %631 x i64 : (i64) -> !llvm.ptr
    llvm.store %630, %632 : i64, !llvm.ptr
    cf.br ^bb93
    ^bb93:
    %633 = llvm.load %632 : !llvm.ptr -> i64
    %634 = llvm.mlir.addressof @M : !llvm.ptr
    %635 = llvm.load %634 : !llvm.ptr -> i64
    %636 = arith.cmpi slt, %633, %635 : i64
    cf.cond_br %636, ^bb94, ^bb95
    ^bb94:
      %637 = llvm.load %624 : !llvm.ptr -> i64
      %639 = llvm.load %632 : !llvm.ptr -> i64
      %640 = llvm.getelementptr %508[%639] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %638 = llvm.load %640 : !llvm.ptr -> i64
      %641 = arith.addi %637, %638 : i64
      llvm.store %641, %624 : i64, !llvm.ptr
      %642 = llvm.load %628 : !llvm.ptr -> i64
      %644 = llvm.load %632 : !llvm.ptr -> i64
      %645 = llvm.getelementptr %513[%644] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %643 = llvm.load %645 : !llvm.ptr -> i64
      %646 = arith.addi %642, %643 : i64
      llvm.store %646, %628 : i64, !llvm.ptr
      %647 = llvm.load %632 : !llvm.ptr -> i64
      %648 = arith.constant 1 : i32
      %650 = arith.extsi %648 : i32 to i64
      %649 = arith.addi %647, %650 : i64
      llvm.store %649, %632 : i64, !llvm.ptr
      cf.br ^bb93
    ^bb95:
    %651 = arith.constant 0 : i32
    %652 = arith.extsi %651 : i32 to i64
    %653 = llvm.mlir.constant(1 : i64) : i64
    %654 = llvm.alloca %653 x i64 : (i64) -> !llvm.ptr
    llvm.store %652, %654 : i64, !llvm.ptr
    %655 = arith.constant 0 : i32
    %657 = arith.extsi %655 : i32 to i64
    %656 = arith.cmpi eq, %620, %657 : i64
    cf.cond_br %656, ^bb96, ^bb97
    ^bb96:
      %659 = arith.constant 0 : i32
      %660 = arith.extsi %659 : i32 to i64
      %661 = llvm.getelementptr %508[%660] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %658 = llvm.load %661 : !llvm.ptr -> i64
      %663 = arith.constant 0 : i32
      %664 = arith.extsi %663 : i32 to i64
      %665 = llvm.getelementptr %513[%664] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %662 = llvm.load %665 : !llvm.ptr -> i64
      %666 = llvm.load %628 : !llvm.ptr -> i64
      %667 = arith.muli %658, %666 : i64
      %668 = llvm.load %624 : !llvm.ptr -> i64
      %669 = arith.subi %668, %658 : i64
      %670 = arith.muli %669, %662 : i64
      %671 = arith.addi %667, %670 : i64
      llvm.store %671, %654 : i64, !llvm.ptr
      cf.br ^bb98
    ^bb97:
      %672 = arith.constant 1 : i32
      %673 = arith.extsi %672 : i32 to i64
      llvm.store %673, %632 : i64, !llvm.ptr
      cf.br ^bb99
      ^bb99:
      %674 = llvm.load %632 : !llvm.ptr -> i64
      %675 = llvm.mlir.addressof @M : !llvm.ptr
      %676 = llvm.load %675 : !llvm.ptr -> i64
      %677 = arith.cmpi slt, %674, %676 : i64
      cf.cond_br %677, ^bb100, ^bb101
      ^bb100:
        %679 = llvm.load %632 : !llvm.ptr -> i64
        %680 = llvm.getelementptr %508[%679] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %678 = llvm.load %680 : !llvm.ptr -> i64
        %681 = arith.constant 0 : i32
        %683 = arith.extsi %681 : i32 to i64
        %682 = arith.cmpi ne, %678, %683 : i64
        cf.cond_br %682, ^bb102, ^bb103
        ^bb102:
          %685 = llvm.load %632 : !llvm.ptr -> i64
          %684 = func.call @nim_inv(%685) : (i64) -> i64
          %686 = func.call @nim_mul(%620, %684) : (i64, i64) -> i64
          %687 = llvm.mlir.addressof @M : !llvm.ptr
          %688 = llvm.load %687 : !llvm.ptr -> i64
          %689 = arith.cmpi slt, %686, %688 : i64
          cf.cond_br %689, ^bb105, ^bb106
          ^bb105:
            %690 = llvm.load %654 : !llvm.ptr -> i64
            %692 = llvm.getelementptr %513[%686] : (!llvm.ptr, i64) -> !llvm.ptr, i64
            %691 = llvm.load %692 : !llvm.ptr -> i64
            %693 = arith.muli %678, %691 : i64
            %694 = arith.addi %690, %693 : i64
            llvm.store %694, %654 : i64, !llvm.ptr
            cf.br ^bb107
          ^bb106:
            cf.br ^bb107
          ^bb107:
          cf.br ^bb104
        ^bb103:
          cf.br ^bb104
        ^bb104:
        %695 = llvm.load %632 : !llvm.ptr -> i64
        %696 = arith.constant 1 : i32
        %698 = arith.extsi %696 : i32 to i64
        %697 = arith.addi %695, %698 : i64
        llvm.store %697, %632 : i64, !llvm.ptr
        cf.br ^bb99
      ^bb101:
      cf.br ^bb98
    ^bb98:
    %699 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %700 = llvm.load %654 : !llvm.ptr -> i64
    %701 = llvm.call @printf(%699, %700) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    func.call @free(%513) : (!llvm.ptr) -> ()
    func.call @free(%508) : (!llvm.ptr) -> ()
    func.call @free(%503) : (!llvm.ptr) -> ()
    func.call @free(%498) : (!llvm.ptr) -> ()
    %707 = llvm.mlir.addressof @G_mu : !llvm.ptr
    %708 = llvm.load %707 : !llvm.ptr -> !llvm.ptr
    func.call @free(%708) : (!llvm.ptr) -> ()
    %710 = llvm.mlir.addressof @G_mv : !llvm.ptr
    %711 = llvm.load %710 : !llvm.ptr -> !llvm.ptr
    func.call @free(%711) : (!llvm.ptr) -> ()
    %713 = llvm.mlir.addressof @G_mk2 : !llvm.ptr
    %714 = llvm.load %713 : !llvm.ptr -> !llvm.ptr
    func.call @free(%714) : (!llvm.ptr) -> ()
    %716 = llvm.mlir.addressof @G_mk1 : !llvm.ptr
    %717 = llvm.load %716 : !llvm.ptr -> !llvm.ptr
    func.call @free(%717) : (!llvm.ptr) -> ()
    %718 = arith.constant 0 : i32
    func.return %718 : i32
  }
}