Problem 910

Polynomial arithmetic in Z/(10^9)[x] mod prod_{k=1}^{40}(x+k). All polynomials are degree-39 remainders.

Answer547480666
Output547480666
StatusPASS
Native helperno
Runtime40 ms
Peak memory1088 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

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

Flow source

# Project Euler 910: L-Expressions II
# Polynomial arithmetic in Z/(10^9)[x] mod prod_{k=1}^{40}(x+k).
# All polynomials are degree-39 remainders.

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

const DEGREE: i64 = 40
const MOD: i64 = 1000000000

let mut FOLD: ptr<i64> = null
let mut ZERO: ptr<i64> = null
let mut ONE: ptr<i64> = null
let mut X: ptr<i64> = null

function init_globals() -> void {
    # Build FOLD: coefficients to replace x^40
    # prod_{k=1}^{40} (x + k) = x^40 + c39*x^39 + ... + c0
    # x^40 = -(c39*x^39 + ... + c0) mod the product
    let coeffs: ptr<i64> = calloc(DEGREE + 1, 8)
    let nxt: ptr<i64> = calloc(DEGREE + 2, 8)
    let mut i: i64 = 0
    while i < DEGREE + 1 {
        coeffs[i] = 0
        i = i + 1
    }
    coeffs[0] = 1
    let mut len: i64 = 1
    let mut k: i64 = 1
    while k <= DEGREE {
        let mut j: i64 = 0
        while j < DEGREE + 2 {
            nxt[j] = 0
            j = j + 1
        }
        j = 0
        while j < len {
            nxt[j] = (nxt[j] + coeffs[j] * k) % MOD
            nxt[j + 1] = (nxt[j + 1] + coeffs[j]) % MOD
            j = j + 1
        }
        len = len + 1
        j = 0
        while j < len {
            coeffs[j] = nxt[j]
            j = j + 1
        }
        k = k + 1
    }
    # FOLD[i] = -coeffs[i] for i=0..39
    i = 0
    while i < DEGREE {
        FOLD[i] = (MOD - coeffs[i]) % MOD
        i = i + 1
    }

    ZERO = calloc(DEGREE, 8)
    i = 0
    while i < DEGREE {
        ZERO[i] = 0
        i = i + 1
    }

    ONE = calloc(DEGREE, 8)
    i = 0
    while i < DEGREE {
        ONE[i] = 0
        i = i + 1
    }
    ONE[0] = 1

    X = calloc(DEGREE, 8)
    i = 0
    while i < DEGREE {
        X[i] = 0
        i = i + 1
    }
    X[1] = 1

    free(coeffs)
    free(nxt)
}

function poly_add(a: ptr<i64>, b: ptr<i64>, out: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < DEGREE {
        out[i] = (a[i] + b[i]) % MOD
        i = i + 1
    }
}

function mul_x(poly: ptr<i64>, out: ptr<i64>) -> void {
    let overflow: i64 = poly[DEGREE - 1]
    let mut i: i64 = DEGREE - 1
    while i > 0 {
        out[i] = poly[i - 1]
        i = i - 1
    }
    out[0] = 0
    if overflow != 0 {
        i = 0
        while i < DEGREE {
            out[i] = (out[i] + overflow * FOLD[i]) % MOD
            i = i + 1
        }
    }
}

function poly_mul(a: ptr<i64>, b: ptr<i64>, out: ptr<i64>) -> void {
    let tmp: ptr<i64> = calloc(DEGREE, 8)
    let shifted: ptr<i64> = calloc(DEGREE, 8)
    let next_shifted: ptr<i64> = calloc(DEGREE, 8)
    let mut i: i64 = 0
    while i < DEGREE {
        shifted[i] = b[i]
        i = i + 1
    }
    i = 0
    while i < DEGREE {
        if a[i] != 0 {
            let mut j1: i64 = 0
            while j1 < DEGREE {
                tmp[j1] = (tmp[j1] + a[i] * shifted[j1]) % MOD
                j1 = j1 + 1
            }
        }
        mul_x(shifted, next_shifted)
        let mut j2: i64 = 0
        while j2 < DEGREE {
            shifted[j2] = next_shifted[j2]
            j2 = j2 + 1
        }
        i = i + 1
    }
    i = 0
    while i < DEGREE {
        out[i] = tmp[i]
        i = i + 1
    }
    free(tmp)
    free(shifted)
    free(next_shifted)
}

function poly_pow(base: ptr<i64>, exponent: i64, result: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < DEGREE {
        result[i] = ONE[i]
        i = i + 1
    }
    let power: ptr<i64> = calloc(DEGREE, 8)
    let tmp: ptr<i64> = calloc(DEGREE, 8)
    i = 0
    while i < DEGREE {
        power[i] = base[i]
        i = i + 1
    }
    let mut exp: i64 = exponent
    while exp != 0 {
        if (exp & 1) == 1 {
            poly_mul(power, result, tmp)
            let mut j: i64 = 0
            while j < DEGREE {
                result[j] = tmp[j]
                j = j + 1
            }
        }
        exp = exp >> 1
        if exp != 0 {
            poly_mul(power, power, tmp)
            let mut j: i64 = 0
            while j < DEGREE {
                power[j] = tmp[j]
                j = j + 1
            }
        }
    }
    free(power)
    free(tmp)
}

function poly_compose(outer: ptr<i64>, inner: ptr<i64>, result: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < DEGREE {
        result[i] = ZERO[i]
        i = i + 1
    }
    let tmp: ptr<i64> = calloc(DEGREE, 8)
    i = DEGREE - 1
    while i >= 0 {
        poly_mul(result, inner, tmp)
        let mut j: i64 = 0
        while j < DEGREE {
            result[j] = tmp[j]
            j = j + 1
        }
        result[0] = (result[0] + outer[i]) % MOD
        i = i - 1
    }
    free(tmp)
}

function iterate_composition(poly: ptr<i64>, count: i64, result: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < DEGREE {
        result[i] = X[i]
        i = i + 1
    }
    let power: ptr<i64> = calloc(DEGREE, 8)
    let tmp: ptr<i64> = calloc(DEGREE, 8)
    i = 0
    while i < DEGREE {
        power[i] = poly[i]
        i = i + 1
    }
    let mut cnt: i64 = count
    while cnt != 0 {
        if (cnt & 1) == 1 {
            poly_compose(power, result, tmp)
            let mut j: i64 = 0
            while j < DEGREE {
                result[j] = tmp[j]
                j = j + 1
            }
        }
        cnt = cnt >> 1
        if cnt != 0 {
            poly_compose(power, power, tmp)
            let mut j: i64 = 0
            while j < DEGREE {
                power[j] = tmp[j]
                j = j + 1
            }
        }
    }
    free(power)
    free(tmp)
}

function d1(length: i64, out: ptr<i64>) -> void {
    let base: ptr<i64> = calloc(DEGREE, 8)
    let base_x: ptr<i64> = calloc(DEGREE, 8)
    poly_pow(X, length, base)
    mul_x(base, base_x)
    poly_add(base, base_x, out)
    free(base)
    free(base_x)
}

function d2(count: i64, poly: ptr<i64>, out: ptr<i64>) -> void {
    let iter: ptr<i64> = calloc(DEGREE, 8)
    let poly_x: ptr<i64> = calloc(DEGREE, 8)
    iterate_composition(poly, count, iter)
    mul_x(poly, poly_x)
    poly_compose(iter, poly_x, out)
    free(iter)
    free(poly_x)
}

function evaluate(poly: ptr<i64>, x: i64) -> i64 {
    let mut result: i64 = 0
    let mut i: i64 = DEGREE - 1
    while i >= 0 {
        result = (result * x + poly[i]) % MOD
        i = i - 1
    }
    return result
}

function main() -> i32 {
    FOLD = calloc(DEGREE, 8)
    init_globals()

    let nesting: i64 = 12
    let middle_count: i64 = 345678
    let length: i64 = 9012345
    let x_val: i64 = 678
    let addend: i64 = 90

    let base: ptr<i64> = calloc(DEGREE, 8)
    d1(length, base)

    let d2val: ptr<i64> = calloc(DEGREE, 8)
    d2(middle_count, base, d2val)

    let current: ptr<i64> = calloc(DEGREE, 8)
    poly_compose(base, d2val, current)

    let mut i: i64 = 0
    while i < nesting {
        let tmp: ptr<i64> = calloc(DEGREE, 8)
        d2(middle_count, current, tmp)
        let mut j: i64 = 0
        while j < DEGREE {
            current[j] = tmp[j]
            j = j + 1
        }
        free(tmp)
        i = i + 1
    }

    let val: i64 = evaluate(current, x_val)
    printf("%lld\n", (val + addend) % MOD)
    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; }

void init_globals(void);
void poly_add_ptr_i64_ptr_i64_ptr_i64(int64_t* a, int64_t* b, int64_t* out);
void mul_x_ptr_i64_ptr_i64(int64_t* poly, int64_t* out);
void poly_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* a, int64_t* b, int64_t* out);
void poly_pow_ptr_i64_i64_ptr_i64(int64_t* base, int64_t exponent, int64_t* result);
void poly_compose_ptr_i64_ptr_i64_ptr_i64(int64_t* outer, int64_t* inner, int64_t* result);
void iterate_composition_ptr_i64_i64_ptr_i64(int64_t* poly, int64_t count, int64_t* result);
void d1_i64_ptr_i64(int64_t length, int64_t* out);
void d2_i64_ptr_i64_ptr_i64(int64_t count, int64_t* poly, int64_t* out);
int64_t evaluate_ptr_i64_i64(int64_t* poly, int64_t x);
int32_t main(void);

static const int64_t DEGREE = 40;
static const int64_t MOD = 1000000000;

/* Module statics */
static int64_t* FOLD = NULL;
static int64_t* ZERO = NULL;
static int64_t* ONE = NULL;
static int64_t* X = NULL;





void init_globals(void) {
    int64_t* coeffs = (int64_t*)(calloc((DEGREE + 1), 8));
    int64_t* nxt = (int64_t*)(calloc((DEGREE + 2), 8));
    int64_t i = 0;
    while (i < (DEGREE + 1)) {
        coeffs[i] = 0;
        i = (i + 1);
    }
    coeffs[0] = 1;
    int64_t len = 1;
    int64_t k = 1;
    while (k <= DEGREE) {
        int64_t j = 0;
        while (j < (DEGREE + 2)) {
            nxt[j] = 0;
            j = (j + 1);
        }
        j = 0;
        while (j < len) {
            nxt[j] = FLOW_CHECKED_MOD(((nxt[j] + (coeffs[j] * k))), (MOD));
            nxt[(j + 1)] = FLOW_CHECKED_MOD(((nxt[(j + 1)] + coeffs[j])), (MOD));
            j = (j + 1);
        }
        len = (len + 1);
        j = 0;
        while (j < len) {
            coeffs[j] = nxt[j];
            j = (j + 1);
        }
        k = (k + 1);
    }
    i = 0;
    while (i < DEGREE) {
        FOLD[i] = FLOW_CHECKED_MOD(((MOD - coeffs[i])), (MOD));
        i = (i + 1);
    }
    ZERO = calloc(DEGREE, 8);
    i = 0;
    while (i < DEGREE) {
        ZERO[i] = 0;
        i = (i + 1);
    }
    ONE = calloc(DEGREE, 8);
    i = 0;
    while (i < DEGREE) {
        ONE[i] = 0;
        i = (i + 1);
    }
    ONE[0] = 1;
    X = calloc(DEGREE, 8);
    i = 0;
    while (i < DEGREE) {
        X[i] = 0;
        i = (i + 1);
    }
    X[1] = 1;
    free(coeffs);
    free(nxt);
}

void poly_add_ptr_i64_ptr_i64_ptr_i64(int64_t* a, int64_t* b, int64_t* out) {
    int64_t i = 0;
    while (i < DEGREE) {
        out[i] = FLOW_CHECKED_MOD(((a[i] + b[i])), (MOD));
        i = (i + 1);
    }
}

void mul_x_ptr_i64_ptr_i64(int64_t* poly, int64_t* out) {
    int64_t overflow = poly[(DEGREE - 1)];
    int64_t i = (DEGREE - 1);
    while (i > 0) {
        out[i] = poly[(i - 1)];
        i = (i - 1);
    }
    out[0] = 0;
    if (overflow != 0) {
        i = 0;
        while (i < DEGREE) {
            out[i] = FLOW_CHECKED_MOD(((out[i] + (overflow * FOLD[i]))), (MOD));
            i = (i + 1);
        }
    }
}

void poly_mul_ptr_i64_ptr_i64_ptr_i64(int64_t* a, int64_t* b, int64_t* out) {
    int64_t* tmp = (int64_t*)(calloc(DEGREE, 8));
    int64_t* shifted = (int64_t*)(calloc(DEGREE, 8));
    int64_t* next_shifted = (int64_t*)(calloc(DEGREE, 8));
    int64_t i = 0;
    while (i < DEGREE) {
        shifted[i] = b[i];
        i = (i + 1);
    }
    i = 0;
    while (i < DEGREE) {
        if (a[i] != 0) {
            int64_t j1 = 0;
            while (j1 < DEGREE) {
                tmp[j1] = FLOW_CHECKED_MOD(((tmp[j1] + (a[i] * shifted[j1]))), (MOD));
                j1 = (j1 + 1);
            }
        }
        mul_x_ptr_i64_ptr_i64(shifted, next_shifted);
        int64_t j2 = 0;
        while (j2 < DEGREE) {
            shifted[j2] = next_shifted[j2];
            j2 = (j2 + 1);
        }
        i = (i + 1);
    }
    i = 0;
    while (i < DEGREE) {
        out[i] = tmp[i];
        i = (i + 1);
    }
    free(tmp);
    free(shifted);
    free(next_shifted);
}

void poly_pow_ptr_i64_i64_ptr_i64(int64_t* base, int64_t exponent, int64_t* result) {
    int64_t i = 0;
    while (i < DEGREE) {
        result[i] = ONE[i];
        i = (i + 1);
    }
    int64_t* power = (int64_t*)(calloc(DEGREE, 8));
    int64_t* tmp = (int64_t*)(calloc(DEGREE, 8));
    i = 0;
    while (i < DEGREE) {
        power[i] = base[i];
        i = (i + 1);
    }
    int64_t exp = exponent;
    while (exp != 0) {
        if ((exp & 1) == 1) {
            poly_mul_ptr_i64_ptr_i64_ptr_i64(power, result, tmp);
            int64_t j = 0;
            while (j < DEGREE) {
                result[j] = tmp[j];
                j = (j + 1);
            }
        }
        exp = FLOW_CHECKED_SHR((exp), (1));
        if (exp != 0) {
            poly_mul_ptr_i64_ptr_i64_ptr_i64(power, power, tmp);
            int64_t j = 0;
            while (j < DEGREE) {
                power[j] = tmp[j];
                j = (j + 1);
            }
        }
    }
    free(power);
    free(tmp);
}

void poly_compose_ptr_i64_ptr_i64_ptr_i64(int64_t* outer, int64_t* inner, int64_t* result) {
    int64_t i = 0;
    while (i < DEGREE) {
        result[i] = ZERO[i];
        i = (i + 1);
    }
    int64_t* tmp = (int64_t*)(calloc(DEGREE, 8));
    i = (DEGREE - 1);
    while (i >= 0) {
        poly_mul_ptr_i64_ptr_i64_ptr_i64(result, inner, tmp);
        int64_t j = 0;
        while (j < DEGREE) {
            result[j] = tmp[j];
            j = (j + 1);
        }
        result[0] = FLOW_CHECKED_MOD(((result[0] + outer[i])), (MOD));
        i = (i - 1);
    }
    free(tmp);
}

void iterate_composition_ptr_i64_i64_ptr_i64(int64_t* poly, int64_t count, int64_t* result) {
    int64_t i = 0;
    while (i < DEGREE) {
        result[i] = X[i];
        i = (i + 1);
    }
    int64_t* power = (int64_t*)(calloc(DEGREE, 8));
    int64_t* tmp = (int64_t*)(calloc(DEGREE, 8));
    i = 0;
    while (i < DEGREE) {
        power[i] = poly[i];
        i = (i + 1);
    }
    int64_t cnt = count;
    while (cnt != 0) {
        if ((cnt & 1) == 1) {
            poly_compose_ptr_i64_ptr_i64_ptr_i64(power, result, tmp);
            int64_t j = 0;
            while (j < DEGREE) {
                result[j] = tmp[j];
                j = (j + 1);
            }
        }
        cnt = FLOW_CHECKED_SHR((cnt), (1));
        if (cnt != 0) {
            poly_compose_ptr_i64_ptr_i64_ptr_i64(power, power, tmp);
            int64_t j = 0;
            while (j < DEGREE) {
                power[j] = tmp[j];
                j = (j + 1);
            }
        }
    }
    free(power);
    free(tmp);
}

void d1_i64_ptr_i64(int64_t length, int64_t* out) {
    int64_t* base = (int64_t*)(calloc(DEGREE, 8));
    int64_t* base_x = (int64_t*)(calloc(DEGREE, 8));
    poly_pow_ptr_i64_i64_ptr_i64(X, length, base);
    mul_x_ptr_i64_ptr_i64(base, base_x);
    poly_add_ptr_i64_ptr_i64_ptr_i64(base, base_x, out);
    free(base);
    free(base_x);
}

void d2_i64_ptr_i64_ptr_i64(int64_t count, int64_t* poly, int64_t* out) {
    int64_t* iter = (int64_t*)(calloc(DEGREE, 8));
    int64_t* poly_x = (int64_t*)(calloc(DEGREE, 8));
    iterate_composition_ptr_i64_i64_ptr_i64(poly, count, iter);
    mul_x_ptr_i64_ptr_i64(poly, poly_x);
    poly_compose_ptr_i64_ptr_i64_ptr_i64(iter, poly_x, out);
    free(iter);
    free(poly_x);
}

int64_t evaluate_ptr_i64_i64(int64_t* poly, int64_t x) {
    int64_t result = 0;
    int64_t i = (DEGREE - 1);
    while (i >= 0) {
        result = FLOW_CHECKED_MOD((((result * x) + poly[i])), (MOD));
        i = (i - 1);
    }
    return result;
}

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