Problem 238

Infinite string tour: BBS digit stream, sum p(k) for k <= 2e15. Period digit-sum T ~ 8e7; cover residues with a u64 limb bitset.

Answer9922545104535661
Output9922545104535661
StatusPASS
Native helperno
Runtime370 ms
Peak memory59056 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)O(n)
Space complexityO(n^2)O(n)
ApproachFlow solutionPeriod finding and digit sum
VerdictSuboptimal

Flow source

# Project Euler 238
# Infinite string tour: BBS digit stream, sum p(k) for k <= 2e15.
# Period digit-sum T ~ 8e7; cover residues with a u64 limb bitset.

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

function pop64(x0: u64) -> i64 {
    let mut x: u64 = x0
    let mut c: i64 = 0
    while x != 0 {
        c = c + 1
        x = x & (x - 1)
    }
    return c
}

function bit_set(bits: ptr<u64>, idx: i64) -> void {
    let limb: i64 = idx >> 6
    let bit: i64 = idx & 63
    let one: u64 = 1
    bits[limb] = bits[limb] | (one << (bit as u64))
}

function bits_copy(src: ptr<u64>, dst: ptr<u64>, nlimbs: i64) -> void {
    let mut i: i64 = 0
    while i < nlimbs {
        dst[i] = src[i]
        i = i + 1
    }
}

function bits_zero(bits: ptr<u64>, nlimbs: i64) -> void {
    let mut i: i64 = 0
    let z: u64 = 0
    while i < nlimbs {
        bits[i] = z
        i = i + 1
    }
}

# Set every bit in [0, T).
function bits_fill(bits: ptr<u64>, T: i64) -> void {
    let nlimbs: i64 = (T + 63) / 64
    let all: u64 = 0
    all = all - 1
    let mut i: i64 = 0
    let full: i64 = T / 64
    while i < full {
        bits[i] = all
        i = i + 1
    }
    let remb: i64 = T & 63
    if remb != 0 {
        let one: u64 = 1
        bits[full] = (one << (remb as u64)) - 1
    }
}

# Circular right shift by d bits (1..9) of a T-bit set into dst.
function circ_rshift(src: ptr<u64>, dst: ptr<u64>, T: i64, d: i64) -> void {
    let nlimbs: i64 = (T + 63) / 64
    let du: u64 = d as u64
    let one: u64 = 1
    let low_mask: u64 = (one << du) - 1
    let low: u64 = src[0] & low_mask
    let sh: u64 = 64 - du
    let mut i: i64 = 0
    while i + 1 < nlimbs {
        dst[i] = (src[i] >> du) | (src[i + 1] << sh)
        i = i + 1
    }
    dst[nlimbs - 1] = src[nlimbs - 1] >> du

    # Wrap the saved low d bits into positions [T-d, T).
    let top: i64 = T - d
    let limb: i64 = top >> 6
    let bit: i64 = top & 63
    let bu: u64 = bit as u64
    dst[limb] = dst[limb] | (low << bu)
    if bit + d > 64 {
        dst[limb + 1] = dst[limb + 1] | (low >> (64 - bu))
    }

    # Mask to exactly T bits.
    let remb: i64 = T & 63
    if remb != 0 {
        dst[nlimbs - 1] = dst[nlimbs - 1] & ((one << (remb as u64)) - 1)
    }
}

# Popcount of bits of v0 whose global indices lie in [lo, hi], for limb li.
function pop_in_range(v0: u64, li: i64, lo: i64, hi: i64) -> i64 {
    if hi < lo { return 0 }
    let base: i64 = li * 64
    if base > hi { return 0 }
    if base + 63 < lo { return 0 }
    let mut start: i64 = lo - base
    if start < 0 { start = 0 }
    let mut endb: i64 = hi - base
    if endb > 63 { endb = 63 }
    let one: u64 = 1
    let width: i64 = endb - start + 1
    let mut mask: u64 = 0
    if width == 64 {
        mask = mask - 1
    } else {
        mask = ((one << (width as u64)) - 1) << (start as u64)
    }
    return pop64(v0 & mask)
}

# Write decimal digits of s0 at digits[pos0..]; return new pos. Digit sum via sum_out.
function digit_sum_and_emit(s0: i64, digits: ptr<i8>, pos0: i64, sum_out: ptr<i64>) -> i64 {
    let mut tmpd: array<i32, 8> = [0, 0, 0, 0, 0, 0, 0, 0]
    let mut t: i64 = s0
    let mut len: i32 = 0
    if t == 0 {
        digits[pos0] = 0
        return pos0 + 1
    }
    while t > 0 {
        tmpd[len] = (t % 10) as i32
        t = t / 10
        len = len + 1
    }
    let mut pos: i64 = pos0
    let mut di: i32 = len - 1
    while di >= 0 {
        let d: i32 = tmpd[di]
        digits[pos] = d as i8
        sum_out[0] = sum_out[0] + (d as i64)
        pos = pos + 1
        di = di - 1
    }
    return pos
}

function bbs_period(s0: i64, mod: i64) -> i64 {
    let mut s: i64 = s0
    let mut n: i64 = 0
    while n < 100000000 {
        s = (s * s) % mod
        n = n + 1
        if s == s0 { return n }
    }
    return 0
}

function main() -> i32 {
    let S0: i64 = 14025256
    let MOD: i64 = 20300713
    let TARGET: i64 = 2000000000000000

    let period: i64 = bbs_period(S0, MOD)

    # One period has < 8 digits per term.
    let dig_cap: i64 = period * 8 + 8
    let digits: ptr<i8> = calloc(dig_cap, 1)
    if digits == null { return 1 }

    let mut s: i64 = S0
    let mut L: i64 = 0
    let mut Tacc: i64 = 0
    let mut i: i64 = 0
    while i < period {
        L = digit_sum_and_emit(s, digits, L, &Tacc)
        s = (s * s) % MOD
        i = i + 1
    }
    let T: i64 = Tacc

    let nlimbs: i64 = (T + 63) / 64
    let present: ptr<u64> = calloc(nlimbs, 8)
    let unknown: ptr<u64> = calloc(nlimbs, 8)
    let rot: ptr<u64> = calloc(nlimbs, 8)
    let tmp: ptr<u64> = calloc(nlimbs, 8)
    if present == null || unknown == null || rot == null || tmp == null { return 1 }

    bits_zero(present, nlimbs)
    bit_set(present, 0)
    let mut ps: i64 = 0
    i = 0
    while i < L {
        ps = ps + (digits[i] as i64)
        if ps == T {
            bit_set(present, 0)
        } else {
            bit_set(present, ps)
        }
        i = i + 1
    }

    bits_fill(unknown, T)
    bits_copy(present, rot, nlimbs)

    let rem: i64 = TARGET % T
    let mut sum_all: i64 = 0
    let mut sum_1000: i64 = 0
    let mut sum_rem: i64 = 0
    let mut left: i64 = T
    let mut z: i64 = 0
    while z < L {
        let mut cnt: i64 = 0
        let mut c1000: i64 = 0
        let mut crem: i64 = 0
        let mut li: i64 = 0
        while li < nlimbs {
            let v: u64 = unknown[li] & rot[li]
            if v != 0 {
                cnt = cnt + pop64(v)
                c1000 = c1000 + pop_in_range(v, li, 1, 1000)
                crem = crem + pop_in_range(v, li, 1, rem)
                unknown[li] = unknown[li] ^ v
            }
            li = li + 1
        }
        let w: i64 = z + 1
        if cnt != 0 {
            sum_all = sum_all + w * cnt
            sum_1000 = sum_1000 + w * c1000
            sum_rem = sum_rem + w * crem
            left = left - cnt
            if left == 0 { break }
        }
        let d: i64 = digits[z] as i64
        if d != 0 {
            bits_zero(tmp, nlimbs)
            circ_rshift(rot, tmp, T, d)
            bits_copy(tmp, rot, nlimbs)
        }
        z = z + 1
    }

    if sum_1000 != 4742 {
        printf("check failed: %lld\n", sum_1000)
        return 1
    }

    let q: i64 = TARGET / T
    let ans: i64 = q * sum_all + sum_rem
    printf("%lld\n", ans)

    free(digits)
    free(present)
    free(unknown)
    free(rot)
    free(tmp)
    return 0
}

Generated C

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

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

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

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

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

#include <math.h>

void* _ui_state = NULL;

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

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

int64_t pop64_u64(uint64_t x0);
void bit_set_ptr_u64_i64(uint64_t* bits, int64_t idx);
void bits_copy_ptr_u64_ptr_u64_i64(uint64_t* src, uint64_t* dst, int64_t nlimbs);
void bits_zero_ptr_u64_i64(uint64_t* bits, int64_t nlimbs);
void bits_fill_ptr_u64_i64(uint64_t* bits, int64_t T);
void circ_rshift_ptr_u64_ptr_u64_i64_i64(uint64_t* src, uint64_t* dst, int64_t T, int64_t d);
int64_t pop_in_range_u64_i64_i64_i64(uint64_t v0, int64_t li, int64_t lo, int64_t hi);
int64_t digit_sum_and_emit_i64_ptr_i8_i64_ptr_i64(int64_t s0, int8_t* digits, int64_t pos0, int64_t* sum_out);
int64_t bbs_period_i64_i64(int64_t s0, int64_t mod);
int32_t main(void);



int64_t pop64_u64(uint64_t x0) {
    uint64_t x = x0;
    int64_t c = 0;
    while (x != 0) {
        c = (c + 1);
        x = (x & (x - 1));
    }
    return c;
}

void bit_set_ptr_u64_i64(uint64_t* bits, int64_t idx) {
    int64_t limb = FLOW_CHECKED_SHR((idx), (6));
    int64_t bit = (idx & 63);
    uint64_t one = 1;
    bits[limb] = (bits[limb] | FLOW_CHECKED_SHL((one), (((uint64_t)(bit)))));
}

void bits_copy_ptr_u64_ptr_u64_i64(uint64_t* src, uint64_t* dst, int64_t nlimbs) {
    int64_t i = 0;
    while (i < nlimbs) {
        dst[i] = src[i];
        i = (i + 1);
    }
}

void bits_zero_ptr_u64_i64(uint64_t* bits, int64_t nlimbs) {
    int64_t i = 0;
    uint64_t z = 0;
    while (i < nlimbs) {
        bits[i] = z;
        i = (i + 1);
    }
}

void bits_fill_ptr_u64_i64(uint64_t* bits, int64_t T) {
    int64_t nlimbs = FLOW_CHECKED_DIV(((T + 63)), (64));
    uint64_t all = 0;
    all = (all - 1);
    int64_t i = 0;
    int64_t full = FLOW_CHECKED_DIV((T), (64));
    while (i < full) {
        bits[i] = all;
        i = (i + 1);
    }
    int64_t remb = (T & 63);
    if (remb != 0) {
        uint64_t one = 1;
        bits[full] = (FLOW_CHECKED_SHL((one), (((uint64_t)(remb)))) - 1);
    }
}

void circ_rshift_ptr_u64_ptr_u64_i64_i64(uint64_t* src, uint64_t* dst, int64_t T, int64_t d) {
    int64_t nlimbs = FLOW_CHECKED_DIV(((T + 63)), (64));
    uint64_t du = ((uint64_t)(d));
    uint64_t one = 1;
    uint64_t low_mask = (FLOW_CHECKED_SHL((one), (du)) - 1);
    uint64_t low = (src[0] & low_mask);
    uint64_t sh = (64 - du);
    int64_t i = 0;
    while ((i + 1) < nlimbs) {
        dst[i] = (FLOW_CHECKED_SHR((src[i]), (du)) | FLOW_CHECKED_SHL((src[(i + 1)]), (sh)));
        i = (i + 1);
    }
    dst[(nlimbs - 1)] = FLOW_CHECKED_SHR((src[(nlimbs - 1)]), (du));
    int64_t top = (T - d);
    int64_t limb = FLOW_CHECKED_SHR((top), (6));
    int64_t bit = (top & 63);
    uint64_t bu = ((uint64_t)(bit));
    dst[limb] = (dst[limb] | FLOW_CHECKED_SHL((low), (bu)));
    if ((bit + d) > 64) {
        dst[(limb + 1)] = (dst[(limb + 1)] | FLOW_CHECKED_SHR((low), ((64 - bu))));
    }
    int64_t remb = (T & 63);
    if (remb != 0) {
        dst[(nlimbs - 1)] = (dst[(nlimbs - 1)] & (FLOW_CHECKED_SHL((one), (((uint64_t)(remb)))) - 1));
    }
}

int64_t pop_in_range_u64_i64_i64_i64(uint64_t v0, int64_t li, int64_t lo, int64_t hi) {
    if (hi < lo) {
        return 0;
    }
    int64_t base = (li * 64);
    if (base > hi) {
        return 0;
    }
    if ((base + 63) < lo) {
        return 0;
    }
    int64_t start = (lo - base);
    if (start < 0) {
        start = 0;
    }
    int64_t endb = (hi - base);
    if (endb > 63) {
        endb = 63;
    }
    uint64_t one = 1;
    int64_t width = ((endb - start) + 1);
    uint64_t mask = 0;
    if (width == 64) {
        mask = (mask - 1);
    } else {
        mask = FLOW_CHECKED_SHL(((FLOW_CHECKED_SHL((one), (((uint64_t)(width)))) - 1)), (((uint64_t)(start))));
    }
    return pop64_u64((v0 & mask));
}

int64_t digit_sum_and_emit_i64_ptr_i8_i64_ptr_i64(int64_t s0, int8_t* digits, int64_t pos0, int64_t* sum_out) {
    int32_t tmpd[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    int64_t t = s0;
    int32_t len = 0;
    if (t == 0) {
        digits[pos0] = 0;
        return (pos0 + 1);
    }
    while (t > 0) {
        tmpd[len] = ((int32_t)(FLOW_CHECKED_MOD((t), (10))));
        t = FLOW_CHECKED_DIV((t), (10));
        len = (len + 1);
    }
    int64_t pos = pos0;
    int32_t di = (len - 1);
    while (di >= 0) {
        int32_t d = (((unsigned)(di) < 8) ? tmpd[di] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(di), 8), flow_fault_handler("array index out of bounds"), tmpd[0]));
        digits[pos] = ((int8_t)(d));
        sum_out[0] = (sum_out[0] + ((int64_t)(d)));
        pos = (pos + 1);
        di = (di - 1);
    }
    return pos;
}

int64_t bbs_period_i64_i64(int64_t s0, int64_t mod) {
    int64_t s = s0;
    int64_t n = 0;
    while (n < 100000000) {
        s = FLOW_CHECKED_MOD(((s * s)), (mod));
        n = (n + 1);
        if (s == s0) {
            return n;
        }
    }
    return 0;
}

int32_t main(void) {
    int64_t S0 = 14025256;
    int64_t MOD = 20300713;
    int64_t TARGET = 2000000000000000;
    int64_t period = bbs_period_i64_i64(S0, MOD);
    int64_t dig_cap = ((period * 8) + 8);
    int8_t* digits = (int8_t*)(calloc(dig_cap, 1));
    if (digits == NULL) {
        return 1;
    }
    int64_t s = S0;
    int64_t L = 0;
    int64_t Tacc = 0;
    int64_t i = 0;
    while (i < period) {
        L = digit_sum_and_emit_i64_ptr_i8_i64_ptr_i64(s, digits, L, (&(Tacc)));
        s = FLOW_CHECKED_MOD(((s * s)), (MOD));
        i = (i + 1);
    }
    int64_t T = Tacc;
    int64_t nlimbs = FLOW_CHECKED_DIV(((T + 63)), (64));
    uint64_t* present = (uint64_t*)(calloc(nlimbs, 8));
    uint64_t* unknown = (uint64_t*)(calloc(nlimbs, 8));
    uint64_t* rot = (uint64_t*)(calloc(nlimbs, 8));
    uint64_t* tmp = (uint64_t*)(calloc(nlimbs, 8));
    if ((((present == NULL || unknown == NULL) || rot == NULL) || tmp == NULL)) {
        return 1;
    }
    bits_zero_ptr_u64_i64(present, nlimbs);
    bit_set_ptr_u64_i64(present, 0);
    int64_t ps = 0;
    i = 0;
    while (i < L) {
        ps = (ps + ((int64_t)(digits[i])));
        if (ps == T) {
            bit_set_ptr_u64_i64(present, 0);
        } else {
            bit_set_ptr_u64_i64(present, ps);
        }
        i = (i + 1);
    }
    bits_fill_ptr_u64_i64(unknown, T);
    bits_copy_ptr_u64_ptr_u64_i64(present, rot, nlimbs);
    int64_t rem = FLOW_CHECKED_MOD((TARGET), (T));
    int64_t sum_all = 0;
    int64_t sum_1000 = 0;
    int64_t sum_rem = 0;
    int64_t left = T;
    int64_t z = 0;
    while (z < L) {
        int64_t cnt = 0;
        int64_t c1000 = 0;
        int64_t crem = 0;
        int64_t li = 0;
        while (li < nlimbs) {
            uint64_t v = (unknown[li] & rot[li]);
            if (v != 0) {
                cnt = (cnt + pop64_u64(v));
                c1000 = (c1000 + pop_in_range_u64_i64_i64_i64(v, li, 1, 1000));
                crem = (crem + pop_in_range_u64_i64_i64_i64(v, li, 1, rem));
                unknown[li] = (unknown[li] ^ v);
            }
            li = (li + 1);
        }
        int64_t w = (z + 1);
        if (cnt != 0) {
            sum_all = (sum_all + (w * cnt));
            sum_1000 = (sum_1000 + (w * c1000));
            sum_rem = (sum_rem + (w * crem));
            left = (left - cnt);
            if (left == 0) {
                break;
            }
        }
        int64_t d = ((int64_t)(digits[z]));
        if (d != 0) {
            bits_zero_ptr_u64_i64(tmp, nlimbs);
            circ_rshift_ptr_u64_ptr_u64_i64_i64(rot, tmp, T, d);
            bits_copy_ptr_u64_ptr_u64_i64(tmp, rot, nlimbs);
        }
        z = (z + 1);
    }
    if (sum_1000 != 4742) {
        printf("check failed: %lld\n", sum_1000);
        return 1;
    }
    int64_t q = FLOW_CHECKED_DIV((TARGET), (T));
    int64_t ans = ((q * sum_all) + sum_rem);
    printf("%lld\n", ans);
    free(digits);
    free(present);
    free(unknown);
    free(rot);
    free(tmp);
    return 0;
}

Generated MLIR

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