Problem 907

S(n) satisfies an order-8 linear recurrence for n >= 10. Compute S(10^7) mod 1e9+7 via matrix exponentiation.

Answer196808901
Output196808901
StatusPASS
Native helperno
Runtime0 ms
Peak memory1072 KB
Time complexityO(n^3) (estimated)
Space complexityO(1) (estimated)

Performance comparison

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

Flow source

# Project Euler 907: Stacking Cups
# S(n) satisfies an order-8 linear recurrence for n >= 10.
# Compute S(10^7) mod 1e9+7 via matrix exponentiation.

extern {
    function calloc(n: i64, size: i64) -> ptr<void>
    function free(p: ptr<void>) -> void
    function memset(dst: ptr<void>, val: i32, n: i64) -> void
    function memcpy(dst: ptr<void>, src: ptr<void>, n: i64) -> void
}

const MOD: i64 = 1000000007

# S(1)..S(9)
function small(n: i32) -> i64 {
    if n == 1 { return 2 }
    if n == 2 { return 2 }
    if n == 3 { return 6 }
    if n == 4 { return 12 }
    if n == 5 { return 16 }
    if n == 6 { return 22 }
    if n == 7 { return 36 }
    if n == 8 { return 58 }
    return 82
}

# Recurrence coefficients
function coeff(j: i32) -> i64 {
    if j == 0 { return 2 }
    if j == 1 { return -3 }
    if j == 2 { return 5 }
    if j == 3 { return -4 }
    if j == 4 { return 4 }
    if j == 5 { return -3 }
    if j == 6 { return 1 }
    return -1
}

function mat_mul(A: ptr<i64>, B: ptr<i64>, C: ptr<i64>) -> void {
    let tmp: ptr<i64> = calloc(64, 8)
    let mut i: i32 = 0
    while i < 8 {
        let mut j: i32 = 0
        while j < 8 {
            let mut s: i64 = 0
            let mut k: i32 = 0
            while k < 8 {
                s = (s + A[i * 8 + k] * B[k * 8 + j]) % MOD
                k = k + 1
            }
            tmp[i * 8 + j] = (s % MOD + MOD) % MOD
            j = j + 1
        }
        i = i + 1
    }
    memcpy(C as ptr<void>, tmp as ptr<void>, 64 * 8)
    free(tmp)
}

function mat_vec_mul(A: ptr<i64>, v: ptr<i64>, out: ptr<i64>) -> void {
    let mut i: i32 = 0
    while i < 8 {
        let mut s: i64 = 0
        let mut j: i32 = 0
        while j < 8 {
            s = (s + A[i * 8 + j] * v[j]) % MOD
            j = j + 1
        }
        out[i] = (s % MOD + MOD) % MOD
        i = i + 1
    }
}

function main() -> i32 {
    let n: i64 = 10000000
    if n <= 9 {
        printf("%lld\n", small(n as i32) % MOD)
        return 0
    }

    let M: ptr<i64> = calloc(64, 8)
    memset(M as ptr<void>, 0, 64 * 8)
    let mut j: i32 = 0
    while j < 8 {
        M[j] = (coeff(j) % MOD + MOD) % MOD
        j = j + 1
    }
    let mut i: i32 = 1
    while i < 8 {
        M[i * 8 + i - 1] = 1
        i = i + 1
    }

    let base: ptr<i64> = calloc(8, 8)
    base[0] = small(9) % MOD
    base[1] = small(8) % MOD
    base[2] = small(7) % MOD
    base[3] = small(6) % MOD
    base[4] = small(5) % MOD
    base[5] = small(4) % MOD
    base[6] = small(3) % MOD
    base[7] = small(2) % MOD

    let result: ptr<i64> = calloc(64, 8)
    memset(result as ptr<void>, 0, 64 * 8)
    i = 0
    while i < 8 {
        result[i * 8 + i] = 1
        i = i + 1
    }

    let base_pow: ptr<i64> = calloc(64, 8)
    memcpy(base_pow as ptr<void>, M as ptr<void>, 64 * 8)

    let mut e: i64 = n - 9
    while e > 0 {
        if (e & 1) != 0 {
            mat_mul(result, base_pow, result)
        }
        e = e >> 1
        if e > 0 {
            mat_mul(base_pow, base_pow, base_pow)
        }
    }

    let out: ptr<i64> = calloc(8, 8)
    mat_vec_mul(result, base, out)
    printf("%lld\n", out[0])

    free(M)
    free(base)
    free(result)
    free(base_pow)
    free(out)
    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 small_i32(int32_t n);
int64_t coeff_i32(int32_t j);
void mat_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* A, int64_t* B, int64_t* C);
void mat_vec_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* A, int64_t* v, int64_t* out);
int32_t main(void);

static const int64_t MOD = 1000000007;





int64_t small_i32(int32_t n) {
    if (n == 1) {
        return 2;
    }
    if (n == 2) {
        return 2;
    }
    if (n == 3) {
        return 6;
    }
    if (n == 4) {
        return 12;
    }
    if (n == 5) {
        return 16;
    }
    if (n == 6) {
        return 22;
    }
    if (n == 7) {
        return 36;
    }
    if (n == 8) {
        return 58;
    }
    return 82;
}

int64_t coeff_i32(int32_t j) {
    if (j == 0) {
        return 2;
    }
    if (j == 1) {
        return (-3);
    }
    if (j == 2) {
        return 5;
    }
    if (j == 3) {
        return (-4);
    }
    if (j == 4) {
        return 4;
    }
    if (j == 5) {
        return (-3);
    }
    if (j == 6) {
        return 1;
    }
    return (-1);
}

void mat_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* A, int64_t* B, int64_t* C) {
    int64_t* tmp = (int64_t*)(calloc(64, 8));
    int32_t i = 0;
    while (i < 8) {
        int32_t j = 0;
        while (j < 8) {
            int64_t s = 0;
            int32_t k = 0;
            while (k < 8) {
                s = FLOW_CHECKED_MOD(((s + (A[((i * 8) + k)] * B[((k * 8) + j)]))), (MOD));
                k = (k + 1);
            }
            tmp[((i * 8) + j)] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((s), (MOD)) + MOD)), (MOD));
            j = (j + 1);
        }
        i = (i + 1);
    }
    memcpy(((void*)(C)), ((void*)(tmp)), (64 * 8));
    free(tmp);
}

void mat_vec_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* A, int64_t* v, int64_t* out) {
    int32_t i = 0;
    while (i < 8) {
        int64_t s = 0;
        int32_t j = 0;
        while (j < 8) {
            s = FLOW_CHECKED_MOD(((s + (A[((i * 8) + j)] * v[j]))), (MOD));
            j = (j + 1);
        }
        out[i] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((s), (MOD)) + MOD)), (MOD));
        i = (i + 1);
    }
}

int32_t main(void) {
    int64_t n = 10000000;
    if (n <= 9) {
        printf("%lld\n", FLOW_CHECKED_MOD((small_i32(((int32_t)(n)))), (MOD)));
        return 0;
    }
    int64_t* M = (int64_t*)(calloc(64, 8));
    memset(((void*)(M)), 0, (64 * 8));
    int32_t j = 0;
    while (j < 8) {
        M[j] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((coeff_i32(j)), (MOD)) + MOD)), (MOD));
        j = (j + 1);
    }
    int32_t i = 1;
    while (i < 8) {
        M[(((i * 8) + i) - 1)] = 1;
        i = (i + 1);
    }
    int64_t* base = (int64_t*)(calloc(8, 8));
    base[0] = FLOW_CHECKED_MOD((small_i32(9)), (MOD));
    base[1] = FLOW_CHECKED_MOD((small_i32(8)), (MOD));
    base[2] = FLOW_CHECKED_MOD((small_i32(7)), (MOD));
    base[3] = FLOW_CHECKED_MOD((small_i32(6)), (MOD));
    base[4] = FLOW_CHECKED_MOD((small_i32(5)), (MOD));
    base[5] = FLOW_CHECKED_MOD((small_i32(4)), (MOD));
    base[6] = FLOW_CHECKED_MOD((small_i32(3)), (MOD));
    base[7] = FLOW_CHECKED_MOD((small_i32(2)), (MOD));
    int64_t* result = (int64_t*)(calloc(64, 8));
    memset(((void*)(result)), 0, (64 * 8));
    i = 0;
    while (i < 8) {
        result[((i * 8) + i)] = 1;
        i = (i + 1);
    }
    int64_t* base_pow = (int64_t*)(calloc(64, 8));
    memcpy(((void*)(base_pow)), ((void*)(M)), (64 * 8));
    int64_t e = (n - 9);
    while (e > 0) {
        if ((e & 1) != 0) {
            mat_mul_ptr_i64_ptr_i64_ptr_i64(result, base_pow, result);
        }
        e = FLOW_CHECKED_SHR((e), (1));
        if (e > 0) {
            mat_mul_ptr_i64_ptr_i64_ptr_i64(base_pow, base_pow, base_pow);
        }
    }
    int64_t* out = (int64_t*)(calloc(8, 8));
    mat_vec_mul_ptr_i64_ptr_i64_ptr_i64(result, base, out);
    printf("%lld\n", out[0]);
    free(M);
    free(base);
    free(result);
    free(base_pow);
    free(out);
    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 private @memset(!llvm.ptr, i32, i64) -> ()
  func.func private @memcpy(!llvm.ptr, !llvm.ptr, i64) -> ()
  // Constant: MOD
  llvm.mlir.global internal constant @MOD(1000000007 : i64) : i64
  func.func @small(%arg0: i32) -> i64 {
    %0 = arith.constant 1 : i32
    %1 = arith.cmpi eq, %arg0, %0 : i32
    cf.cond_br %1, ^bb0, ^bb1
    ^bb0:
      %2 = arith.constant 2 : i32
      %3 = arith.extsi %2 : i32 to i64
      func.return %3 : i64
    ^bb1:
      cf.br ^bb2
    ^bb2:
    %4 = arith.constant 2 : i32
    %5 = arith.cmpi eq, %arg0, %4 : i32
    cf.cond_br %5, ^bb3, ^bb4
    ^bb3:
      %6 = arith.constant 2 : i32
      %7 = arith.extsi %6 : i32 to i64
      func.return %7 : i64
    ^bb4:
      cf.br ^bb5
    ^bb5:
    %8 = arith.constant 3 : i32
    %9 = arith.cmpi eq, %arg0, %8 : i32
    cf.cond_br %9, ^bb6, ^bb7
    ^bb6:
      %10 = arith.constant 6 : i32
      %11 = arith.extsi %10 : i32 to i64
      func.return %11 : i64
    ^bb7:
      cf.br ^bb8
    ^bb8:
    %12 = arith.constant 4 : i32
    %13 = arith.cmpi eq, %arg0, %12 : i32
    cf.cond_br %13, ^bb9, ^bb10
    ^bb9:
      %14 = arith.constant 12 : i32
      %15 = arith.extsi %14 : i32 to i64
      func.return %15 : i64
    ^bb10:
      cf.br ^bb11
    ^bb11:
    %16 = arith.constant 5 : i32
    %17 = arith.cmpi eq, %arg0, %16 : i32
    cf.cond_br %17, ^bb12, ^bb13
    ^bb12:
      %18 = arith.constant 16 : i32
      %19 = arith.extsi %18 : i32 to i64
      func.return %19 : i64
    ^bb13:
      cf.br ^bb14
    ^bb14:
    %20 = arith.constant 6 : i32
    %21 = arith.cmpi eq, %arg0, %20 : i32
    cf.cond_br %21, ^bb15, ^bb16
    ^bb15:
      %22 = arith.constant 22 : i32
      %23 = arith.extsi %22 : i32 to i64
      func.return %23 : i64
    ^bb16:
      cf.br ^bb17
    ^bb17:
    %24 = arith.constant 7 : i32
    %25 = arith.cmpi eq, %arg0, %24 : i32
    cf.cond_br %25, ^bb18, ^bb19
    ^bb18:
      %26 = arith.constant 36 : i32
      %27 = arith.extsi %26 : i32 to i64
      func.return %27 : i64
    ^bb19:
      cf.br ^bb20
    ^bb20:
    %28 = arith.constant 8 : i32
    %29 = arith.cmpi eq, %arg0, %28 : i32
    cf.cond_br %29, ^bb21, ^bb22
    ^bb21:
      %30 = arith.constant 58 : i32
      %31 = arith.extsi %30 : i32 to i64
      func.return %31 : i64
    ^bb22:
      cf.br ^bb23
    ^bb23:
    %32 = arith.constant 82 : i32
    %33 = arith.extsi %32 : i32 to i64
    func.return %33 : i64
  }
  func.func @coeff(%arg0: i32) -> i64 {
    %34 = arith.constant 0 : i32
    %35 = arith.cmpi eq, %arg0, %34 : i32
    cf.cond_br %35, ^bb24, ^bb25
    ^bb24:
      %36 = arith.constant 2 : i32
      %37 = arith.extsi %36 : i32 to i64
      func.return %37 : i64
    ^bb25:
      cf.br ^bb26
    ^bb26:
    %38 = arith.constant 1 : i32
    %39 = arith.cmpi eq, %arg0, %38 : i32
    cf.cond_br %39, ^bb27, ^bb28
    ^bb27:
      %40 = arith.constant 3 : i32
      %42 = arith.constant 0 : i32
      %41 = arith.subi %42, %40 : i32
      %43 = arith.extsi %41 : i32 to i64
      func.return %43 : i64
    ^bb28:
      cf.br ^bb29
    ^bb29:
    %44 = arith.constant 2 : i32
    %45 = arith.cmpi eq, %arg0, %44 : i32
    cf.cond_br %45, ^bb30, ^bb31
    ^bb30:
      %46 = arith.constant 5 : i32
      %47 = arith.extsi %46 : i32 to i64
      func.return %47 : i64
    ^bb31:
      cf.br ^bb32
    ^bb32:
    %48 = arith.constant 3 : i32
    %49 = arith.cmpi eq, %arg0, %48 : i32
    cf.cond_br %49, ^bb33, ^bb34
    ^bb33:
      %50 = arith.constant 4 : i32
      %52 = arith.constant 0 : i32
      %51 = arith.subi %52, %50 : i32
      %53 = arith.extsi %51 : i32 to i64
      func.return %53 : i64
    ^bb34:
      cf.br ^bb35
    ^bb35:
    %54 = arith.constant 4 : i32
    %55 = arith.cmpi eq, %arg0, %54 : i32
    cf.cond_br %55, ^bb36, ^bb37
    ^bb36:
      %56 = arith.constant 4 : i32
      %57 = arith.extsi %56 : i32 to i64
      func.return %57 : i64
    ^bb37:
      cf.br ^bb38
    ^bb38:
    %58 = arith.constant 5 : i32
    %59 = arith.cmpi eq, %arg0, %58 : i32
    cf.cond_br %59, ^bb39, ^bb40
    ^bb39:
      %60 = arith.constant 3 : i32
      %62 = arith.constant 0 : i32
      %61 = arith.subi %62, %60 : i32
      %63 = arith.extsi %61 : i32 to i64
      func.return %63 : i64
    ^bb40:
      cf.br ^bb41
    ^bb41:
    %64 = arith.constant 6 : i32
    %65 = arith.cmpi eq, %arg0, %64 : i32
    cf.cond_br %65, ^bb42, ^bb43
    ^bb42:
      %66 = arith.constant 1 : i32
      %67 = arith.extsi %66 : i32 to i64
      func.return %67 : i64
    ^bb43:
      cf.br ^bb44
    ^bb44:
    %68 = arith.constant 1 : i32
    %70 = arith.constant 0 : i32
    %69 = arith.subi %70, %68 : i32
    %71 = arith.extsi %69 : i32 to i64
    func.return %71 : i64
  }
  func.func @mat_mul(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> () {
    %73 = arith.constant 64 : i32
    %74 = arith.constant 8 : i32
    %75 = arith.extsi %73 : i32 to i64
    %76 = arith.extsi %74 : i32 to i64
    %72 = func.call @calloc(%75, %76) : (i64, i64) -> !llvm.ptr
    %77 = arith.constant 0 : i32
    %78 = llvm.mlir.constant(1 : i64) : i64
    %79 = llvm.alloca %78 x i32 : (i64) -> !llvm.ptr
    llvm.store %77, %79 : i32, !llvm.ptr
    cf.br ^bb45
    ^bb45:
    %80 = llvm.load %79 : !llvm.ptr -> i32
    %81 = arith.constant 8 : i32
    %82 = arith.cmpi slt, %80, %81 : i32
    cf.cond_br %82, ^bb46, ^bb47
    ^bb46:
      %83 = arith.constant 0 : i32
      %84 = llvm.mlir.constant(1 : i64) : i64
      %85 = llvm.alloca %84 x i32 : (i64) -> !llvm.ptr
      llvm.store %83, %85 : i32, !llvm.ptr
      cf.br ^bb48
      ^bb48:
      %86 = llvm.load %85 : !llvm.ptr -> i32
      %87 = arith.constant 8 : i32
      %88 = arith.cmpi slt, %86, %87 : i32
      cf.cond_br %88, ^bb49, ^bb50
      ^bb49:
        %89 = arith.constant 0 : i32
        %90 = arith.extsi %89 : i32 to i64
        %91 = llvm.mlir.constant(1 : i64) : i64
        %92 = llvm.alloca %91 x i64 : (i64) -> !llvm.ptr
        llvm.store %90, %92 : i64, !llvm.ptr
        %93 = arith.constant 0 : i32
        %94 = llvm.mlir.constant(1 : i64) : i64
        %95 = llvm.alloca %94 x i32 : (i64) -> !llvm.ptr
        llvm.store %93, %95 : i32, !llvm.ptr
        cf.br ^bb51
        ^bb51:
        %96 = llvm.load %95 : !llvm.ptr -> i32
        %97 = arith.constant 8 : i32
        %98 = arith.cmpi slt, %96, %97 : i32
        cf.cond_br %98, ^bb52, ^bb53
        ^bb52:
          %99 = llvm.load %92 : !llvm.ptr -> i64
          %101 = llvm.load %79 : !llvm.ptr -> i32
          %102 = arith.constant 8 : i32
          %103 = arith.muli %101, %102 : i32
          %104 = llvm.load %95 : !llvm.ptr -> i32
          %105 = arith.addi %103, %104 : i32
          %106 = arith.extsi %105 : i32 to i64
          %107 = llvm.getelementptr %arg0[%106] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %100 = llvm.load %107 : !llvm.ptr -> i64
          %109 = llvm.load %95 : !llvm.ptr -> i32
          %110 = arith.constant 8 : i32
          %111 = arith.muli %109, %110 : i32
          %112 = llvm.load %85 : !llvm.ptr -> i32
          %113 = arith.addi %111, %112 : i32
          %114 = arith.extsi %113 : i32 to i64
          %115 = llvm.getelementptr %arg1[%114] : (!llvm.ptr, i64) -> !llvm.ptr, i64
          %108 = llvm.load %115 : !llvm.ptr -> i64
          %116 = arith.muli %100, %108 : i64
          %117 = arith.addi %99, %116 : i64
          %118 = llvm.mlir.addressof @MOD : !llvm.ptr
          %119 = llvm.load %118 : !llvm.ptr -> i64
          %120 = arith.remsi %117, %119 : i64
          llvm.store %120, %92 : i64, !llvm.ptr
          %121 = llvm.load %95 : !llvm.ptr -> i32
          %122 = arith.constant 1 : i32
          %123 = arith.addi %121, %122 : i32
          llvm.store %123, %95 : i32, !llvm.ptr
          cf.br ^bb51
        ^bb53:
        %124 = llvm.load %92 : !llvm.ptr -> i64
        %125 = llvm.mlir.addressof @MOD : !llvm.ptr
        %126 = llvm.load %125 : !llvm.ptr -> i64
        %127 = arith.remsi %124, %126 : i64
        %128 = llvm.mlir.addressof @MOD : !llvm.ptr
        %129 = llvm.load %128 : !llvm.ptr -> i64
        %130 = arith.addi %127, %129 : i64
        %131 = llvm.mlir.addressof @MOD : !llvm.ptr
        %132 = llvm.load %131 : !llvm.ptr -> i64
        %133 = arith.remsi %130, %132 : i64
        %134 = llvm.load %79 : !llvm.ptr -> i32
        %135 = arith.constant 8 : i32
        %136 = arith.muli %134, %135 : i32
        %137 = llvm.load %85 : !llvm.ptr -> i32
        %138 = arith.addi %136, %137 : i32
        %139 = arith.extsi %138 : i32 to i64
        %140 = llvm.getelementptr %72[%139] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %133, %140 : i64, !llvm.ptr
        %141 = llvm.load %85 : !llvm.ptr -> i32
        %142 = arith.constant 1 : i32
        %143 = arith.addi %141, %142 : i32
        llvm.store %143, %85 : i32, !llvm.ptr
        cf.br ^bb48
      ^bb50:
      %144 = llvm.load %79 : !llvm.ptr -> i32
      %145 = arith.constant 1 : i32
      %146 = arith.addi %144, %145 : i32
      llvm.store %146, %79 : i32, !llvm.ptr
      cf.br ^bb45
    ^bb47:
    %148 = arith.constant 64 : i32
    %149 = arith.constant 8 : i32
    %150 = arith.muli %148, %149 : i32
    %151 = arith.extsi %150 : i32 to i64
    func.call @memcpy(%arg2, %72, %151) : (!llvm.ptr, !llvm.ptr, i64) -> ()
    func.call @free(%72) : (!llvm.ptr) -> ()
    func.return
  }
  func.func @mat_vec_mul(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> () {
    %153 = arith.constant 0 : i32
    %154 = llvm.mlir.constant(1 : i64) : i64
    %155 = llvm.alloca %154 x i32 : (i64) -> !llvm.ptr
    llvm.store %153, %155 : i32, !llvm.ptr
    cf.br ^bb54
    ^bb54:
    %156 = llvm.load %155 : !llvm.ptr -> i32
    %157 = arith.constant 8 : i32
    %158 = arith.cmpi slt, %156, %157 : i32
    cf.cond_br %158, ^bb55, ^bb56
    ^bb55:
      %159 = arith.constant 0 : i32
      %160 = arith.extsi %159 : i32 to i64
      %161 = llvm.mlir.constant(1 : i64) : i64
      %162 = llvm.alloca %161 x i64 : (i64) -> !llvm.ptr
      llvm.store %160, %162 : i64, !llvm.ptr
      %163 = arith.constant 0 : i32
      %164 = llvm.mlir.constant(1 : i64) : i64
      %165 = llvm.alloca %164 x i32 : (i64) -> !llvm.ptr
      llvm.store %163, %165 : i32, !llvm.ptr
      cf.br ^bb57
      ^bb57:
      %166 = llvm.load %165 : !llvm.ptr -> i32
      %167 = arith.constant 8 : i32
      %168 = arith.cmpi slt, %166, %167 : i32
      cf.cond_br %168, ^bb58, ^bb59
      ^bb58:
        %169 = llvm.load %162 : !llvm.ptr -> i64
        %171 = llvm.load %155 : !llvm.ptr -> i32
        %172 = arith.constant 8 : i32
        %173 = arith.muli %171, %172 : i32
        %174 = llvm.load %165 : !llvm.ptr -> i32
        %175 = arith.addi %173, %174 : i32
        %176 = arith.extsi %175 : i32 to i64
        %177 = llvm.getelementptr %arg0[%176] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %170 = llvm.load %177 : !llvm.ptr -> i64
        %179 = llvm.load %165 : !llvm.ptr -> i32
        %180 = arith.extsi %179 : i32 to i64
        %181 = llvm.getelementptr %arg1[%180] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %178 = llvm.load %181 : !llvm.ptr -> i64
        %182 = arith.muli %170, %178 : i64
        %183 = arith.addi %169, %182 : i64
        %184 = llvm.mlir.addressof @MOD : !llvm.ptr
        %185 = llvm.load %184 : !llvm.ptr -> i64
        %186 = arith.remsi %183, %185 : i64
        llvm.store %186, %162 : i64, !llvm.ptr
        %187 = llvm.load %165 : !llvm.ptr -> i32
        %188 = arith.constant 1 : i32
        %189 = arith.addi %187, %188 : i32
        llvm.store %189, %165 : i32, !llvm.ptr
        cf.br ^bb57
      ^bb59:
      %190 = llvm.load %162 : !llvm.ptr -> i64
      %191 = llvm.mlir.addressof @MOD : !llvm.ptr
      %192 = llvm.load %191 : !llvm.ptr -> i64
      %193 = arith.remsi %190, %192 : i64
      %194 = llvm.mlir.addressof @MOD : !llvm.ptr
      %195 = llvm.load %194 : !llvm.ptr -> i64
      %196 = arith.addi %193, %195 : i64
      %197 = llvm.mlir.addressof @MOD : !llvm.ptr
      %198 = llvm.load %197 : !llvm.ptr -> i64
      %199 = arith.remsi %196, %198 : i64
      %200 = llvm.load %155 : !llvm.ptr -> i32
      %201 = arith.extsi %200 : i32 to i64
      %202 = llvm.getelementptr %arg2[%201] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %199, %202 : i64, !llvm.ptr
      %203 = llvm.load %155 : !llvm.ptr -> i32
      %204 = arith.constant 1 : i32
      %205 = arith.addi %203, %204 : i32
      llvm.store %205, %155 : i32, !llvm.ptr
      cf.br ^bb54
    ^bb56:
    func.return
  }
  func.func @main() -> i32 {
    %206 = arith.constant 10000000 : i32
    %207 = arith.extsi %206 : i32 to i64
    %208 = arith.constant 9 : i32
    %210 = arith.extsi %208 : i32 to i64
    %209 = arith.cmpi sle, %207, %210 : i64
    cf.cond_br %209, ^bb60, ^bb61
    ^bb60:
      %211 = llvm.mlir.addressof @str_0 : !llvm.ptr
      %213 = arith.trunci %207 : i64 to i32
      %212 = func.call @small(%213) : (i32) -> i64
      %214 = llvm.mlir.addressof @MOD : !llvm.ptr
      %215 = llvm.load %214 : !llvm.ptr -> i64
      %216 = arith.remsi %212, %215 : i64
      %217 = llvm.call @printf(%211, %216) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
      %218 = arith.constant 0 : i32
      func.return %218 : i32
    ^bb61:
      cf.br ^bb62
    ^bb62:
    %220 = arith.constant 64 : i32
    %221 = arith.constant 8 : i32
    %222 = arith.extsi %220 : i32 to i64
    %223 = arith.extsi %221 : i32 to i64
    %219 = func.call @calloc(%222, %223) : (i64, i64) -> !llvm.ptr
    %225 = arith.constant 0 : i32
    %226 = arith.constant 64 : i32
    %227 = arith.constant 8 : i32
    %228 = arith.muli %226, %227 : i32
    %229 = arith.extsi %228 : i32 to i64
    func.call @memset(%219, %225, %229) : (!llvm.ptr, i32, i64) -> ()
    %230 = arith.constant 0 : i32
    %231 = llvm.mlir.constant(1 : i64) : i64
    %232 = llvm.alloca %231 x i32 : (i64) -> !llvm.ptr
    llvm.store %230, %232 : i32, !llvm.ptr
    cf.br ^bb63
    ^bb63:
    %233 = llvm.load %232 : !llvm.ptr -> i32
    %234 = arith.constant 8 : i32
    %235 = arith.cmpi slt, %233, %234 : i32
    cf.cond_br %235, ^bb64, ^bb65
    ^bb64:
      %237 = llvm.load %232 : !llvm.ptr -> i32
      %236 = func.call @coeff(%237) : (i32) -> i64
      %238 = llvm.mlir.addressof @MOD : !llvm.ptr
      %239 = llvm.load %238 : !llvm.ptr -> i64
      %240 = arith.remsi %236, %239 : i64
      %241 = llvm.mlir.addressof @MOD : !llvm.ptr
      %242 = llvm.load %241 : !llvm.ptr -> i64
      %243 = arith.addi %240, %242 : i64
      %244 = llvm.mlir.addressof @MOD : !llvm.ptr
      %245 = llvm.load %244 : !llvm.ptr -> i64
      %246 = arith.remsi %243, %245 : i64
      %247 = llvm.load %232 : !llvm.ptr -> i32
      %248 = arith.extsi %247 : i32 to i64
      %249 = llvm.getelementptr %219[%248] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %246, %249 : i64, !llvm.ptr
      %250 = llvm.load %232 : !llvm.ptr -> i32
      %251 = arith.constant 1 : i32
      %252 = arith.addi %250, %251 : i32
      llvm.store %252, %232 : i32, !llvm.ptr
      cf.br ^bb63
    ^bb65:
    %253 = arith.constant 1 : i32
    %254 = llvm.mlir.constant(1 : i64) : i64
    %255 = llvm.alloca %254 x i32 : (i64) -> !llvm.ptr
    llvm.store %253, %255 : i32, !llvm.ptr
    cf.br ^bb66
    ^bb66:
    %256 = llvm.load %255 : !llvm.ptr -> i32
    %257 = arith.constant 8 : i32
    %258 = arith.cmpi slt, %256, %257 : i32
    cf.cond_br %258, ^bb67, ^bb68
    ^bb67:
      %259 = arith.constant 1 : i32
      %260 = llvm.load %255 : !llvm.ptr -> i32
      %261 = arith.constant 8 : i32
      %262 = arith.muli %260, %261 : i32
      %263 = llvm.load %255 : !llvm.ptr -> i32
      %264 = arith.addi %262, %263 : i32
      %265 = arith.constant 1 : i32
      %266 = arith.subi %264, %265 : i32
      %267 = arith.extsi %259 : i32 to i64
      %268 = arith.extsi %266 : i32 to i64
      %269 = llvm.getelementptr %219[%268] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %267, %269 : i64, !llvm.ptr
      %270 = llvm.load %255 : !llvm.ptr -> i32
      %271 = arith.constant 1 : i32
      %272 = arith.addi %270, %271 : i32
      llvm.store %272, %255 : i32, !llvm.ptr
      cf.br ^bb66
    ^bb68:
    %274 = arith.constant 8 : i32
    %275 = arith.constant 8 : i32
    %276 = arith.extsi %274 : i32 to i64
    %277 = arith.extsi %275 : i32 to i64
    %273 = func.call @calloc(%276, %277) : (i64, i64) -> !llvm.ptr
    %279 = arith.constant 9 : i32
    %278 = func.call @small(%279) : (i32) -> i64
    %280 = llvm.mlir.addressof @MOD : !llvm.ptr
    %281 = llvm.load %280 : !llvm.ptr -> i64
    %282 = arith.remsi %278, %281 : i64
    %283 = arith.constant 0 : i32
    %284 = arith.extsi %283 : i32 to i64
    %285 = llvm.getelementptr %273[%284] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %282, %285 : i64, !llvm.ptr
    %287 = arith.constant 8 : i32
    %286 = func.call @small(%287) : (i32) -> i64
    %288 = llvm.mlir.addressof @MOD : !llvm.ptr
    %289 = llvm.load %288 : !llvm.ptr -> i64
    %290 = arith.remsi %286, %289 : i64
    %291 = arith.constant 1 : i32
    %292 = arith.extsi %291 : i32 to i64
    %293 = llvm.getelementptr %273[%292] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %290, %293 : i64, !llvm.ptr
    %295 = arith.constant 7 : i32
    %294 = func.call @small(%295) : (i32) -> i64
    %296 = llvm.mlir.addressof @MOD : !llvm.ptr
    %297 = llvm.load %296 : !llvm.ptr -> i64
    %298 = arith.remsi %294, %297 : i64
    %299 = arith.constant 2 : i32
    %300 = arith.extsi %299 : i32 to i64
    %301 = llvm.getelementptr %273[%300] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %298, %301 : i64, !llvm.ptr
    %303 = arith.constant 6 : i32
    %302 = func.call @small(%303) : (i32) -> i64
    %304 = llvm.mlir.addressof @MOD : !llvm.ptr
    %305 = llvm.load %304 : !llvm.ptr -> i64
    %306 = arith.remsi %302, %305 : i64
    %307 = arith.constant 3 : i32
    %308 = arith.extsi %307 : i32 to i64
    %309 = llvm.getelementptr %273[%308] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %306, %309 : i64, !llvm.ptr
    %311 = arith.constant 5 : i32
    %310 = func.call @small(%311) : (i32) -> i64
    %312 = llvm.mlir.addressof @MOD : !llvm.ptr
    %313 = llvm.load %312 : !llvm.ptr -> i64
    %314 = arith.remsi %310, %313 : i64
    %315 = arith.constant 4 : i32
    %316 = arith.extsi %315 : i32 to i64
    %317 = llvm.getelementptr %273[%316] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %314, %317 : i64, !llvm.ptr
    %319 = arith.constant 4 : i32
    %318 = func.call @small(%319) : (i32) -> i64
    %320 = llvm.mlir.addressof @MOD : !llvm.ptr
    %321 = llvm.load %320 : !llvm.ptr -> i64
    %322 = arith.remsi %318, %321 : i64
    %323 = arith.constant 5 : i32
    %324 = arith.extsi %323 : i32 to i64
    %325 = llvm.getelementptr %273[%324] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %322, %325 : i64, !llvm.ptr
    %327 = arith.constant 3 : i32
    %326 = func.call @small(%327) : (i32) -> i64
    %328 = llvm.mlir.addressof @MOD : !llvm.ptr
    %329 = llvm.load %328 : !llvm.ptr -> i64
    %330 = arith.remsi %326, %329 : i64
    %331 = arith.constant 6 : i32
    %332 = arith.extsi %331 : i32 to i64
    %333 = llvm.getelementptr %273[%332] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %330, %333 : i64, !llvm.ptr
    %335 = arith.constant 2 : i32
    %334 = func.call @small(%335) : (i32) -> i64
    %336 = llvm.mlir.addressof @MOD : !llvm.ptr
    %337 = llvm.load %336 : !llvm.ptr -> i64
    %338 = arith.remsi %334, %337 : i64
    %339 = arith.constant 7 : i32
    %340 = arith.extsi %339 : i32 to i64
    %341 = llvm.getelementptr %273[%340] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %338, %341 : i64, !llvm.ptr
    %343 = arith.constant 64 : i32
    %344 = arith.constant 8 : i32
    %345 = arith.extsi %343 : i32 to i64
    %346 = arith.extsi %344 : i32 to i64
    %342 = func.call @calloc(%345, %346) : (i64, i64) -> !llvm.ptr
    %348 = arith.constant 0 : i32
    %349 = arith.constant 64 : i32
    %350 = arith.constant 8 : i32
    %351 = arith.muli %349, %350 : i32
    %352 = arith.extsi %351 : i32 to i64
    func.call @memset(%342, %348, %352) : (!llvm.ptr, i32, i64) -> ()
    %353 = arith.constant 0 : i32
    llvm.store %353, %255 : i32, !llvm.ptr
    cf.br ^bb69
    ^bb69:
    %354 = llvm.load %255 : !llvm.ptr -> i32
    %355 = arith.constant 8 : i32
    %356 = arith.cmpi slt, %354, %355 : i32
    cf.cond_br %356, ^bb70, ^bb71
    ^bb70:
      %357 = arith.constant 1 : i32
      %358 = llvm.load %255 : !llvm.ptr -> i32
      %359 = arith.constant 8 : i32
      %360 = arith.muli %358, %359 : i32
      %361 = llvm.load %255 : !llvm.ptr -> i32
      %362 = arith.addi %360, %361 : i32
      %363 = arith.extsi %357 : i32 to i64
      %364 = arith.extsi %362 : i32 to i64
      %365 = llvm.getelementptr %342[%364] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %363, %365 : i64, !llvm.ptr
      %366 = llvm.load %255 : !llvm.ptr -> i32
      %367 = arith.constant 1 : i32
      %368 = arith.addi %366, %367 : i32
      llvm.store %368, %255 : i32, !llvm.ptr
      cf.br ^bb69
    ^bb71:
    %370 = arith.constant 64 : i32
    %371 = arith.constant 8 : i32
    %372 = arith.extsi %370 : i32 to i64
    %373 = arith.extsi %371 : i32 to i64
    %369 = func.call @calloc(%372, %373) : (i64, i64) -> !llvm.ptr
    %375 = arith.constant 64 : i32
    %376 = arith.constant 8 : i32
    %377 = arith.muli %375, %376 : i32
    %378 = arith.extsi %377 : i32 to i64
    func.call @memcpy(%369, %219, %378) : (!llvm.ptr, !llvm.ptr, i64) -> ()
    %379 = arith.constant 9 : i32
    %381 = arith.extsi %379 : i32 to i64
    %380 = arith.subi %207, %381 : i64
    %382 = llvm.mlir.constant(1 : i64) : i64
    %383 = llvm.alloca %382 x i64 : (i64) -> !llvm.ptr
    llvm.store %380, %383 : i64, !llvm.ptr
    cf.br ^bb72
    ^bb72:
    %384 = llvm.load %383 : !llvm.ptr -> i64
    %385 = arith.constant 0 : i32
    %387 = arith.extsi %385 : i32 to i64
    %386 = arith.cmpi sgt, %384, %387 : i64
    cf.cond_br %386, ^bb73, ^bb74
    ^bb73:
      %388 = llvm.load %383 : !llvm.ptr -> i64
      %389 = arith.constant 1 : i32
      %391 = arith.extsi %389 : i32 to i64
      %390 = arith.andi %388, %391 : i64
      %392 = arith.constant 0 : i32
      %394 = arith.extsi %392 : i32 to i64
      %393 = arith.cmpi ne, %390, %394 : i64
      cf.cond_br %393, ^bb75, ^bb76
      ^bb75:
        func.call @mat_mul(%342, %369, %342) : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
        cf.br ^bb77
      ^bb76:
        cf.br ^bb77
      ^bb77:
      %396 = llvm.load %383 : !llvm.ptr -> i64
      %397 = arith.constant 1 : i32
      %399 = arith.extsi %397 : i32 to i64
      %398 = arith.shrsi %396, %399 : i64
      llvm.store %398, %383 : i64, !llvm.ptr
      %400 = llvm.load %383 : !llvm.ptr -> i64
      %401 = arith.constant 0 : i32
      %403 = arith.extsi %401 : i32 to i64
      %402 = arith.cmpi sgt, %400, %403 : i64
      cf.cond_br %402, ^bb78, ^bb79
      ^bb78:
        func.call @mat_mul(%369, %369, %369) : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
        cf.br ^bb80
      ^bb79:
        cf.br ^bb80
      ^bb80:
      cf.br ^bb72
    ^bb74:
    %406 = arith.constant 8 : i32
    %407 = arith.constant 8 : i32
    %408 = arith.extsi %406 : i32 to i64
    %409 = arith.extsi %407 : i32 to i64
    %405 = func.call @calloc(%408, %409) : (i64, i64) -> !llvm.ptr
    func.call @mat_vec_mul(%342, %273, %405) : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
    %411 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %413 = arith.constant 0 : i32
    %414 = arith.extsi %413 : i32 to i64
    %415 = llvm.getelementptr %405[%414] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %412 = llvm.load %415 : !llvm.ptr -> i64
    %416 = llvm.call @printf(%411, %412) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    func.call @free(%219) : (!llvm.ptr) -> ()
    func.call @free(%273) : (!llvm.ptr) -> ()
    func.call @free(%342) : (!llvm.ptr) -> ()
    func.call @free(%369) : (!llvm.ptr) -> ()
    func.call @free(%405) : (!llvm.ptr) -> ()
    %422 = arith.constant 0 : i32
    func.return %422 : i32
  }
}