lumbda/c/Makefile
russell@unturf.com 2f342c3be2
c-tier bignum — arbitrary-precision integers unblock secp256k1 widths
Adds tagged bignum support alongside the existing 48-bit fixnum on the C
tier. Tag 6 = bignum, heap struct sign-magnitude with u64 little-endian
limbs. Reader emits bignums for any literal past the fixnum range; +, -,
*, quotient, remainder, modulo, expt, =, <, >, abs, odd?, even?,
integer?, exact?, number->string, string->number all promote fixnum →
bignum on overflow & demote back when results fit. Boehm GC owns every
allocation. Schoolbook O(n²) mul + shift-subtract divmod is sufficient
at our 4-limb / 256-bit scale.

Before: (expt 2 48) = 0, (expt 2 256) = 0, secp256k1-p = -4294968273.
After: all three return their exact arbitrary-precision values, matching
Python tier byte-for-byte.

Validated:
- c/test.c — 85/85 pass (+2 new bignum unit tests).
- tests/functional.lsp — 205/205 pass on both C & Python tiers.
- tests/bignum-cross-tier.lsp — 33/33 pass byte-identical on both tiers
  (diff produces no output).
- ecdsa/runs/lumbda-sweep-003/c-tier-bignum-probe.lsp — all four
  assertions now match the Python oracle.
- ecdsa Phase B byte-identity sweep inside QEMU guest:
  n+1=9  p=251           sha256 c668bbe3... — matches Python oracle.
  n+1=18 p=131071        sha256 8a031f96... — matches Python oracle.
  n+1=33 p=2³²-5         sha256 0bc56905... — matches Python oracle.
  Previously the n+1=33 C tier emitted sha256 b024d6d9... (26,078 fewer
  Toffolis due to silent fixnum wrap). Bignums close that gate.

secp256k1 production-width emit (n+1=257) is now structurally unblocked
on C tier; downstream agent (#55) drives that next-step on the ecdsa
side. Asm tier inherits in a follow-up port.
2026-06-06 20:23:37 -04:00

46 lines
1.3 KiB
Makefile

# Makefile for lumbda C interpreter
# Targets: all, test, bench, clean
CC = gcc
CFLAGS = -O2 -Wall -Wextra -Wno-unused-parameter -std=c11 -D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE
LDFLAGS = -lm
# Boehm GC autodetect — enable when /usr/include/gc.h is present.
# Without GC, every allocation leaks (ul_free is a no-op in our header);
# small REPL snippets work but anything iterating past a few thousand
# allocations OOMs the process. The named-let + per-iteration user-fn
# call pattern in tests/regression/named-let-gc.lsp pins this down.
# Override with USE_GC=0 to force the malloc-only path for diagnostics.
USE_GC ?= $(shell test -f /usr/include/gc.h && echo 1 || echo 0)
ifeq ($(USE_GC),1)
CFLAGS += -DUSE_BOEHM_GC
LDFLAGS += -lgc
endif
SRCS = types.c bignum.c reader.c printer.c eval.c builtins.c vm.c jit.c portal.c
OBJS = $(SRCS:.c=.o)
.PHONY: all clean test bench
all: lumbda
lumbda: main.o $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test: test_runner
./test_runner
test_runner: test.c $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
bench: bench_runner lumbda
ulimit -s 65536 && ./bench_runner
bench_runner: bench.c $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c lumbda.h
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o lumbda test_runner bench_runner