Problem 578

Integers with Decreasing Prime Powers — C(10^13) via Möbius squarefree tails.

Answer9219696799346
Output9219696799346
StatusPASS
Native helperno
Runtime3940 ms
Peak memory1051712 KB
Time complexityO(n) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

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

Flow source

# Project Euler 578
# Integers with Decreasing Prime Powers — C(10^13) via Möbius squarefree tails.

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

function isqrt(n: i64) -> i64 {
    if n <= 0 { return 0 }
    let mut x: i64 = n
    let mut y: i64 = (x + 1) / 2
    while y < x { x = y; y = (x + n / x) / 2 }
    return x
}

const SIEVE_LIMIT: i64 = 31622781
const MCAP: i64 = 16000057

let mut PRIMES: ptr<i64> = null
let mut NPR: i64 = 0
let mut PREF: ptr<i32> = null

let mut QK: ptr<i64> = null
let mut QV: ptr<i64> = null
let mut QU: ptr<i8> = null

let mut FK: ptr<i64> = null
let mut FV: ptr<i64> = null
let mut FU: ptr<i8> = null

let mut CK: ptr<i64> = null
let mut CV: ptr<i64> = null
let mut CU: ptr<i8> = null

function build_sieve() -> void {
    let n: i64 = SIEVE_LIMIT
    let lp: ptr<i32> = calloc(n + 1, 4)
    let mu: ptr<i8> = calloc(n + 1, 1)
    PRIMES = calloc(n / 5, 8)
    NPR = 0
    mu[1] = 1
    let mut i: i64 = 2
    while i <= n {
        if lp[i] == 0 {
            lp[i] = i as i32
            PRIMES[NPR] = i
            NPR = NPR + 1
            mu[i] = 0 - 1
        }
        let mut j: i64 = 0
        while j < NPR {
            let p: i64 = PRIMES[j]
            let ip: i64 = i * p
            if ip > n { break }
            lp[ip] = p as i32
            if p == (lp[i] as i64) {
                mu[ip] = 0
                break
            }
            mu[ip] = 0 - mu[i]
            j = j + 1
        }
        i = i + 1
    }
    PREF = calloc(n + 1, 4)
    let mut s: i32 = 0
    i = 1
    while i <= n {
        s = s + (mu[i] as i32)
        PREF[i] = s
        i = i + 1
    }
    free(lp); free(mu)
    QK = calloc(MCAP, 8); QV = calloc(MCAP, 8); QU = calloc(MCAP, 1)
    FK = calloc(MCAP, 8); FV = calloc(MCAP, 8); FU = calloc(MCAP, 1)
    CK = calloc(MCAP, 8); CV = calloc(MCAP, 8); CU = calloc(MCAP, 1)
}

function memo_get(keys: ptr<i64>, vals: ptr<i64>, used: ptr<i8>, key: i64, out: ptr<i64>) -> i64 {
    let mut h: i64 = key % MCAP
    if h < 0 { h = -h }
    let mut p: i64 = 0
    while p < 10000 {
        if used[h] == 0 { return 0 }
        if keys[h] == key {
            out[0] = vals[h]
            return 1
        }
        h = h + 1
        if h >= MCAP { h = 0 }
        p = p + 1
    }
    return 0
}

function memo_put(keys: ptr<i64>, vals: ptr<i64>, used: ptr<i8>, key: i64, val: i64) -> void {
    let mut h: i64 = key % MCAP
    if h < 0 { h = -h }
    let mut p: i64 = 0
    while p < 10000 {
        if used[h] == 0 {
            used[h] = 1
            keys[h] = key
            vals[h] = val
            return
        }
        if keys[h] == key {
            vals[h] = val
            return
        }
        h = h + 1
        if h >= MCAP { h = 0 }
        p = p + 1
    }
}

function squarefree_upto(x: i64) -> i64 {
    if x <= 0 { return 0 }
    let out: ptr<i64> = calloc(1, 8)
    if memo_get(QK, QV, QU, x, out) != 0 {
        let v: i64 = out[0]
        free(out)
        return v
    }
    let r: i64 = isqrt(x)
    let mut res: i64 = 0
    let mut i: i64 = 1
    while i <= r {
        let t: i64 = x / (i * i)
        let j: i64 = isqrt(x / t)
        res = res + t * ((PREF[j] - PREF[i - 1]) as i64)
        i = j + 1
    }
    memo_put(QK, QV, QU, x, res)
    free(out)
    return res
}

function pack2(a: i64, b: i64) -> i64 {
    return (a << 16) ^ b
}

function squarefree_min(x: i64, start_idx: i64) -> i64 {
    if x <= 0 { return 0 }
    if x == 1 { return 1 }
    if start_idx == 0 { return squarefree_upto(x) }
    if start_idx < NPR && PRIMES[start_idx] > x { return 1 }
    let key: i64 = pack2(x, start_idx)
    let out: ptr<i64> = calloc(1, 8)
    if memo_get(FK, FV, FU, key, out) != 0 {
        let v: i64 = out[0]
        free(out)
        return v
    }
    let mut total: i64 = squarefree_upto(x)
    let mut i: i64 = 0
    while i < start_idx {
        let p: i64 = PRIMES[i]
        if p > x { break }
        total = total - squarefree_min(x / p, i + 1)
        i = i + 1
    }
    memo_put(FK, FV, FU, key, total)
    free(out)
    return total
}

function pack3(a: i64, b: i64, c: i64) -> i64 {
    return ((a * 1315423911) ^ (b * 2654435761) ^ (c * 97531))
}

function count_dpowers(limit: i64, start_idx: i64, max_exp: i64) -> i64 {
    if limit <= 0 { return 0 }
    if limit == 1 { return 1 }
    if max_exp <= 1 { return squarefree_min(limit, start_idx) }
    let key: i64 = pack3(limit, start_idx, max_exp)
    let out: ptr<i64> = calloc(1, 8)
    if memo_get(CK, CV, CU, key, out) != 0 {
        let v: i64 = out[0]
        free(out)
        return v
    }
    let mut res: i64 = squarefree_min(limit, start_idx)
    let mut i: i64 = start_idx
    while i < NPR {
        let p: i64 = PRIMES[i]
        let p2: i64 = p * p
        if p2 > limit { break }
        let mut pe: i64 = p2
        let mut e: i64 = 2
        while e <= max_exp && pe <= limit {
            res = res + count_dpowers(limit / pe, i + 1, e)
            e = e + 1
            if pe > limit / p { break }
            pe = pe * p
        }
        i = i + 1
    }
    memo_put(CK, CV, CU, key, res)
    free(out)
    return res
}

function max_exp(n: i64) -> i64 {
    let mut e: i64 = 0
    let mut v: i64 = 1
    while v * 2 <= n {
        v = v * 2
        e = e + 1
    }
    return e
}

function main() -> i32 {
    build_sieve()
    let n: i64 = 10000000000000
    printf("%lld\n", count_dpowers(n, 0, max_exp(n)))
    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 isqrt_i64(int64_t n);
void build_sieve(void);
int64_t memo_get_ptr_i64_ptr_i64_ptr_i8_i64_ptr_i64(int64_t* keys, int64_t* vals, int8_t* used, int64_t key, int64_t* out);
void memo_put_ptr_i64_ptr_i64_ptr_i8_i64_i64(int64_t* keys, int64_t* vals, int8_t* used, int64_t key, int64_t val);
int64_t squarefree_upto_i64(int64_t x);
int64_t pack2_i64_i64(int64_t a, int64_t b);
int64_t squarefree_min_i64_i64(int64_t x, int64_t start_idx);
int64_t pack3_i64_i64_i64(int64_t a, int64_t b, int64_t c);
int64_t count_dpowers_i64_i64_i64(int64_t limit, int64_t start_idx, int64_t max_exp);
int64_t max_exp_i64(int64_t n);
int32_t main(void);

static const int64_t SIEVE_LIMIT = 31622781;
static const int64_t MCAP = 16000057;

/* Module statics */
static int64_t* PRIMES = NULL;
static int64_t NPR = 0;
static int32_t* PREF = NULL;
static int64_t* QK = NULL;
static int64_t* QV = NULL;
static int8_t* QU = NULL;
static int64_t* FK = NULL;
static int64_t* FV = NULL;
static int8_t* FU = NULL;
static int64_t* CK = NULL;
static int64_t* CV = NULL;
static int8_t* CU = NULL;



int64_t isqrt_i64(int64_t n) {
    if (n <= 0) {
        return 0;
    }
    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;
}

void build_sieve(void) {
    int64_t n = SIEVE_LIMIT;
    int32_t* lp = (int32_t*)(calloc((n + 1), 4));
    int8_t* mu = (int8_t*)(calloc((n + 1), 1));
    PRIMES = calloc(FLOW_CHECKED_DIV((n), (5)), 8);
    NPR = 0;
    mu[1] = 1;
    int64_t i = 2;
    while (i <= n) {
        if (lp[i] == 0) {
            lp[i] = ((int32_t)(i));
            PRIMES[NPR] = i;
            NPR = (NPR + 1);
            mu[i] = (0 - 1);
        }
        int64_t j = 0;
        while (j < NPR) {
            int64_t p = PRIMES[j];
            int64_t ip = (i * p);
            if (ip > n) {
                break;
            }
            lp[ip] = ((int32_t)(p));
            if (p == ((int64_t)(lp[i]))) {
                mu[ip] = 0;
                break;
            }
            mu[ip] = (0 - mu[i]);
            j = (j + 1);
        }
        i = (i + 1);
    }
    PREF = calloc((n + 1), 4);
    int32_t s = 0;
    i = 1;
    while (i <= n) {
        s = (s + ((int32_t)(mu[i])));
        PREF[i] = s;
        i = (i + 1);
    }
    free(lp);
    free(mu);
    QK = calloc(MCAP, 8);
    QV = calloc(MCAP, 8);
    QU = calloc(MCAP, 1);
    FK = calloc(MCAP, 8);
    FV = calloc(MCAP, 8);
    FU = calloc(MCAP, 1);
    CK = calloc(MCAP, 8);
    CV = calloc(MCAP, 8);
    CU = calloc(MCAP, 1);
}

int64_t memo_get_ptr_i64_ptr_i64_ptr_i8_i64_ptr_i64(int64_t* keys, int64_t* vals, int8_t* used, int64_t key, int64_t* out) {
    int64_t h = FLOW_CHECKED_MOD((key), (MCAP));
    if (h < 0) {
        h = (-h);
    }
    int64_t p = 0;
    while (p < 10000) {
        if (used[h] == 0) {
            return 0;
        }
        if (keys[h] == key) {
            out[0] = vals[h];
            return 1;
        }
        h = (h + 1);
        if (h >= MCAP) {
            h = 0;
        }
        p = (p + 1);
    }
    return 0;
}

void memo_put_ptr_i64_ptr_i64_ptr_i8_i64_i64(int64_t* keys, int64_t* vals, int8_t* used, int64_t key, int64_t val) {
    int64_t h = FLOW_CHECKED_MOD((key), (MCAP));
    if (h < 0) {
        h = (-h);
    }
    int64_t p = 0;
    while (p < 10000) {
        if (used[h] == 0) {
            used[h] = 1;
            keys[h] = key;
            vals[h] = val;
            return;
        }
        if (keys[h] == key) {
            vals[h] = val;
            return;
        }
        h = (h + 1);
        if (h >= MCAP) {
            h = 0;
        }
        p = (p + 1);
    }
}

int64_t squarefree_upto_i64(int64_t x) {
    if (x <= 0) {
        return 0;
    }
    int64_t* out = (int64_t*)(calloc(1, 8));
    if (memo_get_ptr_i64_ptr_i64_ptr_i8_i64_ptr_i64(QK, QV, QU, x, out) != 0) {
        int64_t v = out[0];
        free(out);
        return v;
    }
    int64_t r = isqrt_i64(x);
    int64_t res = 0;
    int64_t i = 1;
    while (i <= r) {
        int64_t t = FLOW_CHECKED_DIV((x), ((i * i)));
        int64_t j = isqrt_i64(FLOW_CHECKED_DIV((x), (t)));
        res = (res + (t * ((int64_t)((PREF[j] - PREF[(i - 1)])))));
        i = (j + 1);
    }
    memo_put_ptr_i64_ptr_i64_ptr_i8_i64_i64(QK, QV, QU, x, res);
    free(out);
    return res;
}

int64_t pack2_i64_i64(int64_t a, int64_t b) {
    return (FLOW_CHECKED_SHL((a), (16)) ^ b);
}

int64_t squarefree_min_i64_i64(int64_t x, int64_t start_idx) {
    if (x <= 0) {
        return 0;
    }
    if (x == 1) {
        return 1;
    }
    if (start_idx == 0) {
        return squarefree_upto_i64(x);
    }
    if ((start_idx < NPR && PRIMES[start_idx] > x)) {
        return 1;
    }
    int64_t key = pack2_i64_i64(x, start_idx);
    int64_t* out = (int64_t*)(calloc(1, 8));
    if (memo_get_ptr_i64_ptr_i64_ptr_i8_i64_ptr_i64(FK, FV, FU, key, out) != 0) {
        int64_t v = out[0];
        free(out);
        return v;
    }
    int64_t total = squarefree_upto_i64(x);
    int64_t i = 0;
    while (i < start_idx) {
        int64_t p = PRIMES[i];
        if (p > x) {
            break;
        }
        total = (total - squarefree_min_i64_i64(FLOW_CHECKED_DIV((x), (p)), (i + 1)));
        i = (i + 1);
    }
    memo_put_ptr_i64_ptr_i64_ptr_i8_i64_i64(FK, FV, FU, key, total);
    free(out);
    return total;
}

int64_t pack3_i64_i64_i64(int64_t a, int64_t b, int64_t c) {
    return (((a * 1315423911) ^ (b * 2654435761)) ^ (c * 97531));
}

int64_t count_dpowers_i64_i64_i64(int64_t limit, int64_t start_idx, int64_t max_exp) {
    if (limit <= 0) {
        return 0;
    }
    if (limit == 1) {
        return 1;
    }
    if (max_exp <= 1) {
        return squarefree_min_i64_i64(limit, start_idx);
    }
    int64_t key = pack3_i64_i64_i64(limit, start_idx, max_exp);
    int64_t* out = (int64_t*)(calloc(1, 8));
    if (memo_get_ptr_i64_ptr_i64_ptr_i8_i64_ptr_i64(CK, CV, CU, key, out) != 0) {
        int64_t v = out[0];
        free(out);
        return v;
    }
    int64_t res = squarefree_min_i64_i64(limit, start_idx);
    int64_t i = start_idx;
    while (i < NPR) {
        int64_t p = PRIMES[i];
        int64_t p2 = (p * p);
        if (p2 > limit) {
            break;
        }
        int64_t pe = p2;
        int64_t e = 2;
        while ((e <= max_exp && pe <= limit)) {
            res = (res + count_dpowers_i64_i64_i64(FLOW_CHECKED_DIV((limit), (pe)), (i + 1), e));
            e = (e + 1);
            if (pe > FLOW_CHECKED_DIV((limit), (p))) {
                break;
            }
            pe = (pe * p);
        }
        i = (i + 1);
    }
    memo_put_ptr_i64_ptr_i64_ptr_i8_i64_i64(CK, CV, CU, key, res);
    free(out);
    return res;
}

int64_t max_exp_i64(int64_t n) {
    int64_t e = 0;
    int64_t v = 1;
    while ((v * 2) <= n) {
        v = (v * 2);
        e = (e + 1);
    }
    return e;
}

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