Problem 994

T(1234*10^8, 2345*10^8) mod 1e9+7. Totient sieve and Du Jiao summatory recursion.

Answer350247268
Output350247268
StatusPASS
Native helperno
Runtime8930 ms
Peak memory222480 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-based totient computation
VerdictSuboptimal

Flow source

# Project Euler 994: Counting Triangles
# T(1234*10^8, 2345*10^8) mod 1e9+7.
# Totient sieve and Du Jiao summatory recursion.

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

const MOD: i64 = 1000000007

let mut INV2: i64 = 0
let mut INV6: i64 = 0

# Totient prefix global state
let mut tp_limit: i64 = 0
let mut tp_pref0: ptr<i32> = null
let mut tp_pref1: ptr<i32> = null
let mut tp_pref2: ptr<i32> = null
let mut tp_scratch: ptr<i64> = null
let mut tp_depth: i64 = 0

# Cache (open addressing hash table)
let mut cache_key: ptr<i64> = null
let mut cache_f0: ptr<i64> = null
let mut cache_f1: ptr<i64> = null
let mut cache_f2: ptr<i64> = null
let mut cache_used: ptr<i8> = null
let mut cache_size: i64 = 0
let mut cache_count: i64 = 0

# MOD < 2^30, so a*b < 2^60 fits in i64 (avoids slow i128 division).
function mulmod(a: i64, b: i64) -> i64 {
    return (a * b) % MOD
}

function mod_pow(a0: i64, e0: i64) -> i64 {
    let mut a: i64 = a0 % MOD
    if a < 0 { a = a + MOD }
    let mut r: i64 = 1
    let mut e: i64 = e0
    while e > 0 {
        if (e & 1) != 0 { r = mulmod(r, a) }
        a = mulmod(a, a)
        e = e >> 1
    }
    return r
}

function p1_func(n: i64) -> i64 {
    let a: i64 = n % MOD
    let b: i64 = (a + 1) % MOD
    return mulmod(mulmod(a, b), INV2)
}

function p2_func(n: i64) -> i64 {
    let a: i64 = n % MOD
    let b: i64 = (a + 1) % MOD
    let c: i64 = (2 * a + 1) % MOD
    return mulmod(mulmod(mulmod(a, b), c), INV6)
}

function p3_func(n: i64) -> i64 {
    let s: i64 = p1_func(n)
    return mulmod(s, s)
}

function c2_mod(x: i64) -> i64 {
    let a: i64 = x % MOD
    let b: i64 = (a - 1 + MOD) % MOD
    return mulmod(mulmod(a, b), INV2)
}

function c3_mod(x: i64) -> i64 {
    let a: i64 = x % MOD
    let b: i64 = (a - 1 + MOD) % MOD
    let c: i64 = (a - 2 + MOD) % MOD
    return mulmod(mulmod(mulmod(a, b), c), INV6)
}

function cache_hash(key: i64, size: i64) -> i64 {
    # i64 wrapping multiply (C semantics) avoids slow i128 division.
    let mut r: i64 = (key * 2654435761) % size
    if r < 0 { r = r + size }
    return r
}

function cache_resize(new_size: i64) -> void {
    let old_key: ptr<i64> = cache_key
    let old_f0: ptr<i64> = cache_f0
    let old_f1: ptr<i64> = cache_f1
    let old_f2: ptr<i64> = cache_f2
    let old_used: ptr<i8> = cache_used
    let old_s: i64 = cache_size

    cache_key = calloc(new_size, 8) as ptr<i64>
    cache_f0 = calloc(new_size, 8) as ptr<i64>
    cache_f1 = calloc(new_size, 8) as ptr<i64>
    cache_f2 = calloc(new_size, 8) as ptr<i64>
    cache_used = calloc(new_size, 1) as ptr<i8>
    cache_size = new_size
    cache_count = 0

    let mut i: i64 = 0
    while i < old_s {
        if old_used[i] != 0 {
            cache_put(old_key[i], old_f0[i], old_f1[i], old_f2[i])
        }
        i = i + 1
    }
    free(old_key as ptr<void>)
    free(old_f0 as ptr<void>)
    free(old_f1 as ptr<void>)
    free(old_f2 as ptr<void>)
    free(old_used as ptr<void>)
}

function cache_put(key: i64, f0: i64, f1: i64, f2: i64) -> void {
    if cache_count * 2 >= cache_size {
        cache_resize(cache_size * 2)
    }
    let mut idx: i64 = cache_hash(key, cache_size)
    while cache_used[idx] != 0 {
        if cache_key[idx] == key {
            cache_f0[idx] = f0
            cache_f1[idx] = f1
            cache_f2[idx] = f2
            return
        }
        idx = idx + 1
        if idx >= cache_size { idx = 0 }
    }
    cache_key[idx] = key
    cache_f0[idx] = f0
    cache_f1[idx] = f1
    cache_f2[idx] = f2
    cache_used[idx] = 1
    cache_count = cache_count + 1
}

function cache_get(key: i64, out: ptr<i64>) -> bool {
    let mut idx: i64 = cache_hash(key, cache_size)
    while cache_used[idx] != 0 {
        if cache_key[idx] == key {
            out[0] = cache_f0[idx]
            out[1] = cache_f1[idx]
            out[2] = cache_f2[idx]
            return true
        }
        idx = idx + 1
        if idx >= cache_size { idx = 0 }
    }
    return false
}

function tp_values(n: i64, out: ptr<i64>) -> void {
    if n <= tp_limit {
        out[0] = tp_pref0[n] as i64
        out[1] = tp_pref1[n] as i64
        out[2] = tp_pref2[n] as i64
        return
    }
    if cache_get(n, out) { return }

    let mut f0: i64 = p1_func(n)
    let mut f1: i64 = p2_func(n)
    let mut f2: i64 = p3_func(n)

    let mut l: i64 = 2
    while l <= n {
        let q: i64 = n / l
        let r: i64 = n / q

        let sum0: i64 = (r - l + 1) % MOD
        let sum1: i64 = (p1_func(r) - p1_func(l - 1) + MOD) % MOD
        let sum2: i64 = (p2_func(r) - p2_func(l - 1) + MOD) % MOD

        let depth: i64 = tp_depth
        let sub_out: ptr<i64> = tp_scratch + depth * 3
        tp_depth = tp_depth + 1
        tp_values(q, sub_out)
        tp_depth = tp_depth - 1

        f0 = (f0 - mulmod(sum0, sub_out[0]) + MOD) % MOD
        f1 = (f1 - mulmod(sum1, sub_out[1]) + MOD) % MOD
        f2 = (f2 - mulmod(sum2, sub_out[2]) + MOD) % MOD

        l = r + 1
    }

    out[0] = f0
    out[1] = f1
    out[2] = f2
    cache_put(n, f0, f1, f2)
}

function tp_init(limit: i64) -> void {
    tp_limit = limit

    let phi: ptr<i32> = malloc((limit + 1) * 4) as ptr<i32>
    let mut i: i64 = 0
    while i <= limit {
        phi[i] = i as i32
        i = i + 1
    }
    let mut p: i64 = 2
    while p <= limit {
        if phi[p] as i64 == p {
            let mut j: i64 = p
            while j <= limit {
                phi[j] = phi[j] - phi[j] / (p as i32)
                j = j + p
            }
        }
        p = p + 1
    }

    tp_pref0 = calloc(limit + 1, 4) as ptr<i32>
    tp_pref1 = calloc(limit + 1, 4) as ptr<i32>
    tp_pref2 = calloc(limit + 1, 4) as ptr<i32>

    let mut s0: i64 = 0
    let mut s1: i64 = 0
    let mut s2: i64 = 0
    i = 1
    while i <= limit {
        let ph: i64 = phi[i] as i64
        let im: i64 = i % MOD
        s0 = (s0 + ph) % MOD
        s1 = (s1 + im * ph % MOD) % MOD
        s2 = (s2 + im * im % MOD * ph % MOD) % MOD
        tp_pref0[i] = s0 as i32
        tp_pref1[i] = s1 as i32
        tp_pref2[i] = s2 as i32
        i = i + 1
    }
    free(phi as ptr<void>)

    cache_size = 1 << 20
    cache_count = 0
    cache_key = calloc(cache_size, 8) as ptr<i64>
    cache_f0 = calloc(cache_size, 8) as ptr<i64>
    cache_f1 = calloc(cache_size, 8) as ptr<i64>
    cache_f2 = calloc(cache_size, 8) as ptr<i64>
    cache_used = calloc(cache_size, 1) as ptr<i8>

    tp_scratch = calloc(768, 8) as ptr<i64>
    tp_depth = 0
}

function nonconcurrent_candidate_count(m: i64, n: i64) -> i64 {
    let mm: i64 = m % MOD
    let mm1: i64 = (mm - 1 + MOD) % MOD
    let nn: i64 = n % MOD
    let nn1: i64 = (nn - 1 + MOD) % MOD
    let nn1p: i64 = (nn + 1) % MOD

    let two_same: i64 = mulmod(mulmod(mulmod(mulmod(mulmod(mm, mm1), nn), nn1), nn1p), INV6)

    let diff: i64 = (c3_mod(n + 2) - (n % MOD) + MOD) % MOD
    let distinct_val: i64 = mulmod(c3_mod(m), diff)

    return (two_same + distinct_val) % MOD
}

function weighted_gcd_sum(m: i64, n: i64) -> i64 {
    let m1: i64 = m - 1
    let n1: i64 = n - 1
    let upper: i64 = if m1 < n1 { m1 } else { n1 }
    let mut total: i64 = 0

    let r_out: ptr<i64> = tp_scratch + 0 * 3
    let l_out: ptr<i64> = tp_scratch + 1 * 3
    tp_depth = 2

    let mut l: i64 = 1
    while l <= upper {
        let qm: i64 = m1 / l
        let qn: i64 = n1 / l
        let mut r: i64 = m1 / qm
        if n1 / qn < r { r = n1 / qn }
        if upper < r { r = upper }

        tp_values(r, r_out)
        tp_values(l - 1, l_out)

        let s0: i64 = (r_out[0] - l_out[0] + MOD) % MOD
        let s1: i64 = (r_out[1] - l_out[1] + MOD) % MOD
        let s2: i64 = (r_out[2] - l_out[2] + MOD) % MOD

        let qm_mod: i64 = qm % MOD
        let qn_mod: i64 = qn % MOD

        let a0m: i64 = mulmod(qm_mod, m % MOD)
        let a1m: i64 = mulmod(mulmod(-qm_mod + MOD, (qm + 1) % MOD), INV2)
        let a0n: i64 = mulmod(qn_mod, n % MOD)
        let a1n: i64 = mulmod(mulmod(-qn_mod + MOD, (qn + 1) % MOD), INV2)

        let c0: i64 = mulmod(a0m, a0n)
        let c1: i64 = (mulmod(a0m, a1n) + mulmod(a1m, a0n)) % MOD
        let c2: i64 = mulmod(a1m, a1n)

        let sum_val: i64 = c0 * s0 + c1 * s1 + c2 * s2
        let mut sum_mod: i64 = sum_val % MOD
        total = (total + sum_mod) % MOD

        l = r + 1
    }

    return total
}

function concurrent_triple_count(m: i64, n: i64) -> i64 {
    let gcd_part: i64 = weighted_gcd_sum(m, n)
    let endpoint: i64 = mulmod(c2_mod(m), c2_mod(n))
    return (gcd_part - endpoint + MOD) % MOD
}

function main() -> i32 {
    INV2 = (MOD + 1) / 2
    INV6 = mod_pow(6, MOD - 2)

    let sieve_limit: i64 = 12000000
    tp_init(sieve_limit)

    let m: i64 = (1234 as i64) * 100000000
    let n: i64 = (2345 as i64) * 100000000

    let nc: i64 = nonconcurrent_candidate_count(m, n)
    let ct: i64 = concurrent_triple_count(m, n)
    let result: i64 = (nc - ct + MOD) % MOD

    printf("%lld\n", result)

    free(tp_pref0 as ptr<void>)
    free(tp_pref1 as ptr<void>)
    free(tp_pref2 as ptr<void>)
    free(tp_scratch as ptr<void>)
    free(cache_key as ptr<void>)
    free(cache_f0 as ptr<void>)
    free(cache_f1 as ptr<void>)
    free(cache_f2 as ptr<void>)
    free(cache_used as ptr<void>)

    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 mulmod_i64_i64(int64_t a, int64_t b);
int64_t mod_pow_i64_i64(int64_t a0, int64_t e0);
int64_t p1_func_i64(int64_t n);
int64_t p2_func_i64(int64_t n);
int64_t p3_func_i64(int64_t n);
int64_t c2_mod_i64(int64_t x);
int64_t c3_mod_i64(int64_t x);
int64_t cache_hash_i64_i64(int64_t key, int64_t size);
void cache_resize_i64(int64_t new_size);
void cache_put_i64_i64_i64_i64(int64_t key, int64_t f0, int64_t f1, int64_t f2);
bool cache_get_i64_ptr_i64(int64_t key, int64_t* out);
void tp_values_i64_ptr_i64(int64_t n, int64_t* out);
void tp_init_i64(int64_t limit);
int64_t nonconcurrent_candidate_count_i64_i64(int64_t m, int64_t n);
int64_t weighted_gcd_sum_i64_i64(int64_t m, int64_t n);
int64_t concurrent_triple_count_i64_i64(int64_t m, int64_t n);
int32_t main(void);

static const int64_t MOD = 1000000007;

/* Module statics */
static int64_t INV2 = 0;
static int64_t INV6 = 0;
static int64_t tp_limit = 0;
static int32_t* tp_pref0 = NULL;
static int32_t* tp_pref1 = NULL;
static int32_t* tp_pref2 = NULL;
static int64_t* tp_scratch = NULL;
static int64_t tp_depth = 0;
static int64_t* cache_key = NULL;
static int64_t* cache_f0 = NULL;
static int64_t* cache_f1 = NULL;
static int64_t* cache_f2 = NULL;
static int8_t* cache_used = NULL;
static int64_t cache_size = 0;
static int64_t cache_count = 0;




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

int64_t mod_pow_i64_i64(int64_t a0, int64_t e0) {
    int64_t a = FLOW_CHECKED_MOD((a0), (MOD));
    if (a < 0) {
        a = (a + MOD);
    }
    int64_t r = 1;
    int64_t e = e0;
    while (e > 0) {
        if ((e & 1) != 0) {
            r = mulmod_i64_i64(r, a);
        }
        a = mulmod_i64_i64(a, a);
        e = FLOW_CHECKED_SHR((e), (1));
    }
    return r;
}

int64_t p1_func_i64(int64_t n) {
    int64_t a = FLOW_CHECKED_MOD((n), (MOD));
    int64_t b = FLOW_CHECKED_MOD(((a + 1)), (MOD));
    return mulmod_i64_i64(mulmod_i64_i64(a, b), INV2);
}

int64_t p2_func_i64(int64_t n) {
    int64_t a = FLOW_CHECKED_MOD((n), (MOD));
    int64_t b = FLOW_CHECKED_MOD(((a + 1)), (MOD));
    int64_t c = FLOW_CHECKED_MOD((((2 * a) + 1)), (MOD));
    return mulmod_i64_i64(mulmod_i64_i64(mulmod_i64_i64(a, b), c), INV6);
}

int64_t p3_func_i64(int64_t n) {
    int64_t s = p1_func_i64(n);
    return mulmod_i64_i64(s, s);
}

int64_t c2_mod_i64(int64_t x) {
    int64_t a = FLOW_CHECKED_MOD((x), (MOD));
    int64_t b = FLOW_CHECKED_MOD((((a - 1) + MOD)), (MOD));
    return mulmod_i64_i64(mulmod_i64_i64(a, b), INV2);
}

int64_t c3_mod_i64(int64_t x) {
    int64_t a = FLOW_CHECKED_MOD((x), (MOD));
    int64_t b = FLOW_CHECKED_MOD((((a - 1) + MOD)), (MOD));
    int64_t c = FLOW_CHECKED_MOD((((a - 2) + MOD)), (MOD));
    return mulmod_i64_i64(mulmod_i64_i64(mulmod_i64_i64(a, b), c), INV6);
}

int64_t cache_hash_i64_i64(int64_t key, int64_t size) {
    int64_t r = FLOW_CHECKED_MOD(((key * 2654435761)), (size));
    if (r < 0) {
        r = (r + size);
    }
    return r;
}

void cache_resize_i64(int64_t new_size) {
    int64_t* old_key = (int64_t*)(cache_key);
    int64_t* old_f0 = (int64_t*)(cache_f0);
    int64_t* old_f1 = (int64_t*)(cache_f1);
    int64_t* old_f2 = (int64_t*)(cache_f2);
    int8_t* old_used = (int8_t*)(cache_used);
    int64_t old_s = cache_size;
    cache_key = ((int64_t*)(calloc(new_size, 8)));
    cache_f0 = ((int64_t*)(calloc(new_size, 8)));
    cache_f1 = ((int64_t*)(calloc(new_size, 8)));
    cache_f2 = ((int64_t*)(calloc(new_size, 8)));
    cache_used = ((int8_t*)(calloc(new_size, 1)));
    cache_size = new_size;
    cache_count = 0;
    int64_t i = 0;
    while (i < old_s) {
        if (old_used[i] != 0) {
            cache_put_i64_i64_i64_i64(old_key[i], old_f0[i], old_f1[i], old_f2[i]);
        }
        i = (i + 1);
    }
    free(((void*)(old_key)));
    free(((void*)(old_f0)));
    free(((void*)(old_f1)));
    free(((void*)(old_f2)));
    free(((void*)(old_used)));
}

void cache_put_i64_i64_i64_i64(int64_t key, int64_t f0, int64_t f1, int64_t f2) {
    if ((cache_count * 2) >= cache_size) {
        cache_resize_i64((cache_size * 2));
    }
    int64_t idx = cache_hash_i64_i64(key, cache_size);
    while (cache_used[idx] != 0) {
        if (cache_key[idx] == key) {
            cache_f0[idx] = f0;
            cache_f1[idx] = f1;
            cache_f2[idx] = f2;
            return;
        }
        idx = (idx + 1);
        if (idx >= cache_size) {
            idx = 0;
        }
    }
    cache_key[idx] = key;
    cache_f0[idx] = f0;
    cache_f1[idx] = f1;
    cache_f2[idx] = f2;
    cache_used[idx] = 1;
    cache_count = (cache_count + 1);
}

bool cache_get_i64_ptr_i64(int64_t key, int64_t* out) {
    int64_t idx = cache_hash_i64_i64(key, cache_size);
    while (cache_used[idx] != 0) {
        if (cache_key[idx] == key) {
            out[0] = cache_f0[idx];
            out[1] = cache_f1[idx];
            out[2] = cache_f2[idx];
            return 1;
        }
        idx = (idx + 1);
        if (idx >= cache_size) {
            idx = 0;
        }
    }
    return 0;
}

void tp_values_i64_ptr_i64(int64_t n, int64_t* out) {
    if (n <= tp_limit) {
        out[0] = ((int64_t)(tp_pref0[n]));
        out[1] = ((int64_t)(tp_pref1[n]));
        out[2] = ((int64_t)(tp_pref2[n]));
        return;
    }
    if (cache_get_i64_ptr_i64(n, out)) {
        return;
    }
    int64_t f0 = p1_func_i64(n);
    int64_t f1 = p2_func_i64(n);
    int64_t f2 = p3_func_i64(n);
    int64_t l = 2;
    while (l <= n) {
        int64_t q = FLOW_CHECKED_DIV((n), (l));
        int64_t r = FLOW_CHECKED_DIV((n), (q));
        int64_t sum0 = FLOW_CHECKED_MOD((((r - l) + 1)), (MOD));
        int64_t sum1 = FLOW_CHECKED_MOD((((p1_func_i64(r) - p1_func_i64((l - 1))) + MOD)), (MOD));
        int64_t sum2 = FLOW_CHECKED_MOD((((p2_func_i64(r) - p2_func_i64((l - 1))) + MOD)), (MOD));
        int64_t depth = tp_depth;
        int64_t* sub_out = (int64_t*)((tp_scratch + (depth * 3)));
        tp_depth = (tp_depth + 1);
        tp_values_i64_ptr_i64(q, sub_out);
        tp_depth = (tp_depth - 1);
        f0 = FLOW_CHECKED_MOD((((f0 - mulmod_i64_i64(sum0, sub_out[0])) + MOD)), (MOD));
        f1 = FLOW_CHECKED_MOD((((f1 - mulmod_i64_i64(sum1, sub_out[1])) + MOD)), (MOD));
        f2 = FLOW_CHECKED_MOD((((f2 - mulmod_i64_i64(sum2, sub_out[2])) + MOD)), (MOD));
        l = (r + 1);
    }
    out[0] = f0;
    out[1] = f1;
    out[2] = f2;
    cache_put_i64_i64_i64_i64(n, f0, f1, f2);
}

void tp_init_i64(int64_t limit) {
    tp_limit = limit;
    int32_t* phi = (int32_t*)(((int32_t*)(malloc(((limit + 1) * 4)))));
    int64_t i = 0;
    while (i <= limit) {
        phi[i] = ((int32_t)(i));
        i = (i + 1);
    }
    int64_t p = 2;
    while (p <= limit) {
        if (((int64_t)(phi[p])) == p) {
            int64_t j = p;
            while (j <= limit) {
                phi[j] = (phi[j] - FLOW_CHECKED_DIV((phi[j]), (((int32_t)(p)))));
                j = (j + p);
            }
        }
        p = (p + 1);
    }
    tp_pref0 = ((int32_t*)(calloc((limit + 1), 4)));
    tp_pref1 = ((int32_t*)(calloc((limit + 1), 4)));
    tp_pref2 = ((int32_t*)(calloc((limit + 1), 4)));
    int64_t s0 = 0;
    int64_t s1 = 0;
    int64_t s2 = 0;
    i = 1;
    while (i <= limit) {
        int64_t ph = ((int64_t)(phi[i]));
        int64_t im = FLOW_CHECKED_MOD((i), (MOD));
        s0 = FLOW_CHECKED_MOD(((s0 + ph)), (MOD));
        s1 = FLOW_CHECKED_MOD(((s1 + FLOW_CHECKED_MOD(((im * ph)), (MOD)))), (MOD));
        s2 = FLOW_CHECKED_MOD(((s2 + FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD(((im * im)), (MOD)) * ph)), (MOD)))), (MOD));
        tp_pref0[i] = ((int32_t)(s0));
        tp_pref1[i] = ((int32_t)(s1));
        tp_pref2[i] = ((int32_t)(s2));
        i = (i + 1);
    }
    free(((void*)(phi)));
    cache_size = FLOW_CHECKED_SHL((1), (20));
    cache_count = 0;
    cache_key = ((int64_t*)(calloc(cache_size, 8)));
    cache_f0 = ((int64_t*)(calloc(cache_size, 8)));
    cache_f1 = ((int64_t*)(calloc(cache_size, 8)));
    cache_f2 = ((int64_t*)(calloc(cache_size, 8)));
    cache_used = ((int8_t*)(calloc(cache_size, 1)));
    tp_scratch = ((int64_t*)(calloc(768, 8)));
    tp_depth = 0;
}

int64_t nonconcurrent_candidate_count_i64_i64(int64_t m, int64_t n) {
    int64_t mm = FLOW_CHECKED_MOD((m), (MOD));
    int64_t mm1 = FLOW_CHECKED_MOD((((mm - 1) + MOD)), (MOD));
    int64_t nn = FLOW_CHECKED_MOD((n), (MOD));
    int64_t nn1 = FLOW_CHECKED_MOD((((nn - 1) + MOD)), (MOD));
    int64_t nn1p = FLOW_CHECKED_MOD(((nn + 1)), (MOD));
    int64_t two_same = mulmod_i64_i64(mulmod_i64_i64(mulmod_i64_i64(mulmod_i64_i64(mulmod_i64_i64(mm, mm1), nn), nn1), nn1p), INV6);
    int64_t diff = FLOW_CHECKED_MOD((((c3_mod_i64((n + 2)) - FLOW_CHECKED_MOD((n), (MOD))) + MOD)), (MOD));
    int64_t distinct_val = mulmod_i64_i64(c3_mod_i64(m), diff);
    return FLOW_CHECKED_MOD(((two_same + distinct_val)), (MOD));
}

int64_t weighted_gcd_sum_i64_i64(int64_t m, int64_t n) {
    int64_t m1 = (m - 1);
    int64_t n1 = (n - 1);
    int64_t upper = ((m1 < n1) ? (m1) : (n1));
    int64_t total = 0;
    int64_t* r_out = (int64_t*)((tp_scratch + (0 * 3)));
    int64_t* l_out = (int64_t*)((tp_scratch + (1 * 3)));
    tp_depth = 2;
    int64_t l = 1;
    while (l <= upper) {
        int64_t qm = FLOW_CHECKED_DIV((m1), (l));
        int64_t qn = FLOW_CHECKED_DIV((n1), (l));
        int64_t r = FLOW_CHECKED_DIV((m1), (qm));
        if (FLOW_CHECKED_DIV((n1), (qn)) < r) {
            r = FLOW_CHECKED_DIV((n1), (qn));
        }
        if (upper < r) {
            r = upper;
        }
        tp_values_i64_ptr_i64(r, r_out);
        tp_values_i64_ptr_i64((l - 1), l_out);
        int64_t s0 = FLOW_CHECKED_MOD((((r_out[0] - l_out[0]) + MOD)), (MOD));
        int64_t s1 = FLOW_CHECKED_MOD((((r_out[1] - l_out[1]) + MOD)), (MOD));
        int64_t s2 = FLOW_CHECKED_MOD((((r_out[2] - l_out[2]) + MOD)), (MOD));
        int64_t qm_mod = FLOW_CHECKED_MOD((qm), (MOD));
        int64_t qn_mod = FLOW_CHECKED_MOD((qn), (MOD));
        int64_t a0m = mulmod_i64_i64(qm_mod, FLOW_CHECKED_MOD((m), (MOD)));
        int64_t a1m = mulmod_i64_i64(mulmod_i64_i64(((-qm_mod) + MOD), FLOW_CHECKED_MOD(((qm + 1)), (MOD))), INV2);
        int64_t a0n = mulmod_i64_i64(qn_mod, FLOW_CHECKED_MOD((n), (MOD)));
        int64_t a1n = mulmod_i64_i64(mulmod_i64_i64(((-qn_mod) + MOD), FLOW_CHECKED_MOD(((qn + 1)), (MOD))), INV2);
        int64_t c0 = mulmod_i64_i64(a0m, a0n);
        int64_t c1 = FLOW_CHECKED_MOD(((mulmod_i64_i64(a0m, a1n) + mulmod_i64_i64(a1m, a0n))), (MOD));
        int64_t c2 = mulmod_i64_i64(a1m, a1n);
        int64_t sum_val = (((c0 * s0) + (c1 * s1)) + (c2 * s2));
        int64_t sum_mod = FLOW_CHECKED_MOD((sum_val), (MOD));
        total = FLOW_CHECKED_MOD(((total + sum_mod)), (MOD));
        l = (r + 1);
    }
    return total;
}

int64_t concurrent_triple_count_i64_i64(int64_t m, int64_t n) {
    int64_t gcd_part = weighted_gcd_sum_i64_i64(m, n);
    int64_t endpoint = mulmod_i64_i64(c2_mod_i64(m), c2_mod_i64(n));
    return FLOW_CHECKED_MOD((((gcd_part - endpoint) + MOD)), (MOD));
}

int32_t main(void) {
    INV2 = FLOW_CHECKED_DIV(((MOD + 1)), (2));
    INV6 = mod_pow_i64_i64(6, (MOD - 2));
    int64_t sieve_limit = 12000000;
    tp_init_i64(sieve_limit);
    int64_t m = (((int64_t)(1234)) * 100000000);
    int64_t n = (((int64_t)(2345)) * 100000000);
    int64_t nc = nonconcurrent_candidate_count_i64_i64(m, n);
    int64_t ct = concurrent_triple_count_i64_i64(m, n);
    int64_t result = FLOW_CHECKED_MOD((((nc - ct) + MOD)), (MOD));
    printf("%lld\n", result);
    free(((void*)(tp_pref0)));
    free(((void*)(tp_pref1)));
    free(((void*)(tp_pref2)));
    free(((void*)(tp_scratch)));
    free(((void*)(cache_key)));
    free(((void*)(cache_f0)));
    free(((void*)(cache_f1)));
    free(((void*)(cache_f2)));
    free(((void*)(cache_used)));
    return 0;
}

Generated MLIR

module {
  llvm.func @printf(!llvm.ptr, ...) -> i32
  llvm.mlir.global internal constant @str_0("%lld\n\00") {addr_space = 0 : i32} : !llvm.array<6 x i8>
  func.func private @calloc(i64, i64) -> !llvm.ptr
  func.func private @free(!llvm.ptr) -> ()
  func.func private @malloc(i64) -> !llvm.ptr
  // Constant: MOD
  llvm.mlir.global internal constant @MOD(1000000007 : i64) : i64
  // Module static: INV2
  llvm.mlir.global internal @INV2(0 : i64) : i64
  // Module static: INV6
  llvm.mlir.global internal @INV6(0 : i64) : i64
  // Module static: tp_limit
  llvm.mlir.global internal @tp_limit(0 : i64) : i64
  // Module static: tp_pref0
  llvm.mlir.global internal @tp_pref0() {addr_space = 0 : i32} : !llvm.ptr {
    %0 = llvm.mlir.zero : !llvm.ptr
    llvm.return %0 : !llvm.ptr
  }
  // Module static: tp_pref1
  llvm.mlir.global internal @tp_pref1() {addr_space = 0 : i32} : !llvm.ptr {
    %1 = llvm.mlir.zero : !llvm.ptr
    llvm.return %1 : !llvm.ptr
  }
  // Module static: tp_pref2
  llvm.mlir.global internal @tp_pref2() {addr_space = 0 : i32} : !llvm.ptr {
    %2 = llvm.mlir.zero : !llvm.ptr
    llvm.return %2 : !llvm.ptr
  }
  // Module static: tp_scratch
  llvm.mlir.global internal @tp_scratch() {addr_space = 0 : i32} : !llvm.ptr {
    %3 = llvm.mlir.zero : !llvm.ptr
    llvm.return %3 : !llvm.ptr
  }
  // Module static: tp_depth
  llvm.mlir.global internal @tp_depth(0 : i64) : i64
  // Module static: cache_key
  llvm.mlir.global internal @cache_key() {addr_space = 0 : i32} : !llvm.ptr {
    %4 = llvm.mlir.zero : !llvm.ptr
    llvm.return %4 : !llvm.ptr
  }
  // Module static: cache_f0
  llvm.mlir.global internal @cache_f0() {addr_space = 0 : i32} : !llvm.ptr {
    %5 = llvm.mlir.zero : !llvm.ptr
    llvm.return %5 : !llvm.ptr
  }
  // Module static: cache_f1
  llvm.mlir.global internal @cache_f1() {addr_space = 0 : i32} : !llvm.ptr {
    %6 = llvm.mlir.zero : !llvm.ptr
    llvm.return %6 : !llvm.ptr
  }
  // Module static: cache_f2
  llvm.mlir.global internal @cache_f2() {addr_space = 0 : i32} : !llvm.ptr {
    %7 = llvm.mlir.zero : !llvm.ptr
    llvm.return %7 : !llvm.ptr
  }
  // Module static: cache_used
  llvm.mlir.global internal @cache_used() {addr_space = 0 : i32} : !llvm.ptr {
    %8 = llvm.mlir.zero : !llvm.ptr
    llvm.return %8 : !llvm.ptr
  }
  // Module static: cache_size
  llvm.mlir.global internal @cache_size(0 : i64) : i64
  // Module static: cache_count
  llvm.mlir.global internal @cache_count(0 : i64) : i64
  func.func @mulmod(%arg0: i64, %arg1: i64) -> i64 {
    %9 = arith.muli %arg0, %arg1 : i64
    %10 = llvm.mlir.addressof @MOD : !llvm.ptr
    %11 = llvm.load %10 : !llvm.ptr -> i64
    %12 = arith.remsi %9, %11 : i64
    func.return %12 : i64
  }
  func.func @mod_pow(%arg0: i64, %arg1: i64) -> i64 {
    %13 = llvm.mlir.addressof @MOD : !llvm.ptr
    %14 = llvm.load %13 : !llvm.ptr -> i64
    %15 = arith.remsi %arg0, %14 : i64
    %16 = llvm.mlir.constant(1 : i64) : i64
    %17 = llvm.alloca %16 x i64 : (i64) -> !llvm.ptr
    llvm.store %15, %17 : i64, !llvm.ptr
    %18 = llvm.load %17 : !llvm.ptr -> i64
    %19 = arith.constant 0 : i32
    %21 = arith.extsi %19 : i32 to i64
    %20 = arith.cmpi slt, %18, %21 : i64
    cf.cond_br %20, ^bb0, ^bb1
    ^bb0:
      %22 = llvm.load %17 : !llvm.ptr -> i64
      %23 = llvm.mlir.addressof @MOD : !llvm.ptr
      %24 = llvm.load %23 : !llvm.ptr -> i64
      %25 = arith.addi %22, %24 : i64
      llvm.store %25, %17 : i64, !llvm.ptr
      cf.br ^bb2
    ^bb1:
      cf.br ^bb2
    ^bb2:
    %26 = arith.constant 1 : i32
    %27 = arith.extsi %26 : i32 to i64
    %28 = llvm.mlir.constant(1 : i64) : i64
    %29 = llvm.alloca %28 x i64 : (i64) -> !llvm.ptr
    llvm.store %27, %29 : i64, !llvm.ptr
    %30 = llvm.mlir.constant(1 : i64) : i64
    %31 = llvm.alloca %30 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %31 : i64, !llvm.ptr
    cf.br ^bb3
    ^bb3:
    %32 = llvm.load %31 : !llvm.ptr -> i64
    %33 = arith.constant 0 : i32
    %35 = arith.extsi %33 : i32 to i64
    %34 = arith.cmpi sgt, %32, %35 : i64
    cf.cond_br %34, ^bb4, ^bb5
    ^bb4:
      %36 = llvm.load %31 : !llvm.ptr -> i64
      %37 = arith.constant 1 : i32
      %39 = arith.extsi %37 : i32 to i64
      %38 = arith.andi %36, %39 : i64
      %40 = arith.constant 0 : i32
      %42 = arith.extsi %40 : i32 to i64
      %41 = arith.cmpi ne, %38, %42 : i64
      cf.cond_br %41, ^bb6, ^bb7
      ^bb6:
        %44 = llvm.load %29 : !llvm.ptr -> i64
        %45 = llvm.load %17 : !llvm.ptr -> i64
        %43 = func.call @mulmod(%44, %45) : (i64, i64) -> i64
        llvm.store %43, %29 : i64, !llvm.ptr
        cf.br ^bb8
      ^bb7:
        cf.br ^bb8
      ^bb8:
      %47 = llvm.load %17 : !llvm.ptr -> i64
      %48 = llvm.load %17 : !llvm.ptr -> i64
      %46 = func.call @mulmod(%47, %48) : (i64, i64) -> i64
      llvm.store %46, %17 : i64, !llvm.ptr
      %49 = llvm.load %31 : !llvm.ptr -> i64
      %50 = arith.constant 1 : i32
      %52 = arith.extsi %50 : i32 to i64
      %51 = arith.shrsi %49, %52 : i64
      llvm.store %51, %31 : i64, !llvm.ptr
      cf.br ^bb3
    ^bb5:
    %53 = llvm.load %29 : !llvm.ptr -> i64
    func.return %53 : i64
  }
  func.func @p1_func(%arg0: i64) -> i64 {
    %54 = llvm.mlir.addressof @MOD : !llvm.ptr
    %55 = llvm.load %54 : !llvm.ptr -> i64
    %56 = arith.remsi %arg0, %55 : i64
    %57 = arith.constant 1 : i32
    %59 = arith.extsi %57 : i32 to i64
    %58 = arith.addi %56, %59 : i64
    %60 = llvm.mlir.addressof @MOD : !llvm.ptr
    %61 = llvm.load %60 : !llvm.ptr -> i64
    %62 = arith.remsi %58, %61 : i64
    %64 = func.call @mulmod(%56, %62) : (i64, i64) -> i64
    %65 = llvm.mlir.addressof @INV2 : !llvm.ptr
    %66 = llvm.load %65 : !llvm.ptr -> i64
    %63 = func.call @mulmod(%64, %66) : (i64, i64) -> i64
    func.return %63 : i64
  }
  func.func @p2_func(%arg0: i64) -> i64 {
    %67 = llvm.mlir.addressof @MOD : !llvm.ptr
    %68 = llvm.load %67 : !llvm.ptr -> i64
    %69 = arith.remsi %arg0, %68 : i64
    %70 = arith.constant 1 : i32
    %72 = arith.extsi %70 : i32 to i64
    %71 = arith.addi %69, %72 : i64
    %73 = llvm.mlir.addressof @MOD : !llvm.ptr
    %74 = llvm.load %73 : !llvm.ptr -> i64
    %75 = arith.remsi %71, %74 : i64
    %76 = arith.constant 2 : i32
    %78 = arith.extsi %76 : i32 to i64
    %77 = arith.muli %78, %69 : i64
    %79 = arith.constant 1 : i32
    %81 = arith.extsi %79 : i32 to i64
    %80 = arith.addi %77, %81 : i64
    %82 = llvm.mlir.addressof @MOD : !llvm.ptr
    %83 = llvm.load %82 : !llvm.ptr -> i64
    %84 = arith.remsi %80, %83 : i64
    %87 = func.call @mulmod(%69, %75) : (i64, i64) -> i64
    %86 = func.call @mulmod(%87, %84) : (i64, i64) -> i64
    %88 = llvm.mlir.addressof @INV6 : !llvm.ptr
    %89 = llvm.load %88 : !llvm.ptr -> i64
    %85 = func.call @mulmod(%86, %89) : (i64, i64) -> i64
    func.return %85 : i64
  }
  func.func @p3_func(%arg0: i64) -> i64 {
    %90 = func.call @p1_func(%arg0) : (i64) -> i64
    %91 = func.call @mulmod(%90, %90) : (i64, i64) -> i64
    func.return %91 : i64
  }
  func.func @c2_mod(%arg0: i64) -> i64 {
    %92 = llvm.mlir.addressof @MOD : !llvm.ptr
    %93 = llvm.load %92 : !llvm.ptr -> i64
    %94 = arith.remsi %arg0, %93 : i64
    %95 = arith.constant 1 : i32
    %97 = arith.extsi %95 : i32 to i64
    %96 = arith.subi %94, %97 : i64
    %98 = llvm.mlir.addressof @MOD : !llvm.ptr
    %99 = llvm.load %98 : !llvm.ptr -> i64
    %100 = arith.addi %96, %99 : i64
    %101 = llvm.mlir.addressof @MOD : !llvm.ptr
    %102 = llvm.load %101 : !llvm.ptr -> i64
    %103 = arith.remsi %100, %102 : i64
    %105 = func.call @mulmod(%94, %103) : (i64, i64) -> i64
    %106 = llvm.mlir.addressof @INV2 : !llvm.ptr
    %107 = llvm.load %106 : !llvm.ptr -> i64
    %104 = func.call @mulmod(%105, %107) : (i64, i64) -> i64
    func.return %104 : i64
  }
  func.func @c3_mod(%arg0: i64) -> i64 {
    %108 = llvm.mlir.addressof @MOD : !llvm.ptr
    %109 = llvm.load %108 : !llvm.ptr -> i64
    %110 = arith.remsi %arg0, %109 : i64
    %111 = arith.constant 1 : i32
    %113 = arith.extsi %111 : i32 to i64
    %112 = arith.subi %110, %113 : i64
    %114 = llvm.mlir.addressof @MOD : !llvm.ptr
    %115 = llvm.load %114 : !llvm.ptr -> i64
    %116 = arith.addi %112, %115 : i64
    %117 = llvm.mlir.addressof @MOD : !llvm.ptr
    %118 = llvm.load %117 : !llvm.ptr -> i64
    %119 = arith.remsi %116, %118 : i64
    %120 = arith.constant 2 : i32
    %122 = arith.extsi %120 : i32 to i64
    %121 = arith.subi %110, %122 : i64
    %123 = llvm.mlir.addressof @MOD : !llvm.ptr
    %124 = llvm.load %123 : !llvm.ptr -> i64
    %125 = arith.addi %121, %124 : i64
    %126 = llvm.mlir.addressof @MOD : !llvm.ptr
    %127 = llvm.load %126 : !llvm.ptr -> i64
    %128 = arith.remsi %125, %127 : i64
    %131 = func.call @mulmod(%110, %119) : (i64, i64) -> i64
    %130 = func.call @mulmod(%131, %128) : (i64, i64) -> i64
    %132 = llvm.mlir.addressof @INV6 : !llvm.ptr
    %133 = llvm.load %132 : !llvm.ptr -> i64
    %129 = func.call @mulmod(%130, %133) : (i64, i64) -> i64
    func.return %129 : i64
  }
  func.func @cache_hash(%arg0: i64, %arg1: i64) -> i64 {
    %134 = arith.constant -1640531535 : i32
    %136 = arith.extsi %134 : i32 to i64
    %135 = arith.muli %arg0, %136 : i64
    %137 = arith.remsi %135, %arg1 : i64
    %138 = llvm.mlir.constant(1 : i64) : i64
    %139 = llvm.alloca %138 x i64 : (i64) -> !llvm.ptr
    llvm.store %137, %139 : i64, !llvm.ptr
    %140 = llvm.load %139 : !llvm.ptr -> i64
    %141 = arith.constant 0 : i32
    %143 = arith.extsi %141 : i32 to i64
    %142 = arith.cmpi slt, %140, %143 : i64
    cf.cond_br %142, ^bb9, ^bb10
    ^bb9:
      %144 = llvm.load %139 : !llvm.ptr -> i64
      %145 = arith.addi %144, %arg1 : i64
      llvm.store %145, %139 : i64, !llvm.ptr
      cf.br ^bb11
    ^bb10:
      cf.br ^bb11
    ^bb11:
    %146 = llvm.load %139 : !llvm.ptr -> i64
    func.return %146 : i64
  }
  func.func @cache_resize(%arg0: i64) -> () {
    %147 = llvm.mlir.addressof @cache_key : !llvm.ptr
    %148 = llvm.load %147 : !llvm.ptr -> !llvm.ptr
    %149 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
    %150 = llvm.load %149 : !llvm.ptr -> !llvm.ptr
    %151 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
    %152 = llvm.load %151 : !llvm.ptr -> !llvm.ptr
    %153 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
    %154 = llvm.load %153 : !llvm.ptr -> !llvm.ptr
    %155 = llvm.mlir.addressof @cache_used : !llvm.ptr
    %156 = llvm.load %155 : !llvm.ptr -> !llvm.ptr
    %157 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %158 = llvm.load %157 : !llvm.ptr -> i64
    %160 = arith.constant 8 : i32
    %161 = arith.extsi %160 : i32 to i64
    %159 = func.call @calloc(%arg0, %161) : (i64, i64) -> !llvm.ptr
    %162 = llvm.mlir.addressof @cache_key : !llvm.ptr
    llvm.store %159, %162 : !llvm.ptr, !llvm.ptr
    %164 = arith.constant 8 : i32
    %165 = arith.extsi %164 : i32 to i64
    %163 = func.call @calloc(%arg0, %165) : (i64, i64) -> !llvm.ptr
    %166 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
    llvm.store %163, %166 : !llvm.ptr, !llvm.ptr
    %168 = arith.constant 8 : i32
    %169 = arith.extsi %168 : i32 to i64
    %167 = func.call @calloc(%arg0, %169) : (i64, i64) -> !llvm.ptr
    %170 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
    llvm.store %167, %170 : !llvm.ptr, !llvm.ptr
    %172 = arith.constant 8 : i32
    %173 = arith.extsi %172 : i32 to i64
    %171 = func.call @calloc(%arg0, %173) : (i64, i64) -> !llvm.ptr
    %174 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
    llvm.store %171, %174 : !llvm.ptr, !llvm.ptr
    %176 = arith.constant 1 : i32
    %177 = arith.extsi %176 : i32 to i64
    %175 = func.call @calloc(%arg0, %177) : (i64, i64) -> !llvm.ptr
    %178 = llvm.mlir.addressof @cache_used : !llvm.ptr
    llvm.store %175, %178 : !llvm.ptr, !llvm.ptr
    %179 = llvm.mlir.addressof @cache_size : !llvm.ptr
    llvm.store %arg0, %179 : i64, !llvm.ptr
    %180 = arith.constant 0 : i32
    %181 = arith.extsi %180 : i32 to i64
    %182 = llvm.mlir.addressof @cache_count : !llvm.ptr
    llvm.store %181, %182 : i64, !llvm.ptr
    %183 = arith.constant 0 : i32
    %184 = arith.extsi %183 : i32 to i64
    %185 = llvm.mlir.constant(1 : i64) : i64
    %186 = llvm.alloca %185 x i64 : (i64) -> !llvm.ptr
    llvm.store %184, %186 : i64, !llvm.ptr
    cf.br ^bb12
    ^bb12:
    %187 = llvm.load %186 : !llvm.ptr -> i64
    %188 = arith.cmpi slt, %187, %158 : i64
    cf.cond_br %188, ^bb13, ^bb14
    ^bb13:
      %190 = llvm.load %186 : !llvm.ptr -> i64
      %191 = llvm.getelementptr %156[%190] : (!llvm.ptr, i64) -> !llvm.ptr, i8
      %189 = llvm.load %191 : !llvm.ptr -> i8
      %192 = arith.constant 0 : i32
      %194 = arith.extsi %189 : i8 to i32
      %193 = arith.cmpi ne, %194, %192 : i32
      cf.cond_br %193, ^bb15, ^bb16
      ^bb15:
        %197 = llvm.load %186 : !llvm.ptr -> i64
        %198 = llvm.getelementptr %148[%197] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %196 = llvm.load %198 : !llvm.ptr -> i64
        %200 = llvm.load %186 : !llvm.ptr -> i64
        %201 = llvm.getelementptr %150[%200] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %199 = llvm.load %201 : !llvm.ptr -> i64
        %203 = llvm.load %186 : !llvm.ptr -> i64
        %204 = llvm.getelementptr %152[%203] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %202 = llvm.load %204 : !llvm.ptr -> i64
        %206 = llvm.load %186 : !llvm.ptr -> i64
        %207 = llvm.getelementptr %154[%206] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %205 = llvm.load %207 : !llvm.ptr -> i64
        func.call @cache_put(%196, %199, %202, %205) : (i64, i64, i64, i64) -> ()
        cf.br ^bb17
      ^bb16:
        cf.br ^bb17
      ^bb17:
      %208 = llvm.load %186 : !llvm.ptr -> i64
      %209 = arith.constant 1 : i32
      %211 = arith.extsi %209 : i32 to i64
      %210 = arith.addi %208, %211 : i64
      llvm.store %210, %186 : i64, !llvm.ptr
      cf.br ^bb12
    ^bb14:
    func.call @free(%148) : (!llvm.ptr) -> ()
    func.call @free(%150) : (!llvm.ptr) -> ()
    func.call @free(%152) : (!llvm.ptr) -> ()
    func.call @free(%154) : (!llvm.ptr) -> ()
    func.call @free(%156) : (!llvm.ptr) -> ()
    func.return
  }
  func.func @cache_put(%arg0: i64, %arg1: i64, %arg2: i64, %arg3: i64) -> () {
    %217 = llvm.mlir.addressof @cache_count : !llvm.ptr
    %218 = llvm.load %217 : !llvm.ptr -> i64
    %219 = arith.constant 2 : i32
    %221 = arith.extsi %219 : i32 to i64
    %220 = arith.muli %218, %221 : i64
    %222 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %223 = llvm.load %222 : !llvm.ptr -> i64
    %224 = arith.cmpi sge, %220, %223 : i64
    cf.cond_br %224, ^bb18, ^bb19
    ^bb18:
      %226 = llvm.mlir.addressof @cache_size : !llvm.ptr
      %227 = llvm.load %226 : !llvm.ptr -> i64
      %228 = arith.constant 2 : i32
      %230 = arith.extsi %228 : i32 to i64
      %229 = arith.muli %227, %230 : i64
      func.call @cache_resize(%229) : (i64) -> ()
      cf.br ^bb20
    ^bb19:
      cf.br ^bb20
    ^bb20:
    %232 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %233 = llvm.load %232 : !llvm.ptr -> i64
    %231 = func.call @cache_hash(%arg0, %233) : (i64, i64) -> i64
    %234 = llvm.mlir.constant(1 : i64) : i64
    %235 = llvm.alloca %234 x i64 : (i64) -> !llvm.ptr
    llvm.store %231, %235 : i64, !llvm.ptr
    cf.br ^bb21
    ^bb21:
    %237 = llvm.mlir.addressof @cache_used : !llvm.ptr
    %238 = llvm.load %237 : !llvm.ptr -> !llvm.ptr
    %239 = llvm.load %235 : !llvm.ptr -> i64
    %240 = llvm.getelementptr %238[%239] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    %236 = llvm.load %240 : !llvm.ptr -> i8
    %241 = arith.constant 0 : i32
    %243 = arith.extsi %236 : i8 to i32
    %242 = arith.cmpi ne, %243, %241 : i32
    cf.cond_br %242, ^bb22, ^bb23
    ^bb22:
      %245 = llvm.mlir.addressof @cache_key : !llvm.ptr
      %246 = llvm.load %245 : !llvm.ptr -> !llvm.ptr
      %247 = llvm.load %235 : !llvm.ptr -> i64
      %248 = llvm.getelementptr %246[%247] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %244 = llvm.load %248 : !llvm.ptr -> i64
      %249 = arith.cmpi eq, %244, %arg0 : i64
      cf.cond_br %249, ^bb24, ^bb25
      ^bb24:
        %250 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
        %251 = llvm.load %250 : !llvm.ptr -> !llvm.ptr
        %252 = llvm.load %235 : !llvm.ptr -> i64
        %253 = llvm.getelementptr %251[%252] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %arg1, %253 : i64, !llvm.ptr
        %254 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
        %255 = llvm.load %254 : !llvm.ptr -> !llvm.ptr
        %256 = llvm.load %235 : !llvm.ptr -> i64
        %257 = llvm.getelementptr %255[%256] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %arg2, %257 : i64, !llvm.ptr
        %258 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
        %259 = llvm.load %258 : !llvm.ptr -> !llvm.ptr
        %260 = llvm.load %235 : !llvm.ptr -> i64
        %261 = llvm.getelementptr %259[%260] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %arg3, %261 : i64, !llvm.ptr
        func.return
      ^bb25:
        cf.br ^bb26
      ^bb26:
      %262 = llvm.load %235 : !llvm.ptr -> i64
      %263 = arith.constant 1 : i32
      %265 = arith.extsi %263 : i32 to i64
      %264 = arith.addi %262, %265 : i64
      llvm.store %264, %235 : i64, !llvm.ptr
      %266 = llvm.load %235 : !llvm.ptr -> i64
      %267 = llvm.mlir.addressof @cache_size : !llvm.ptr
      %268 = llvm.load %267 : !llvm.ptr -> i64
      %269 = arith.cmpi sge, %266, %268 : i64
      cf.cond_br %269, ^bb27, ^bb28
      ^bb27:
        %270 = arith.constant 0 : i32
        %271 = arith.extsi %270 : i32 to i64
        llvm.store %271, %235 : i64, !llvm.ptr
        cf.br ^bb29
      ^bb28:
        cf.br ^bb29
      ^bb29:
      cf.br ^bb21
    ^bb23:
    %272 = llvm.mlir.addressof @cache_key : !llvm.ptr
    %273 = llvm.load %272 : !llvm.ptr -> !llvm.ptr
    %274 = llvm.load %235 : !llvm.ptr -> i64
    %275 = llvm.getelementptr %273[%274] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg0, %275 : i64, !llvm.ptr
    %276 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
    %277 = llvm.load %276 : !llvm.ptr -> !llvm.ptr
    %278 = llvm.load %235 : !llvm.ptr -> i64
    %279 = llvm.getelementptr %277[%278] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg1, %279 : i64, !llvm.ptr
    %280 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
    %281 = llvm.load %280 : !llvm.ptr -> !llvm.ptr
    %282 = llvm.load %235 : !llvm.ptr -> i64
    %283 = llvm.getelementptr %281[%282] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg2, %283 : i64, !llvm.ptr
    %284 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
    %285 = llvm.load %284 : !llvm.ptr -> !llvm.ptr
    %286 = llvm.load %235 : !llvm.ptr -> i64
    %287 = llvm.getelementptr %285[%286] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg3, %287 : i64, !llvm.ptr
    %288 = arith.constant 1 : i32
    %289 = llvm.mlir.addressof @cache_used : !llvm.ptr
    %290 = llvm.load %289 : !llvm.ptr -> !llvm.ptr
    %291 = llvm.load %235 : !llvm.ptr -> i64
    %292 = arith.trunci %288 : i32 to i8
    %293 = llvm.getelementptr %290[%291] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    llvm.store %292, %293 : i8, !llvm.ptr
    %294 = llvm.mlir.addressof @cache_count : !llvm.ptr
    %295 = llvm.load %294 : !llvm.ptr -> i64
    %296 = arith.constant 1 : i32
    %298 = arith.extsi %296 : i32 to i64
    %297 = arith.addi %295, %298 : i64
    %299 = llvm.mlir.addressof @cache_count : !llvm.ptr
    llvm.store %297, %299 : i64, !llvm.ptr
    func.return
  }
  func.func @cache_get(%arg0: i64, %arg1: !llvm.ptr) -> i1 {
    %301 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %302 = llvm.load %301 : !llvm.ptr -> i64
    %300 = func.call @cache_hash(%arg0, %302) : (i64, i64) -> i64
    %303 = llvm.mlir.constant(1 : i64) : i64
    %304 = llvm.alloca %303 x i64 : (i64) -> !llvm.ptr
    llvm.store %300, %304 : i64, !llvm.ptr
    cf.br ^bb30
    ^bb30:
    %306 = llvm.mlir.addressof @cache_used : !llvm.ptr
    %307 = llvm.load %306 : !llvm.ptr -> !llvm.ptr
    %308 = llvm.load %304 : !llvm.ptr -> i64
    %309 = llvm.getelementptr %307[%308] : (!llvm.ptr, i64) -> !llvm.ptr, i8
    %305 = llvm.load %309 : !llvm.ptr -> i8
    %310 = arith.constant 0 : i32
    %312 = arith.extsi %305 : i8 to i32
    %311 = arith.cmpi ne, %312, %310 : i32
    cf.cond_br %311, ^bb31, ^bb32
    ^bb31:
      %314 = llvm.mlir.addressof @cache_key : !llvm.ptr
      %315 = llvm.load %314 : !llvm.ptr -> !llvm.ptr
      %316 = llvm.load %304 : !llvm.ptr -> i64
      %317 = llvm.getelementptr %315[%316] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %313 = llvm.load %317 : !llvm.ptr -> i64
      %318 = arith.cmpi eq, %313, %arg0 : i64
      cf.cond_br %318, ^bb33, ^bb34
      ^bb33:
        %320 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
        %321 = llvm.load %320 : !llvm.ptr -> !llvm.ptr
        %322 = llvm.load %304 : !llvm.ptr -> i64
        %323 = llvm.getelementptr %321[%322] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %319 = llvm.load %323 : !llvm.ptr -> i64
        %324 = arith.constant 0 : i32
        %325 = arith.extsi %324 : i32 to i64
        %326 = llvm.getelementptr %arg1[%325] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %319, %326 : i64, !llvm.ptr
        %328 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
        %329 = llvm.load %328 : !llvm.ptr -> !llvm.ptr
        %330 = llvm.load %304 : !llvm.ptr -> i64
        %331 = llvm.getelementptr %329[%330] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %327 = llvm.load %331 : !llvm.ptr -> i64
        %332 = arith.constant 1 : i32
        %333 = arith.extsi %332 : i32 to i64
        %334 = llvm.getelementptr %arg1[%333] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %327, %334 : i64, !llvm.ptr
        %336 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
        %337 = llvm.load %336 : !llvm.ptr -> !llvm.ptr
        %338 = llvm.load %304 : !llvm.ptr -> i64
        %339 = llvm.getelementptr %337[%338] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %335 = llvm.load %339 : !llvm.ptr -> i64
        %340 = arith.constant 2 : i32
        %341 = arith.extsi %340 : i32 to i64
        %342 = llvm.getelementptr %arg1[%341] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %335, %342 : i64, !llvm.ptr
        %343 = arith.constant 1 : i1
        func.return %343 : i1
      ^bb34:
        cf.br ^bb35
      ^bb35:
      %344 = llvm.load %304 : !llvm.ptr -> i64
      %345 = arith.constant 1 : i32
      %347 = arith.extsi %345 : i32 to i64
      %346 = arith.addi %344, %347 : i64
      llvm.store %346, %304 : i64, !llvm.ptr
      %348 = llvm.load %304 : !llvm.ptr -> i64
      %349 = llvm.mlir.addressof @cache_size : !llvm.ptr
      %350 = llvm.load %349 : !llvm.ptr -> i64
      %351 = arith.cmpi sge, %348, %350 : i64
      cf.cond_br %351, ^bb36, ^bb37
      ^bb36:
        %352 = arith.constant 0 : i32
        %353 = arith.extsi %352 : i32 to i64
        llvm.store %353, %304 : i64, !llvm.ptr
        cf.br ^bb38
      ^bb37:
        cf.br ^bb38
      ^bb38:
      cf.br ^bb30
    ^bb32:
    %354 = arith.constant 0 : i1
    func.return %354 : i1
  }
  func.func @tp_values(%arg0: i64, %arg1: !llvm.ptr) -> () {
    %355 = llvm.mlir.addressof @tp_limit : !llvm.ptr
    %356 = llvm.load %355 : !llvm.ptr -> i64
    %357 = arith.cmpi sle, %arg0, %356 : i64
    cf.cond_br %357, ^bb39, ^bb40
    ^bb39:
      %359 = llvm.mlir.addressof @tp_pref0 : !llvm.ptr
      %360 = llvm.load %359 : !llvm.ptr -> !llvm.ptr
      %361 = llvm.getelementptr %360[%arg0] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %358 = llvm.load %361 : !llvm.ptr -> i32
      %362 = arith.extsi %358 : i32 to i64
      %363 = arith.constant 0 : i32
      %364 = arith.extsi %363 : i32 to i64
      %365 = llvm.getelementptr %arg1[%364] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %362, %365 : i64, !llvm.ptr
      %367 = llvm.mlir.addressof @tp_pref1 : !llvm.ptr
      %368 = llvm.load %367 : !llvm.ptr -> !llvm.ptr
      %369 = llvm.getelementptr %368[%arg0] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %366 = llvm.load %369 : !llvm.ptr -> i32
      %370 = arith.extsi %366 : i32 to i64
      %371 = arith.constant 1 : i32
      %372 = arith.extsi %371 : i32 to i64
      %373 = llvm.getelementptr %arg1[%372] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %370, %373 : i64, !llvm.ptr
      %375 = llvm.mlir.addressof @tp_pref2 : !llvm.ptr
      %376 = llvm.load %375 : !llvm.ptr -> !llvm.ptr
      %377 = llvm.getelementptr %376[%arg0] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %374 = llvm.load %377 : !llvm.ptr -> i32
      %378 = arith.extsi %374 : i32 to i64
      %379 = arith.constant 2 : i32
      %380 = arith.extsi %379 : i32 to i64
      %381 = llvm.getelementptr %arg1[%380] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %378, %381 : i64, !llvm.ptr
      func.return
    ^bb40:
      cf.br ^bb41
    ^bb41:
    %382 = func.call @cache_get(%arg0, %arg1) : (i64, !llvm.ptr) -> i1
    cf.cond_br %382, ^bb42, ^bb43
    ^bb42:
      func.return
    ^bb43:
      cf.br ^bb44
    ^bb44:
    %383 = func.call @p1_func(%arg0) : (i64) -> i64
    %384 = llvm.mlir.constant(1 : i64) : i64
    %385 = llvm.alloca %384 x i64 : (i64) -> !llvm.ptr
    llvm.store %383, %385 : i64, !llvm.ptr
    %386 = func.call @p2_func(%arg0) : (i64) -> i64
    %387 = llvm.mlir.constant(1 : i64) : i64
    %388 = llvm.alloca %387 x i64 : (i64) -> !llvm.ptr
    llvm.store %386, %388 : i64, !llvm.ptr
    %389 = func.call @p3_func(%arg0) : (i64) -> i64
    %390 = llvm.mlir.constant(1 : i64) : i64
    %391 = llvm.alloca %390 x i64 : (i64) -> !llvm.ptr
    llvm.store %389, %391 : i64, !llvm.ptr
    %392 = arith.constant 2 : i32
    %393 = arith.extsi %392 : i32 to i64
    %394 = llvm.mlir.constant(1 : i64) : i64
    %395 = llvm.alloca %394 x i64 : (i64) -> !llvm.ptr
    llvm.store %393, %395 : i64, !llvm.ptr
    cf.br ^bb45
    ^bb45:
    %396 = llvm.load %395 : !llvm.ptr -> i64
    %397 = arith.cmpi sle, %396, %arg0 : i64
    cf.cond_br %397, ^bb46, ^bb47
    ^bb46:
      %398 = llvm.load %395 : !llvm.ptr -> i64
      %399 = arith.divsi %arg0, %398 : i64
      %400 = arith.divsi %arg0, %399 : i64
      %401 = llvm.load %395 : !llvm.ptr -> i64
      %402 = arith.subi %400, %401 : i64
      %403 = arith.constant 1 : i32
      %405 = arith.extsi %403 : i32 to i64
      %404 = arith.addi %402, %405 : i64
      %406 = llvm.mlir.addressof @MOD : !llvm.ptr
      %407 = llvm.load %406 : !llvm.ptr -> i64
      %408 = arith.remsi %404, %407 : i64
      %409 = func.call @p1_func(%400) : (i64) -> i64
      %411 = llvm.load %395 : !llvm.ptr -> i64
      %412 = arith.constant 1 : i32
      %414 = arith.extsi %412 : i32 to i64
      %413 = arith.subi %411, %414 : i64
      %410 = func.call @p1_func(%413) : (i64) -> i64
      %415 = arith.subi %409, %410 : i64
      %416 = llvm.mlir.addressof @MOD : !llvm.ptr
      %417 = llvm.load %416 : !llvm.ptr -> i64
      %418 = arith.addi %415, %417 : i64
      %419 = llvm.mlir.addressof @MOD : !llvm.ptr
      %420 = llvm.load %419 : !llvm.ptr -> i64
      %421 = arith.remsi %418, %420 : i64
      %422 = func.call @p2_func(%400) : (i64) -> i64
      %424 = llvm.load %395 : !llvm.ptr -> i64
      %425 = arith.constant 1 : i32
      %427 = arith.extsi %425 : i32 to i64
      %426 = arith.subi %424, %427 : i64
      %423 = func.call @p2_func(%426) : (i64) -> i64
      %428 = arith.subi %422, %423 : i64
      %429 = llvm.mlir.addressof @MOD : !llvm.ptr
      %430 = llvm.load %429 : !llvm.ptr -> i64
      %431 = arith.addi %428, %430 : i64
      %432 = llvm.mlir.addressof @MOD : !llvm.ptr
      %433 = llvm.load %432 : !llvm.ptr -> i64
      %434 = arith.remsi %431, %433 : i64
      %435 = llvm.mlir.addressof @tp_depth : !llvm.ptr
      %436 = llvm.load %435 : !llvm.ptr -> i64
      # String concatenation: !llvm.ptr + i64
      %438 = llvm.mlir.addressof @tp_depth : !llvm.ptr
      %439 = llvm.load %438 : !llvm.ptr -> i64
      %440 = arith.constant 1 : i32
      %442 = arith.extsi %440 : i32 to i64
      %441 = arith.addi %439, %442 : i64
      %443 = llvm.mlir.addressof @tp_depth : !llvm.ptr
      llvm.store %441, %443 : i64, !llvm.ptr
      func.call @tp_values(%399, %437) : (i64, !llvm.ptr) -> ()
      %445 = llvm.mlir.addressof @tp_depth : !llvm.ptr
      %446 = llvm.load %445 : !llvm.ptr -> i64
      %447 = arith.constant 1 : i32
      %449 = arith.extsi %447 : i32 to i64
      %448 = arith.subi %446, %449 : i64
      %450 = llvm.mlir.addressof @tp_depth : !llvm.ptr
      llvm.store %448, %450 : i64, !llvm.ptr
      %451 = llvm.load %385 : !llvm.ptr -> i64
      %454 = arith.constant 0 : i32
      %455 = arith.extsi %454 : i32 to i64
      %456 = llvm.getelementptr %437[%455] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %453 = llvm.load %456 : !llvm.ptr -> i64
      %452 = func.call @mulmod(%408, %453) : (i64, i64) -> i64
      %457 = arith.subi %451, %452 : i64
      %458 = llvm.mlir.addressof @MOD : !llvm.ptr
      %459 = llvm.load %458 : !llvm.ptr -> i64
      %460 = arith.addi %457, %459 : i64
      %461 = llvm.mlir.addressof @MOD : !llvm.ptr
      %462 = llvm.load %461 : !llvm.ptr -> i64
      %463 = arith.remsi %460, %462 : i64
      llvm.store %463, %385 : i64, !llvm.ptr
      %464 = llvm.load %388 : !llvm.ptr -> i64
      %467 = arith.constant 1 : i32
      %468 = arith.extsi %467 : i32 to i64
      %469 = llvm.getelementptr %437[%468] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %466 = llvm.load %469 : !llvm.ptr -> i64
      %465 = func.call @mulmod(%421, %466) : (i64, i64) -> i64
      %470 = arith.subi %464, %465 : i64
      %471 = llvm.mlir.addressof @MOD : !llvm.ptr
      %472 = llvm.load %471 : !llvm.ptr -> i64
      %473 = arith.addi %470, %472 : i64
      %474 = llvm.mlir.addressof @MOD : !llvm.ptr
      %475 = llvm.load %474 : !llvm.ptr -> i64
      %476 = arith.remsi %473, %475 : i64
      llvm.store %476, %388 : i64, !llvm.ptr
      %477 = llvm.load %391 : !llvm.ptr -> i64
      %480 = arith.constant 2 : i32
      %481 = arith.extsi %480 : i32 to i64
      %482 = llvm.getelementptr %437[%481] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %479 = llvm.load %482 : !llvm.ptr -> i64
      %478 = func.call @mulmod(%434, %479) : (i64, i64) -> i64
      %483 = arith.subi %477, %478 : i64
      %484 = llvm.mlir.addressof @MOD : !llvm.ptr
      %485 = llvm.load %484 : !llvm.ptr -> i64
      %486 = arith.addi %483, %485 : i64
      %487 = llvm.mlir.addressof @MOD : !llvm.ptr
      %488 = llvm.load %487 : !llvm.ptr -> i64
      %489 = arith.remsi %486, %488 : i64
      llvm.store %489, %391 : i64, !llvm.ptr
      %490 = arith.constant 1 : i32
      %492 = arith.extsi %490 : i32 to i64
      %491 = arith.addi %400, %492 : i64
      llvm.store %491, %395 : i64, !llvm.ptr
      cf.br ^bb45
    ^bb47:
    %493 = llvm.load %385 : !llvm.ptr -> i64
    %494 = arith.constant 0 : i32
    %495 = arith.extsi %494 : i32 to i64
    %496 = llvm.getelementptr %arg1[%495] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %493, %496 : i64, !llvm.ptr
    %497 = llvm.load %388 : !llvm.ptr -> i64
    %498 = arith.constant 1 : i32
    %499 = arith.extsi %498 : i32 to i64
    %500 = llvm.getelementptr %arg1[%499] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %497, %500 : i64, !llvm.ptr
    %501 = llvm.load %391 : !llvm.ptr -> i64
    %502 = arith.constant 2 : i32
    %503 = arith.extsi %502 : i32 to i64
    %504 = llvm.getelementptr %arg1[%503] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %501, %504 : i64, !llvm.ptr
    %506 = llvm.load %385 : !llvm.ptr -> i64
    %507 = llvm.load %388 : !llvm.ptr -> i64
    %508 = llvm.load %391 : !llvm.ptr -> i64
    func.call @cache_put(%arg0, %506, %507, %508) : (i64, i64, i64, i64) -> ()
    func.return
  }
  func.func @tp_init(%arg0: i64) -> () {
    %509 = llvm.mlir.addressof @tp_limit : !llvm.ptr
    llvm.store %arg0, %509 : i64, !llvm.ptr
    %511 = arith.constant 1 : i32
    %513 = arith.extsi %511 : i32 to i64
    %512 = arith.addi %arg0, %513 : i64
    %514 = arith.constant 4 : i32
    %516 = arith.extsi %514 : i32 to i64
    %515 = arith.muli %512, %516 : i64
    %510 = func.call @malloc(%515) : (i64) -> !llvm.ptr
    %517 = arith.constant 0 : i32
    %518 = arith.extsi %517 : i32 to i64
    %519 = llvm.mlir.constant(1 : i64) : i64
    %520 = llvm.alloca %519 x i64 : (i64) -> !llvm.ptr
    llvm.store %518, %520 : i64, !llvm.ptr
    cf.br ^bb48
    ^bb48:
    %521 = llvm.load %520 : !llvm.ptr -> i64
    %522 = arith.cmpi sle, %521, %arg0 : i64
    cf.cond_br %522, ^bb49, ^bb50
    ^bb49:
      %523 = llvm.load %520 : !llvm.ptr -> i64
      %524 = arith.trunci %523 : i64 to i32
      %525 = llvm.load %520 : !llvm.ptr -> i64
      %526 = llvm.getelementptr %510[%525] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %524, %526 : i32, !llvm.ptr
      %527 = llvm.load %520 : !llvm.ptr -> i64
      %528 = arith.constant 1 : i32
      %530 = arith.extsi %528 : i32 to i64
      %529 = arith.addi %527, %530 : i64
      llvm.store %529, %520 : i64, !llvm.ptr
      cf.br ^bb48
    ^bb50:
    %531 = arith.constant 2 : i32
    %532 = arith.extsi %531 : i32 to i64
    %533 = llvm.mlir.constant(1 : i64) : i64
    %534 = llvm.alloca %533 x i64 : (i64) -> !llvm.ptr
    llvm.store %532, %534 : i64, !llvm.ptr
    cf.br ^bb51
    ^bb51:
    %535 = llvm.load %534 : !llvm.ptr -> i64
    %536 = arith.cmpi sle, %535, %arg0 : i64
    cf.cond_br %536, ^bb52, ^bb53
    ^bb52:
      %538 = llvm.load %534 : !llvm.ptr -> i64
      %539 = llvm.getelementptr %510[%538] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %537 = llvm.load %539 : !llvm.ptr -> i32
      %540 = arith.extsi %537 : i32 to i64
      %541 = llvm.load %534 : !llvm.ptr -> i64
      %542 = arith.cmpi eq, %540, %541 : i64
      cf.cond_br %542, ^bb54, ^bb55
      ^bb54:
        %543 = llvm.load %534 : !llvm.ptr -> i64
        %544 = llvm.mlir.constant(1 : i64) : i64
        %545 = llvm.alloca %544 x i64 : (i64) -> !llvm.ptr
        llvm.store %543, %545 : i64, !llvm.ptr
        cf.br ^bb57
        ^bb57:
        %546 = llvm.load %545 : !llvm.ptr -> i64
        %547 = arith.cmpi sle, %546, %arg0 : i64
        cf.cond_br %547, ^bb58, ^bb59
        ^bb58:
          %549 = llvm.load %545 : !llvm.ptr -> i64
          %550 = llvm.getelementptr %510[%549] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          %548 = llvm.load %550 : !llvm.ptr -> i32
          %552 = llvm.load %545 : !llvm.ptr -> i64
          %553 = llvm.getelementptr %510[%552] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          %551 = llvm.load %553 : !llvm.ptr -> i32
          %554 = llvm.load %534 : !llvm.ptr -> i64
          %555 = arith.trunci %554 : i64 to i32
          %556 = arith.divsi %551, %555 : i32
          %557 = arith.subi %548, %556 : i32
          %558 = llvm.load %545 : !llvm.ptr -> i64
          %559 = llvm.getelementptr %510[%558] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %557, %559 : i32, !llvm.ptr
          %560 = llvm.load %545 : !llvm.ptr -> i64
          %561 = llvm.load %534 : !llvm.ptr -> i64
          %562 = arith.addi %560, %561 : i64
          llvm.store %562, %545 : i64, !llvm.ptr
          cf.br ^bb57
        ^bb59:
        cf.br ^bb56
      ^bb55:
        cf.br ^bb56
      ^bb56:
      %563 = llvm.load %534 : !llvm.ptr -> i64
      %564 = arith.constant 1 : i32
      %566 = arith.extsi %564 : i32 to i64
      %565 = arith.addi %563, %566 : i64
      llvm.store %565, %534 : i64, !llvm.ptr
      cf.br ^bb51
    ^bb53:
    %568 = arith.constant 1 : i32
    %570 = arith.extsi %568 : i32 to i64
    %569 = arith.addi %arg0, %570 : i64
    %571 = arith.constant 4 : i32
    %572 = arith.extsi %571 : i32 to i64
    %567 = func.call @calloc(%569, %572) : (i64, i64) -> !llvm.ptr
    %573 = llvm.mlir.addressof @tp_pref0 : !llvm.ptr
    llvm.store %567, %573 : !llvm.ptr, !llvm.ptr
    %575 = arith.constant 1 : i32
    %577 = arith.extsi %575 : i32 to i64
    %576 = arith.addi %arg0, %577 : i64
    %578 = arith.constant 4 : i32
    %579 = arith.extsi %578 : i32 to i64
    %574 = func.call @calloc(%576, %579) : (i64, i64) -> !llvm.ptr
    %580 = llvm.mlir.addressof @tp_pref1 : !llvm.ptr
    llvm.store %574, %580 : !llvm.ptr, !llvm.ptr
    %582 = arith.constant 1 : i32
    %584 = arith.extsi %582 : i32 to i64
    %583 = arith.addi %arg0, %584 : i64
    %585 = arith.constant 4 : i32
    %586 = arith.extsi %585 : i32 to i64
    %581 = func.call @calloc(%583, %586) : (i64, i64) -> !llvm.ptr
    %587 = llvm.mlir.addressof @tp_pref2 : !llvm.ptr
    llvm.store %581, %587 : !llvm.ptr, !llvm.ptr
    %588 = arith.constant 0 : i32
    %589 = arith.extsi %588 : i32 to i64
    %590 = llvm.mlir.constant(1 : i64) : i64
    %591 = llvm.alloca %590 x i64 : (i64) -> !llvm.ptr
    llvm.store %589, %591 : i64, !llvm.ptr
    %592 = arith.constant 0 : i32
    %593 = arith.extsi %592 : i32 to i64
    %594 = llvm.mlir.constant(1 : i64) : i64
    %595 = llvm.alloca %594 x i64 : (i64) -> !llvm.ptr
    llvm.store %593, %595 : i64, !llvm.ptr
    %596 = arith.constant 0 : i32
    %597 = arith.extsi %596 : i32 to i64
    %598 = llvm.mlir.constant(1 : i64) : i64
    %599 = llvm.alloca %598 x i64 : (i64) -> !llvm.ptr
    llvm.store %597, %599 : i64, !llvm.ptr
    %600 = arith.constant 1 : i32
    %601 = arith.extsi %600 : i32 to i64
    llvm.store %601, %520 : i64, !llvm.ptr
    cf.br ^bb60
    ^bb60:
    %602 = llvm.load %520 : !llvm.ptr -> i64
    %603 = arith.cmpi sle, %602, %arg0 : i64
    cf.cond_br %603, ^bb61, ^bb62
    ^bb61:
      %605 = llvm.load %520 : !llvm.ptr -> i64
      %606 = llvm.getelementptr %510[%605] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %604 = llvm.load %606 : !llvm.ptr -> i32
      %607 = arith.extsi %604 : i32 to i64
      %608 = llvm.load %520 : !llvm.ptr -> i64
      %609 = llvm.mlir.addressof @MOD : !llvm.ptr
      %610 = llvm.load %609 : !llvm.ptr -> i64
      %611 = arith.remsi %608, %610 : i64
      %612 = llvm.load %591 : !llvm.ptr -> i64
      %613 = arith.addi %612, %607 : i64
      %614 = llvm.mlir.addressof @MOD : !llvm.ptr
      %615 = llvm.load %614 : !llvm.ptr -> i64
      %616 = arith.remsi %613, %615 : i64
      llvm.store %616, %591 : i64, !llvm.ptr
      %617 = llvm.load %595 : !llvm.ptr -> i64
      %618 = arith.muli %611, %607 : i64
      %619 = llvm.mlir.addressof @MOD : !llvm.ptr
      %620 = llvm.load %619 : !llvm.ptr -> i64
      %621 = arith.remsi %618, %620 : i64
      %622 = arith.addi %617, %621 : i64
      %623 = llvm.mlir.addressof @MOD : !llvm.ptr
      %624 = llvm.load %623 : !llvm.ptr -> i64
      %625 = arith.remsi %622, %624 : i64
      llvm.store %625, %595 : i64, !llvm.ptr
      %626 = llvm.load %599 : !llvm.ptr -> i64
      %627 = arith.muli %611, %611 : i64
      %628 = llvm.mlir.addressof @MOD : !llvm.ptr
      %629 = llvm.load %628 : !llvm.ptr -> i64
      %630 = arith.remsi %627, %629 : i64
      %631 = arith.muli %630, %607 : i64
      %632 = llvm.mlir.addressof @MOD : !llvm.ptr
      %633 = llvm.load %632 : !llvm.ptr -> i64
      %634 = arith.remsi %631, %633 : i64
      %635 = arith.addi %626, %634 : i64
      %636 = llvm.mlir.addressof @MOD : !llvm.ptr
      %637 = llvm.load %636 : !llvm.ptr -> i64
      %638 = arith.remsi %635, %637 : i64
      llvm.store %638, %599 : i64, !llvm.ptr
      %639 = llvm.load %591 : !llvm.ptr -> i64
      %640 = arith.trunci %639 : i64 to i32
      %641 = llvm.mlir.addressof @tp_pref0 : !llvm.ptr
      %642 = llvm.load %641 : !llvm.ptr -> !llvm.ptr
      %643 = llvm.load %520 : !llvm.ptr -> i64
      %644 = llvm.getelementptr %642[%643] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %640, %644 : i32, !llvm.ptr
      %645 = llvm.load %595 : !llvm.ptr -> i64
      %646 = arith.trunci %645 : i64 to i32
      %647 = llvm.mlir.addressof @tp_pref1 : !llvm.ptr
      %648 = llvm.load %647 : !llvm.ptr -> !llvm.ptr
      %649 = llvm.load %520 : !llvm.ptr -> i64
      %650 = llvm.getelementptr %648[%649] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %646, %650 : i32, !llvm.ptr
      %651 = llvm.load %599 : !llvm.ptr -> i64
      %652 = arith.trunci %651 : i64 to i32
      %653 = llvm.mlir.addressof @tp_pref2 : !llvm.ptr
      %654 = llvm.load %653 : !llvm.ptr -> !llvm.ptr
      %655 = llvm.load %520 : !llvm.ptr -> i64
      %656 = llvm.getelementptr %654[%655] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %652, %656 : i32, !llvm.ptr
      %657 = llvm.load %520 : !llvm.ptr -> i64
      %658 = arith.constant 1 : i32
      %660 = arith.extsi %658 : i32 to i64
      %659 = arith.addi %657, %660 : i64
      llvm.store %659, %520 : i64, !llvm.ptr
      cf.br ^bb60
    ^bb62:
    func.call @free(%510) : (!llvm.ptr) -> ()
    %662 = arith.constant 1 : i32
    %663 = arith.constant 20 : i32
    %664 = arith.shli %662, %663 : i32
    %665 = arith.extsi %664 : i32 to i64
    %666 = llvm.mlir.addressof @cache_size : !llvm.ptr
    llvm.store %665, %666 : i64, !llvm.ptr
    %667 = arith.constant 0 : i32
    %668 = arith.extsi %667 : i32 to i64
    %669 = llvm.mlir.addressof @cache_count : !llvm.ptr
    llvm.store %668, %669 : i64, !llvm.ptr
    %671 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %672 = llvm.load %671 : !llvm.ptr -> i64
    %673 = arith.constant 8 : i32
    %674 = arith.extsi %673 : i32 to i64
    %670 = func.call @calloc(%672, %674) : (i64, i64) -> !llvm.ptr
    %675 = llvm.mlir.addressof @cache_key : !llvm.ptr
    llvm.store %670, %675 : !llvm.ptr, !llvm.ptr
    %677 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %678 = llvm.load %677 : !llvm.ptr -> i64
    %679 = arith.constant 8 : i32
    %680 = arith.extsi %679 : i32 to i64
    %676 = func.call @calloc(%678, %680) : (i64, i64) -> !llvm.ptr
    %681 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
    llvm.store %676, %681 : !llvm.ptr, !llvm.ptr
    %683 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %684 = llvm.load %683 : !llvm.ptr -> i64
    %685 = arith.constant 8 : i32
    %686 = arith.extsi %685 : i32 to i64
    %682 = func.call @calloc(%684, %686) : (i64, i64) -> !llvm.ptr
    %687 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
    llvm.store %682, %687 : !llvm.ptr, !llvm.ptr
    %689 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %690 = llvm.load %689 : !llvm.ptr -> i64
    %691 = arith.constant 8 : i32
    %692 = arith.extsi %691 : i32 to i64
    %688 = func.call @calloc(%690, %692) : (i64, i64) -> !llvm.ptr
    %693 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
    llvm.store %688, %693 : !llvm.ptr, !llvm.ptr
    %695 = llvm.mlir.addressof @cache_size : !llvm.ptr
    %696 = llvm.load %695 : !llvm.ptr -> i64
    %697 = arith.constant 1 : i32
    %698 = arith.extsi %697 : i32 to i64
    %694 = func.call @calloc(%696, %698) : (i64, i64) -> !llvm.ptr
    %699 = llvm.mlir.addressof @cache_used : !llvm.ptr
    llvm.store %694, %699 : !llvm.ptr, !llvm.ptr
    %701 = arith.constant 768 : i32
    %702 = arith.constant 8 : i32
    %703 = arith.extsi %701 : i32 to i64
    %704 = arith.extsi %702 : i32 to i64
    %700 = func.call @calloc(%703, %704) : (i64, i64) -> !llvm.ptr
    %705 = llvm.mlir.addressof @tp_scratch : !llvm.ptr
    llvm.store %700, %705 : !llvm.ptr, !llvm.ptr
    %706 = arith.constant 0 : i32
    %707 = arith.extsi %706 : i32 to i64
    %708 = llvm.mlir.addressof @tp_depth : !llvm.ptr
    llvm.store %707, %708 : i64, !llvm.ptr
    func.return
  }
  func.func @nonconcurrent_candidate_count(%arg0: i64, %arg1: i64) -> i64 {
    %709 = llvm.mlir.addressof @MOD : !llvm.ptr
    %710 = llvm.load %709 : !llvm.ptr -> i64
    %711 = arith.remsi %arg0, %710 : i64
    %712 = arith.constant 1 : i32
    %714 = arith.extsi %712 : i32 to i64
    %713 = arith.subi %711, %714 : i64
    %715 = llvm.mlir.addressof @MOD : !llvm.ptr
    %716 = llvm.load %715 : !llvm.ptr -> i64
    %717 = arith.addi %713, %716 : i64
    %718 = llvm.mlir.addressof @MOD : !llvm.ptr
    %719 = llvm.load %718 : !llvm.ptr -> i64
    %720 = arith.remsi %717, %719 : i64
    %721 = llvm.mlir.addressof @MOD : !llvm.ptr
    %722 = llvm.load %721 : !llvm.ptr -> i64
    %723 = arith.remsi %arg1, %722 : i64
    %724 = arith.constant 1 : i32
    %726 = arith.extsi %724 : i32 to i64
    %725 = arith.subi %723, %726 : i64
    %727 = llvm.mlir.addressof @MOD : !llvm.ptr
    %728 = llvm.load %727 : !llvm.ptr -> i64
    %729 = arith.addi %725, %728 : i64
    %730 = llvm.mlir.addressof @MOD : !llvm.ptr
    %731 = llvm.load %730 : !llvm.ptr -> i64
    %732 = arith.remsi %729, %731 : i64
    %733 = arith.constant 1 : i32
    %735 = arith.extsi %733 : i32 to i64
    %734 = arith.addi %723, %735 : i64
    %736 = llvm.mlir.addressof @MOD : !llvm.ptr
    %737 = llvm.load %736 : !llvm.ptr -> i64
    %738 = arith.remsi %734, %737 : i64
    %743 = func.call @mulmod(%711, %720) : (i64, i64) -> i64
    %742 = func.call @mulmod(%743, %723) : (i64, i64) -> i64
    %741 = func.call @mulmod(%742, %732) : (i64, i64) -> i64
    %740 = func.call @mulmod(%741, %738) : (i64, i64) -> i64
    %744 = llvm.mlir.addressof @INV6 : !llvm.ptr
    %745 = llvm.load %744 : !llvm.ptr -> i64
    %739 = func.call @mulmod(%740, %745) : (i64, i64) -> i64
    %747 = arith.constant 2 : i32
    %749 = arith.extsi %747 : i32 to i64
    %748 = arith.addi %arg1, %749 : i64
    %746 = func.call @c3_mod(%748) : (i64) -> i64
    %750 = llvm.mlir.addressof @MOD : !llvm.ptr
    %751 = llvm.load %750 : !llvm.ptr -> i64
    %752 = arith.remsi %arg1, %751 : i64
    %753 = arith.subi %746, %752 : i64
    %754 = llvm.mlir.addressof @MOD : !llvm.ptr
    %755 = llvm.load %754 : !llvm.ptr -> i64
    %756 = arith.addi %753, %755 : i64
    %757 = llvm.mlir.addressof @MOD : !llvm.ptr
    %758 = llvm.load %757 : !llvm.ptr -> i64
    %759 = arith.remsi %756, %758 : i64
    %761 = func.call @c3_mod(%arg0) : (i64) -> i64
    %760 = func.call @mulmod(%761, %759) : (i64, i64) -> i64
    %762 = arith.addi %739, %760 : i64
    %763 = llvm.mlir.addressof @MOD : !llvm.ptr
    %764 = llvm.load %763 : !llvm.ptr -> i64
    %765 = arith.remsi %762, %764 : i64
    func.return %765 : i64
  }
  func.func @weighted_gcd_sum(%arg0: i64, %arg1: i64) -> i64 {
    %766 = arith.constant 1 : i32
    %768 = arith.extsi %766 : i32 to i64
    %767 = arith.subi %arg0, %768 : i64
    %769 = arith.constant 1 : i32
    %771 = arith.extsi %769 : i32 to i64
    %770 = arith.subi %arg1, %771 : i64
    %772 = arith.cmpi slt, %767, %770 : i64
    %773 = scf.if %772 -> (i64) {
      scf.yield %767 : i64
    } else {
      scf.yield %770 : i64
    }
    %774 = arith.constant 0 : i32
    %775 = arith.extsi %774 : i32 to i64
    %776 = llvm.mlir.constant(1 : i64) : i64
    %777 = llvm.alloca %776 x i64 : (i64) -> !llvm.ptr
    llvm.store %775, %777 : i64, !llvm.ptr
    # String concatenation: !llvm.ptr + i32
    # String concatenation: !llvm.ptr + i32
    %780 = arith.constant 2 : i32
    %781 = arith.extsi %780 : i32 to i64
    %782 = llvm.mlir.addressof @tp_depth : !llvm.ptr
    llvm.store %781, %782 : i64, !llvm.ptr
    %783 = arith.constant 1 : i32
    %784 = arith.extsi %783 : i32 to i64
    %785 = llvm.mlir.constant(1 : i64) : i64
    %786 = llvm.alloca %785 x i64 : (i64) -> !llvm.ptr
    llvm.store %784, %786 : i64, !llvm.ptr
    cf.br ^bb63
    ^bb63:
    %787 = llvm.load %786 : !llvm.ptr -> i64
    %788 = arith.cmpi sle, %787, %773 : i64
    cf.cond_br %788, ^bb64, ^bb65
    ^bb64:
      %789 = llvm.load %786 : !llvm.ptr -> i64
      %790 = arith.divsi %767, %789 : i64
      %791 = llvm.load %786 : !llvm.ptr -> i64
      %792 = arith.divsi %770, %791 : i64
      %793 = arith.divsi %767, %790 : i64
      %794 = llvm.mlir.constant(1 : i64) : i64
      %795 = llvm.alloca %794 x i64 : (i64) -> !llvm.ptr
      llvm.store %793, %795 : i64, !llvm.ptr
      %796 = arith.divsi %770, %792 : i64
      %797 = llvm.load %795 : !llvm.ptr -> i64
      %798 = arith.cmpi slt, %796, %797 : i64
      cf.cond_br %798, ^bb66, ^bb67
      ^bb66:
        %799 = arith.divsi %770, %792 : i64
        llvm.store %799, %795 : i64, !llvm.ptr
        cf.br ^bb68
      ^bb67:
        cf.br ^bb68
      ^bb68:
      %800 = llvm.load %795 : !llvm.ptr -> i64
      %801 = arith.cmpi slt, %773, %800 : i64
      cf.cond_br %801, ^bb69, ^bb70
      ^bb69:
        llvm.store %773, %795 : i64, !llvm.ptr
        cf.br ^bb71
      ^bb70:
        cf.br ^bb71
      ^bb71:
      %803 = llvm.load %795 : !llvm.ptr -> i64
      func.call @tp_values(%803, %778) : (i64, !llvm.ptr) -> ()
      %805 = llvm.load %786 : !llvm.ptr -> i64
      %806 = arith.constant 1 : i32
      %808 = arith.extsi %806 : i32 to i64
      %807 = arith.subi %805, %808 : i64
      func.call @tp_values(%807, %779) : (i64, !llvm.ptr) -> ()
      %810 = arith.constant 0 : i32
      %811 = arith.extsi %810 : i32 to i64
      %812 = llvm.getelementptr %778[%811] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %809 = llvm.load %812 : !llvm.ptr -> i64
      %814 = arith.constant 0 : i32
      %815 = arith.extsi %814 : i32 to i64
      %816 = llvm.getelementptr %779[%815] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %813 = llvm.load %816 : !llvm.ptr -> i64
      %817 = arith.subi %809, %813 : i64
      %818 = llvm.mlir.addressof @MOD : !llvm.ptr
      %819 = llvm.load %818 : !llvm.ptr -> i64
      %820 = arith.addi %817, %819 : i64
      %821 = llvm.mlir.addressof @MOD : !llvm.ptr
      %822 = llvm.load %821 : !llvm.ptr -> i64
      %823 = arith.remsi %820, %822 : i64
      %825 = arith.constant 1 : i32
      %826 = arith.extsi %825 : i32 to i64
      %827 = llvm.getelementptr %778[%826] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %824 = llvm.load %827 : !llvm.ptr -> i64
      %829 = arith.constant 1 : i32
      %830 = arith.extsi %829 : i32 to i64
      %831 = llvm.getelementptr %779[%830] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %828 = llvm.load %831 : !llvm.ptr -> i64
      %832 = arith.subi %824, %828 : i64
      %833 = llvm.mlir.addressof @MOD : !llvm.ptr
      %834 = llvm.load %833 : !llvm.ptr -> i64
      %835 = arith.addi %832, %834 : i64
      %836 = llvm.mlir.addressof @MOD : !llvm.ptr
      %837 = llvm.load %836 : !llvm.ptr -> i64
      %838 = arith.remsi %835, %837 : i64
      %840 = arith.constant 2 : i32
      %841 = arith.extsi %840 : i32 to i64
      %842 = llvm.getelementptr %778[%841] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %839 = llvm.load %842 : !llvm.ptr -> i64
      %844 = arith.constant 2 : i32
      %845 = arith.extsi %844 : i32 to i64
      %846 = llvm.getelementptr %779[%845] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %843 = llvm.load %846 : !llvm.ptr -> i64
      %847 = arith.subi %839, %843 : i64
      %848 = llvm.mlir.addressof @MOD : !llvm.ptr
      %849 = llvm.load %848 : !llvm.ptr -> i64
      %850 = arith.addi %847, %849 : i64
      %851 = llvm.mlir.addressof @MOD : !llvm.ptr
      %852 = llvm.load %851 : !llvm.ptr -> i64
      %853 = arith.remsi %850, %852 : i64
      %854 = llvm.mlir.addressof @MOD : !llvm.ptr
      %855 = llvm.load %854 : !llvm.ptr -> i64
      %856 = arith.remsi %790, %855 : i64
      %857 = llvm.mlir.addressof @MOD : !llvm.ptr
      %858 = llvm.load %857 : !llvm.ptr -> i64
      %859 = arith.remsi %792, %858 : i64
      %861 = llvm.mlir.addressof @MOD : !llvm.ptr
      %862 = llvm.load %861 : !llvm.ptr -> i64
      %863 = arith.remsi %arg0, %862 : i64
      %860 = func.call @mulmod(%856, %863) : (i64, i64) -> i64
      %867 = arith.constant 0 : i64
      %866 = arith.subi %867, %856 : i64
      %868 = llvm.mlir.addressof @MOD : !llvm.ptr
      %869 = llvm.load %868 : !llvm.ptr -> i64
      %870 = arith.addi %866, %869 : i64
      %871 = arith.constant 1 : i32
      %873 = arith.extsi %871 : i32 to i64
      %872 = arith.addi %790, %873 : i64
      %874 = llvm.mlir.addressof @MOD : !llvm.ptr
      %875 = llvm.load %874 : !llvm.ptr -> i64
      %876 = arith.remsi %872, %875 : i64
      %865 = func.call @mulmod(%870, %876) : (i64, i64) -> i64
      %877 = llvm.mlir.addressof @INV2 : !llvm.ptr
      %878 = llvm.load %877 : !llvm.ptr -> i64
      %864 = func.call @mulmod(%865, %878) : (i64, i64) -> i64
      %880 = llvm.mlir.addressof @MOD : !llvm.ptr
      %881 = llvm.load %880 : !llvm.ptr -> i64
      %882 = arith.remsi %arg1, %881 : i64
      %879 = func.call @mulmod(%859, %882) : (i64, i64) -> i64
      %886 = arith.constant 0 : i64
      %885 = arith.subi %886, %859 : i64
      %887 = llvm.mlir.addressof @MOD : !llvm.ptr
      %888 = llvm.load %887 : !llvm.ptr -> i64
      %889 = arith.addi %885, %888 : i64
      %890 = arith.constant 1 : i32
      %892 = arith.extsi %890 : i32 to i64
      %891 = arith.addi %792, %892 : i64
      %893 = llvm.mlir.addressof @MOD : !llvm.ptr
      %894 = llvm.load %893 : !llvm.ptr -> i64
      %895 = arith.remsi %891, %894 : i64
      %884 = func.call @mulmod(%889, %895) : (i64, i64) -> i64
      %896 = llvm.mlir.addressof @INV2 : !llvm.ptr
      %897 = llvm.load %896 : !llvm.ptr -> i64
      %883 = func.call @mulmod(%884, %897) : (i64, i64) -> i64
      %898 = func.call @mulmod(%860, %879) : (i64, i64) -> i64
      %899 = func.call @mulmod(%860, %883) : (i64, i64) -> i64
      %900 = func.call @mulmod(%864, %879) : (i64, i64) -> i64
      %901 = arith.addi %899, %900 : i64
      %902 = llvm.mlir.addressof @MOD : !llvm.ptr
      %903 = llvm.load %902 : !llvm.ptr -> i64
      %904 = arith.remsi %901, %903 : i64
      %905 = func.call @mulmod(%864, %883) : (i64, i64) -> i64
      %906 = arith.muli %898, %823 : i64
      %907 = arith.muli %904, %838 : i64
      %908 = arith.addi %906, %907 : i64
      %909 = arith.muli %905, %853 : i64
      %910 = arith.addi %908, %909 : i64
      %911 = llvm.mlir.addressof @MOD : !llvm.ptr
      %912 = llvm.load %911 : !llvm.ptr -> i64
      %913 = arith.remsi %910, %912 : i64
      %914 = llvm.mlir.constant(1 : i64) : i64
      %915 = llvm.alloca %914 x i64 : (i64) -> !llvm.ptr
      llvm.store %913, %915 : i64, !llvm.ptr
      %916 = llvm.load %777 : !llvm.ptr -> i64
      %917 = llvm.load %915 : !llvm.ptr -> i64
      %918 = arith.addi %916, %917 : i64
      %919 = llvm.mlir.addressof @MOD : !llvm.ptr
      %920 = llvm.load %919 : !llvm.ptr -> i64
      %921 = arith.remsi %918, %920 : i64
      llvm.store %921, %777 : i64, !llvm.ptr
      %922 = llvm.load %795 : !llvm.ptr -> i64
      %923 = arith.constant 1 : i32
      %925 = arith.extsi %923 : i32 to i64
      %924 = arith.addi %922, %925 : i64
      llvm.store %924, %786 : i64, !llvm.ptr
      cf.br ^bb63
    ^bb65:
    %926 = llvm.load %777 : !llvm.ptr -> i64
    func.return %926 : i64
  }
  func.func @concurrent_triple_count(%arg0: i64, %arg1: i64) -> i64 {
    %927 = func.call @weighted_gcd_sum(%arg0, %arg1) : (i64, i64) -> i64
    %929 = func.call @c2_mod(%arg0) : (i64) -> i64
    %930 = func.call @c2_mod(%arg1) : (i64) -> i64
    %928 = func.call @mulmod(%929, %930) : (i64, i64) -> i64
    %931 = arith.subi %927, %928 : i64
    %932 = llvm.mlir.addressof @MOD : !llvm.ptr
    %933 = llvm.load %932 : !llvm.ptr -> i64
    %934 = arith.addi %931, %933 : i64
    %935 = llvm.mlir.addressof @MOD : !llvm.ptr
    %936 = llvm.load %935 : !llvm.ptr -> i64
    %937 = arith.remsi %934, %936 : i64
    func.return %937 : i64
  }
  func.func @main() -> i32 {
    %938 = llvm.mlir.addressof @MOD : !llvm.ptr
    %939 = llvm.load %938 : !llvm.ptr -> i64
    %940 = arith.constant 1 : i32
    %942 = arith.extsi %940 : i32 to i64
    %941 = arith.addi %939, %942 : i64
    %943 = arith.constant 2 : i32
    %945 = arith.extsi %943 : i32 to i64
    %944 = arith.divsi %941, %945 : i64
    %946 = llvm.mlir.addressof @INV2 : !llvm.ptr
    llvm.store %944, %946 : i64, !llvm.ptr
    %948 = arith.constant 6 : i32
    %949 = llvm.mlir.addressof @MOD : !llvm.ptr
    %950 = llvm.load %949 : !llvm.ptr -> i64
    %951 = arith.constant 2 : i32
    %953 = arith.extsi %951 : i32 to i64
    %952 = arith.subi %950, %953 : i64
    %954 = arith.extsi %948 : i32 to i64
    %947 = func.call @mod_pow(%954, %952) : (i64, i64) -> i64
    %955 = llvm.mlir.addressof @INV6 : !llvm.ptr
    llvm.store %947, %955 : i64, !llvm.ptr
    %956 = arith.constant 12000000 : i32
    %957 = arith.extsi %956 : i32 to i64
    func.call @tp_init(%957) : (i64) -> ()
    %959 = arith.constant 1234 : i32
    %960 = arith.extsi %959 : i32 to i64
    %961 = arith.constant 100000000 : i32
    %963 = arith.extsi %961 : i32 to i64
    %962 = arith.muli %960, %963 : i64
    %964 = arith.constant 2345 : i32
    %965 = arith.extsi %964 : i32 to i64
    %966 = arith.constant 100000000 : i32
    %968 = arith.extsi %966 : i32 to i64
    %967 = arith.muli %965, %968 : i64
    %969 = func.call @nonconcurrent_candidate_count(%962, %967) : (i64, i64) -> i64
    %970 = func.call @concurrent_triple_count(%962, %967) : (i64, i64) -> i64
    %971 = arith.subi %969, %970 : i64
    %972 = llvm.mlir.addressof @MOD : !llvm.ptr
    %973 = llvm.load %972 : !llvm.ptr -> i64
    %974 = arith.addi %971, %973 : i64
    %975 = llvm.mlir.addressof @MOD : !llvm.ptr
    %976 = llvm.load %975 : !llvm.ptr -> i64
    %977 = arith.remsi %974, %976 : i64
    %978 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %979 = llvm.call @printf(%978, %977) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    %981 = llvm.mlir.addressof @tp_pref0 : !llvm.ptr
    %982 = llvm.load %981 : !llvm.ptr -> !llvm.ptr
    func.call @free(%982) : (!llvm.ptr) -> ()
    %984 = llvm.mlir.addressof @tp_pref1 : !llvm.ptr
    %985 = llvm.load %984 : !llvm.ptr -> !llvm.ptr
    func.call @free(%985) : (!llvm.ptr) -> ()
    %987 = llvm.mlir.addressof @tp_pref2 : !llvm.ptr
    %988 = llvm.load %987 : !llvm.ptr -> !llvm.ptr
    func.call @free(%988) : (!llvm.ptr) -> ()
    %990 = llvm.mlir.addressof @tp_scratch : !llvm.ptr
    %991 = llvm.load %990 : !llvm.ptr -> !llvm.ptr
    func.call @free(%991) : (!llvm.ptr) -> ()
    %993 = llvm.mlir.addressof @cache_key : !llvm.ptr
    %994 = llvm.load %993 : !llvm.ptr -> !llvm.ptr
    func.call @free(%994) : (!llvm.ptr) -> ()
    %996 = llvm.mlir.addressof @cache_f0 : !llvm.ptr
    %997 = llvm.load %996 : !llvm.ptr -> !llvm.ptr
    func.call @free(%997) : (!llvm.ptr) -> ()
    %999 = llvm.mlir.addressof @cache_f1 : !llvm.ptr
    %1000 = llvm.load %999 : !llvm.ptr -> !llvm.ptr
    func.call @free(%1000) : (!llvm.ptr) -> ()
    %1002 = llvm.mlir.addressof @cache_f2 : !llvm.ptr
    %1003 = llvm.load %1002 : !llvm.ptr -> !llvm.ptr
    func.call @free(%1003) : (!llvm.ptr) -> ()
    %1005 = llvm.mlir.addressof @cache_used : !llvm.ptr
    %1006 = llvm.load %1005 : !llvm.ptr -> !llvm.ptr
    func.call @free(%1006) : (!llvm.ptr) -> ()
    %1007 = arith.constant 0 : i32
    func.return %1007 : i32
  }
}