Problem 758

Buckets of Water: sum over prime pairs p<q<1000 of the minimal pour count P(2^{p^5}-1, 2^{q^5}-1), modulo 1e9+7. P(a,b) = 2*(pen_p + pen_q) - 2 where pen_p/pen_q is the penultimate convergent of b/a. For Mersenne arguments the Euclidean step reduces to Euclid on the exponents, so CF terms are computed mod MOD.

Answer331196954
Output331196954
StatusPASS
Native helperno
Runtime3690 ms
Peak memory1104 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)O(n log log n)
Space complexityO(n^2)O(n)
ApproachFlow solutionSieve of Eratosthenes
VerdictSuboptimal

Flow source

# Project Euler 758
# Buckets of Water: sum over prime pairs p<q<1000 of the minimal pour
# count P(2^{p^5}-1, 2^{q^5}-1), modulo 1e9+7.
#
# P(a,b) = 2*(pen_p + pen_q) - 2 where pen_p/pen_q is the penultimate
# convergent of b/a.  For Mersenne arguments the Euclidean step reduces
# to Euclid on the exponents, so CF terms are computed mod MOD.

import euler.nt { mod_pow }

const MOD: i64 = 1000000007

function mulmod(a0: i64, b0: i64) -> i64 {
    let a: i64 = a0 % MOD
    let b: i64 = b0 % MOD
    return a * b % MOD
}

function invmod(a: i64) -> i64 {
    return mod_pow(a % MOD, MOD - 2, MOD)
}

# S = 1 + ratio + ... + ratio^(m-1) (mod MOD), m >= 1.
function geom_sum_ratio(ratio0: i64, m: i64) -> i64 {
    if m <= 0 {
        return 0
    }
    let mut ratio: i64 = ratio0 % MOD
    if ratio < 0 {
        ratio = ratio + MOD
    }
    if ratio == 1 {
        return m % MOD
    }
    let rm: i64 = mod_pow(ratio, m, MOD)
    let mut num: i64 = (rm - 1) % MOD
    if num < 0 {
        num = num + MOD
    }
    return mulmod(num, invmod(ratio - 1))
}

# Continued-fraction terms of (2^e_large - 1)/(2^e_small - 1), each mod MOD.
# Writes into terms[] and returns the count.
function cf_terms_mersenne(e_small: i64, e_large: i64, terms: ptr<i64>, cap: i32) -> i32 {
    let mut n: i32 = 0
    let mut hi: i64 = e_large
    let mut lo: i64 = e_small
    while true {
        let m: i64 = hi / lo
        let r: i64 = hi % lo
        let ratio: i64 = mod_pow(2, lo, MOD)
        let shift: i64 = mod_pow(2, r, MOD)
        let series: i64 = geom_sum_ratio(ratio, m)
        let q_mod: i64 = mulmod(shift, series)
        terms[n] = q_mod
        n = n + 1
        if r == 0 {
            break
        }
        hi = lo
        lo = r
    }
    return n
}

# Penultimate convergent (p, q) of the CF with the given terms, mod MOD.
function pen_p(terms: ptr<i64>, n: i32) -> i64 {
    let mut p_m2: i64 = 0
    let mut p_m1: i64 = 1
    let mut last_p: i64 = 0
    let mut prev_p: i64 = 0
    for i in 0..n {
        let a: i64 = terms[i]
        let p: i64 = (mulmod(a, p_m1) + p_m2) % MOD
        prev_p = last_p
        last_p = p
        p_m2 = p_m1
        p_m1 = p
    }
    if n == 1 {
        return last_p
    }
    return prev_p
}

function pen_q(terms: ptr<i64>, n: i32) -> i64 {
    let mut q_m2: i64 = 1
    let mut q_m1: i64 = 0
    let mut last_q: i64 = 0
    let mut prev_q: i64 = 0
    for i in 0..n {
        let a: i64 = terms[i]
        let q: i64 = (mulmod(a, q_m1) + q_m2) % MOD
        prev_q = last_q
        last_q = q
        q_m2 = q_m1
        q_m1 = q
    }
    if n == 1 {
        return last_q
    }
    return prev_q
}

function P_mersenne_exponents(ea: i64, eb: i64, terms: ptr<i64>) -> i64 {
    let n: i32 = cf_terms_mersenne(ea, eb, terms, 256)
    let p: i64 = pen_p(terms, n)
    let q: i64 = pen_q(terms, n)
    let s: i64 = (p + q) % MOD
    let mut result: i64 = (2 * s - 2) % MOD
    if result < 0 {
        result = result + MOD
    }
    return result
}

function primes_below(n: i32, out: ptr<i32>) -> i32 {
    let sieve: ptr<i8> = calloc((n as i64), 1)
    for i in 0..n {
        sieve[i] = 1
    }
    let mut p: i32 = 2
    while (p as i64) * (p as i64) < (n as i64) {
        if sieve[p] != 0 {
            let mut k: i32 = p * p
            while k < n {
                sieve[k] = 0
                k = k + p
            }
        }
        p = p + 1
    }
    let mut count: i32 = 0
    for i in 0..n {
        if i >= 2 {
            if sieve[i] != 0 {
                out[count] = i
                count = count + 1
            }
        }
    }
    free(sieve)
    return count
}

function main() -> i32 {
    let primes: ptr<i32> = calloc(1000, 4)
    let np: i32 = primes_below(1000, primes)

    let exps: ptr<i64> = calloc(1000, 8)
    for i in 0..np {
        let p: i64 = (primes[i] as i64)
        let e: i64 = p * p * p * p * p
        exps[i] = e
    }

    let terms: ptr<i64> = calloc(256, 8)

    let mut total: i64 = 0
    for i in 0..np {
        for j in 0..np {
            if j > i {
                total = (total + P_mersenne_exponents(exps[i], exps[j], terms)) % MOD
            }
        }
    }

    printf("%lld\n", total)
    free(primes)
    free(exps)
    free(terms)
    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 gcd_i64_i64(int64_t a0, int64_t b0);
int64_t lcm_i64_i64(int64_t a, int64_t b);
int64_t isqrt_i64(int64_t n);
int64_t mulmod_i64_i64_i64(int64_t a0, int64_t b0, int64_t mod);
int64_t mod_pow_i64_i64_i64(int64_t base, int64_t exp, int64_t mod);
bool is_prime_i64(int64_t n);
int64_t mulmod_i64_i64(int64_t a0, int64_t b0);
int64_t invmod_i64(int64_t a);
int64_t geom_sum_ratio_i64_i64(int64_t ratio0, int64_t m);
int32_t cf_terms_mersenne_i64_i64_ptr_i64_i32(int64_t e_small, int64_t e_large, int64_t* terms, int32_t cap);
int64_t pen_p_ptr_i64_i32(int64_t* terms, int32_t n);
int64_t pen_q_ptr_i64_i32(int64_t* terms, int32_t n);
int64_t P_mersenne_exponents_i64_i64_ptr_i64(int64_t ea, int64_t eb, int64_t* terms);
int32_t primes_below_i32_ptr_i32(int32_t n, int32_t* out);
int32_t main(void);

static const int64_t MOD = 1000000007;

int64_t gcd_i64_i64(int64_t a0, int64_t b0) {
    int64_t a = a0;
    int64_t b = b0;
    while (b != 0) {
        int64_t t = FLOW_CHECKED_MOD((a), (b));
        a = b;
        b = t;
    }
    return a;
}

int64_t lcm_i64_i64(int64_t a, int64_t b) {
    if ((a == 0 || b == 0)) {
        return 0;
    }
    return (FLOW_CHECKED_DIV((a), (gcd_i64_i64(a, b))) * b);
}

int64_t isqrt_i64(int64_t n) {
    if (n < 2) {
        return n;
    }
    int64_t x = n;
    int64_t y = FLOW_CHECKED_DIV(((x + 1)), (2));
    while (y < x) {
        x = y;
        y = FLOW_CHECKED_DIV(((x + FLOW_CHECKED_DIV((n), (x)))), (2));
    }
    return x;
}

int64_t mulmod_i64_i64_i64(int64_t a0, int64_t b0, int64_t mod) {
    int64_t a = FLOW_CHECKED_MOD((a0), (mod));
    int64_t b = FLOW_CHECKED_MOD((b0), (mod));
    int64_t result = 0;
    while (b > 0) {
        if (FLOW_CHECKED_MOD((b), (2)) == 1) {
            result = FLOW_CHECKED_MOD(((result + a)), (mod));
        }
        a = FLOW_CHECKED_MOD(((a * 2)), (mod));
        b = FLOW_CHECKED_DIV((b), (2));
    }
    return result;
}

int64_t mod_pow_i64_i64_i64(int64_t base, int64_t exp, int64_t mod) {
    if (mod == 1) {
        return 0;
    }
    int64_t result = 1;
    int64_t b = FLOW_CHECKED_MOD((base), (mod));
    int64_t e = exp;
    while (e > 0) {
        if (FLOW_CHECKED_MOD((e), (2)) == 1) {
            result = mulmod_i64_i64_i64(result, b, mod);
        }
        b = mulmod_i64_i64_i64(b, b, mod);
        e = FLOW_CHECKED_DIV((e), (2));
    }
    return result;
}

bool is_prime_i64(int64_t n) {
    if (n < 2) {
        return 0;
    }
    if (n < 4) {
        return 1;
    }
    if ((FLOW_CHECKED_MOD((n), (2)) == 0 || FLOW_CHECKED_MOD((n), (3)) == 0)) {
        return 0;
    }
    int64_t i = 5;
    while ((i * i) <= n) {
        if ((FLOW_CHECKED_MOD((n), (i)) == 0 || FLOW_CHECKED_MOD((n), ((i + 2))) == 0)) {
            return 0;
        }
        i = (i + 6);
    }
    return 1;
}

int64_t mulmod_i64_i64(int64_t a0, int64_t b0) {
    int64_t a = FLOW_CHECKED_MOD((a0), (MOD));
    int64_t b = FLOW_CHECKED_MOD((b0), (MOD));
    return FLOW_CHECKED_MOD(((a * b)), (MOD));
}

int64_t invmod_i64(int64_t a) {
    return mod_pow_i64_i64_i64(FLOW_CHECKED_MOD((a), (MOD)), (MOD - 2), MOD);
}

int64_t geom_sum_ratio_i64_i64(int64_t ratio0, int64_t m) {
    if (m <= 0) {
        return 0;
    }
    int64_t ratio = FLOW_CHECKED_MOD((ratio0), (MOD));
    if (ratio < 0) {
        ratio = (ratio + MOD);
    }
    if (ratio == 1) {
        return FLOW_CHECKED_MOD((m), (MOD));
    }
    int64_t rm = mod_pow_i64_i64_i64(ratio, m, MOD);
    int64_t num = FLOW_CHECKED_MOD(((rm - 1)), (MOD));
    if (num < 0) {
        num = (num + MOD);
    }
    return mulmod_i64_i64(num, invmod_i64((ratio - 1)));
}

int32_t cf_terms_mersenne_i64_i64_ptr_i64_i32(int64_t e_small, int64_t e_large, int64_t* terms, int32_t cap) {
    int32_t n = 0;
    int64_t hi = e_large;
    int64_t lo = e_small;
    while (1) {
        int64_t m = FLOW_CHECKED_DIV((hi), (lo));
        int64_t r = FLOW_CHECKED_MOD((hi), (lo));
        int64_t ratio = mod_pow_i64_i64_i64(2, lo, MOD);
        int64_t shift = mod_pow_i64_i64_i64(2, r, MOD);
        int64_t series = geom_sum_ratio_i64_i64(ratio, m);
        int64_t q_mod = mulmod_i64_i64(shift, series);
        terms[n] = q_mod;
        n = (n + 1);
        if (r == 0) {
            break;
        }
        hi = lo;
        lo = r;
    }
    return n;
}

int64_t pen_p_ptr_i64_i32(int64_t* terms, int32_t n) {
    int64_t p_m2 = 0;
    int64_t p_m1 = 1;
    int64_t last_p = 0;
    int64_t prev_p = 0;
    int32_t __flow_step_1 = 1;
    for (int32_t i = 0; (0 <= n) ? i < n : i > n; i += (0 <= n) ? 1 : -1) {
        int64_t a = terms[i];
        int64_t p = FLOW_CHECKED_MOD(((mulmod_i64_i64(a, p_m1) + p_m2)), (MOD));
        prev_p = last_p;
        last_p = p;
        p_m2 = p_m1;
        p_m1 = p;
    }
    if (n == 1) {
        return last_p;
    }
    return prev_p;
}

int64_t pen_q_ptr_i64_i32(int64_t* terms, int32_t n) {
    int64_t q_m2 = 1;
    int64_t q_m1 = 0;
    int64_t last_q = 0;
    int64_t prev_q = 0;
    int32_t __flow_step_2 = 1;
    for (int32_t i = 0; (0 <= n) ? i < n : i > n; i += (0 <= n) ? 1 : -1) {
        int64_t a = terms[i];
        int64_t q = FLOW_CHECKED_MOD(((mulmod_i64_i64(a, q_m1) + q_m2)), (MOD));
        prev_q = last_q;
        last_q = q;
        q_m2 = q_m1;
        q_m1 = q;
    }
    if (n == 1) {
        return last_q;
    }
    return prev_q;
}

int64_t P_mersenne_exponents_i64_i64_ptr_i64(int64_t ea, int64_t eb, int64_t* terms) {
    int32_t n = cf_terms_mersenne_i64_i64_ptr_i64_i32(ea, eb, terms, 256);
    int64_t p = pen_p_ptr_i64_i32(terms, n);
    int64_t q = pen_q_ptr_i64_i32(terms, n);
    int64_t s = FLOW_CHECKED_MOD(((p + q)), (MOD));
    int64_t result = FLOW_CHECKED_MOD((((2 * s) - 2)), (MOD));
    if (result < 0) {
        result = (result + MOD);
    }
    return result;
}

int32_t primes_below_i32_ptr_i32(int32_t n, int32_t* out) {
    int8_t* sieve = (int8_t*)(calloc(((int64_t)(n)), 1));
    int32_t __flow_step_3 = 1;
    for (int32_t i = 0; (0 <= n) ? i < n : i > n; i += (0 <= n) ? 1 : -1) {
        sieve[i] = 1;
    }
    int32_t p = 2;
    while ((((int64_t)(p)) * ((int64_t)(p))) < ((int64_t)(n))) {
        if (sieve[p] != 0) {
            int32_t k = (p * p);
            while (k < n) {
                sieve[k] = 0;
                k = (k + p);
            }
        }
        p = (p + 1);
    }
    int32_t count = 0;
    int32_t __flow_step_4 = 1;
    for (int32_t i = 0; (0 <= n) ? i < n : i > n; i += (0 <= n) ? 1 : -1) {
        if (i >= 2) {
            if (sieve[i] != 0) {
                out[count] = i;
                count = (count + 1);
            }
        }
    }
    free(sieve);
    return count;
}

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