Problem 558

Ported from C to pure Flow. Uses big number arithmetic with a recurrence to compute the POWERS table at runtime (no precomputed data needed). The constant x = real root of t^3 - t^2 - 1 = 0 (approx 1.46557). POWERS[k] = floor(x^(k-200) * 10^90), computed via 12-limb fixed point with 256 extra bits of precision, then truncated by right-shifting 256 bits.

Answer226754889
Output226754889
StatusPASS
Native helperno
Runtime11920 ms
Peak memory1184 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 558
# Ported from C to pure Flow. Uses big number arithmetic with a recurrence
# to compute the POWERS table at runtime (no precomputed data needed).
# The constant x = real root of t^3 - t^2 - 1 = 0 (approx 1.46557).
# POWERS[k] = floor(x^(k-200) * 10^90), computed via 12-limb fixed point
# with 256 extra bits of precision, then truncated by right-shifting 256 bits.

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

const NLIMBS: i64 = 8
const NLIMBS_EXT: i64 = 12
const NPOW: i64 = 329
const ZERO_INDEX: i64 = 200
const LIMIT: i64 = 5000000

# Unsigned comparison of i64-stored u64 limbs.
function u64_lt(a: i64, b: i64) -> bool {
    let a_neg: bool = a < 0
    let b_neg: bool = b < 0
    if a_neg && !b_neg { return false }
    if !a_neg && b_neg { return true }
    return a < b
}

function u64_gt(a: i64, b: i64) -> bool {
    let a_neg: bool = a < 0
    let b_neg: bool = b < 0
    if a_neg && !b_neg { return true }
    if !a_neg && b_neg { return false }
    return a > b
}

# Big add: a += b, both NLIMBS_EXT limbs, using i128 for carry.
function big_add_ext(a: ptr<i64>, b: ptr<i64>) -> void {
    let mut carry: i128 = 0
    let mut i: i64 = 0
    while i < NLIMBS_EXT {
        let sum: i128 = ((a[i] as u64) as i128) + ((b[i] as u64) as i128) + carry
        a[i] = (sum as u64) as i64
        carry = sum >> 64
        i = i + 1
    }
}

# Big sub: a -= b, both NLIMBS_EXT limbs, using i128 for borrow.
function big_sub_ext(a: ptr<i64>, b: ptr<i64>) -> void {
    let mut borrow: i128 = 0
    let mut i: i64 = 0
    while i < NLIMBS_EXT {
        let diff: i128 = ((a[i] as u64) as i128) - ((b[i] as u64) as i128) - borrow
        if diff < 0 {
            a[i] = ((diff + ((1 as i128) << 64)) as u64) as i64
            borrow = 1
        } else {
            a[i] = (diff as u64) as i64
            borrow = 0
        }
        i = i + 1
    }
}

# Big compare (8 limbs, unsigned). Returns -1, 0, or 1.
function big_cmp(a: ptr<i64>, b: ptr<i64>) -> i32 {
    let mut i: i64 = NLIMBS - 1
    while i >= 0 {
        if u64_lt(a[i], b[i]) { return -1 }
        if u64_gt(a[i], b[i]) { return 1 }
        i = i - 1
    }
    return 0
}

# Big sub (8 limbs, unsigned): a -= b
function big_sub_u(a: ptr<i64>, b: ptr<i64>) -> void {
    let mut borrow: i128 = 0
    let mut i: i64 = 0
    while i < NLIMBS {
        let diff: i128 = ((a[i] as u64) as i128) - ((b[i] as u64) as i128) - borrow
        if diff < 0 {
            a[i] = ((diff + ((1 as i128) << 64)) as u64) as i64
            borrow = 1
        } else {
            a[i] = (diff as u64) as i64
            borrow = 0
        }
        i = i + 1
    }
}

# Big add (8 limbs, unsigned): a += b
function big_add(a: ptr<i64>, b: ptr<i64>) -> void {
    let mut carry: i128 = 0
    let mut i: i64 = 0
    while i < NLIMBS {
        let sum: i128 = ((a[i] as u64) as i128) + ((b[i] as u64) as i128) + carry
        a[i] = (sum as u64) as i64
        carry = sum >> 64
        i = i + 1
    }
}

# Compute 10^90 as 8-limb big number (multiply 1 by 10 ninety times).
function make_scale(p: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < NLIMBS { p[i] = 0; i = i + 1 }
    p[0] = 1
    let mut step: i64 = 0
    while step < 90 {
        let mut carry: i128 = 0
        let mut j: i64 = 0
        while j < NLIMBS {
            let cur: i128 = ((p[j] as u64) as i128) * 10 + carry
            p[j] = (cur as u64) as i64
            carry = cur >> 64
            j = j + 1
        }
        step = step + 1
    }
}

# Initialize the 12-limb P[0], P[1], P[2] from hardcoded values.
# P[0] = 10^90 * 2^256, P[1] = floor(x * 10^90 * 2^256), P[2] = floor(x^2 * 10^90 * 2^256).
# Values stored as i64 (negative for u64 > 2^63-1).
function init_P0(p: ptr<i64>) -> void {
    p[0]=0; p[1]=0; p[2]=0; p[3]=0; p[4]=0
    p[5]=-3619769923250683904
    p[6]=3330727700749618282
    p[7]=8201890710707044867
    p[8]=8636168555094
    p[9]=0; p[10]=0; p[11]=0
}

function init_P1(p: ptr<i64>) -> void {
    p[0]=4360708573770252141
    p[1]=-7319485783113527405
    p[2]=1035423025400803779
    p[3]=3595441422471201580
    p[4]=-7667592780024054039
    p[5]=3575780253858083788
    p[6]=2562988277936900661
    p[7]=3191154164227192640
    p[8]=12656920187985
    p[9]=0; p[10]=0; p[11]=0
}

function init_P2(p: ptr<i64>) -> void {
    p[0]=9196756730258272993
    p[1]=-2479220855341455651
    p[2]=5021121319498967611
    p[3]=-348377860131556272
    p[4]=-1825087821658844492
    p[5]=3558213820333459890
    p[6]=1502675205283376518
    p[7]=6720694847164083296
    p[8]=18549618111671
    p[9]=0; p[10]=0; p[11]=0
}

# Truncate 12-limb to 8-limb by dropping lower 4 limbs (right shift 256 bits).
function truncate_to_8(src: ptr<i64>, dst: ptr<i64>) -> void {
    let mut i: i64 = 0
    while i < NLIMBS {
        dst[i] = src[i + 4]
        i = i + 1
    }
}

# Compute all 329 POWERS entries (8 limbs each) using the recurrence.
# P[j+3] = P[j+2] + P[j] (forward), P[j] = P[j+3] - P[j+2] (reverse).
function compute_powers(powers: ptr<i64>) -> void {
    # P_ext: 329 entries of 12 limbs each, indexed as P_ext[(j+200)*12 + limb]
    let P_ext: ptr<i64> = calloc(NPOW * NLIMBS_EXT, 8) as ptr<i64>
    # Initialize P[0], P[1], P[2] (indices 200, 201, 202 in the array)
    init_P0(P_ext + 200 * NLIMBS_EXT)
    init_P1(P_ext + 201 * NLIMBS_EXT)
    init_P2(P_ext + 202 * NLIMBS_EXT)
    # Forward: P[j+3] = P[j+2] + P[j] for j = 0 to 127
    let mut j: i64 = 0
    while j < 128 {
        let dst: ptr<i64> = P_ext + (j + 3 + 200) * NLIMBS_EXT
        let src1: ptr<i64> = P_ext + (j + 2 + 200) * NLIMBS_EXT
        let src2: ptr<i64> = P_ext + (j + 200) * NLIMBS_EXT
        let mut k: i64 = 0
        while k < NLIMBS_EXT { dst[k] = src1[k]; k = k + 1 }
        big_add_ext(dst, src2)
        j = j + 1
    }
    # Reverse: P[j] = P[j+3] - P[j+2] for j = -1 to -200
    j = -1
    while j >= -200 {
        let dst: ptr<i64> = P_ext + (j + 200) * NLIMBS_EXT
        let src1: ptr<i64> = P_ext + (j + 3 + 200) * NLIMBS_EXT
        let src2: ptr<i64> = P_ext + (j + 2 + 200) * NLIMBS_EXT
        let mut k: i64 = 0
        while k < NLIMBS_EXT { dst[k] = src1[k]; k = k + 1 }
        big_sub_ext(dst, src2)
        j = j - 1
    }
    # Truncate all 329 entries to 8 limbs
    let mut idx: i64 = 0
    while idx < NPOW {
        truncate_to_8(P_ext + idx * NLIMBS_EXT, powers + idx * NLIMBS)
        idx = idx + 1
    }
    free(P_ext as ptr<void>)
}

function main() -> i32 {
    # Compute POWERS table
    let powers: ptr<i64> = calloc(NPOW * NLIMBS, 8) as ptr<i64>
    compute_powers(powers)
    # Compute scale = 10^90
    let scale: ptr<i64> = calloc(NLIMBS, 8) as ptr<i64>
    make_scale(scale)
    let two_scale: ptr<i64> = calloc(NLIMBS, 8) as ptr<i64>
    let mut i: i64 = 0
    while i < NLIMBS { two_scale[i] = scale[i]; i = i + 1 }
    big_add(two_scale, scale)
    # Main loop
    let square: ptr<i64> = calloc(NLIMBS, 8) as ptr<i64>
    let odd: ptr<i64> = calloc(NLIMBS, 8) as ptr<i64>
    i = 0
    while i < NLIMBS { odd[i] = scale[i]; i = i + 1 }
    let mut lead: i64 = ZERO_INDEX
    let mut total: i64 = 0
    let mut n: i64 = 0
    while n < LIMIT {
        big_add(square, odd)
        big_add(odd, two_scale)
        while lead + 1 < NPOW {
            if big_cmp(powers + (lead + 1) * NLIMBS, square) <= 0 {
                lead = lead + 1
            } else {
                break
            }
        }
        let residual: ptr<i64> = calloc(NLIMBS, 8) as ptr<i64>
        let mut k: i64 = 0
        while k < NLIMBS { residual[k] = square[k]; k = k + 1 }
        big_sub_u(residual, powers + lead * NLIMBS)
        let mut terms: i64 = 1
        let mut pos: i64 = lead - 3
        while pos >= 0 {
            while pos >= 0 && big_cmp(powers + pos * NLIMBS, residual) > 0 {
                pos = pos - 1
            }
            if pos < 0 { break }
            big_sub_u(residual, powers + pos * NLIMBS)
            terms = terms + 1
            pos = pos - 3
        }
        total = total + terms
        free(residual as ptr<void>)
        n = n + 1
    }
    printf("%lld\n", total)
    free(powers as ptr<void>)
    free(scale as ptr<void>)
    free(two_scale as ptr<void>)
    free(square as ptr<void>)
    free(odd as ptr<void>)
    return 0
}

Generated C

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Flow runtime helpers */
typedef struct flow_temp_node { struct flow_temp_node* next; } flow_temp_node;
static flow_temp_node* flow_temp_head = NULL;
static int flow_temp_atexit_set = 0;
__attribute__((unused)) static void flow_temp_free_all(void) {
    while (flow_temp_head) {
        flow_temp_node* n = flow_temp_head;
        flow_temp_head = n->next;
        free(n);
    }
}
__attribute__((unused)) static void* flow_temp_alloc(size_t nbytes) {
    flow_temp_node* node = (flow_temp_node*)malloc(sizeof(flow_temp_node) + nbytes);
    if (!node) return NULL;
    node->next = flow_temp_head;
    flow_temp_head = node;
    if (!flow_temp_atexit_set) {
        flow_temp_atexit_set = 1;
        atexit(flow_temp_free_all);
    }
    return (void*)(node + 1);
}
#ifndef FLOW_DIAG
#define FLOW_DIAG(msg) fprintf(stderr, "%s", (msg))
#endif
#ifndef FLOW_LOG
#define FLOW_LOG(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
#ifndef FLOW_LOG_EMPTY
#define FLOW_LOG_EMPTY(fmt) printf(fmt)
#endif
static char* flow_strcat(const char* a, const char* b) {
    size_t la = strlen(a ? a : ""), lb = strlen(b ? b : "");
    char* r = (char*)flow_temp_alloc(la + lb + 1);
    if (!r) return NULL;
    if (la) memcpy(r, a, la);
    if (lb) memcpy(r + la, b, lb);
    r[la + lb] = '\0';
    return r;
}

#define __flow_in_arr(arr, val) __extension__ ({ \
    int _found = 0; \
    size_t _n = sizeof(arr)/sizeof((arr)[0]); \
    for (size_t _i = 0; _i < _n; _i++) { \
        if ((arr)[_i] == (val)) { _found = 1; break; } \
    } _found; })

/* Unified fault handler (MISRA #279) — override with -DFLOW_FAULT_HANDLER=fn */
#ifndef FLOW_FAULT_HANDLER
__attribute__((unused)) static inline void flow_fault_handler(const char* msg) {
    fprintf(stderr, "flow: %s\n", msg ? msg : "fault");
    abort();
#if defined(__GNUC__) || defined(__clang__)
    __builtin_unreachable();
#endif
}
#else
#define flow_fault_handler FLOW_FAULT_HANDLER
#endif
#define flow_div_by_zero_handler() flow_fault_handler("division by zero")
#define flow_shift_ub_handler() flow_fault_handler("invalid shift (amount out of range or left-shift of negative)")

#ifndef FLOW_CHECKED_DIV
#define FLOW_CHECKED_DIV(L, R) (((R) != 0) ? ((L) / (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_MOD
#define FLOW_CHECKED_MOD(L, R) (((R) != 0) ? ((L) % (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHL
#define FLOW_CHECKED_SHL(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull)) && ((L) >= 0)) ? ((L) << (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHR
#define FLOW_CHECKED_SHR(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull))) ? ((L) >> (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif

#include <math.h>

void* _ui_state = NULL;

static inline float i32_to_f32(int32_t v) { return (float)v; }

/* Host stub for @gpu kernels (device codegen replaces this). */
static inline int32_t gpu_thread_id(void) { return 0; }

bool u64_lt_i64_i64(int64_t a, int64_t b);
bool u64_gt_i64_i64(int64_t a, int64_t b);
void big_add_ext_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
void big_sub_ext_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
int32_t big_cmp_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
void big_sub_u_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
void big_add_ptr_i64_ptr_i64(int64_t* a, int64_t* b);
void make_scale_ptr_i64(int64_t* p);
void init_P0_ptr_i64(int64_t* p);
void init_P1_ptr_i64(int64_t* p);
void init_P2_ptr_i64(int64_t* p);
void truncate_to_8_ptr_i64_ptr_i64(int64_t* src, int64_t* dst);
void compute_powers_ptr_i64(int64_t* powers);
int32_t main(void);

static const int64_t NLIMBS = 8;
static const int64_t NLIMBS_EXT = 12;
static const int64_t NPOW = 329;
static const int64_t ZERO_INDEX = 200;
static const int64_t LIMIT = 5000000;




bool u64_lt_i64_i64(int64_t a, int64_t b) {
    bool a_neg = a < 0;
    bool b_neg = b < 0;
    if ((a_neg && (!(b_neg)))) {
        return 0;
    }
    if (((!(a_neg)) && b_neg)) {
        return 1;
    }
    return a < b;
}

bool u64_gt_i64_i64(int64_t a, int64_t b) {
    bool a_neg = a < 0;
    bool b_neg = b < 0;
    if ((a_neg && (!(b_neg)))) {
        return 1;
    }
    if (((!(a_neg)) && b_neg)) {
        return 0;
    }
    return a > b;
}

void big_add_ext_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    __int128 carry = 0;
    int64_t i = 0;
    while (i < NLIMBS_EXT) {
        __int128 sum = ((((__int128)(((uint64_t)(a[i])))) + ((__int128)(((uint64_t)(b[i]))))) + carry);
        a[i] = ((int64_t)(((uint64_t)(sum))));
        carry = FLOW_CHECKED_SHR((sum), (64));
        i = (i + 1);
    }
}

void big_sub_ext_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    __int128 borrow = 0;
    int64_t i = 0;
    while (i < NLIMBS_EXT) {
        __int128 diff = ((((__int128)(((uint64_t)(a[i])))) - ((__int128)(((uint64_t)(b[i]))))) - borrow);
        if (diff < 0) {
            a[i] = ((int64_t)(((uint64_t)((diff + FLOW_CHECKED_SHL((((__int128)(1))), (64)))))));
            borrow = 1;
        } else {
            a[i] = ((int64_t)(((uint64_t)(diff))));
            borrow = 0;
        }
        i = (i + 1);
    }
}

int32_t big_cmp_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    int64_t i = (NLIMBS - 1);
    while (i >= 0) {
        if (u64_lt_i64_i64(a[i], b[i])) {
            return (-1);
        }
        if (u64_gt_i64_i64(a[i], b[i])) {
            return 1;
        }
        i = (i - 1);
    }
    return 0;
}

void big_sub_u_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    __int128 borrow = 0;
    int64_t i = 0;
    while (i < NLIMBS) {
        __int128 diff = ((((__int128)(((uint64_t)(a[i])))) - ((__int128)(((uint64_t)(b[i]))))) - borrow);
        if (diff < 0) {
            a[i] = ((int64_t)(((uint64_t)((diff + FLOW_CHECKED_SHL((((__int128)(1))), (64)))))));
            borrow = 1;
        } else {
            a[i] = ((int64_t)(((uint64_t)(diff))));
            borrow = 0;
        }
        i = (i + 1);
    }
}

void big_add_ptr_i64_ptr_i64(int64_t* a, int64_t* b) {
    __int128 carry = 0;
    int64_t i = 0;
    while (i < NLIMBS) {
        __int128 sum = ((((__int128)(((uint64_t)(a[i])))) + ((__int128)(((uint64_t)(b[i]))))) + carry);
        a[i] = ((int64_t)(((uint64_t)(sum))));
        carry = FLOW_CHECKED_SHR((sum), (64));
        i = (i + 1);
    }
}

void make_scale_ptr_i64(int64_t* p) {
    int64_t i = 0;
    while (i < NLIMBS) {
        p[i] = 0;
        i = (i + 1);
    }
    p[0] = 1;
    int64_t step = 0;
    while (step < 90) {
        __int128 carry = 0;
        int64_t j = 0;
        while (j < NLIMBS) {
            __int128 cur = ((((__int128)(((uint64_t)(p[j])))) * 10) + carry);
            p[j] = ((int64_t)(((uint64_t)(cur))));
            carry = FLOW_CHECKED_SHR((cur), (64));
            j = (j + 1);
        }
        step = (step + 1);
    }
}

void init_P0_ptr_i64(int64_t* p) {
    p[0] = 0;
    p[1] = 0;
    p[2] = 0;
    p[3] = 0;
    p[4] = 0;
    p[5] = (-3619769923250683904);
    p[6] = 3330727700749618282;
    p[7] = 8201890710707044867;
    p[8] = 8636168555094;
    p[9] = 0;
    p[10] = 0;
    p[11] = 0;
}

void init_P1_ptr_i64(int64_t* p) {
    p[0] = 4360708573770252141;
    p[1] = (-7319485783113527405);
    p[2] = 1035423025400803779;
    p[3] = 3595441422471201580;
    p[4] = (-7667592780024054039);
    p[5] = 3575780253858083788;
    p[6] = 2562988277936900661;
    p[7] = 3191154164227192640;
    p[8] = 12656920187985;
    p[9] = 0;
    p[10] = 0;
    p[11] = 0;
}

void init_P2_ptr_i64(int64_t* p) {
    p[0] = 9196756730258272993;
    p[1] = (-2479220855341455651);
    p[2] = 5021121319498967611;
    p[3] = (-348377860131556272);
    p[4] = (-1825087821658844492);
    p[5] = 3558213820333459890;
    p[6] = 1502675205283376518;
    p[7] = 6720694847164083296;
    p[8] = 18549618111671;
    p[9] = 0;
    p[10] = 0;
    p[11] = 0;
}

void truncate_to_8_ptr_i64_ptr_i64(int64_t* src, int64_t* dst) {
    int64_t i = 0;
    while (i < NLIMBS) {
        dst[i] = src[(i + 4)];
        i = (i + 1);
    }
}

void compute_powers_ptr_i64(int64_t* powers) {
    int64_t* P_ext = (int64_t*)(((int64_t*)(calloc((NPOW * NLIMBS_EXT), 8))));
    init_P0_ptr_i64((P_ext + (200 * NLIMBS_EXT)));
    init_P1_ptr_i64((P_ext + (201 * NLIMBS_EXT)));
    init_P2_ptr_i64((P_ext + (202 * NLIMBS_EXT)));
    int64_t j = 0;
    while (j < 128) {
        int64_t* dst = (int64_t*)((P_ext + (((j + 3) + 200) * NLIMBS_EXT)));
        int64_t* src1 = (int64_t*)((P_ext + (((j + 2) + 200) * NLIMBS_EXT)));
        int64_t* src2 = (int64_t*)((P_ext + ((j + 200) * NLIMBS_EXT)));
        int64_t k = 0;
        while (k < NLIMBS_EXT) {
            dst[k] = src1[k];
            k = (k + 1);
        }
        big_add_ext_ptr_i64_ptr_i64(dst, src2);
        j = (j + 1);
    }
    j = (-1);
    while (j >= (-200)) {
        int64_t* dst = (int64_t*)((P_ext + ((j + 200) * NLIMBS_EXT)));
        int64_t* src1 = (int64_t*)((P_ext + (((j + 3) + 200) * NLIMBS_EXT)));
        int64_t* src2 = (int64_t*)((P_ext + (((j + 2) + 200) * NLIMBS_EXT)));
        int64_t k = 0;
        while (k < NLIMBS_EXT) {
            dst[k] = src1[k];
            k = (k + 1);
        }
        big_sub_ext_ptr_i64_ptr_i64(dst, src2);
        j = (j - 1);
    }
    int64_t idx = 0;
    while (idx < NPOW) {
        truncate_to_8_ptr_i64_ptr_i64((P_ext + (idx * NLIMBS_EXT)), (powers + (idx * NLIMBS)));
        idx = (idx + 1);
    }
    free(((void*)(P_ext)));
}

int32_t main(void) {
    int64_t* powers = (int64_t*)(((int64_t*)(calloc((NPOW * NLIMBS), 8))));
    compute_powers_ptr_i64(powers);
    int64_t* scale = (int64_t*)(((int64_t*)(calloc(NLIMBS, 8))));
    make_scale_ptr_i64(scale);
    int64_t* two_scale = (int64_t*)(((int64_t*)(calloc(NLIMBS, 8))));
    int64_t i = 0;
    while (i < NLIMBS) {
        two_scale[i] = scale[i];
        i = (i + 1);
    }
    big_add_ptr_i64_ptr_i64(two_scale, scale);
    int64_t* square = (int64_t*)(((int64_t*)(calloc(NLIMBS, 8))));
    int64_t* odd = (int64_t*)(((int64_t*)(calloc(NLIMBS, 8))));
    i = 0;
    while (i < NLIMBS) {
        odd[i] = scale[i];
        i = (i + 1);
    }
    int64_t lead = ZERO_INDEX;
    int64_t total = 0;
    int64_t n = 0;
    while (n < LIMIT) {
        big_add_ptr_i64_ptr_i64(square, odd);
        big_add_ptr_i64_ptr_i64(odd, two_scale);
        while ((lead + 1) < NPOW) {
            if (big_cmp_ptr_i64_ptr_i64((powers + ((lead + 1) * NLIMBS)), square) <= 0) {
                lead = (lead + 1);
            } else {
                break;
            }
        }
        int64_t* residual = (int64_t*)(((int64_t*)(calloc(NLIMBS, 8))));
        int64_t k = 0;
        while (k < NLIMBS) {
            residual[k] = square[k];
            k = (k + 1);
        }
        big_sub_u_ptr_i64_ptr_i64(residual, (powers + (lead * NLIMBS)));
        int64_t terms = 1;
        int64_t pos = (lead - 3);
        while (pos >= 0) {
            while ((pos >= 0 && big_cmp_ptr_i64_ptr_i64((powers + (pos * NLIMBS)), residual) > 0)) {
                pos = (pos - 1);
            }
            if (pos < 0) {
                break;
            }
            big_sub_u_ptr_i64_ptr_i64(residual, (powers + (pos * NLIMBS)));
            terms = (terms + 1);
            pos = (pos - 3);
        }
        total = (total + terms);
        free(((void*)(residual)));
        n = (n + 1);
    }
    printf("%lld\n", total);
    free(((void*)(powers)));
    free(((void*)(scale)));
    free(((void*)(two_scale)));
    free(((void*)(square)));
    free(((void*)(odd)));
    return 0;
}

Generated MLIR

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