commit a3869ad6ec05587cfa7835042f2f8ab305be2f06
parent 798416f66481be1b1adac24baf7d3ab281f6552d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 27 Apr 2026 03:43:49 -0700
scheme1: bump heap to 64 MiB, ELF p_memsz to 128 MiB; reorder arenas
Reorder arena_table so heap is last (readbuf -> symtab -> heap)
instead of sandwiched between readbuf and symtab. Bump
HEAP_CAP_BYTES from 16 MiB to 64 MiB and ph_memsz across all three
vendor seeds from 32 MiB to 128 MiB. The reordering means the heap
can grow into the full remainder of the bss segment if we ever lift
the explicit cap; the cap stays for now so heap-exhausted diagnostics
fire at a known boundary.
Also: add tests/cc-e2e/01-kitchen-sink.c — single-TU integration
test that hits every codegen capability in compositions
(struct-member access through fn-ptr-returned ptrs, variadic +
recursion + ptr arith, etc.). Currently FAILS with heap-exhausted
even at 64 MiB; that's the next investigation target — instrumenting
scheme1's heap usage and cc's per-phase memory consumption to find
the runaway.
Diffstat:
6 files changed, 351 insertions(+), 10 deletions(-)
diff --git a/scheme1/scheme1.P1pp b/scheme1/scheme1.P1pp
@@ -32,15 +32,17 @@
# BSS arenas anchored past :ELF_end. readbuf is 256 KiB (sized to fit
# the catm'd cc compiler source incl. prelude — see READBUF_CAP_BYTES),
-# then the heap (HEAP_CAP_BYTES, currently 16 MiB), then symtab. The three are packed
-# back-to-back; everything lives within the ELF p_memsz reservation
-# (currently 32 MiB) declared in vendor/seed/<arch>/ELF.hex2. p1_main
-# calls libp1pp's init_arenas, which walks arena_table and writes
-# &ELF_end + sum of prior sizes into each pointer slot.
+# then symtab, then the heap last so it can use the full remainder of
+# the ELF p_memsz reservation (currently 128 MiB) declared in
+# vendor/seed/<arch>/ELF.hex2. HEAP_CAP_BYTES (currently 64 MiB) is
+# the explicit cap; total bss usage = readbuf + symtab + heap and must
+# fit inside p_memsz. p1_main calls libp1pp's init_arenas, which walks
+# arena_table and writes &ELF_end + sum of prior sizes into each
+# pointer slot.
%macro SYMTAB_CAP_SLOTS() 8192 %endm
%macro READBUF_CAP_BYTES() 262144 %endm
-%macro HEAP_CAP_BYTES() 0x1000000 %endm
+%macro HEAP_CAP_BYTES() 0x4000000 %endm
# =========================================================================
# Tag idioms
@@ -5022,8 +5024,8 @@
# previous one ended.
:arena_table
%arena_entry(&readbuf_buf_ptr, %READBUF_CAP_BYTES)
-%arena_entry(&heap_buf_ptr, %HEAP_CAP_BYTES)
%arena_entry(&symtab_buf_ptr, (* %SYMTAB_CAP_SLOTS %SYMENT.SIZE))
+%arena_entry(&heap_buf_ptr, %HEAP_CAP_BYTES)
:arena_table_end
# =========================================================================
diff --git a/tests/cc-e2e/01-kitchen-sink.c b/tests/cc-e2e/01-kitchen-sink.c
@@ -0,0 +1,338 @@
+/* tests/cc-e2e/01-kitchen-sink.c — single-TU integration test.
+ *
+ * Single-file end-to-end exercise of the codegen surface that the
+ * parser drives today. Each numbered test computes a value; main
+ * checks each against an expected literal and exits with the test
+ * number (1..N) on first mismatch, 0 on full pass.
+ *
+ * Designed to stress *interactions* between features (e.g., struct
+ * members through fn-ptr-returned pointer, variadic + recursion +
+ * pointer arith, etc.) that the per-feature cc-cg fixtures don't.
+ */
+
+typedef char *va_list;
+
+/* -------- Globals: scalar, bss, array, string, struct, designated, fn-ptr table -- */
+
+int g_scalar = 42;
+int g_zero; /* bss */
+int g_arr[3] = { 10, 20, 30 };
+char g_msg[] = "hello";
+struct Point { int x; int y; };
+struct Point g_pt = { 100, 200 }; /* positional */
+struct Point g_pt2 = { .y = 5, .x = 7 }; /* designated */
+
+typedef int (*op2_t)(int, int);
+int op_add(int a, int b) { return a + b; }
+int op_mul(int a, int b) { return a * b; }
+op2_t g_ops[2] = { op_add, op_mul };
+
+enum Color { RED, GREEN = 5, BLUE };
+
+/* -------- Tests ----------------------------------------------------------- */
+
+int test_arith(void) {
+ int a = 5;
+ int b = 3;
+ int r = 0;
+ r = r + (a + b); /* 8 */
+ r = r + (a - b); /* 2 */
+ r = r + (a * b); /* 15 */
+ r = r + (10 / 3); /* 3 */
+ r = r + (10 % 3); /* 1 */
+ r = r + (1 << 4); /* 16 */
+ r = r + (64 >> 2); /* 16 */
+ r = r + (12 & 10); /* 8 */
+ r = r + (12 | 10); /* 14 */
+ r = r + (12 ^ 10); /* 6 */
+ r = r + !0; /* 1 */
+ r = r + ~0; /* -1 */
+ r = r + (-1); /* -1 */
+ return r; /* 88 */
+}
+
+int test_compound(void) {
+ int x = 10;
+ x += 5; /* 15 */
+ x -= 3; /* 12 */
+ x *= 2; /* 24 */
+ x /= 4; /* 6 */
+ x %= 4; /* 2 */
+ x <<= 3; /* 16 */
+ x >>= 1; /* 8 */
+ x &= 12; /* 8 */
+ x |= 1; /* 9 */
+ x ^= 6; /* 15 */
+ return x;
+}
+
+int test_inc_dec(void) {
+ int x = 5;
+ int a = x++; /* a=5, x=6 */
+ int b = ++x; /* b=7, x=7 */
+ int c = x--; /* c=7, x=6 */
+ int d = --x; /* d=5, x=5 */
+ return a + b + c + d + x; /* 5+7+7+5+5 = 29 */
+}
+
+int test_logical(void) {
+ int r = 0;
+ if (1 && 1) r = r + 1;
+ if (0 && 1) r = r + 100;
+ if (1 || 0) r = r + 2;
+ if (0 || 0) r = r + 100;
+ int side = 0;
+ if (1 || (side = 100)) r = r + 4; /* short-circuit; side stays 0 */
+ if (0 && (side = 100)) r = r + 100;
+ return r + side; /* 1+2+4+0 = 7 */
+}
+
+int test_ternary(void) {
+ int x = 5;
+ int y = (x > 3) ? 10 : 20; /* 10 */
+ int z = (x < 3) ? 100 : 200; /* 200 */
+ return y + z; /* 210 */
+}
+
+int test_compare(void) {
+ int r = 0;
+ if (5 == 5) r = r + 1;
+ if (5 != 6) r = r + 2;
+ if (5 < 6) r = r + 4;
+ if (6 > 5) r = r + 8;
+ if (5 <= 5) r = r + 16;
+ if (5 >= 5) r = r + 32;
+ return r; /* 63 */
+}
+
+int test_pointer(void) {
+ int x = 7;
+ int *p = &x;
+ *p = *p + 3; /* x = 10 */
+ int **pp = &p;
+ int v = **pp; /* 10 */
+ return *p + v; /* 20 */
+}
+
+int test_array(void) {
+ int a[5] = { 1, 2, 3, 4, 5 };
+ int sum = 0;
+ int i;
+ for (i = 0; i < 5; i = i + 1) sum = sum + a[i];
+ return sum; /* 15 */
+}
+
+int test_array_2d(void) {
+ int m[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
+ int sum = 0;
+ int i; int j;
+ for (i = 0; i < 2; i = i + 1)
+ for (j = 0; j < 3; j = j + 1)
+ sum = sum + m[i][j];
+ return sum; /* 21 */
+}
+
+int test_struct(void) {
+ struct Point local = { 3, 4 };
+ return local.x + local.y; /* 7 */
+}
+
+int f_struct_arg(struct Point *p) { return p->x + p->y; }
+
+int test_struct_ptr(void) {
+ return f_struct_arg(&g_pt) + g_pt2.x + g_pt2.y; /* 300 + 7 + 5 = 312 */
+}
+
+int f_basic(int a, int b) { return a + b; }
+
+int test_call(void) {
+ int x = f_basic(3, 4); /* 7 */
+ int y = f_basic(10, -2); /* 8 */
+ return x + y; /* 15 */
+}
+
+int factorial(int n) {
+ if (n <= 1) return 1;
+ return n * factorial(n - 1);
+}
+
+int test_recursion(void) { return factorial(5); } /* 120 */
+
+int f_variadic(int n, ...) {
+ va_list ap;
+ int total;
+ int i;
+ __builtin_va_start(ap, n);
+ total = 0;
+ i = 0;
+ while (i < n) {
+ total = total + __builtin_va_arg(ap, int);
+ i = i + 1;
+ }
+ __builtin_va_end(ap);
+ return total;
+}
+
+int test_variadic(void) { return f_variadic(4, 1, 2, 3, 4); } /* 10 */
+
+int test_fn_ptr(void) {
+ op2_t add = g_ops[0];
+ op2_t mul = g_ops[1];
+ return add(3, 4) + mul(5, 6); /* 7 + 30 = 37 */
+}
+
+/* Interaction: fn-ptr param + struct-ptr param + member access via -> */
+int apply2(op2_t f, struct Point *p) { return f(p->x, p->y); }
+
+int test_apply(void) {
+ return apply2(op_add, &g_pt) + apply2(op_mul, &g_pt2); /* 300 + 35 = 335 */
+}
+
+/* Interaction: pointer arith + deref + recursion + global-array decay */
+int sum_arr(int *p, int n) {
+ if (n == 0) return 0;
+ return *p + sum_arr(p + 1, n - 1);
+}
+
+int test_ptr_recursion(void) { return sum_arr(g_arr, 3); } /* 60 */
+
+int counter(void) {
+ static int n = 0;
+ n = n + 1;
+ return n;
+}
+
+int test_static(void) {
+ int a = counter(); /* 1 */
+ int b = counter(); /* 2 */
+ int c = counter(); /* 3 */
+ return a + b + c; /* 6 */
+}
+
+int test_switch(void) {
+ int r = 0;
+ int i;
+ for (i = 0; i < 4; i = i + 1) {
+ switch (i) {
+ case 0: r = r + 1; break;
+ case 1: r = r + 2; break;
+ case 2:
+ case 3: r = r + 10; break;
+ default: r = r + 100; break;
+ }
+ }
+ return r; /* 1 + 2 + 10 + 10 = 23 */
+}
+
+int test_goto(void) {
+ int n = 0;
+loop:
+ n = n + 1;
+ if (n < 5) goto loop;
+ return n; /* 5 */
+}
+
+int test_loops(void) {
+ int x = 0;
+ do { x = x + 1; } while (x < 3); /* x = 3 */
+ int y = 0;
+ while (y < 10) {
+ y = y + 1;
+ if (y == 5) continue;
+ x = x + 1;
+ } /* x = 3 + 9 = 12 */
+ return x; /* 12 */
+}
+
+int test_strings(void) {
+ char *s = "world";
+ int sum = 0;
+ while (*s) {
+ sum = sum + *s;
+ s = s + 1;
+ }
+ return sum; /* w+o+r+l+d = 119+111+114+108+100 = 552 */
+}
+
+int test_globals(void) {
+ g_zero = g_zero + 1; /* now 1 */
+ return g_scalar + g_zero + g_arr[1] + g_msg[0]; /* 42+1+20+'h'(104) = 167 */
+}
+
+int test_sizeof(void) {
+ return sizeof(int) + sizeof(char) + sizeof(struct Point) + sizeof(g_arr);
+ /* 4 + 1 + 8 + 12 = 25 */
+}
+
+int test_enum(void) {
+ return RED + GREEN + BLUE; /* 0 + 5 + 6 = 11 */
+}
+
+void f_void(int *out, int v) { *out = v; }
+
+int test_void_call(void) {
+ int x = 0;
+ f_void(&x, 42);
+ return x; /* 42 */
+}
+
+int test_cast(void) {
+ int a = 300;
+ int b = (int)(char)a; /* (char)300 = 44 (sign-extends back to int) */
+ int c = (int)(short)a; /* (short)300 = 300 (fits in 16 bits) */
+ return b + c; /* 344 */
+}
+
+int test_void_ptr(void) {
+ int x = 99;
+ void *p = &x;
+ int *q = (int *)p;
+ return *q; /* 99 */
+}
+
+int test_comma(void) {
+ int a = 0; int b = 0;
+ int x = (a = 5, b = 10, a + b); /* 15 */
+ return x;
+}
+
+int test_addr_array(void) {
+ int (*p)[3] = &g_arr;
+ return (*p)[0] + (*p)[1] + (*p)[2]; /* 60 */
+}
+
+/* -------- main ------------------------------------------------------------ */
+
+int main(int argc, char **argv) {
+ if (test_arith() != 88) return 1;
+ if (test_compound() != 15) return 2;
+ if (test_inc_dec() != 29) return 3;
+ if (test_logical() != 7) return 4;
+ if (test_ternary() != 210) return 5;
+ if (test_compare() != 63) return 6;
+ if (test_pointer() != 20) return 7;
+ if (test_array() != 15) return 8;
+ if (test_array_2d() != 21) return 9;
+ if (test_struct() != 7) return 10;
+ if (test_struct_ptr() != 312) return 11;
+ if (test_call() != 15) return 12;
+ if (test_recursion() != 120) return 13;
+ if (test_variadic() != 10) return 14;
+ if (test_fn_ptr() != 37) return 15;
+ if (test_apply() != 335) return 16;
+ if (test_ptr_recursion() != 60) return 17;
+ if (test_static() != 6) return 18;
+ if (test_switch() != 23) return 19;
+ if (test_goto() != 5) return 20;
+ if (test_loops() != 12) return 21;
+ if (test_strings() != 552) return 22;
+ if (test_globals() != 167) return 23;
+ if (test_sizeof() != 25) return 24;
+ if (test_enum() != 11) return 25;
+ if (test_void_call() != 42) return 26;
+ if (test_cast() != 344) return 27;
+ if (test_void_ptr() != 99) return 28;
+ if (test_comma() != 15) return 29;
+ if (test_addr_array() != 60) return 30;
+ return 0;
+}
diff --git a/tests/cc-e2e/01-kitchen-sink.expected-exit b/tests/cc-e2e/01-kitchen-sink.expected-exit
@@ -0,0 +1 @@
+0
diff --git a/vendor/seed/aarch64/ELF.hex2 b/vendor/seed/aarch64/ELF.hex2
@@ -62,7 +62,7 @@ B7 00 # e_machine Indicating AArch64
&ELF_base 00 00 00 00 # ph_physaddr
%ELF_end>ELF_base 00 00 00 00 # ph_filesz
-00 00 00 02 00 00 00 00 # ph_memsz = 32 MB (boot2: BSS past ELF_end)
+00 00 00 08 00 00 00 00 # ph_memsz = 128 MB (boot2: BSS past ELF_end; sized for scheme1's 64 MiB heap)
01 00 00 00 00 00 00 00 # ph_align
diff --git a/vendor/seed/amd64/ELF.hex2 b/vendor/seed/amd64/ELF.hex2
@@ -61,7 +61,7 @@
&ELF_base 00 00 00 00 ## p_physaddr
%ELF_end>ELF_base 00 00 00 00 ## p_filesz
-00 00 00 02 00 00 00 00 ## p_memsz = 32 MB (boot2: BSS past ELF_end)
+00 00 00 08 00 00 00 00 ## p_memsz = 128 MB (boot2: BSS past ELF_end; sized for scheme1's 64 MiB heap)
01 00 00 00 00 00 00 00 ## Required alignment
diff --git a/vendor/seed/riscv64/ELF.hex2 b/vendor/seed/riscv64/ELF.hex2
@@ -61,7 +61,7 @@ F3 00 ## e_machine Indicating RISC-V
&ELF_base 00 00 00 00 ## p_physaddr
%ELF_end>ELF_base 00 00 00 00 ## p_filesz
-00 00 00 02 00 00 00 00 ## p_memsz = 32 MB (boot2: BSS past ELF_end)
+00 00 00 08 00 00 00 00 ## p_memsz = 128 MB (boot2: BSS past ELF_end; sized for scheme1's 64 MiB heap)
01 00 00 00 00 00 00 00 ## Required alignment