Total of all name scores in data/p022.txt. Parse into NameEntry { packed strcmp keys, letter-score }, then declarative `|> sortBy` (fixed-size array — required by the sort lowering).
# Project Euler 022
# Total of all name scores in data/p022.txt.
#
# Parse into NameEntry { packed strcmp keys, letter-score }, then
# declarative `|> sortBy` (fixed-size array — required by the sort lowering).
extern {
function fopen(path: string, mode: string) -> ptr<void>
function fgetc(f: ptr<void>) -> i32
function fclose(f: ptr<void>) -> i32
function calloc(n: i64, size: i64) -> ptr<void>
function free(p: ptr<void>) -> void
}
struct NameEntry {
key0: i64
key1: i64
score: i64
}
# Pack 8 bytes of a fixed-width name row into one i64 (MSB-first)
# so ascending key order matches C strcmp on the null-padded row.
function pack8(names: ptr<i8>, row: i32, width: i32, start: i32) -> i64 {
let mut k: i64 = 0
for i in 0..8 {
let mut c: i64 = (names[row * width + start + i] as i32) as i64
if c < 0 {
c = c + 256
}
k = (k << 8) | c
}
return k
}
function name_score(names: ptr<i8>, row: i32, width: i32) -> i64 {
let mut total: i64 = 0
for i in 0..width {
let c: i32 = names[row * width + i] as i32
if c == 0 {
break
}
if c >= 65 && c <= 90 {
total = total + ((c - 64) as i64)
}
}
return total
}
function main() -> i32 {
let width: i32 = 16
let max_names: i32 = 6000
let names: ptr<i8> = calloc((max_names * width) as i64, 1)
if names == null {
return 1
}
let f: ptr<void> = fopen("data/p022.txt", "r")
if f == null {
printf("failed to read data/p022.txt\n")
free(names)
return 1
}
let mut count: i32 = 0
let mut blen: i32 = 0
let mut in_name: bool = false
let mut c: i32 = fgetc(f)
while c >= 0 {
if c == 34 {
if in_name {
names[count * width + blen] = 0
count = count + 1
blen = 0
in_name = false
} else {
in_name = true
blen = 0
}
} elif in_name {
if blen < width - 1 {
names[count * width + blen] = c as i8
blen = blen + 1
}
}
c = fgetc(f)
}
fclose(f)
# Fixed capacity required by `|> sortBy`; unused slots get max keys
# so they sort after every real name.
let mut entries: array<NameEntry, 6000>
let hi: i64 = 9223372036854775807
for i in 0..max_names {
if i < count {
entries[i] = NameEntry {
key0: pack8(names, i, width, 0),
key1: pack8(names, i, width, 8),
score: name_score(names, i, width)
}
} else {
entries[i] = NameEntry { key0: hi, key1: hi, score: 0 }
}
}
entries |> sortBy [asc .key0, asc .key1]
let mut total: i64 = 0
for i in 0..count {
total = total + ((i + 1) as i64) * entries[i].score
}
printf("%lld\n", total)
free(names)
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; }
typedef struct NameEntry NameEntry;
struct NameEntry {
int64_t key0;
int64_t key1;
int64_t score;
};
int64_t pack8_ptr_i8_i32_i32_i32(int8_t* names, int32_t row, int32_t width, int32_t start);
int64_t name_score_ptr_i8_i32_i32(int8_t* names, int32_t row, int32_t width);
int32_t main(void);
// Auto-generated declarative sort helpers
/* plan: natural_merge -- cheapest applicable plan: 75304 vs 81304 for bottom_up_merge (7% less work) */
static void __flow_sort_a40743a4ed6d(NameEntry *a, int32_t n) {
if (n < 2) { return; }
NameEntry buf[6000];
int32_t starts[190];
int32_t nr = 0;
int32_t i = 0;
/* Pass 1: walk natural runs. A strictly descending run is
reversed in place (stable, because it is strict); a run
shorter than the minimum is grown by insertion. */
while (i < n) {
starts[nr++] = i;
int32_t j = i + 1;
if (j < n && ((((((a[j]).key0) < ((a[i]).key0) ? -1 : (((a[j]).key0) > ((a[i]).key0) ? 1 : 0))) != 0 ? ((((a[j]).key0) < ((a[i]).key0) ? -1 : (((a[j]).key0) > ((a[i]).key0) ? 1 : 0))) : ((((a[j]).key1) < ((a[i]).key1) ? -1 : (((a[j]).key1) > ((a[i]).key1) ? 1 : 0))))) < 0) {
while (j < n && ((((((a[j]).key0) < ((a[j - 1]).key0) ? -1 : (((a[j]).key0) > ((a[j - 1]).key0) ? 1 : 0))) != 0 ? ((((a[j]).key0) < ((a[j - 1]).key0) ? -1 : (((a[j]).key0) > ((a[j - 1]).key0) ? 1 : 0))) : ((((a[j]).key1) < ((a[j - 1]).key1) ? -1 : (((a[j]).key1) > ((a[j - 1]).key1) ? 1 : 0))))) < 0) { j++; }
for (int32_t lo = i, hi = j - 1; lo < hi; lo++, hi--) {
NameEntry t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
} else {
while (j < n && ((((((a[j]).key0) < ((a[j - 1]).key0) ? -1 : (((a[j]).key0) > ((a[j - 1]).key0) ? 1 : 0))) != 0 ? ((((a[j]).key0) < ((a[j - 1]).key0) ? -1 : (((a[j]).key0) > ((a[j - 1]).key0) ? 1 : 0))) : ((((a[j]).key1) < ((a[j - 1]).key1) ? -1 : (((a[j]).key1) > ((a[j - 1]).key1) ? 1 : 0))))) >= 0) { j++; }
}
int32_t want = i + 32; if (want > n) { want = n; }
while (j < want) {
NameEntry key = a[j];
int32_t k = j - 1;
while (k >= i && ((((((a[k]).key0) < ((key).key0) ? -1 : (((a[k]).key0) > ((key).key0) ? 1 : 0))) != 0 ? ((((a[k]).key0) < ((key).key0) ? -1 : (((a[k]).key0) > ((key).key0) ? 1 : 0))) : ((((a[k]).key1) < ((key).key1) ? -1 : (((a[k]).key1) > ((key).key1) ? 1 : 0))))) > 0) { a[k + 1] = a[k]; k--; }
a[k + 1] = key;
j++;
}
i = j;
}
starts[nr] = n;
/* Pass 2: merge adjacent runs pairwise until one remains. */
while (nr > 1) {
int32_t w = 0;
for (int32_t r = 0; r + 1 < nr; r += 2) {
int32_t lo = starts[r], mid = starts[r + 1], hi = starts[r + 2];
int32_t x = lo, y = mid, k = lo;
while (x < mid && y < hi) {
if (((((((a[y]).key0) < ((a[x]).key0) ? -1 : (((a[y]).key0) > ((a[x]).key0) ? 1 : 0))) != 0 ? ((((a[y]).key0) < ((a[x]).key0) ? -1 : (((a[y]).key0) > ((a[x]).key0) ? 1 : 0))) : ((((a[y]).key1) < ((a[x]).key1) ? -1 : (((a[y]).key1) > ((a[x]).key1) ? 1 : 0))))) < 0) { buf[k++] = a[y++]; }
else { buf[k++] = a[x++]; }
}
while (x < mid) { buf[k++] = a[x++]; }
while (y < hi) { buf[k++] = a[y++]; }
for (int32_t t = lo; t < hi; t++) { a[t] = buf[t]; }
starts[w++] = lo;
}
if (nr % 2 == 1) { starts[w++] = starts[nr - 1]; }
starts[w] = n;
nr = w;
}
}
int64_t pack8_ptr_i8_i32_i32_i32(int8_t* names, int32_t row, int32_t width, int32_t start) {
int64_t k = 0;
int32_t __flow_step_1 = 1;
for (int32_t i = 0; (0 <= 8) ? i < 8 : i > 8; i += (0 <= 8) ? 1 : -1) {
int64_t c = ((int64_t)(((int32_t)(names[(((row * width) + start) + i)]))));
if (c < 0) {
c = (c + 256);
}
k = (FLOW_CHECKED_SHL((k), (8)) | c);
}
return k;
}
int64_t name_score_ptr_i8_i32_i32(int8_t* names, int32_t row, int32_t width) {
int64_t total = 0;
int32_t __flow_step_2 = 1;
for (int32_t i = 0; (0 <= width) ? i < width : i > width; i += (0 <= width) ? 1 : -1) {
int32_t c = ((int32_t)(names[((row * width) + i)]));
if (c == 0) {
break;
}
if ((c >= 65 && c <= 90)) {
total = (total + ((int64_t)((c - 64))));
}
}
return total;
}
int32_t main(void) {
int32_t width = 16;
int32_t max_names = 6000;
int8_t* names = (int8_t*)(calloc(((int64_t)((max_names * width))), 1));
if (names == NULL) {
return 1;
}
void* f = (void*)(fopen("data/p022.txt", "r"));
if (f == NULL) {
printf("failed to read data/p022.txt\n");
free(names);
return 1;
}
int32_t count = 0;
int32_t blen = 0;
bool in_name = 0;
int32_t c = fgetc(f);
while (c >= 0) {
if (c == 34) {
if (in_name) {
names[((count * width) + blen)] = 0;
count = (count + 1);
blen = 0;
in_name = 0;
} else {
in_name = 1;
blen = 0;
}
} else if (in_name) {
if (blen < (width - 1)) {
names[((count * width) + blen)] = ((int8_t)(c));
blen = (blen + 1);
}
}
c = fgetc(f);
}
fclose(f);
NameEntry entries[6000];
int64_t hi = 9223372036854775807;
int32_t __flow_step_3 = 1;
for (int32_t i = 0; (0 <= max_names) ? i < max_names : i > max_names; i += (0 <= max_names) ? 1 : -1) {
if (i < count) {
entries[i] = (NameEntry){ .key0 = pack8_ptr_i8_i32_i32_i32(names, i, width, 0), .key1 = pack8_ptr_i8_i32_i32_i32(names, i, width, 8), .score = name_score_ptr_i8_i32_i32(names, i, width) };
} else {
entries[i] = (NameEntry){ .key0 = hi, .key1 = hi, .score = 0 };
}
}
({ __flow_sort_a40743a4ed6d((NameEntry*)(entries), 6000); entries; });
int64_t total = 0;
int32_t __flow_step_4 = 1;
for (int32_t i = 0; (0 <= count) ? i < count : i > count; i += (0 <= count) ? 1 : -1) {
total = (total + (((int64_t)((i + 1))) * (((unsigned)(i) < 6000) ? entries[i] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(i), 6000), flow_fault_handler("array index out of bounds"), entries[0])).score));
}
printf("%lld\n", total);
free(names);
return 0;
}
Generated MLIR
(transpilation failed: Resolving modules...
Parsed 8 functions, 1 structs, 0 effects, 0 capabilities
MLIR generation error: MLIR backend does not support statement type SortExpr; use the C backend (--c))