Problem 996

Overtaking - polynomial generating function approach, mod 1234567891.

Answer137726405
Output137726405
StatusPASS
Native helperno
Runtime380 ms
Peak memory1552 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)O(n^2)
Space complexityO(n^2)O(n)
ApproachFlow solutionPolynomial interpolation
VerdictOptimal

Flow source

# Project Euler 996
# Overtaking - polynomial generating function approach, mod 1234567891.

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

const MOD: i64 = 1234567891

function mod_add(a: i64, b: i64) -> i64 {
    let mut r: i64 = a + b
    if r >= MOD { r = r - MOD }
    if r < 0 { r = r + MOD }
    return r
}

function mod_sub(a: i64, b: i64) -> i64 {
    let mut r: i64 = a - b
    if r < 0 { r = r + MOD }
    return r
}

function mod_mul(a: i64, b: i64) -> i64 {
    let prod: i128 = (a as i128) * (b as i128)
    let m: i128 = MOD as i128
    return (prod % m) as i64
}

function ext_gcd(a: i64, b: i64, x: ptr<i64>, y: ptr<i64>) -> i64 {
    if b == 0 {
        x[0] = 1
        y[0] = 0
        return a
    }
    let x1: ptr<i64> = calloc(1, 8) as ptr<i64>
    let y1: ptr<i64> = calloc(1, 8) as ptr<i64>
    let g: i64 = ext_gcd(b, a % b, x1, y1)
    x[0] = y1[0]
    y[0] = x1[0] - (a / b) * y1[0]
    free(x1 as ptr<void>)
    free(y1 as ptr<void>)
    return g
}

function mod_inv(a: i64) -> i64 {
    let mut v: i64 = a % MOD
    if v < 0 { v = v + MOD }
    let x: ptr<i64> = calloc(1, 8) as ptr<i64>
    let y: ptr<i64> = calloc(1, 8) as ptr<i64>
    ext_gcd(v, MOD, x, y)
    let mut r: i64 = x[0] % MOD
    if r < 0 { r = r + MOD }
    free(x as ptr<void>)
    free(y as ptr<void>)
    return r
}

# Compute C(n, k) mod MOD for small k.
function comb_mod(n: i64, k: i64) -> i64 {
    if k < 0 || k > n || n < 0 { return 0 }
    if k == 0 || k == n { return 1 }
    let mut kk: i64 = k
    if kk > n - kk { kk = n - kk }
    let mut num: i64 = 1
    let mut den: i64 = 1
    let mut i: i64 = 0
    while i < kk {
        num = mod_mul(num, (n - i) % MOD)
        den = mod_mul(den, (i + 1) % MOD)
        i = i + 1
    }
    return mod_mul(num, mod_inv(den))
}

function trim(poly: ptr<i64>, len: ptr<i32>) -> void {
    while len[0] > 1 && poly[len[0] - 1] == 0 {
        len[0] = len[0] - 1
    }
}

function add_to(dst: ptr<i64>, dst_len: ptr<i32>, src: ptr<i64>, src_len: i32) -> void {
    if dst_len[0] < src_len {
        let mut i: i32 = dst_len[0]
        while i < src_len {
            dst[i] = 0
            i = i + 1
        }
        dst_len[0] = src_len
    }
    let mut i: i32 = 0
    while i < src_len {
        dst[i] = mod_add(dst[i], src[i])
        i = i + 1
    }
}

# Multiply poly by (1 - q), return result in out.
function mul_one_minus_q(poly: ptr<i64>, plen: i32, out: ptr<i64>, out_len: ptr<i32>) -> void {
    let n: i32 = plen + 1
    let mut i: i32 = 0
    while i < n {
        out[i] = 0
        i = i + 1
    }
    i = 0
    while i < plen {
        out[i] = mod_add(out[i], poly[i])
        out[i + 1] = mod_sub(out[i + 1], poly[i])
        i = i + 1
    }
    out_len[0] = n
    trim(out, out_len)
}

# Multiply a and b, discarding terms above max_degree.
function mul_poly(a: ptr<i64>, alen: i32, b: ptr<i64>, blen: i32, max_degree: i32, out: ptr<i64>, out_len: ptr<i32>) -> void {
    if alen == 0 || blen == 0 {
        out[0] = 0
        out_len[0] = 1
        return
    }
    let cand: i32 = alen + blen - 2
    let n: i32 = (if cand < max_degree { cand } else { max_degree }) + 1
    let mut i: i32 = 0
    while i < n {
        out[i] = 0
        i = i + 1
    }
    i = 0
    while i < alen {
        if a[i] == 0 {
            i = i + 1
            continue
        }
        let last_j: i32 = if blen - 1 < max_degree - i { blen - 1 } else { max_degree - i }
        let mut j: i32 = 0
        while j <= last_j {
            if b[j] != 0 {
                out[i + j] = mod_add(out[i + j], mod_mul(a[i], b[j]))
            }
            j = j + 1
        }
        i = i + 1
    }
    out_len[0] = n
    trim(out, out_len)
}

function block_count(length: i32, cost: i32) -> i64 {
    if cost <= 0 || 2 * cost < length { return 0 }
    let total: i64 = comb_mod((2 * cost - 1) as i64, (length - 1) as i64)
    let too_large: i64 = if cost < length { 0 } else { comb_mod((cost - 1) as i64, (length - 1) as i64) }
    return mod_sub(total, mod_mul(length as i64, too_large))
}

function block_numerator(length: i32, out: ptr<i64>, out_len: ptr<i32>) -> void {
    let mut j: i32 = 0
    while j <= length {
        let mut value: i64 = 0
        let mut i: i32 = 0
        while i <= j {
            let sign: i64 = if i % 2 != 0 { 0 - 1 } else { 1 }
            let term: i64 = mod_mul(comb_mod(length as i64, i as i64), block_count(length, j - i))
            if sign < 0 {
                value = mod_sub(value, term)
            } else {
                value = mod_add(value, term)
            }
            i = i + 1
        }
        out[j] = value
        j = j + 1
    }
    out_len[0] = length + 1
    trim(out, out_len)
}

# Main DP: compute numerator polynomial for all valid vectors of length n.
function numerator_for_all_valid_vectors(n: i32, result: ptr<i64>, result_len: ptr<i32>) -> void {
    # block_num[length] for length 2..n
    let block_num: ptr<ptr<i64> > = calloc(128, 8) as ptr<ptr<i64> >
    let block_num_len: ptr<i32> = calloc(128, 4) as ptr<i32>
    let mut len: i32 = 2
    while len <= n {
        block_num[len] = calloc((len + 2) as i64, 8) as ptr<i64>
        block_numerator(len, block_num[len], block_num_len + len)
        len = len + 1
    }

    # total[pos] and zero_end[pos]: arrays of polynomials
    let total: ptr<ptr<i64> > = calloc(128, 8) as ptr<ptr<i64> >
    let total_len: ptr<i32> = calloc(128, 4) as ptr<i32>
    let zero_end: ptr<ptr<i64> > = calloc(128, 8) as ptr<ptr<i64> >
    let zero_end_len: ptr<i32> = calloc(128, 4) as ptr<i32>

    let mut pos: i32 = 0
    while pos <= n {
        total[pos] = calloc((n + 2) as i64, 8) as ptr<i64>
        total_len[pos] = 1
        total[pos][0] = 0
        zero_end[pos] = calloc((n + 2) as i64, 8) as ptr<i64>
        zero_end_len[pos] = 1
        zero_end[pos][0] = 0
        pos = pos + 1
    }
    total[0][0] = 1
    total_len[0] = 1
    zero_end[0][0] = 1
    zero_end_len[0] = 1

    let tmp: ptr<i64> = calloc((n + 2) as i64, 8) as ptr<i64>
    let prod: ptr<i64> = calloc((n + 2) as i64, 8) as ptr<i64>
    let tmp_len: ptr<i32> = calloc(1, 4) as ptr<i32>
    let prod_len: ptr<i32> = calloc(1, 4) as ptr<i32>

    pos = 0
    while pos <= n {
        if pos < n && total_len[pos] > 0 && !(total_len[pos] == 1 && total[pos][0] == 0) {
            mul_one_minus_q(total[pos], total_len[pos], tmp, tmp_len)
            add_to(total[pos + 1], total_len + pos + 1, tmp, tmp_len[0])
            add_to(zero_end[pos + 1], zero_end_len + pos + 1, tmp, tmp_len[0])
        }

        if zero_end_len[pos] > 0 && !(zero_end_len[pos] == 1 && zero_end[pos][0] == 0) {
            let mut length: i32 = 2
            while length <= n - pos {
                mul_poly(zero_end[pos], zero_end_len[pos], block_num[length], block_num_len[length], pos + length, prod, prod_len)
                add_to(total[pos + length], total_len + pos + length, prod, prod_len[0])
                length = length + 1
            }
        }
        pos = pos + 1
    }

    memcpy(result as ptr<void>, total[n] as ptr<void>, (total_len[n] as i64) * 8)
    result_len[0] = total_len[n]

    len = 2
    while len <= n {
        free(block_num[len] as ptr<void>)
        len = len + 1
    }
    pos = 0
    while pos <= n {
        free(total[pos] as ptr<void>)
        free(zero_end[pos] as ptr<void>)
        pos = pos + 1
    }
    free(block_num as ptr<void>)
    free(block_num_len as ptr<void>)
    free(total as ptr<void>)
    free(total_len as ptr<void>)
    free(zero_end as ptr<void>)
    free(zero_end_len as ptr<void>)
    free(tmp as ptr<void>)
    free(prod as ptr<void>)
    free(tmp_len as ptr<void>)
    free(prod_len as ptr<void>)
}

function count_tuples(n: i32, k: i64) -> i64 {
    let max_cost: i64 = k / 2
    let numer: ptr<i64> = calloc((n + 2) as i64, 8) as ptr<i64>
    let numer_len: ptr<i32> = calloc(1, 4) as ptr<i32>
    numerator_for_all_valid_vectors(n, numer, numer_len)

    let mut answer: i64 = 0
    let mut degree: i32 = 0
    while degree < numer_len[0] {
        if numer[degree] != 0 && (degree as i64) <= max_cost {
            let ways: i64 = comb_mod(max_cost - (degree as i64) + (n as i64), n as i64)
            answer = mod_add(answer, mod_mul(numer[degree], ways))
        }
        degree = degree + 1
    }
    free(numer as ptr<void>)
    free(numer_len as ptr<void>)
    return answer
}

function main() -> i32 {
    printf("%lld\n", count_tuples(123, 4567891))
    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 mod_add_i64_i64(int64_t a, int64_t b);
int64_t mod_sub_i64_i64(int64_t a, int64_t b);
int64_t mod_mul_i64_i64(int64_t a, int64_t b);
int64_t ext_gcd_i64_i64_ptr_i64_ptr_i64(int64_t a, int64_t b, int64_t* x, int64_t* y);
int64_t mod_inv_i64(int64_t a);
int64_t comb_mod_i64_i64(int64_t n, int64_t k);
void trim_ptr_i64_ptr_i32(int64_t* poly, int32_t* len);
void add_to_ptr_i64_ptr_i32_ptr_i64_i32(int64_t* dst, int32_t* dst_len, int64_t* src, int32_t src_len);
void mul_one_minus_q_ptr_i64_i32_ptr_i64_ptr_i32(int64_t* poly, int32_t plen, int64_t* out, int32_t* out_len);
void mul_poly_ptr_i64_i32_ptr_i64_i32_i32_ptr_i64_ptr_i32(int64_t* a, int32_t alen, int64_t* b, int32_t blen, int32_t max_degree, int64_t* out, int32_t* out_len);
int64_t block_count_i32_i32(int32_t length, int32_t cost);
void block_numerator_i32_ptr_i64_ptr_i32(int32_t length, int64_t* out, int32_t* out_len);
void numerator_for_all_valid_vectors_i32_ptr_i64_ptr_i32(int32_t n, int64_t* result, int32_t* result_len);
int64_t count_tuples_i32_i64(int32_t n, int64_t k);
int32_t main(void);

static const int64_t MOD = 1234567891;




int64_t mod_add_i64_i64(int64_t a, int64_t b) {
    int64_t r = (a + b);
    if (r >= MOD) {
        r = (r - MOD);
    }
    if (r < 0) {
        r = (r + MOD);
    }
    return r;
}

int64_t mod_sub_i64_i64(int64_t a, int64_t b) {
    int64_t r = (a - b);
    if (r < 0) {
        r = (r + MOD);
    }
    return r;
}

int64_t mod_mul_i64_i64(int64_t a, int64_t b) {
    __int128 prod = (((__int128)(a)) * ((__int128)(b)));
    __int128 m = ((__int128)(MOD));
    return ((int64_t)(FLOW_CHECKED_MOD((prod), (m))));
}

int64_t ext_gcd_i64_i64_ptr_i64_ptr_i64(int64_t a, int64_t b, int64_t* x, int64_t* y) {
    if (b == 0) {
        x[0] = 1;
        y[0] = 0;
        return a;
    }
    int64_t* x1 = (int64_t*)(((int64_t*)(calloc(1, 8))));
    int64_t* y1 = (int64_t*)(((int64_t*)(calloc(1, 8))));
    int64_t g = ext_gcd_i64_i64_ptr_i64_ptr_i64(b, FLOW_CHECKED_MOD((a), (b)), x1, y1);
    x[0] = y1[0];
    y[0] = (x1[0] - (FLOW_CHECKED_DIV((a), (b)) * y1[0]));
    free(((void*)(x1)));
    free(((void*)(y1)));
    return g;
}

int64_t mod_inv_i64(int64_t a) {
    int64_t v = FLOW_CHECKED_MOD((a), (MOD));
    if (v < 0) {
        v = (v + MOD);
    }
    int64_t* x = (int64_t*)(((int64_t*)(calloc(1, 8))));
    int64_t* y = (int64_t*)(((int64_t*)(calloc(1, 8))));
    ext_gcd_i64_i64_ptr_i64_ptr_i64(v, MOD, x, y);
    int64_t r = FLOW_CHECKED_MOD((x[0]), (MOD));
    if (r < 0) {
        r = (r + MOD);
    }
    free(((void*)(x)));
    free(((void*)(y)));
    return r;
}

int64_t comb_mod_i64_i64(int64_t n, int64_t k) {
    if (((k < 0 || k > n) || n < 0)) {
        return 0;
    }
    if ((k == 0 || k == n)) {
        return 1;
    }
    int64_t kk = k;
    if (kk > (n - kk)) {
        kk = (n - kk);
    }
    int64_t num = 1;
    int64_t den = 1;
    int64_t i = 0;
    while (i < kk) {
        num = mod_mul_i64_i64(num, FLOW_CHECKED_MOD(((n - i)), (MOD)));
        den = mod_mul_i64_i64(den, FLOW_CHECKED_MOD(((i + 1)), (MOD)));
        i = (i + 1);
    }
    return mod_mul_i64_i64(num, mod_inv_i64(den));
}

void trim_ptr_i64_ptr_i32(int64_t* poly, int32_t* len) {
    while ((len[0] > 1 && poly[(len[0] - 1)] == 0)) {
        len[0] = (len[0] - 1);
    }
}

void add_to_ptr_i64_ptr_i32_ptr_i64_i32(int64_t* dst, int32_t* dst_len, int64_t* src, int32_t src_len) {
    if (dst_len[0] < src_len) {
        int32_t i = dst_len[0];
        while (i < src_len) {
            dst[i] = 0;
            i = (i + 1);
        }
        dst_len[0] = src_len;
    }
    int32_t i = 0;
    while (i < src_len) {
        dst[i] = mod_add_i64_i64(dst[i], src[i]);
        i = (i + 1);
    }
}

void mul_one_minus_q_ptr_i64_i32_ptr_i64_ptr_i32(int64_t* poly, int32_t plen, int64_t* out, int32_t* out_len) {
    int32_t n = (plen + 1);
    int32_t i = 0;
    while (i < n) {
        out[i] = 0;
        i = (i + 1);
    }
    i = 0;
    while (i < plen) {
        out[i] = mod_add_i64_i64(out[i], poly[i]);
        out[(i + 1)] = mod_sub_i64_i64(out[(i + 1)], poly[i]);
        i = (i + 1);
    }
    out_len[0] = n;
    trim_ptr_i64_ptr_i32(out, out_len);
}

void mul_poly_ptr_i64_i32_ptr_i64_i32_i32_ptr_i64_ptr_i32(int64_t* a, int32_t alen, int64_t* b, int32_t blen, int32_t max_degree, int64_t* out, int32_t* out_len) {
    if ((alen == 0 || blen == 0)) {
        out[0] = 0;
        out_len[0] = 1;
        return;
    }
    int32_t cand = ((alen + blen) - 2);
    int32_t n = (((cand < max_degree) ? (cand) : (max_degree)) + 1);
    int32_t i = 0;
    while (i < n) {
        out[i] = 0;
        i = (i + 1);
    }
    i = 0;
    while (i < alen) {
        if (a[i] == 0) {
            i = (i + 1);
            continue;
        }
        int32_t last_j = (((blen - 1) < (max_degree - i)) ? ((blen - 1)) : ((max_degree - i)));
        int32_t j = 0;
        while (j <= last_j) {
            if (b[j] != 0) {
                out[(i + j)] = mod_add_i64_i64(out[(i + j)], mod_mul_i64_i64(a[i], b[j]));
            }
            j = (j + 1);
        }
        i = (i + 1);
    }
    out_len[0] = n;
    trim_ptr_i64_ptr_i32(out, out_len);
}

int64_t block_count_i32_i32(int32_t length, int32_t cost) {
    if ((cost <= 0 || (2 * cost) < length)) {
        return 0;
    }
    int64_t total = comb_mod_i64_i64(((int64_t)(((2 * cost) - 1))), ((int64_t)((length - 1))));
    int64_t too_large = ((cost < length) ? (0) : (comb_mod_i64_i64(((int64_t)((cost - 1))), ((int64_t)((length - 1))))));
    return mod_sub_i64_i64(total, mod_mul_i64_i64(((int64_t)(length)), too_large));
}

void block_numerator_i32_ptr_i64_ptr_i32(int32_t length, int64_t* out, int32_t* out_len) {
    int32_t j = 0;
    while (j <= length) {
        int64_t value = 0;
        int32_t i = 0;
        while (i <= j) {
            int64_t sign = ((FLOW_CHECKED_MOD((i), (2)) != 0) ? ((0 - 1)) : (1));
            int64_t term = mod_mul_i64_i64(comb_mod_i64_i64(((int64_t)(length)), ((int64_t)(i))), block_count_i32_i32(length, (j - i)));
            if (sign < 0) {
                value = mod_sub_i64_i64(value, term);
            } else {
                value = mod_add_i64_i64(value, term);
            }
            i = (i + 1);
        }
        out[j] = value;
        j = (j + 1);
    }
    out_len[0] = (length + 1);
    trim_ptr_i64_ptr_i32(out, out_len);
}

void numerator_for_all_valid_vectors_i32_ptr_i64_ptr_i32(int32_t n, int64_t* result, int32_t* result_len) {
    int64_t** block_num = (int64_t**)(((int64_t**)(calloc(128, 8))));
    int32_t* block_num_len = (int32_t*)(((int32_t*)(calloc(128, 4))));
    int32_t len = 2;
    while (len <= n) {
        block_num[len] = ((int64_t*)(calloc(((int64_t)((len + 2))), 8)));
        block_numerator_i32_ptr_i64_ptr_i32(len, block_num[len], (block_num_len + len));
        len = (len + 1);
    }
    int64_t** total = (int64_t**)(((int64_t**)(calloc(128, 8))));
    int32_t* total_len = (int32_t*)(((int32_t*)(calloc(128, 4))));
    int64_t** zero_end = (int64_t**)(((int64_t**)(calloc(128, 8))));
    int32_t* zero_end_len = (int32_t*)(((int32_t*)(calloc(128, 4))));
    int32_t pos = 0;
    while (pos <= n) {
        total[pos] = ((int64_t*)(calloc(((int64_t)((n + 2))), 8)));
        total_len[pos] = 1;
        total[pos][0] = 0;
        zero_end[pos] = ((int64_t*)(calloc(((int64_t)((n + 2))), 8)));
        zero_end_len[pos] = 1;
        zero_end[pos][0] = 0;
        pos = (pos + 1);
    }
    total[0][0] = 1;
    total_len[0] = 1;
    zero_end[0][0] = 1;
    zero_end_len[0] = 1;
    int64_t* tmp = (int64_t*)(((int64_t*)(calloc(((int64_t)((n + 2))), 8))));
    int64_t* prod = (int64_t*)(((int64_t*)(calloc(((int64_t)((n + 2))), 8))));
    int32_t* tmp_len = (int32_t*)(((int32_t*)(calloc(1, 4))));
    int32_t* prod_len = (int32_t*)(((int32_t*)(calloc(1, 4))));
    pos = 0;
    while (pos <= n) {
        if (((pos < n && total_len[pos] > 0) && (!((total_len[pos] == 1 && total[pos][0] == 0))))) {
            mul_one_minus_q_ptr_i64_i32_ptr_i64_ptr_i32(total[pos], total_len[pos], tmp, tmp_len);
            add_to_ptr_i64_ptr_i32_ptr_i64_i32(total[(pos + 1)], ((total_len + pos) + 1), tmp, tmp_len[0]);
            add_to_ptr_i64_ptr_i32_ptr_i64_i32(zero_end[(pos + 1)], ((zero_end_len + pos) + 1), tmp, tmp_len[0]);
        }
        if ((zero_end_len[pos] > 0 && (!((zero_end_len[pos] == 1 && zero_end[pos][0] == 0))))) {
            int32_t length = 2;
            while (length <= (n - pos)) {
                mul_poly_ptr_i64_i32_ptr_i64_i32_i32_ptr_i64_ptr_i32(zero_end[pos], zero_end_len[pos], block_num[length], block_num_len[length], (pos + length), prod, prod_len);
                add_to_ptr_i64_ptr_i32_ptr_i64_i32(total[(pos + length)], ((total_len + pos) + length), prod, prod_len[0]);
                length = (length + 1);
            }
        }
        pos = (pos + 1);
    }
    memcpy(((void*)(result)), ((void*)(total[n])), (((int64_t)(total_len[n])) * 8));
    result_len[0] = total_len[n];
    len = 2;
    while (len <= n) {
        free(((void*)(block_num[len])));
        len = (len + 1);
    }
    pos = 0;
    while (pos <= n) {
        free(((void*)(total[pos])));
        free(((void*)(zero_end[pos])));
        pos = (pos + 1);
    }
    free(((void*)(block_num)));
    free(((void*)(block_num_len)));
    free(((void*)(total)));
    free(((void*)(total_len)));
    free(((void*)(zero_end)));
    free(((void*)(zero_end_len)));
    free(((void*)(tmp)));
    free(((void*)(prod)));
    free(((void*)(tmp_len)));
    free(((void*)(prod_len)));
}

int64_t count_tuples_i32_i64(int32_t n, int64_t k) {
    int64_t max_cost = FLOW_CHECKED_DIV((k), (2));
    int64_t* numer = (int64_t*)(((int64_t*)(calloc(((int64_t)((n + 2))), 8))));
    int32_t* numer_len = (int32_t*)(((int32_t*)(calloc(1, 4))));
    numerator_for_all_valid_vectors_i32_ptr_i64_ptr_i32(n, numer, numer_len);
    int64_t answer = 0;
    int32_t degree = 0;
    while (degree < numer_len[0]) {
        if ((numer[degree] != 0 && ((int64_t)(degree)) <= max_cost)) {
            int64_t ways = comb_mod_i64_i64(((max_cost - ((int64_t)(degree))) + ((int64_t)(n))), ((int64_t)(n)));
            answer = mod_add_i64_i64(answer, mod_mul_i64_i64(numer[degree], ways));
        }
        degree = (degree + 1);
    }
    free(((void*)(numer)));
    free(((void*)(numer_len)));
    return answer;
}

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