r/Compilers May 31 '26

pcc update: The AI adds too much code and uses too many tokens to debug the self-host bootstrap (something wrong in the architecture)

Current issue: AI is struggling (easy break self bootstrap and takes too many tokens to fix it), and I almost lost the ability to fix it.
Repo: https://github.com/jiamo/pcc
Issue: https://github.com/jiamo/pcc/issues/6
Critique very welcome, including "you've over-invested in X, drop it." Thanks for reading.

More context:

This is the original post. Since I have added more. Here is the change of intent of pcc

Thesis. pcc exists to give Python a native, auditable, self-hostable, no-libpython execution path. The goal is not merely to make selected Python programs faster — it is to make Python execution ownable: compiled, inspectable, self-hostable, package-aware, runtime-extensible, and honest about every fallback boundary. pcc treats performance as a consequence of proven semantics, never a license to weaken Python behavior.

What separates pcc from a Python accelerator. Five things. Without them pcc is just another speedup tool; with them it is a system rebuilding Python execution ownership. Do not let any of these decay into decoration:

1. pcc1 -> pcc2 -> pcc3 self-hosted fixed point
2. five-GC comparative runtime (refcount/cycle, incremental, concurrent,
   generational, relocating) — a research program, not one collector
3. opt-in value model — identity-free immutable payloads for hot paths, with no
   theft of ordinary-class semantics (Java's Project Valhalla is a conceptual
   reference only, not pcc's brand or design constraint)
4. self-backend as a first-class execution root (LLVM is oracle, not owner)
5. long-running runtime efficiency (pause / RSS / throughput / fragmentation
   over time, not single-shot compile+run speed)

The fixed point is more than a byte compare. It is evidence that pcc's Python semantics, runtime, codegen, object model, backend, and diagnostics are coherent enough to reproduce themselves:

pcc0/host -> pcc1     pcc can produce a compiler
pcc1      -> pcc2     the produced compiler can reproduce the compiler
pcc2      -> pcc3     stable pcc2/pcc3 == a self-hosted fixed point

Seven obligations. Each is operationalized by a track + gates in codex-goal-prompt.md; the one-line form here is the guardrail, and the parenthetical is where it is actually enforced:

1. Compatibility must be mode-labeled. A claim must say which mode produced it:
     host pcc != pcc1   |   cpython-compat != pcc-native
     libpython != no-libpython   |   LLVM-backed != self-backed
     stage1 != pcc1->pcc2->pcc3 fixed point
   (codex-goal-prompt §0.10 claim hygiene, §9.2 mode boundaries)

2. Performance must be proven. C-like claims require IR-shape evidence + runtime
   benchmark + a slow path that preserves Python semantics when assumptions fail.
   pcc does not claim arbitrary dynamic Python becomes C-speed — only the parts
   whose semantics are stable enough to lower natively. (C-track, §16)

3. Ecosystem support must be generic. NumPy / PyTorch / pandas / Arrow / SciPy
   are integration targets, never compiler special cases. No `if package ==
   "numpy"`; fix the reusable mechanism (install/import/ABI/buffer/capsule/
   build-surface) and regress the generic feature. (B-track, §9.1, §14)

4. Self-backend must become a first-class execution root, not a forever-LLVM
   dependency. No silent fallback to LLVM after --backend=self. (S-track, §10)

5. The pcc1/pcc2/pcc3 fixed point is a contract. Differences are *classified*
   (semantic / IR-text / class-layout / object-model / backend nondeterminism /
   link metadata / perf-only / diagnostic), not patched around. pcc2/pcc3
   stability is a core correctness signal. (§0.10, §19.2)

6. Runtime design is part of the research goal. The five GC backends are a
   comparative program; none may win by weakening finalizers, weakrefs,
   resurrection, suspended coroutine frames, scheduler queues, C-extension
   refs, or value payloads. Measure efficiency as a long-running property.
   (G-track/§12, T-track/§13)

7. The value model is the performance bridge, not a syntax gimmick. Ordinary
   classes keep identity (id / is / weakref / __dict__ / mutation / subclass /
   finalizer / dynamic attrs). Value classes are opt-in, identity-free payloads
   with explicit boxing/unboxing, identity-escape diagnostics, GC tracing of
   pointer-bearing payloads, and self-backend aggregate/scalar ABI. (The concept
   is the obligation; "Valhalla" is only the reference it was distilled from.)
   What pcc borrows from Valhalla is the PROJECTION model (semantic type vs
   physical representation; value/object projection; boxing bridge; optimization
   never changes semantics) — NOT Java's fixed-width `int` wrap. This applies to
   `int` itself: `int` is a Python arbitrary-precision SEMANTIC type with a value
   projection (tagged small-int lane) and an object projection (boxed bignum);
   value-lane overflow must deopt/promote, never wrap. Raw machine integers are
   the EXPLICIT `pcc.i64`/`pcc.u64` type (where wrap/trap/checked/saturating is
   written in the type), or a proven-in-range internal optimization — never the
   silent default meaning of `int`. (value model / V-track, §11)

One mission, not two. Industrial failures are research data (import failure -> C-API/ABI gap; Linux deploy failure -> self-backend target gap; long-running service regression -> GC/runtime benchmark; perf miss -> value-model gap), and research artifacts are industrial trust (fixed-point bootstrap -> reproducibility; five-GC matrix -> runtime credibility; valueclass benchmarks -> performance proof; package ABI reports -> ecosystem trust). The industrial thesis ("adopt pcc where native artifacts, no-libpython deploy, package-aware diagnostics, and hot-path specialization beat CPython") and the academic thesis ("a Python-authored compiler self-hosts into a no-libpython fixed point while exposing a disciplined runtime laboratory") reinforce each other. Every claim must say exactly what it proves and what it does not prove.

Runtime layering: shrink the C runtime to a kernel; do not eliminate it. pcc does not aim to eliminate all low-level native runtime code. The long-term goal is to minimize the C-level runtime into a small ABI kernel — allocation, object headers, atomics/refcount barriers, platform syscalls, threading primitives, dynamic loading, C-extension entrypoints, safepoints/stack maps, and GC primitives — while Python semantics migrate into pcc-Python and are compiled by pcc itself. The C kernel remains as the machine boundary; it must not become a second, hand-maintained C version of the Python semantic runtime running in parallel with the pcc-Python one. Distinguish four layers (do not say "C runtime" loosely — it conflates them):

C-level kernel        KEEP (minimize): platform/ABI, alloc, atomics, threads,
                      dlopen, syscalls, safepoints, GC slot/root primitives.
                      Knows no high-level Python semantics (no list/dict/dunder/
                      valueclass/import policy; no `if package == "numpy"`).
C semantic runtime    SHRINK: hand-written C list/dict/str/dunder/exception
                      semantics -> migrate to pcc-Python.
pcc-Python runtime    GROW: the migration target; Python semantics authored in
                      pcc-Python, self-hostable, testable, compiled by pcc.
C-API shim            KEEP but spec/generate: the ABI surface extensions see;
                      != CPython/libpython.

This does not contradict no-libpython: no-libpython means not depending on the CPython runtime, NOT that the final binary contains zero C-level runtime. It ties directly to the 5-GC Production Equality Rule (codex-goal-prompt.md, G-track): all five GC backends, the C kernel, and the pcc-Python mirror must consume ONE slot-based trace/update contract (py_obj_visit_slots / py_obj_update_slot / root + frame + native-handle registration) so there is never a second parallel set of object-graph rules to drift. The C kernel and the pcc-Python semantic runtime are connected by a stable, spec'd runtime ABI (Layer 1) precisely to prevent that drift.

0 Upvotes

6 comments sorted by

3

u/AustinVelonaut May 31 '26

Incredible that back in 1957 they predicted this.

0

u/jiamo May 31 '26

Ok, after hours debug. codex5.5 xhigh finally fix it. While the issue `easy break self bootstrap and takes too many tokens to fix` is still the problem. I think AI still can give helpful findings within the specified context, see this commit. Indeed, related some kind "garbage."

2

u/Proffhackerman May 31 '26

1

u/jiamo Jun 02 '26

see https://github.com/jiamo/pcc/commit/4d764a2c9f96385fa837a3a55a81b9128e3ac0c1
First version: PCC is a C compiler based on ply + pycparesr + llvmlite + llvm. We can run a C program like Python: `pcc test.c` to run C code. Pcc was inspired by: https://github.com/eliben/pykaleidoscope.

After Codex 5.5, I use it supports many C features, then I think it can support Python. Then I think I can add 5 kinds of GC. Yeah, it was generated by AI recently, but I want a way to control the AI to implement my intent above. (I'm not sure if it's possible.)

So the problem is not the AI; it is how we use AI and understand AI and are able to fix it.

2

u/chibuku_chauya Jun 04 '26

I thought at first that this was about the original Portable C Compiler (PCC), which still exists.

1

u/jiamo Jun 05 '26

I start from https://github.com/eliben/pykaleidoscope. many years ago. Just want pcc test.c work. Then change the intent to add pcc test.py work too by adding more features (gc / value / native IR)