Problem 487

Sums of Power Sums — sum_p S_10000(10^12) mod p over primes in [2e9, 2e9+2000].

Answer106650212746
Output106650212746
StatusPASS
Native helperno
Runtime390 ms
Peak memory2704 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)?
Space complexityO(n^2)?
ApproachFlow solutionNot curated
VerdictUnknown

Flow source

# Project Euler 487
# Sums of Power Sums — sum_p S_10000(10^12) mod p over primes in [2e9, 2e9+2000].

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

function modpow(base0: i64, exp0: i64, mod: i64) -> i64 {
    let mut r: i64 = 1
    let mut b: i64 = base0 % mod
    let mut e: i64 = exp0
    while e > 0 {
        if e % 2 == 1 {
            let t: i128 = (r as i128) * (b as i128) % (mod as i128)
            r = t as i64
        }
        let t2: i128 = (b as i128) * (b as i128) % (mod as i128)
        b = t2 as i64
        e = e / 2
    }
    return r
}

function sieve_primes(limit: i64, out: ptr<i64>) -> i64 {
    let is_p: ptr<i8> = calloc(limit + 1, 1)
    let mut i: i64 = 0
    while i <= limit {
        is_p[i] = 1
        i = i + 1
    }
    is_p[0] = 0
    is_p[1] = 0
    i = 2
    while i * i <= limit {
        if is_p[i] != 0 {
            let mut j: i64 = i * i
            while j <= limit {
                is_p[j] = 0
                j = j + i
            }
        }
        i = i + 1
    }
    let mut n: i64 = 0
    i = 2
    while i <= limit {
        if is_p[i] != 0 {
            out[n] = i
            n = n + 1
        }
        i = i + 1
    }
    free(is_p)
    return n
}

function primes_in_interval(L: i64, R: i64, out: ptr<i64>) -> i64 {
    let mut lim: i64 = 1
    while lim * lim <= R {
        lim = lim + 1
    }
    lim = lim + 1
    let small: ptr<i64> = calloc(lim + 16, 8)
    let ns: i64 = sieve_primes(lim, small)
    let mut nout: i64 = 0
    let mut x: i64 = L
    while x <= R {
        let mut ok: i64 = 1
        let mut i: i64 = 0
        while i < ns {
            let p: i64 = small[i]
            if p * p > x { break }
            if x % p == 0 {
                ok = 0
                break
            }
            i = i + 1
        }
        if ok != 0 {
            out[nout] = x
            nout = nout + 1
        }
        x = x + 1
    }
    free(small)
    return nout
}

function inv_factorials(max_d: i64, p: i64, inv_fact: ptr<i64>) -> void {
    let fact: ptr<i64> = calloc(max_d + 1, 8)
    fact[0] = 1
    let mut i: i64 = 1
    while i <= max_d {
        fact[i] = (fact[i - 1] * i) % p
        i = i + 1
    }
    inv_fact[max_d] = modpow(fact[max_d], p - 2, p)
    i = max_d
    while i > 0 {
        inv_fact[i - 1] = (inv_fact[i] * i) % p
        i = i - 1
    }
    free(fact)
}

function lagrange_eval(y: ptr<i64>, n: i64, d: i64, p: i64, inv_fact: ptr<i64>) -> i64 {
    if n <= d { return y[n] }
    let pre: ptr<i64> = calloc(d + 2, 8)
    let suf: ptr<i64> = calloc(d + 2, 8)
    pre[0] = 1
    let mut i: i64 = 0
    while i <= d {
        pre[i + 1] = (pre[i] * ((n - i) % p + p) % p) % p
        i = i + 1
    }
    suf[d + 1] = 1
    i = d
    while i >= 0 {
        suf[i] = (suf[i + 1] * ((n - i) % p + p) % p) % p
        i = i - 1
    }
    let mut res: i64 = 0
    i = 0
    while i <= d {
        let num: i64 = (pre[i] * suf[i + 1]) % p
        let mut term: i64 = (y[i] * num) % p
        term = (term * inv_fact[i]) % p
        term = (term * inv_fact[d - i]) % p
        if ((d - i) & 1) != 0 {
            res = res - term
        } else {
            res = res + term
        }
        i = i + 1
    }
    free(suf)
    free(pre)
    let mut r: i64 = res % p
    if r < 0 { r = r + p }
    return r
}

function S_k_mod_prime(k: i64, n: i64, p: i64) -> i64 {
    let d1: i64 = k + 1
    let d2: i64 = k + 2
    let n0: i64 = n % p
    let inv_fact: ptr<i64> = calloc(d2 + 1, 8)
    inv_factorials(d2, p, inv_fact)
    let yk: ptr<i64> = calloc(d1 + 1, 8)
    let yk1: ptr<i64> = calloc(d2 + 1, 8)
    let mut s0: i64 = 0
    let mut s1: i64 = 0
    let mut i: i64 = 1
    while i <= d2 {
        let pk: i64 = modpow(i, k, p)
        s0 = (s0 + pk) % p
        if i <= d1 { yk[i] = s0 }
        s1 = (s1 + (pk * i) % p) % p
        yk1[i] = s1
        i = i + 1
    }
    let fk: i64 = lagrange_eval(yk, n0, d1, p, inv_fact)
    let fk1: i64 = lagrange_eval(yk1, n0, d2, p, inv_fact)
    let mut ans: i64 = (((n + 1) % p) * fk - fk1) % p
    if ans < 0 { ans = ans + p }
    free(yk1)
    free(yk)
    free(inv_fact)
    return ans
}

function main() -> i32 {
    let L: i64 = 2000000000
    let R: i64 = L + 2000
    let n: i64 = 1000000000000
    let k: i64 = 10000
    let primes: ptr<i64> = calloc(256, 8)
    let np: i64 = primes_in_interval(L, R, primes)
    let mut total: i64 = 0
    let mut i: i64 = 0
    while i < np {
        total = total + S_k_mod_prime(k, n, primes[i])
        i = i + 1
    }
    printf("%lld\n", total)
    free(primes)
    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 modpow_i64_i64_i64(int64_t base0, int64_t exp0, int64_t mod);
int64_t sieve_primes_i64_ptr_i64(int64_t limit, int64_t* out);
int64_t primes_in_interval_i64_i64_ptr_i64(int64_t L, int64_t R, int64_t* out);
void inv_factorials_i64_i64_ptr_i64(int64_t max_d, int64_t p, int64_t* inv_fact);
int64_t lagrange_eval_ptr_i64_i64_i64_i64_ptr_i64(int64_t* y, int64_t n, int64_t d, int64_t p, int64_t* inv_fact);
int64_t S_k_mod_prime_i64_i64_i64(int64_t k, int64_t n, int64_t p);
int32_t main(void);



int64_t modpow_i64_i64_i64(int64_t base0, int64_t exp0, int64_t mod) {
    int64_t r = 1;
    int64_t b = FLOW_CHECKED_MOD((base0), (mod));
    int64_t e = exp0;
    while (e > 0) {
        if (FLOW_CHECKED_MOD((e), (2)) == 1) {
            __int128 t = FLOW_CHECKED_MOD(((((__int128)(r)) * ((__int128)(b)))), (((__int128)(mod))));
            r = ((int64_t)(t));
        }
        __int128 t2 = FLOW_CHECKED_MOD(((((__int128)(b)) * ((__int128)(b)))), (((__int128)(mod))));
        b = ((int64_t)(t2));
        e = FLOW_CHECKED_DIV((e), (2));
    }
    return r;
}

int64_t sieve_primes_i64_ptr_i64(int64_t limit, int64_t* out) {
    int8_t* is_p = (int8_t*)(calloc((limit + 1), 1));
    int64_t i = 0;
    while (i <= limit) {
        is_p[i] = 1;
        i = (i + 1);
    }
    is_p[0] = 0;
    is_p[1] = 0;
    i = 2;
    while ((i * i) <= limit) {
        if (is_p[i] != 0) {
            int64_t j = (i * i);
            while (j <= limit) {
                is_p[j] = 0;
                j = (j + i);
            }
        }
        i = (i + 1);
    }
    int64_t n = 0;
    i = 2;
    while (i <= limit) {
        if (is_p[i] != 0) {
            out[n] = i;
            n = (n + 1);
        }
        i = (i + 1);
    }
    free(is_p);
    return n;
}

int64_t primes_in_interval_i64_i64_ptr_i64(int64_t L, int64_t R, int64_t* out) {
    int64_t lim = 1;
    while ((lim * lim) <= R) {
        lim = (lim + 1);
    }
    lim = (lim + 1);
    int64_t* small = (int64_t*)(calloc((lim + 16), 8));
    int64_t ns = sieve_primes_i64_ptr_i64(lim, small);
    int64_t nout = 0;
    int64_t x = L;
    while (x <= R) {
        int64_t ok = 1;
        int64_t i = 0;
        while (i < ns) {
            int64_t p = small[i];
            if ((p * p) > x) {
                break;
            }
            if (FLOW_CHECKED_MOD((x), (p)) == 0) {
                ok = 0;
                break;
            }
            i = (i + 1);
        }
        if (ok != 0) {
            out[nout] = x;
            nout = (nout + 1);
        }
        x = (x + 1);
    }
    free(small);
    return nout;
}

void inv_factorials_i64_i64_ptr_i64(int64_t max_d, int64_t p, int64_t* inv_fact) {
    int64_t* fact = (int64_t*)(calloc((max_d + 1), 8));
    fact[0] = 1;
    int64_t i = 1;
    while (i <= max_d) {
        fact[i] = FLOW_CHECKED_MOD(((fact[(i - 1)] * i)), (p));
        i = (i + 1);
    }
    inv_fact[max_d] = modpow_i64_i64_i64(fact[max_d], (p - 2), p);
    i = max_d;
    while (i > 0) {
        inv_fact[(i - 1)] = FLOW_CHECKED_MOD(((inv_fact[i] * i)), (p));
        i = (i - 1);
    }
    free(fact);
}

int64_t lagrange_eval_ptr_i64_i64_i64_i64_ptr_i64(int64_t* y, int64_t n, int64_t d, int64_t p, int64_t* inv_fact) {
    if (n <= d) {
        return y[n];
    }
    int64_t* pre = (int64_t*)(calloc((d + 2), 8));
    int64_t* suf = (int64_t*)(calloc((d + 2), 8));
    pre[0] = 1;
    int64_t i = 0;
    while (i <= d) {
        pre[(i + 1)] = FLOW_CHECKED_MOD((FLOW_CHECKED_MOD(((pre[i] * (FLOW_CHECKED_MOD(((n - i)), (p)) + p))), (p))), (p));
        i = (i + 1);
    }
    suf[(d + 1)] = 1;
    i = d;
    while (i >= 0) {
        suf[i] = FLOW_CHECKED_MOD((FLOW_CHECKED_MOD(((suf[(i + 1)] * (FLOW_CHECKED_MOD(((n - i)), (p)) + p))), (p))), (p));
        i = (i - 1);
    }
    int64_t res = 0;
    i = 0;
    while (i <= d) {
        int64_t num = FLOW_CHECKED_MOD(((pre[i] * suf[(i + 1)])), (p));
        int64_t term = FLOW_CHECKED_MOD(((y[i] * num)), (p));
        term = FLOW_CHECKED_MOD(((term * inv_fact[i])), (p));
        term = FLOW_CHECKED_MOD(((term * inv_fact[(d - i)])), (p));
        if (((d - i) & 1) != 0) {
            res = (res - term);
        } else {
            res = (res + term);
        }
        i = (i + 1);
    }
    free(suf);
    free(pre);
    int64_t r = FLOW_CHECKED_MOD((res), (p));
    if (r < 0) {
        r = (r + p);
    }
    return r;
}

int64_t S_k_mod_prime_i64_i64_i64(int64_t k, int64_t n, int64_t p) {
    int64_t d1 = (k + 1);
    int64_t d2 = (k + 2);
    int64_t n0 = FLOW_CHECKED_MOD((n), (p));
    int64_t* inv_fact = (int64_t*)(calloc((d2 + 1), 8));
    inv_factorials_i64_i64_ptr_i64(d2, p, inv_fact);
    int64_t* yk = (int64_t*)(calloc((d1 + 1), 8));
    int64_t* yk1 = (int64_t*)(calloc((d2 + 1), 8));
    int64_t s0 = 0;
    int64_t s1 = 0;
    int64_t i = 1;
    while (i <= d2) {
        int64_t pk = modpow_i64_i64_i64(i, k, p);
        s0 = FLOW_CHECKED_MOD(((s0 + pk)), (p));
        if (i <= d1) {
            yk[i] = s0;
        }
        s1 = FLOW_CHECKED_MOD(((s1 + FLOW_CHECKED_MOD(((pk * i)), (p)))), (p));
        yk1[i] = s1;
        i = (i + 1);
    }
    int64_t fk = lagrange_eval_ptr_i64_i64_i64_i64_ptr_i64(yk, n0, d1, p, inv_fact);
    int64_t fk1 = lagrange_eval_ptr_i64_i64_i64_i64_ptr_i64(yk1, n0, d2, p, inv_fact);
    int64_t ans = FLOW_CHECKED_MOD((((FLOW_CHECKED_MOD(((n + 1)), (p)) * fk) - fk1)), (p));
    if (ans < 0) {
        ans = (ans + p);
    }
    free(yk1);
    free(yk);
    free(inv_fact);
    return ans;
}

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