Problem 707

F(w,h) = 2^(w*h - d) where d is the GF(2) nullity of the w x h Lights Out matrix. By Sutner, d = deg gcd(p_w(x), p_h(x+1)) with p_0 = 1, p_1 = x, p_{n+1} = x*p_n + p_{n-1} over GF(2). For S(199,199) the heights are the Fibonacci numbers f_1..f_199 (astronomically large), so p_{f_k}(x+1) is computed modulo P = p_199(x) via the 2x2 companion matrix B = [[x+1,1],[1,0]] using the Fibonacci addition chain B^{f_k} = B^{f_{k-1}} * B^{f_{k-2}}. Polynomials are bitsets: 14 words of 32 bits each held in i64 slots. Exponents are tracked mod 1e9+6 (Fermat), sum taken mod 1e9+7.

Answer652907799
Output652907799
StatusPASS
Native helperno
Runtime0 ms
Peak memory1088 KB
Time complexityO(n^2) (estimated)
Space complexityO(1) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)O(log n)
Space complexityO(1)O(1)
ApproachFlow solutionMatrix exponentiation
VerdictSuboptimal

Flow source

# Project Euler 707: Lights Out
# F(w,h) = 2^(w*h - d) where d is the GF(2) nullity of the w x h Lights Out
# matrix. By Sutner, d = deg gcd(p_w(x), p_h(x+1)) with p_0 = 1, p_1 = x,
# p_{n+1} = x*p_n + p_{n-1} over GF(2). For S(199,199) the heights are the
# Fibonacci numbers f_1..f_199 (astronomically large), so p_{f_k}(x+1) is
# computed modulo P = p_199(x) via the 2x2 companion matrix B = [[x+1,1],[1,0]]
# using the Fibonacci addition chain B^{f_k} = B^{f_{k-1}} * B^{f_{k-2}}.
# Polynomials are bitsets: 14 words of 32 bits each held in i64 slots.
# Exponents are tracked mod 1e9+6 (Fermat), sum taken mod 1e9+7.

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

# degree of poly at base b, or -1 if zero
function pdeg(p: ptr<i64>, b: i64) -> i64 {
    let mut i: i64 = 13
    while i >= 0 {
        if p[b + i] != 0 {
            let mut w: i64 = p[b + i]
            let mut d: i64 = 0
            while w > 1 {
                w = w / 2
                d = d + 1
            }
            return i * 32 + d
        }
        i = i - 1
    }
    return -1
}

function pclear(p: ptr<i64>, b: i64) -> void {
    for i in 0..14 { p[b + i] = 0 }
}

function pcopy(d: ptr<i64>, db: i64, s: ptr<i64>, sb: i64) -> void {
    for i in 0..14 { d[db + i] = s[sb + i] }
}

function pxorinto(d: ptr<i64>, db: i64, s: ptr<i64>, sb: i64) -> void {
    for i in 0..14 { d[db + i] = d[db + i] ^ s[sb + i] }
}

function pbit(p: ptr<i64>, b: i64, i: i64) -> i64 {
    return (p[b + i / 32] >> (i % 32)) & 1
}

# a ^= m << s (words are 32-bit values so shifted parts stay below bit 63)
function pxshift(a: ptr<i64>, ab: i64, m: ptr<i64>, mb: i64, s: i64) -> void {
    let wo: i64 = s / 32
    let bo: i64 = s % 32
    let mask: i64 = 4294967295
    for j in 0..14 {
        let w: i64 = m[mb + j]
        if w != 0 {
            let k: i64 = wo + j
            if k < 14 {
                a[ab + k] = a[ab + k] ^ ((w << bo) & mask)
            }
            let hi: i64 = w >> (32 - bo)
            if hi != 0 && k + 1 < 14 {
                a[ab + k + 1] = a[ab + k + 1] ^ hi
            }
        }
    }
}

# r = a * c (carryless product over GF(2)); r is cleared first
function pmul(r: ptr<i64>, rb: i64, a: ptr<i64>, ab: i64, c: ptr<i64>, cb: i64) -> void {
    pclear(r, rb)
    let da: i64 = pdeg(a, ab)
    let mut i: i64 = 0
    while i <= da {
        if pbit(a, ab, i) == 1 {
            pxshift(r, rb, c, cb, i)
        }
        i = i + 1
    }
}

# a = a mod m in place (m must be nonzero)
function pred(a: ptr<i64>, ab: i64, m: ptr<i64>, mb: i64) -> void {
    let dm: i64 = pdeg(m, mb)
    let mut da: i64 = pdeg(a, ab)
    while da >= dm {
        pxshift(a, ab, m, mb, da - dm)
        da = pdeg(a, ab)
    }
}

# degree of gcd(a, b); both buffers (base 0) are destroyed
function pgcddeg(a: ptr<i64>, b: ptr<i64>) -> i64 {
    let mut x: ptr<i64> = a
    let mut y: ptr<i64> = b
    while pdeg(y, 0) >= 0 {
        pred(x, 0, y, 0)
        let t: ptr<i64> = x
        x = y
        y = t
    }
    return pdeg(x, 0)
}

function powmod2(e: i64, md: i64) -> i64 {
    let mut r: i64 = 1
    let mut bs: i64 = 2
    let mut ee: i64 = e
    while ee > 0 {
        if ee % 2 == 1 { r = r * bs % md }
        bs = bs * bs % md
        ee = ee / 2
    }
    return r
}

# C = A * B with entries reduced mod P; matrices are 4 polys at bases e*14
function matmul(cm: ptr<i64>, am: ptr<i64>, bm: ptr<i64>, pp: ptr<i64>, t1: ptr<i64>, t2: ptr<i64>) -> void {
    for e in 0..4 {
        let i: i64 = e / 2
        let j: i64 = e % 2
        pmul(t1, 0, am, (2 * i) * 14, bm, j * 14)
        pmul(t2, 0, am, (2 * i + 1) * 14, bm, (2 + j) * 14)
        pxorinto(t1, 0, t2, 0)
        pred(t1, 0, pp, 0)
        pcopy(cm, e * 14, t1, 0)
    }
}

function main() -> i32 {
    let md: i64 = 1000000007
    let q: i64 = 1000000006
    let w: i64 = 199

    let mut pa: ptr<i64> = calloc(14, 8)
    let mut pb: ptr<i64> = calloc(14, 8)
    let mut pt: ptr<i64> = calloc(14, 8)
    let t1: ptr<i64> = calloc(14, 8)
    let t2: ptr<i64> = calloc(14, 8)
    let ga: ptr<i64> = calloc(14, 8)
    let gb: ptr<i64> = calloc(14, 8)
    let mut ma: ptr<i64> = calloc(56, 8)
    let mut mb: ptr<i64> = calloc(56, 8)
    let mut mc: ptr<i64> = calloc(56, 8)

    # build P = p_199(x): p_0 = 1, p_1 = x, p_{k} = x*p_{k-1} + p_{k-2}
    pa[0] = 1
    pb[0] = 2
    let mut k: i64 = 2
    while k <= w {
        pclear(pt, 0)
        pxshift(pt, 0, pb, 0, 1)
        pxorinto(pt, 0, pa, 0)
        let tp: ptr<i64> = pa
        pa = pb
        pb = pt
        pt = tp
        k = k + 1
    }
    # pb now holds P, degree 199

    # B = [[x+1, 1], [1, 0]]; entries at bases 0, 14, 28, 42
    ma[0] = 3
    ma[14] = 1
    ma[28] = 1
    pcopy(mb, 0, ma, 0)
    pcopy(mb, 14, ma, 14)
    pcopy(mb, 28, ma, 28)
    pcopy(mb, 42, ma, 42)

    # k = 1 and k = 2: h = f_k = 1, p_1(x+1) = x + 1
    pcopy(ga, 0, pb, 0)
    pclear(gb, 0)
    gb[0] = 3
    let d12: i64 = pgcddeg(ga, gb)
    let e12: i64 = ((w * 1 - d12) % q + q) % q
    let mut total: i64 = 2 * powmod2(e12, md) % md

    # k = 3..199: M_k = M_{k-1} * M_{k-2}, f_k tracked mod q
    let mut fib1: i64 = 1
    let mut fib2: i64 = 1
    k = 3
    while k <= 199 {
        matmul(mc, ma, mb, pb, t1, t2)
        let fm: i64 = (fib1 + fib2) % q
        let tm: ptr<i64> = mb
        mb = ma
        ma = mc
        mc = tm
        fib2 = fib1
        fib1 = fm

        pcopy(ga, 0, pb, 0)
        pcopy(gb, 0, ma, 0)
        let d: i64 = pgcddeg(ga, gb)
        let e: i64 = ((w * fm - d) % q + q) % q
        total = (total + powmod2(e, md)) % md
        k = k + 1
    }

    printf("%lld\n", total)
    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 pdeg_ptr_i64_i64(int64_t* p, int64_t b);
void pclear_ptr_i64_i64(int64_t* p, int64_t b);
void pcopy_ptr_i64_i64_ptr_i64_i64(int64_t* d, int64_t db, int64_t* s, int64_t sb);
void pxorinto_ptr_i64_i64_ptr_i64_i64(int64_t* d, int64_t db, int64_t* s, int64_t sb);
int64_t pbit_ptr_i64_i64_i64(int64_t* p, int64_t b, int64_t i);
void pxshift_ptr_i64_i64_ptr_i64_i64_i64(int64_t* a, int64_t ab, int64_t* m, int64_t mb, int64_t s);
void pmul_ptr_i64_i64_ptr_i64_i64_ptr_i64_i64(int64_t* r, int64_t rb, int64_t* a, int64_t ab, int64_t* c, int64_t cb);
void pred_ptr_i64_i64_ptr_i64_i64(int64_t* a, int64_t ab, int64_t* m, int64_t mb);
int64_t pgcddeg_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
int64_t powmod2_i64_i64(int64_t e, int64_t md);
void matmul_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64(int64_t* cm, int64_t* am, int64_t* bm, int64_t* pp, int64_t* t1, int64_t* t2);
int32_t main(void);



int64_t pdeg_ptr_i64_i64(int64_t* p, int64_t b) {
    int64_t i = 13;
    while (i >= 0) {
        if (p[(b + i)] != 0) {
            int64_t w = p[(b + i)];
            int64_t d = 0;
            while (w > 1) {
                w = FLOW_CHECKED_DIV((w), (2));
                d = (d + 1);
            }
            return ((i * 32) + d);
        }
        i = (i - 1);
    }
    return (-1);
}

void pclear_ptr_i64_i64(int64_t* p, int64_t b) {
    int32_t __flow_step_1 = 1;
    for (int32_t i = 0; (0 <= 14) ? i < 14 : i > 14; i += (0 <= 14) ? 1 : -1) {
        p[(b + i)] = 0;
    }
}

void pcopy_ptr_i64_i64_ptr_i64_i64(int64_t* d, int64_t db, int64_t* s, int64_t sb) {
    int32_t __flow_step_2 = 1;
    for (int32_t i = 0; (0 <= 14) ? i < 14 : i > 14; i += (0 <= 14) ? 1 : -1) {
        d[(db + i)] = s[(sb + i)];
    }
}

void pxorinto_ptr_i64_i64_ptr_i64_i64(int64_t* d, int64_t db, int64_t* s, int64_t sb) {
    int32_t __flow_step_3 = 1;
    for (int32_t i = 0; (0 <= 14) ? i < 14 : i > 14; i += (0 <= 14) ? 1 : -1) {
        d[(db + i)] = (d[(db + i)] ^ s[(sb + i)]);
    }
}

int64_t pbit_ptr_i64_i64_i64(int64_t* p, int64_t b, int64_t i) {
    return (FLOW_CHECKED_SHR((p[(b + FLOW_CHECKED_DIV((i), (32)))]), (FLOW_CHECKED_MOD((i), (32)))) & 1);
}

void pxshift_ptr_i64_i64_ptr_i64_i64_i64(int64_t* a, int64_t ab, int64_t* m, int64_t mb, int64_t s) {
    int64_t wo = FLOW_CHECKED_DIV((s), (32));
    int64_t bo = FLOW_CHECKED_MOD((s), (32));
    int64_t mask = 4294967295;
    int32_t __flow_step_4 = 1;
    for (int32_t j = 0; (0 <= 14) ? j < 14 : j > 14; j += (0 <= 14) ? 1 : -1) {
        int64_t w = m[(mb + j)];
        if (w != 0) {
            int64_t k = (wo + j);
            if (k < 14) {
                a[(ab + k)] = (a[(ab + k)] ^ (FLOW_CHECKED_SHL((w), (bo)) & mask));
            }
            int64_t hi = FLOW_CHECKED_SHR((w), ((32 - bo)));
            if ((hi != 0 && (k + 1) < 14)) {
                a[((ab + k) + 1)] = (a[((ab + k) + 1)] ^ hi);
            }
        }
    }
}

void pmul_ptr_i64_i64_ptr_i64_i64_ptr_i64_i64(int64_t* r, int64_t rb, int64_t* a, int64_t ab, int64_t* c, int64_t cb) {
    pclear_ptr_i64_i64(r, rb);
    int64_t da = pdeg_ptr_i64_i64(a, ab);
    int64_t i = 0;
    while (i <= da) {
        if (pbit_ptr_i64_i64_i64(a, ab, i) == 1) {
            pxshift_ptr_i64_i64_ptr_i64_i64_i64(r, rb, c, cb, i);
        }
        i = (i + 1);
    }
}

void pred_ptr_i64_i64_ptr_i64_i64(int64_t* a, int64_t ab, int64_t* m, int64_t mb) {
    int64_t dm = pdeg_ptr_i64_i64(m, mb);
    int64_t da = pdeg_ptr_i64_i64(a, ab);
    while (da >= dm) {
        pxshift_ptr_i64_i64_ptr_i64_i64_i64(a, ab, m, mb, (da - dm));
        da = pdeg_ptr_i64_i64(a, ab);
    }
}

int64_t pgcddeg_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    int64_t* x = (int64_t*)(a);
    int64_t* y = (int64_t*)(b);
    while (pdeg_ptr_i64_i64(y, 0) >= 0) {
        pred_ptr_i64_i64_ptr_i64_i64(x, 0, y, 0);
        int64_t* t = (int64_t*)(x);
        x = y;
        y = t;
    }
    return pdeg_ptr_i64_i64(x, 0);
}

int64_t powmod2_i64_i64(int64_t e, int64_t md) {
    int64_t r = 1;
    int64_t bs = 2;
    int64_t ee = e;
    while (ee > 0) {
        if (FLOW_CHECKED_MOD((ee), (2)) == 1) {
            r = FLOW_CHECKED_MOD(((r * bs)), (md));
        }
        bs = FLOW_CHECKED_MOD(((bs * bs)), (md));
        ee = FLOW_CHECKED_DIV((ee), (2));
    }
    return r;
}

void matmul_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64(int64_t* cm, int64_t* am, int64_t* bm, int64_t* pp, int64_t* t1, int64_t* t2) {
    int32_t __flow_step_5 = 1;
    for (int32_t e = 0; (0 <= 4) ? e < 4 : e > 4; e += (0 <= 4) ? 1 : -1) {
        int64_t i = FLOW_CHECKED_DIV((e), (2));
        int64_t j = FLOW_CHECKED_MOD((e), (2));
        pmul_ptr_i64_i64_ptr_i64_i64_ptr_i64_i64(t1, 0, am, ((2 * i) * 14), bm, (j * 14));
        pmul_ptr_i64_i64_ptr_i64_i64_ptr_i64_i64(t2, 0, am, (((2 * i) + 1) * 14), bm, ((2 + j) * 14));
        pxorinto_ptr_i64_i64_ptr_i64_i64(t1, 0, t2, 0);
        pred_ptr_i64_i64_ptr_i64_i64(t1, 0, pp, 0);
        pcopy_ptr_i64_i64_ptr_i64_i64(cm, (e * 14), t1, 0);
    }
}

int32_t main(void) {
    int64_t md = 1000000007;
    int64_t q = 1000000006;
    int64_t w = 199;
    int64_t* pa = (int64_t*)(calloc(14, 8));
    int64_t* pb = (int64_t*)(calloc(14, 8));
    int64_t* pt = (int64_t*)(calloc(14, 8));
    int64_t* t1 = (int64_t*)(calloc(14, 8));
    int64_t* t2 = (int64_t*)(calloc(14, 8));
    int64_t* ga = (int64_t*)(calloc(14, 8));
    int64_t* gb = (int64_t*)(calloc(14, 8));
    int64_t* ma = (int64_t*)(calloc(56, 8));
    int64_t* mb = (int64_t*)(calloc(56, 8));
    int64_t* mc = (int64_t*)(calloc(56, 8));
    pa[0] = 1;
    pb[0] = 2;
    int64_t k = 2;
    while (k <= w) {
        pclear_ptr_i64_i64(pt, 0);
        pxshift_ptr_i64_i64_ptr_i64_i64_i64(pt, 0, pb, 0, 1);
        pxorinto_ptr_i64_i64_ptr_i64_i64(pt, 0, pa, 0);
        int64_t* tp = (int64_t*)(pa);
        pa = pb;
        pb = pt;
        pt = tp;
        k = (k + 1);
    }
    ma[0] = 3;
    ma[14] = 1;
    ma[28] = 1;
    pcopy_ptr_i64_i64_ptr_i64_i64(mb, 0, ma, 0);
    pcopy_ptr_i64_i64_ptr_i64_i64(mb, 14, ma, 14);
    pcopy_ptr_i64_i64_ptr_i64_i64(mb, 28, ma, 28);
    pcopy_ptr_i64_i64_ptr_i64_i64(mb, 42, ma, 42);
    pcopy_ptr_i64_i64_ptr_i64_i64(ga, 0, pb, 0);
    pclear_ptr_i64_i64(gb, 0);
    gb[0] = 3;
    int64_t d12 = pgcddeg_ptr_i64_ptr_i64(ga, gb);
    int64_t e12 = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((((w * 1) - d12)), (q)) + q)), (q));
    int64_t total = FLOW_CHECKED_MOD(((2 * powmod2_i64_i64(e12, md))), (md));
    int64_t fib1 = 1;
    int64_t fib2 = 1;
    k = 3;
    while (k <= 199) {
        matmul_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64_ptr_i64(mc, ma, mb, pb, t1, t2);
        int64_t fm = FLOW_CHECKED_MOD(((fib1 + fib2)), (q));
        int64_t* tm = (int64_t*)(mb);
        mb = ma;
        ma = mc;
        mc = tm;
        fib2 = fib1;
        fib1 = fm;
        pcopy_ptr_i64_i64_ptr_i64_i64(ga, 0, pb, 0);
        pcopy_ptr_i64_i64_ptr_i64_i64(gb, 0, ma, 0);
        int64_t d = pgcddeg_ptr_i64_ptr_i64(ga, gb);
        int64_t e = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((((w * fm) - d)), (q)) + q)), (q));
        total = FLOW_CHECKED_MOD(((total + powmod2_i64_i64(e, md))), (md));
        k = (k + 1);
    }
    printf("%lld\n", total);
    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) -> ()
  func.func @pdeg(%arg0: !llvm.ptr, %arg1: i64) -> i64 {
    %0 = arith.constant 13 : i32
    %1 = arith.extsi %0 : i32 to i64
    %2 = llvm.mlir.constant(1 : i64) : i64
    %3 = llvm.alloca %2 x i64 : (i64) -> !llvm.ptr
    llvm.store %1, %3 : i64, !llvm.ptr
    cf.br ^bb0
    ^bb0:
    %4 = llvm.load %3 : !llvm.ptr -> i64
    %5 = arith.constant 0 : i32
    %7 = arith.extsi %5 : i32 to i64
    %6 = arith.cmpi sge, %4, %7 : i64
    cf.cond_br %6, ^bb1, ^bb2
    ^bb1:
      %9 = llvm.load %3 : !llvm.ptr -> i64
      %10 = arith.addi %arg1, %9 : i64
      %11 = llvm.getelementptr %arg0[%10] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %8 = llvm.load %11 : !llvm.ptr -> i64
      %12 = arith.constant 0 : i32
      %14 = arith.extsi %12 : i32 to i64
      %13 = arith.cmpi ne, %8, %14 : i64
      cf.cond_br %13, ^bb3, ^bb4
      ^bb3:
        %16 = llvm.load %3 : !llvm.ptr -> i64
        %17 = arith.addi %arg1, %16 : i64
        %18 = llvm.getelementptr %arg0[%17] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %15 = llvm.load %18 : !llvm.ptr -> i64
        %19 = llvm.mlir.constant(1 : i64) : i64
        %20 = llvm.alloca %19 x i64 : (i64) -> !llvm.ptr
        llvm.store %15, %20 : i64, !llvm.ptr
        %21 = arith.constant 0 : i32
        %22 = arith.extsi %21 : i32 to i64
        %23 = llvm.mlir.constant(1 : i64) : i64
        %24 = llvm.alloca %23 x i64 : (i64) -> !llvm.ptr
        llvm.store %22, %24 : i64, !llvm.ptr
        cf.br ^bb6
        ^bb6:
        %25 = llvm.load %20 : !llvm.ptr -> i64
        %26 = arith.constant 1 : i32
        %28 = arith.extsi %26 : i32 to i64
        %27 = arith.cmpi sgt, %25, %28 : i64
        cf.cond_br %27, ^bb7, ^bb8
        ^bb7:
          %29 = llvm.load %20 : !llvm.ptr -> i64
          %30 = arith.constant 2 : i32
          %32 = arith.extsi %30 : i32 to i64
          %31 = arith.divsi %29, %32 : i64
          llvm.store %31, %20 : i64, !llvm.ptr
          %33 = llvm.load %24 : !llvm.ptr -> i64
          %34 = arith.constant 1 : i32
          %36 = arith.extsi %34 : i32 to i64
          %35 = arith.addi %33, %36 : i64
          llvm.store %35, %24 : i64, !llvm.ptr
          cf.br ^bb6
        ^bb8:
        %37 = llvm.load %3 : !llvm.ptr -> i64
        %38 = arith.constant 32 : i32
        %40 = arith.extsi %38 : i32 to i64
        %39 = arith.muli %37, %40 : i64
        %41 = llvm.load %24 : !llvm.ptr -> i64
        %42 = arith.addi %39, %41 : i64
        func.return %42 : i64
      ^bb4:
        cf.br ^bb5
      ^bb5:
      %43 = llvm.load %3 : !llvm.ptr -> i64
      %44 = arith.constant 1 : i32
      %46 = arith.extsi %44 : i32 to i64
      %45 = arith.subi %43, %46 : i64
      llvm.store %45, %3 : i64, !llvm.ptr
      cf.br ^bb0
    ^bb2:
    %47 = arith.constant 1 : i32
    %49 = arith.constant 0 : i32
    %48 = arith.subi %49, %47 : i32
    %50 = arith.extsi %48 : i32 to i64
    func.return %50 : i64
  }
  func.func @pclear(%arg0: !llvm.ptr, %arg1: i64) -> () {
    %51 = arith.constant 0 : i32
    %52 = arith.constant 14 : i32
    %53 = arith.index_cast %51 : i32 to index
    %54 = arith.index_cast %52 : i32 to index
    %56 = arith.constant 1 : index
    %57 = arith.constant -1 : index
    %58 = arith.cmpi sle, %53, %54 : index
    %55 = arith.select %58, %56, %57 : index
    cf.br ^bb9(%53 : index)
    ^bb9(%59: index):
    %60 = arith.cmpi slt, %59, %54 : index
    %61 = arith.cmpi sgt, %59, %54 : index
    %62 = arith.select %58, %60, %61 : i1
    cf.cond_br %62, ^bb10(%59 : index), ^bb11(%59 : index)
    ^bb10(%63: index):
      %64 = arith.constant 0 : i32
      %66 = arith.trunci %arg1 : i64 to i32
      %67 = arith.index_cast %63 : index to i32
      %65 = arith.addi %66, %67 : i32
      %68 = arith.extsi %64 : i32 to i64
      %69 = arith.extsi %65 : i32 to i64
      %70 = llvm.getelementptr %arg0[%69] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %68, %70 : i64, !llvm.ptr
      %71 = arith.addi %63, %55 : index
      cf.br ^bb9(%71 : index)
    ^bb11(%72: index):
    func.return
  }
  func.func @pcopy(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64) -> () {
    %73 = arith.constant 0 : i32
    %74 = arith.constant 14 : i32
    %75 = arith.index_cast %73 : i32 to index
    %76 = arith.index_cast %74 : i32 to index
    %78 = arith.constant 1 : index
    %79 = arith.constant -1 : index
    %80 = arith.cmpi sle, %75, %76 : index
    %77 = arith.select %80, %78, %79 : index
    cf.br ^bb12(%75 : index)
    ^bb12(%81: index):
    %82 = arith.cmpi slt, %81, %76 : index
    %83 = arith.cmpi sgt, %81, %76 : index
    %84 = arith.select %80, %82, %83 : i1
    cf.cond_br %84, ^bb13(%81 : index), ^bb14(%81 : index)
    ^bb13(%85: index):
      %88 = arith.trunci %arg3 : i64 to i32
      %89 = arith.index_cast %85 : index to i32
      %87 = arith.addi %88, %89 : i32
      %90 = arith.extsi %87 : i32 to i64
      %91 = llvm.getelementptr %arg2[%90] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %86 = llvm.load %91 : !llvm.ptr -> i64
      %93 = arith.trunci %arg1 : i64 to i32
      %94 = arith.index_cast %85 : index to i32
      %92 = arith.addi %93, %94 : i32
      %95 = arith.extsi %92 : i32 to i64
      %96 = llvm.getelementptr %arg0[%95] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %86, %96 : i64, !llvm.ptr
      %97 = arith.addi %85, %77 : index
      cf.br ^bb12(%97 : index)
    ^bb14(%98: index):
    func.return
  }
  func.func @pxorinto(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64) -> () {
    %99 = arith.constant 0 : i32
    %100 = arith.constant 14 : i32
    %101 = arith.index_cast %99 : i32 to index
    %102 = arith.index_cast %100 : i32 to index
    %104 = arith.constant 1 : index
    %105 = arith.constant -1 : index
    %106 = arith.cmpi sle, %101, %102 : index
    %103 = arith.select %106, %104, %105 : index
    cf.br ^bb15(%101 : index)
    ^bb15(%107: index):
    %108 = arith.cmpi slt, %107, %102 : index
    %109 = arith.cmpi sgt, %107, %102 : index
    %110 = arith.select %106, %108, %109 : i1
    cf.cond_br %110, ^bb16(%107 : index), ^bb17(%107 : index)
    ^bb16(%111: index):
      %114 = arith.trunci %arg1 : i64 to i32
      %115 = arith.index_cast %111 : index to i32
      %113 = arith.addi %114, %115 : i32
      %116 = arith.extsi %113 : i32 to i64
      %117 = llvm.getelementptr %arg0[%116] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %112 = llvm.load %117 : !llvm.ptr -> i64
      %120 = arith.trunci %arg3 : i64 to i32
      %121 = arith.index_cast %111 : index to i32
      %119 = arith.addi %120, %121 : i32
      %122 = arith.extsi %119 : i32 to i64
      %123 = llvm.getelementptr %arg2[%122] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %118 = llvm.load %123 : !llvm.ptr -> i64
      %124 = arith.xori %112, %118 : i64
      %126 = arith.trunci %arg1 : i64 to i32
      %127 = arith.index_cast %111 : index to i32
      %125 = arith.addi %126, %127 : i32
      %128 = arith.extsi %125 : i32 to i64
      %129 = llvm.getelementptr %arg0[%128] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %124, %129 : i64, !llvm.ptr
      %130 = arith.addi %111, %103 : index
      cf.br ^bb15(%130 : index)
    ^bb17(%131: index):
    func.return
  }
  func.func @pbit(%arg0: !llvm.ptr, %arg1: i64, %arg2: i64) -> i64 {
    %133 = arith.constant 32 : i32
    %135 = arith.extsi %133 : i32 to i64
    %134 = arith.divsi %arg2, %135 : i64
    %136 = arith.addi %arg1, %134 : i64
    %137 = llvm.getelementptr %arg0[%136] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %132 = llvm.load %137 : !llvm.ptr -> i64
    %138 = arith.constant 32 : i32
    %140 = arith.extsi %138 : i32 to i64
    %139 = arith.remsi %arg2, %140 : i64
    %141 = arith.shrsi %132, %139 : i64
    %142 = arith.constant 1 : i32
    %144 = arith.extsi %142 : i32 to i64
    %143 = arith.andi %141, %144 : i64
    func.return %143 : i64
  }
  func.func @pxshift(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64, %arg4: i64) -> () {
    %145 = arith.constant 32 : i32
    %147 = arith.extsi %145 : i32 to i64
    %146 = arith.divsi %arg4, %147 : i64
    %148 = arith.constant 32 : i32
    %150 = arith.extsi %148 : i32 to i64
    %149 = arith.remsi %arg4, %150 : i64
    %151 = arith.constant -1 : i32
    %152 = arith.extsi %151 : i32 to i64
    %153 = arith.constant 0 : i32
    %154 = arith.constant 14 : i32
    %155 = arith.index_cast %153 : i32 to index
    %156 = arith.index_cast %154 : i32 to index
    %158 = arith.constant 1 : index
    %159 = arith.constant -1 : index
    %160 = arith.cmpi sle, %155, %156 : index
    %157 = arith.select %160, %158, %159 : index
    cf.br ^bb18(%155 : index)
    ^bb18(%161: index):
    %162 = arith.cmpi slt, %161, %156 : index
    %163 = arith.cmpi sgt, %161, %156 : index
    %164 = arith.select %160, %162, %163 : i1
    cf.cond_br %164, ^bb19(%161 : index), ^bb20(%161 : index)
    ^bb19(%165: index):
      %168 = arith.trunci %arg3 : i64 to i32
      %169 = arith.index_cast %165 : index to i32
      %167 = arith.addi %168, %169 : i32
      %170 = arith.extsi %167 : i32 to i64
      %171 = llvm.getelementptr %arg2[%170] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %166 = llvm.load %171 : !llvm.ptr -> i64
      %172 = arith.constant 0 : i32
      %174 = arith.extsi %172 : i32 to i64
      %173 = arith.cmpi ne, %166, %174 : i64
      cf.cond_br %173, ^bb21, ^bb22
      ^bb21:
        %176 = arith.trunci %146 : i64 to i32
        %177 = arith.index_cast %165 : index to i32
        %175 = arith.addi %176, %177 : i32
        %178 = arith.extsi %175 : i32 to i64
        %179 = arith.constant 14 : i32
        %181 = arith.extsi %179 : i32 to i64
        %180 = arith.cmpi slt, %178, %181 : i64
        cf.cond_br %180, ^bb24, ^bb25
        ^bb24:
          %183 = arith.addi %arg1, %178 : i64
          %184 = llvm.getelementptr %arg0[%183] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %182 = llvm.load %184 : !llvm.ptr -> i64
          %185 = arith.shli %166, %149 : i64
          %186 = arith.andi %185, %152 : i64
          %187 = arith.xori %182, %186 : i64
          %188 = arith.addi %arg1, %178 : i64
          %189 = llvm.getelementptr %arg0[%188] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          llvm.store %187, %189 : i64, !llvm.ptr
          cf.br ^bb26
        ^bb25:
          cf.br ^bb26
        ^bb26:
        %190 = arith.constant 32 : i32
        %192 = arith.extsi %190 : i32 to i64
        %191 = arith.subi %192, %149 : i64
        %193 = arith.shrsi %166, %191 : i64
        %194 = arith.constant 0 : i32
        %196 = arith.extsi %194 : i32 to i64
        %195 = arith.cmpi ne, %193, %196 : i64
        %197 = scf.if %195 -> (i1) {
          %198 = arith.constant 1 : i32
          %200 = arith.extsi %198 : i32 to i64
          %199 = arith.addi %178, %200 : i64
          %201 = arith.constant 14 : i32
          %203 = arith.extsi %201 : i32 to i64
          %202 = arith.cmpi slt, %199, %203 : i64
          scf.yield %202 : i1
        } else {
          %204 = arith.constant false
          scf.yield %204 : i1
        }
        cf.cond_br %197, ^bb27, ^bb28
        ^bb27:
          %206 = arith.addi %arg1, %178 : i64
          %207 = arith.constant 1 : i32
          %209 = arith.extsi %207 : i32 to i64
          %208 = arith.addi %206, %209 : i64
          %210 = llvm.getelementptr %arg0[%208] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %205 = llvm.load %210 : !llvm.ptr -> i64
          %211 = arith.xori %205, %193 : i64
          %212 = arith.addi %arg1, %178 : i64
          %213 = arith.constant 1 : i32
          %215 = arith.extsi %213 : i32 to i64
          %214 = arith.addi %212, %215 : i64
          %216 = llvm.getelementptr %arg0[%214] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          llvm.store %211, %216 : i64, !llvm.ptr
          cf.br ^bb29
        ^bb28:
          cf.br ^bb29
        ^bb29:
        cf.br ^bb23
      ^bb22:
        cf.br ^bb23
      ^bb23:
      %217 = arith.addi %165, %157 : index
      cf.br ^bb18(%217 : index)
    ^bb20(%218: index):
    func.return
  }
  func.func @pmul(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64, %arg4: !llvm.ptr, %arg5: i64) -> () {
    func.call @pclear(%arg0, %arg1) : (!llvm.ptr, i64) -> ()
    %220 = func.call @pdeg(%arg2, %arg3) : (!llvm.ptr, i64) -> i64
    %221 = arith.constant 0 : i32
    %222 = arith.extsi %221 : i32 to i64
    %223 = llvm.mlir.constant(1 : i64) : i64
    %224 = llvm.alloca %223 x i64 : (i64) -> !llvm.ptr
    llvm.store %222, %224 : i64, !llvm.ptr
    cf.br ^bb30
    ^bb30:
    %225 = llvm.load %224 : !llvm.ptr -> i64
    %226 = arith.cmpi sle, %225, %220 : i64
    cf.cond_br %226, ^bb31, ^bb32
    ^bb31:
      %228 = llvm.load %224 : !llvm.ptr -> i64
      %227 = func.call @pbit(%arg2, %arg3, %228) : (!llvm.ptr, i64, i64) -> i64
      %229 = arith.constant 1 : i32
      %231 = arith.extsi %229 : i32 to i64
      %230 = arith.cmpi eq, %227, %231 : i64
      cf.cond_br %230, ^bb33, ^bb34
      ^bb33:
        %233 = llvm.load %224 : !llvm.ptr -> i64
        func.call @pxshift(%arg0, %arg1, %arg4, %arg5, %233) : (!llvm.ptr, i64, !llvm.ptr, i64, i64) -> ()
        cf.br ^bb35
      ^bb34:
        cf.br ^bb35
      ^bb35:
      %234 = llvm.load %224 : !llvm.ptr -> i64
      %235 = arith.constant 1 : i32
      %237 = arith.extsi %235 : i32 to i64
      %236 = arith.addi %234, %237 : i64
      llvm.store %236, %224 : i64, !llvm.ptr
      cf.br ^bb30
    ^bb32:
    func.return
  }
  func.func @pred(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64) -> () {
    %238 = func.call @pdeg(%arg2, %arg3) : (!llvm.ptr, i64) -> i64
    %239 = func.call @pdeg(%arg0, %arg1) : (!llvm.ptr, i64) -> i64
    %240 = llvm.mlir.constant(1 : i64) : i64
    %241 = llvm.alloca %240 x i64 : (i64) -> !llvm.ptr
    llvm.store %239, %241 : i64, !llvm.ptr
    cf.br ^bb36
    ^bb36:
    %242 = llvm.load %241 : !llvm.ptr -> i64
    %243 = arith.cmpi sge, %242, %238 : i64
    cf.cond_br %243, ^bb37, ^bb38
    ^bb37:
      %245 = llvm.load %241 : !llvm.ptr -> i64
      %246 = arith.subi %245, %238 : i64
      func.call @pxshift(%arg0, %arg1, %arg2, %arg3, %246) : (!llvm.ptr, i64, !llvm.ptr, i64, i64) -> ()
      %247 = func.call @pdeg(%arg0, %arg1) : (!llvm.ptr, i64) -> i64
      llvm.store %247, %241 : i64, !llvm.ptr
      cf.br ^bb36
    ^bb38:
    func.return
  }
  func.func @pgcddeg(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> i64 {
    %248 = llvm.mlir.constant(1 : i64) : i64
    %249 = llvm.alloca %248 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %arg0, %249 : !llvm.ptr, !llvm.ptr
    %250 = llvm.mlir.constant(1 : i64) : i64
    %251 = llvm.alloca %250 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %arg1, %251 : !llvm.ptr, !llvm.ptr
    cf.br ^bb39
    ^bb39:
    %253 = llvm.load %251 : !llvm.ptr -> !llvm.ptr
    %254 = arith.constant 0 : i32
    %255 = arith.extsi %254 : i32 to i64
    %252 = func.call @pdeg(%253, %255) : (!llvm.ptr, i64) -> i64
    %256 = arith.constant 0 : i32
    %258 = arith.extsi %256 : i32 to i64
    %257 = arith.cmpi sge, %252, %258 : i64
    cf.cond_br %257, ^bb40, ^bb41
    ^bb40:
      %260 = llvm.load %249 : !llvm.ptr -> !llvm.ptr
      %261 = arith.constant 0 : i32
      %262 = llvm.load %251 : !llvm.ptr -> !llvm.ptr
      %263 = arith.constant 0 : i32
      %264 = arith.extsi %261 : i32 to i64
      %265 = arith.extsi %263 : i32 to i64
      func.call @pred(%260, %264, %262, %265) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %266 = llvm.load %249 : !llvm.ptr -> !llvm.ptr
      %267 = llvm.load %251 : !llvm.ptr -> !llvm.ptr
      llvm.store %267, %249 : !llvm.ptr, !llvm.ptr
      llvm.store %266, %251 : !llvm.ptr, !llvm.ptr
      cf.br ^bb39
    ^bb41:
    %269 = llvm.load %249 : !llvm.ptr -> !llvm.ptr
    %270 = arith.constant 0 : i32
    %271 = arith.extsi %270 : i32 to i64
    %268 = func.call @pdeg(%269, %271) : (!llvm.ptr, i64) -> i64
    func.return %268 : i64
  }
  func.func @powmod2(%arg0: i64, %arg1: i64) -> i64 {
    %272 = arith.constant 1 : i32
    %273 = arith.extsi %272 : i32 to i64
    %274 = llvm.mlir.constant(1 : i64) : i64
    %275 = llvm.alloca %274 x i64 : (i64) -> !llvm.ptr
    llvm.store %273, %275 : i64, !llvm.ptr
    %276 = arith.constant 2 : i32
    %277 = arith.extsi %276 : i32 to i64
    %278 = llvm.mlir.constant(1 : i64) : i64
    %279 = llvm.alloca %278 x i64 : (i64) -> !llvm.ptr
    llvm.store %277, %279 : i64, !llvm.ptr
    %280 = llvm.mlir.constant(1 : i64) : i64
    %281 = llvm.alloca %280 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg0, %281 : i64, !llvm.ptr
    cf.br ^bb42
    ^bb42:
    %282 = llvm.load %281 : !llvm.ptr -> i64
    %283 = arith.constant 0 : i32
    %285 = arith.extsi %283 : i32 to i64
    %284 = arith.cmpi sgt, %282, %285 : i64
    cf.cond_br %284, ^bb43, ^bb44
    ^bb43:
      %286 = llvm.load %281 : !llvm.ptr -> i64
      %287 = arith.constant 2 : i32
      %289 = arith.extsi %287 : i32 to i64
      %288 = arith.remsi %286, %289 : i64
      %290 = arith.constant 1 : i32
      %292 = arith.extsi %290 : i32 to i64
      %291 = arith.cmpi eq, %288, %292 : i64
      cf.cond_br %291, ^bb45, ^bb46
      ^bb45:
        %293 = llvm.load %275 : !llvm.ptr -> i64
        %294 = llvm.load %279 : !llvm.ptr -> i64
        %295 = arith.muli %293, %294 : i64
        %296 = arith.remsi %295, %arg1 : i64
        llvm.store %296, %275 : i64, !llvm.ptr
        cf.br ^bb47
      ^bb46:
        cf.br ^bb47
      ^bb47:
      %297 = llvm.load %279 : !llvm.ptr -> i64
      %298 = llvm.load %279 : !llvm.ptr -> i64
      %299 = arith.muli %297, %298 : i64
      %300 = arith.remsi %299, %arg1 : i64
      llvm.store %300, %279 : i64, !llvm.ptr
      %301 = llvm.load %281 : !llvm.ptr -> i64
      %302 = arith.constant 2 : i32
      %304 = arith.extsi %302 : i32 to i64
      %303 = arith.divsi %301, %304 : i64
      llvm.store %303, %281 : i64, !llvm.ptr
      cf.br ^bb42
    ^bb44:
    %305 = llvm.load %275 : !llvm.ptr -> i64
    func.return %305 : i64
  }
  func.func @matmul(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr, %arg4: !llvm.ptr, %arg5: !llvm.ptr) -> () {
    %306 = arith.constant 0 : i32
    %307 = arith.constant 4 : i32
    %308 = arith.index_cast %306 : i32 to index
    %309 = arith.index_cast %307 : i32 to index
    %311 = arith.constant 1 : index
    %312 = arith.constant -1 : index
    %313 = arith.cmpi sle, %308, %309 : index
    %310 = arith.select %313, %311, %312 : index
    cf.br ^bb48(%308 : index)
    ^bb48(%314: index):
    %315 = arith.cmpi slt, %314, %309 : index
    %316 = arith.cmpi sgt, %314, %309 : index
    %317 = arith.select %313, %315, %316 : i1
    cf.cond_br %317, ^bb49(%314 : index), ^bb50(%314 : index)
    ^bb49(%318: index):
      %319 = arith.constant 2 : i32
      %321 = arith.index_cast %318 : index to i32
      %320 = arith.divsi %321, %319 : i32
      %322 = arith.extsi %320 : i32 to i64
      %323 = arith.constant 2 : i32
      %325 = arith.index_cast %318 : index to i32
      %324 = arith.remsi %325, %323 : i32
      %326 = arith.extsi %324 : i32 to i64
      %328 = arith.constant 0 : i32
      %329 = arith.constant 2 : i32
      %331 = arith.extsi %329 : i32 to i64
      %330 = arith.muli %331, %322 : i64
      %332 = arith.constant 14 : i32
      %334 = arith.extsi %332 : i32 to i64
      %333 = arith.muli %330, %334 : i64
      %335 = arith.constant 14 : i32
      %337 = arith.extsi %335 : i32 to i64
      %336 = arith.muli %326, %337 : i64
      %338 = arith.extsi %328 : i32 to i64
      func.call @pmul(%arg4, %338, %arg1, %333, %arg2, %336) : (!llvm.ptr, i64, !llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %340 = arith.constant 0 : i32
      %341 = arith.constant 2 : i32
      %343 = arith.extsi %341 : i32 to i64
      %342 = arith.muli %343, %322 : i64
      %344 = arith.constant 1 : i32
      %346 = arith.extsi %344 : i32 to i64
      %345 = arith.addi %342, %346 : i64
      %347 = arith.constant 14 : i32
      %349 = arith.extsi %347 : i32 to i64
      %348 = arith.muli %345, %349 : i64
      %350 = arith.constant 2 : i32
      %352 = arith.extsi %350 : i32 to i64
      %351 = arith.addi %352, %326 : i64
      %353 = arith.constant 14 : i32
      %355 = arith.extsi %353 : i32 to i64
      %354 = arith.muli %351, %355 : i64
      %356 = arith.extsi %340 : i32 to i64
      func.call @pmul(%arg5, %356, %arg1, %348, %arg2, %354) : (!llvm.ptr, i64, !llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %358 = arith.constant 0 : i32
      %359 = arith.constant 0 : i32
      %360 = arith.extsi %358 : i32 to i64
      %361 = arith.extsi %359 : i32 to i64
      func.call @pxorinto(%arg4, %360, %arg5, %361) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %363 = arith.constant 0 : i32
      %364 = arith.constant 0 : i32
      %365 = arith.extsi %363 : i32 to i64
      %366 = arith.extsi %364 : i32 to i64
      func.call @pred(%arg4, %365, %arg3, %366) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %368 = arith.constant 14 : i32
      %370 = arith.index_cast %318 : index to i32
      %369 = arith.muli %370, %368 : i32
      %371 = arith.constant 0 : i32
      %372 = arith.extsi %369 : i32 to i64
      %373 = arith.extsi %371 : i32 to i64
      func.call @pcopy(%arg0, %372, %arg4, %373) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %374 = arith.addi %318, %310 : index
      cf.br ^bb48(%374 : index)
    ^bb50(%375: index):
    func.return
  }
  func.func @main() -> i32 {
    %376 = arith.constant 1000000007 : i32
    %377 = arith.extsi %376 : i32 to i64
    %378 = arith.constant 1000000006 : i32
    %379 = arith.extsi %378 : i32 to i64
    %380 = arith.constant 199 : i32
    %381 = arith.extsi %380 : i32 to i64
    %383 = arith.constant 14 : i32
    %384 = arith.constant 8 : i32
    %385 = arith.extsi %383 : i32 to i64
    %386 = arith.extsi %384 : i32 to i64
    %382 = func.call @calloc(%385, %386) : (i64, i64) -> !llvm.ptr
    %387 = llvm.mlir.constant(1 : i64) : i64
    %388 = llvm.alloca %387 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %382, %388 : !llvm.ptr, !llvm.ptr
    %390 = arith.constant 14 : i32
    %391 = arith.constant 8 : i32
    %392 = arith.extsi %390 : i32 to i64
    %393 = arith.extsi %391 : i32 to i64
    %389 = func.call @calloc(%392, %393) : (i64, i64) -> !llvm.ptr
    %394 = llvm.mlir.constant(1 : i64) : i64
    %395 = llvm.alloca %394 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %389, %395 : !llvm.ptr, !llvm.ptr
    %397 = arith.constant 14 : i32
    %398 = arith.constant 8 : i32
    %399 = arith.extsi %397 : i32 to i64
    %400 = arith.extsi %398 : i32 to i64
    %396 = func.call @calloc(%399, %400) : (i64, i64) -> !llvm.ptr
    %401 = llvm.mlir.constant(1 : i64) : i64
    %402 = llvm.alloca %401 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %396, %402 : !llvm.ptr, !llvm.ptr
    %404 = arith.constant 14 : i32
    %405 = arith.constant 8 : i32
    %406 = arith.extsi %404 : i32 to i64
    %407 = arith.extsi %405 : i32 to i64
    %403 = func.call @calloc(%406, %407) : (i64, i64) -> !llvm.ptr
    %409 = arith.constant 14 : i32
    %410 = arith.constant 8 : i32
    %411 = arith.extsi %409 : i32 to i64
    %412 = arith.extsi %410 : i32 to i64
    %408 = func.call @calloc(%411, %412) : (i64, i64) -> !llvm.ptr
    %414 = arith.constant 14 : i32
    %415 = arith.constant 8 : i32
    %416 = arith.extsi %414 : i32 to i64
    %417 = arith.extsi %415 : i32 to i64
    %413 = func.call @calloc(%416, %417) : (i64, i64) -> !llvm.ptr
    %419 = arith.constant 14 : i32
    %420 = arith.constant 8 : i32
    %421 = arith.extsi %419 : i32 to i64
    %422 = arith.extsi %420 : i32 to i64
    %418 = func.call @calloc(%421, %422) : (i64, i64) -> !llvm.ptr
    %424 = arith.constant 56 : i32
    %425 = arith.constant 8 : i32
    %426 = arith.extsi %424 : i32 to i64
    %427 = arith.extsi %425 : i32 to i64
    %423 = func.call @calloc(%426, %427) : (i64, i64) -> !llvm.ptr
    %428 = llvm.mlir.constant(1 : i64) : i64
    %429 = llvm.alloca %428 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %423, %429 : !llvm.ptr, !llvm.ptr
    %431 = arith.constant 56 : i32
    %432 = arith.constant 8 : i32
    %433 = arith.extsi %431 : i32 to i64
    %434 = arith.extsi %432 : i32 to i64
    %430 = func.call @calloc(%433, %434) : (i64, i64) -> !llvm.ptr
    %435 = llvm.mlir.constant(1 : i64) : i64
    %436 = llvm.alloca %435 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %430, %436 : !llvm.ptr, !llvm.ptr
    %438 = arith.constant 56 : i32
    %439 = arith.constant 8 : i32
    %440 = arith.extsi %438 : i32 to i64
    %441 = arith.extsi %439 : i32 to i64
    %437 = func.call @calloc(%440, %441) : (i64, i64) -> !llvm.ptr
    %442 = llvm.mlir.constant(1 : i64) : i64
    %443 = llvm.alloca %442 x !llvm.ptr : (i64) -> !llvm.ptr
    llvm.store %437, %443 : !llvm.ptr, !llvm.ptr
    %444 = arith.constant 1 : i32
    %445 = llvm.load %388 : !llvm.ptr -> !llvm.ptr
    %446 = arith.constant 0 : i32
    %447 = arith.extsi %444 : i32 to i64
    %448 = arith.extsi %446 : i32 to i64
    %449 = llvm.getelementptr %445[%448] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %447, %449 : i64, !llvm.ptr
    %450 = arith.constant 2 : i32
    %451 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
    %452 = arith.constant 0 : i32
    %453 = arith.extsi %450 : i32 to i64
    %454 = arith.extsi %452 : i32 to i64
    %455 = llvm.getelementptr %451[%454] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %453, %455 : i64, !llvm.ptr
    %456 = arith.constant 2 : i32
    %457 = arith.extsi %456 : i32 to i64
    %458 = llvm.mlir.constant(1 : i64) : i64
    %459 = llvm.alloca %458 x i64 : (i64) -> !llvm.ptr
    llvm.store %457, %459 : i64, !llvm.ptr
    cf.br ^bb51
    ^bb51:
    %460 = llvm.load %459 : !llvm.ptr -> i64
    %461 = arith.cmpi sle, %460, %381 : i64
    cf.cond_br %461, ^bb52, ^bb53
    ^bb52:
      %463 = llvm.load %402 : !llvm.ptr -> !llvm.ptr
      %464 = arith.constant 0 : i32
      %465 = arith.extsi %464 : i32 to i64
      func.call @pclear(%463, %465) : (!llvm.ptr, i64) -> ()
      %467 = llvm.load %402 : !llvm.ptr -> !llvm.ptr
      %468 = arith.constant 0 : i32
      %469 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
      %470 = arith.constant 0 : i32
      %471 = arith.constant 1 : i32
      %472 = arith.extsi %468 : i32 to i64
      %473 = arith.extsi %470 : i32 to i64
      %474 = arith.extsi %471 : i32 to i64
      func.call @pxshift(%467, %472, %469, %473, %474) : (!llvm.ptr, i64, !llvm.ptr, i64, i64) -> ()
      %476 = llvm.load %402 : !llvm.ptr -> !llvm.ptr
      %477 = arith.constant 0 : i32
      %478 = llvm.load %388 : !llvm.ptr -> !llvm.ptr
      %479 = arith.constant 0 : i32
      %480 = arith.extsi %477 : i32 to i64
      %481 = arith.extsi %479 : i32 to i64
      func.call @pxorinto(%476, %480, %478, %481) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %482 = llvm.load %388 : !llvm.ptr -> !llvm.ptr
      %483 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
      llvm.store %483, %388 : !llvm.ptr, !llvm.ptr
      %484 = llvm.load %402 : !llvm.ptr -> !llvm.ptr
      llvm.store %484, %395 : !llvm.ptr, !llvm.ptr
      llvm.store %482, %402 : !llvm.ptr, !llvm.ptr
      %485 = llvm.load %459 : !llvm.ptr -> i64
      %486 = arith.constant 1 : i32
      %488 = arith.extsi %486 : i32 to i64
      %487 = arith.addi %485, %488 : i64
      llvm.store %487, %459 : i64, !llvm.ptr
      cf.br ^bb51
    ^bb53:
    %489 = arith.constant 3 : i32
    %490 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %491 = arith.constant 0 : i32
    %492 = arith.extsi %489 : i32 to i64
    %493 = arith.extsi %491 : i32 to i64
    %494 = llvm.getelementptr %490[%493] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %492, %494 : i64, !llvm.ptr
    %495 = arith.constant 1 : i32
    %496 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %497 = arith.constant 14 : i32
    %498 = arith.extsi %495 : i32 to i64
    %499 = arith.extsi %497 : i32 to i64
    %500 = llvm.getelementptr %496[%499] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %498, %500 : i64, !llvm.ptr
    %501 = arith.constant 1 : i32
    %502 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %503 = arith.constant 28 : i32
    %504 = arith.extsi %501 : i32 to i64
    %505 = arith.extsi %503 : i32 to i64
    %506 = llvm.getelementptr %502[%505] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %504, %506 : i64, !llvm.ptr
    %508 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
    %509 = arith.constant 0 : i32
    %510 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %511 = arith.constant 0 : i32
    %512 = arith.extsi %509 : i32 to i64
    %513 = arith.extsi %511 : i32 to i64
    func.call @pcopy(%508, %512, %510, %513) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
    %515 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
    %516 = arith.constant 14 : i32
    %517 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %518 = arith.constant 14 : i32
    %519 = arith.extsi %516 : i32 to i64
    %520 = arith.extsi %518 : i32 to i64
    func.call @pcopy(%515, %519, %517, %520) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
    %522 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
    %523 = arith.constant 28 : i32
    %524 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %525 = arith.constant 28 : i32
    %526 = arith.extsi %523 : i32 to i64
    %527 = arith.extsi %525 : i32 to i64
    func.call @pcopy(%522, %526, %524, %527) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
    %529 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
    %530 = arith.constant 42 : i32
    %531 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %532 = arith.constant 42 : i32
    %533 = arith.extsi %530 : i32 to i64
    %534 = arith.extsi %532 : i32 to i64
    func.call @pcopy(%529, %533, %531, %534) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
    %536 = arith.constant 0 : i32
    %537 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
    %538 = arith.constant 0 : i32
    %539 = arith.extsi %536 : i32 to i64
    %540 = arith.extsi %538 : i32 to i64
    func.call @pcopy(%413, %539, %537, %540) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
    %542 = arith.constant 0 : i32
    %543 = arith.extsi %542 : i32 to i64
    func.call @pclear(%418, %543) : (!llvm.ptr, i64) -> ()
    %544 = arith.constant 3 : i32
    %545 = arith.constant 0 : i32
    %546 = arith.extsi %544 : i32 to i64
    %547 = arith.extsi %545 : i32 to i64
    %548 = llvm.getelementptr %418[%547] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %546, %548 : i64, !llvm.ptr
    %549 = func.call @pgcddeg(%413, %418) : (!llvm.ptr, !llvm.ptr) -> i64
    %550 = arith.constant 1 : i32
    %552 = arith.extsi %550 : i32 to i64
    %551 = arith.muli %381, %552 : i64
    %553 = arith.subi %551, %549 : i64
    %554 = arith.remsi %553, %379 : i64
    %555 = arith.addi %554, %379 : i64
    %556 = arith.remsi %555, %379 : i64
    %557 = arith.constant 2 : i32
    %558 = func.call @powmod2(%556, %377) : (i64, i64) -> i64
    %560 = arith.extsi %557 : i32 to i64
    %559 = arith.muli %560, %558 : i64
    %561 = arith.remsi %559, %377 : i64
    %562 = llvm.mlir.constant(1 : i64) : i64
    %563 = llvm.alloca %562 x i64 : (i64) -> !llvm.ptr
    llvm.store %561, %563 : i64, !llvm.ptr
    %564 = arith.constant 1 : i32
    %565 = arith.extsi %564 : i32 to i64
    %566 = llvm.mlir.constant(1 : i64) : i64
    %567 = llvm.alloca %566 x i64 : (i64) -> !llvm.ptr
    llvm.store %565, %567 : i64, !llvm.ptr
    %568 = arith.constant 1 : i32
    %569 = arith.extsi %568 : i32 to i64
    %570 = llvm.mlir.constant(1 : i64) : i64
    %571 = llvm.alloca %570 x i64 : (i64) -> !llvm.ptr
    llvm.store %569, %571 : i64, !llvm.ptr
    %572 = arith.constant 3 : i32
    %573 = arith.extsi %572 : i32 to i64
    llvm.store %573, %459 : i64, !llvm.ptr
    cf.br ^bb54
    ^bb54:
    %574 = llvm.load %459 : !llvm.ptr -> i64
    %575 = arith.constant 199 : i32
    %577 = arith.extsi %575 : i32 to i64
    %576 = arith.cmpi sle, %574, %577 : i64
    cf.cond_br %576, ^bb55, ^bb56
    ^bb55:
      %579 = llvm.load %443 : !llvm.ptr -> !llvm.ptr
      %580 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
      %581 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
      %582 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
      func.call @matmul(%579, %580, %581, %582, %403, %408) : (!llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
      %583 = llvm.load %567 : !llvm.ptr -> i64
      %584 = llvm.load %571 : !llvm.ptr -> i64
      %585 = arith.addi %583, %584 : i64
      %586 = arith.remsi %585, %379 : i64
      %587 = llvm.load %436 : !llvm.ptr -> !llvm.ptr
      %588 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
      llvm.store %588, %436 : !llvm.ptr, !llvm.ptr
      %589 = llvm.load %443 : !llvm.ptr -> !llvm.ptr
      llvm.store %589, %429 : !llvm.ptr, !llvm.ptr
      llvm.store %587, %443 : !llvm.ptr, !llvm.ptr
      %590 = llvm.load %567 : !llvm.ptr -> i64
      llvm.store %590, %571 : i64, !llvm.ptr
      llvm.store %586, %567 : i64, !llvm.ptr
      %592 = arith.constant 0 : i32
      %593 = llvm.load %395 : !llvm.ptr -> !llvm.ptr
      %594 = arith.constant 0 : i32
      %595 = arith.extsi %592 : i32 to i64
      %596 = arith.extsi %594 : i32 to i64
      func.call @pcopy(%413, %595, %593, %596) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %598 = arith.constant 0 : i32
      %599 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
      %600 = arith.constant 0 : i32
      %601 = arith.extsi %598 : i32 to i64
      %602 = arith.extsi %600 : i32 to i64
      func.call @pcopy(%418, %601, %599, %602) : (!llvm.ptr, i64, !llvm.ptr, i64) -> ()
      %603 = func.call @pgcddeg(%413, %418) : (!llvm.ptr, !llvm.ptr) -> i64
      %604 = arith.muli %381, %586 : i64
      %605 = arith.subi %604, %603 : i64
      %606 = arith.remsi %605, %379 : i64
      %607 = arith.addi %606, %379 : i64
      %608 = arith.remsi %607, %379 : i64
      %609 = llvm.load %563 : !llvm.ptr -> i64
      %610 = func.call @powmod2(%608, %377) : (i64, i64) -> i64
      %611 = arith.addi %609, %610 : i64
      %612 = arith.remsi %611, %377 : i64
      llvm.store %612, %563 : i64, !llvm.ptr
      %613 = llvm.load %459 : !llvm.ptr -> i64
      %614 = arith.constant 1 : i32
      %616 = arith.extsi %614 : i32 to i64
      %615 = arith.addi %613, %616 : i64
      llvm.store %615, %459 : i64, !llvm.ptr
      cf.br ^bb54
    ^bb56:
    %617 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %618 = llvm.load %563 : !llvm.ptr -> i64
    %619 = llvm.call @printf(%617, %618) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    %620 = arith.constant 0 : i32
    func.return %620 : i32
  }
}