Compilation model
PCFC11 is a compact C compiler derived from Rui Ueyama’s chibicc, designed for exclusive distribution with PyCForge.
The compiler performs preprocessing, parsing, type analysis, optimization and x64 assembly generation. GCC-compatible external tools assemble and link its output and supply the platform runtime. Linux x86-64 and Windows x64 have separate data-model and calling-convention profiles.
| Stage | Contract |
|---|---|
| Frontend | Tokenization, macros, includes, declarations, type conversions and a typed abstract syntax tree (AST). |
| Integer analysis | Bounded control-flow analysis with a verifier, copy equivalence, conditional constants, known-bit masks across control flow and local value numbering. Unsupported effects invalidate local facts. |
| Optimization | Defined integer folding, bounded helper expansion, dead-store removal, dedicated integer registers, selected expression lowering and constant multiplication strength reduction. |
| Code generation | AST-based x64 emission with System V and Windows argument, return, frame and preserved-register handling. |
| Process boundary | Compiler state and allocations belong to one translation-unit process. Independent compiler invocations do not share global compiler state. |
Optimizations preserve observable effects, target widths and signedness. Floating-point reassociation and implicit fast-math transformations are not enabled. Analyses that exceed their supported scope or resource budget retain the established compilation path.
Independent compiler comparisons, native execution, mixed-compiler object tests, self-compilation and compiler sanitizers provide complementary evidence. Full ISO C11 conformance and production reliability have not been established; the machine interface explicitly reports full_conformance_verified: false.
Language and target behavior
-std=c11 selects the C11 language mode. It does not certify every C11 constraint, library requirement or required diagnostic. The gnu11 mode is also accepted; broad GCC language and command-line parity is not promised.
Integer constant contexts reject evaluated comma expressions while preserving valid unevaluated numeric subexpressions. Linux variable-length array bounds retain their effects; VLA typedefs capture their size at declaration and reuse it. Static initializers reject discarded operands that require runtime effects or reads. Pure-constant comma initializers remain a documented PCFC11 extension in both language modes, outside strict C11 compliance.
Constant numeric conversions. For integer types other than _Bool, floating-to-integer constant conversions truncate the fractional part and must fit the destination type. Out-of-range or non-finite values receive a source-located error. Narrow unsigned conversions from floating point do not use integer wraparound. Boolean conversion uses comparison with zero.
Runtime conversion from Linux x87 long double to unsigned 64-bit integer supports the defined upper-half range by splitting at 263. The conversion restores the caller’s x87 control word and consumes its input stack value. Runtime out-of-range conversion remains outside the defined input contract.
| Area | Implemented / tested scope | Boundary |
|---|---|---|
| Types & expressions | Scalar and aggregate operations, qualifier retention, selected pointer constraints, integer/bit-field promotions and side-effect regressions. | Complete conversion, declaration, sequencing and constant-expression coverage is unverified. |
| Initialization & layout | 146 initializer fixtures; 130 bit-field layouts. Static-address checks cover nested arrays and reject automatic-storage addresses in static initializers. | Exhaustive layout/initializer coverage is unverified. Packed bit-fields spanning more than eight bytes are rejected. |
| Preprocessor | Macros, includes, Unicode and line control; nine focused fixtures plus inherited coverage. | Full translation-phase, translation-limit, pragma and hostile-input coverage is unverified. |
| Floating point | float, double, target-specific long double; selected conversion and scalar numerical regressions. | No complete rounding-mode, floating-environment, excess-precision or exceptional-input certification. |
| Atomics | Naturally aligned integer/pointer objects through eight bytes; conservative sequentially consistent operations, compare/exchange and fences. | Other atomic types and packed/misaligned atomics are unsupported; complete memory-model diagnostics remain unverified. |
| Hosted C library | Linux host libc and a limited Windows UCRT header bridge; tested file, formatting, classification and numerical paths. | Full C11 library coverage and arbitrary Windows SDK headers are unverified; complex arithmetic is not implemented. |
| Compliance claims | Implementation and regression evidence scoped to the documented target profiles. | No full ISO C11 conformance, MISRA compliance, safety qualification or independent certification claim is made. |
Generic selection. All _Generic association expressions are type-checked; the control and unselected expressions are not evaluated. Variable-length array controls decay to pointers, nested variably modified association types are rejected, and a control matching multiple associations receives a diagnostic. Fixed and variable-length array types use compatible element types, requiring equal bounds when both are integer constants. Runtime size requirements still apply; no dynamic compatibility checks are inserted. This does not complete the generic-selection or compatible-type audit.
Target profiles
| Property | Linux x86-64 | Windows x64 |
|---|---|---|
| Target triple | x86_64-linux-gnu | x86_64-w64-mingw32 |
| Data model / ABI | LP64 / System V AMD64 | LLP64 / Windows x64 |
char / short / int | 1 / 2 / 4 bytes | 1 / 2 / 4 bytes |
long / long long | 8 / 8 bytes | 4 / 8 bytes |
Pointers / size_t / ptrdiff_t | 8 bytes | 8 bytes |
wchar_t | Signed 32-bit | Unsigned 16-bit |
long double | x87 extended; 16-byte storage | Binary64; 8-byte storage |
| Object / executable tools | ELF via external GCC-compatible tools | PE/COFF via MinGW-w64 UCRT64 tools |
Windows foreign objects using long double must agree with the binary64 profile; compatible GCC objects may require -mlong-double-64. Long-double CRT formatting and arbitrary foreign objects are not qualified.
Windows currently diagnoses VLAs, alloca, emitted thread-local objects, local alignment above 16 bytes and ELF PIC mode as unsupported. ARM64, macOS, MSVC-hosted builds, C++ interoperability and vector calling conventions are outside the current qualified targets.
Qualification methods and coverage
Tests compare output, diagnostics, exit status, file effects and selected machine-code properties against independent expectations. Generated arithmetic answers use Python integer arithmetic; GCC references check executable C behavior. Pinned Csmith and upstream software provide additional input diversity.
Counts below use distinct units. A fixture can run under several compilers, targets and optimization levels. Phases, fixtures, configurations and numerical comparisons must not be added together as a single test total.
| Area | Coverage | Qualification boundary |
|---|---|---|
| Language constraints | 350 cases, including 87 new generic-selection and array-compatibility regressions alongside all retained constraints. | The Windows target retains two documented exclusions and forty VLA-limit diagnostics (30 valid inputs and 10 invalid inputs). Native Windows 0.2.27 execution is pending; older native results retain their recorded versions. |
| Initializers / constants | 146 cases; 730 Linux/reference/model checks. Includes 40 floating-conversion cases and four explicit PCFC11 extension cases. Native Windows records 146 cases / 438 passing checks, without skips. | Extension checks are separate from C11 acceptance; PCFC11-only forms use explicit equivalent reference programs. Not exhaustive C11 coverage. |
| Integer code generation | 6,465 Python-derived products per configuration; seven native Windows/reference configurations pass, alongside Linux mixed-compiler calls and Windows instruction-model checks at O0/O1. | Signed products stay within range; unsigned results use the documented target widths. Side effects and fallback paths are checked separately. |
| Discarded integer values | 43,776 output comparisons and 77 assembly assertions per target/level. Includes result values, call counts, ordered traces, generated cases and resource-limit fallbacks. | Required conversions, statement-expression values, calls, qualified/memory reads, floating work and division remain. The expanded suite includes bounded branch chains, loop dependencies and retained effects. Linux execution and the Windows instruction model are distinct from native Windows qualification. |
| Integer facts / reuse | Arithmetic bits: 18,048 outputs / 92,534 IR checks and 9,228 concrete oracle cases. CFG bits: 17,024 outputs, 3,864 IR checks and 256 concrete-state oracle graphs per configuration. Local-bit tests: 17,280 outputs / 14,811 IR checks. Value numbering: 13,632 outputs / 62,641 IR checks. | Joins, cycles, types, effects and bounded fallback are tested. Arithmetic-bit qualification covers Linux and native Windows 0.2.25, including four native direct-analysis configurations. CFG bits and the preceding suites also pass. |
| Floating conversion execution | Repeated float/double/long-double to unsigned-64 checks, including values above 263. Linux GCC callers also test all four x87 rounding modes, control-word restoration and stack balance. | Tests execute defined conversions only. Windows long double uses binary64; the Linux Windows model is not a native runtime test. |
| Bit-fields / ABI | 130 layouts × nine inputs, two-way aggregate calls, initialization, mutation and bounded accesses. | The recorded native Windows 0.2.25 tests also cover protected page boundaries and register-frame virtual unwinding. |
| Warnings / robustness | 275 Linux diagnostic checks, including the Windows language model; 151 applicable native Windows checks. Malformed-input corpus includes 286 inputs. | Diagnostics cover the documented subset; malformed-input checks do not establish a hardened hostile-source service. |
| PyCForge output | 49 pinned C programs from PyCForge 1.3.57, plus a separate 1.3.68 fresh-conversion gate covering their Python inputs and four multi-file applications. | Checks generated C, observable results and declared file effects. The separate headless BuildService gate checks application builds and failed/stale/canceled output preservation; GUI, installer and general application compatibility remain unqualified. |
| Csmith corpus | 128 pinned inputs: 81 executable programs, 46 separately counted diagnostic rejections and one reference-timeout skip. | The skipped input is unqualified. A separate 32-input campaign has three reference timeouts and is not a passing campaign. |
| Upstream software | 15 inih profiles, four jsmn profiles, 48 LZ4 round trips and four selected Lua 5.4.8 suites on Linux. | Lua is not qualified on Windows. Selected portable/soft test modes do not represent complete project certification. |
| Numerical kernels | Float/double dot, AXPY, GEMV and GEMM; 1,184 scenarios and 415,872 numerical/byte comparisons per positive configuration. | Independent error bounds and input/padding/guard checks; no full floating-environment or numerical-regime certification. |
Platform qualification. Version 0.2.27 is a Linux-validated development checkpoint with self-compilation, compiler-sanitizer and Windows instruction-model gates. Native Windows execution of 0.2.27 is pending. The retained 0.2.25 feedback passed 36 native Windows phases, including PE/UCRT execution and register-frame virtual unwinding; that evidence does not qualify later compiler changes. Language, Lua and Csmith exclusions remain explicit, and external Windows OpenBLAS/LAPACKE remains unqualified. Finite checks do not establish exhaustive ABI, stack-probe or unwind coverage.
Compiler sanitizer tests instrument the compiler process using AddressSanitizer, UndefinedBehaviorSanitizer and floating-cast-overflow checks. Leak detection is disabled for the process-lifetime allocation model. Separately sanitized GCC reference programs do not imply instrumentation of PCFC11-generated applications.
External numerical qualification covers Linux OpenBLAS LP64 with real CBLAS and LAPACKE sgesv/dgesv calls. The installed library supplies its optimized kernels. Native Windows external-library, real ILP64 and complete LAPACK qualification are not established.
Optimization behavior and measured execution
-O0 is the baseline. -O1 enables conservative integer optimizations, including exact-width folding, constant/copy propagation, CFG known bits and local value numbering, bounded helper expansion, dead stores and unused integer calculations, power-of-two division and selected register placement.
Multiplication of a converted 32- or 64-bit integer by 3, 5 or 9 can use a single x64 scaled-address LEA instruction. The operand is evaluated once; 32-bit results retain their width. This is a code-generation property, not a guaranteed runtime speed multiplier.
Within one basic block, a pure integer expression may reuse an exact result still held in a same-type eligible local. Operand snapshots and ordered typed keys prevent reuse after incompatible writes or conversions; calls and opaque effects invalidate availability. A complete verified plan and a separate AST effect check precede substitution. No floating-point reassociation, cross-block reuse or speculative evaluation is introduced.
Known-bit analysis follows integer masks, casts, valid shifts, addition, subtraction and negation across structural control flow. Arithmetic carries and borrows preserve only proven bits. Unsigned results wrap at the target width; potentially overflowing signed operations yield no arithmetic facts. Joins retain shared facts; loop backedges must stabilize before use. For unsigned n, ((n & ~15U) + 3U) & 15U is proven equal to 3. If both branches mask a value below 16, its right shift by four is zero after the join. Only fully known pure results become literals; effects and budgets constrain proofs.
After the complete bounded liveness solve, a discarded ordinary integer calculation can be removed. Required assignment conversions, return/argument values and final statement-expression results remain. Calls, qualified and memory reads, pointer and floating work, and division/remainder are retained. Unsupported control flow or exhausted analysis limits prevent that round from rewriting. Liveness is rebuilt after each successful rewrite, for at most eight rewrite rounds and a final analysis before register placement. Longer chains can retain a safe remainder.
Historical 0.2.25 comparison: against 0.2.24, 17 focused O1 probes lose 19 multiplications per backend. Of 24 existing benchmark assembly comparisons, 22 are identical; the signed benchmark loses one unused register move in its loop on both targets. These are static reductions, with no new elapsed-time speedup claim.
Native Windows benchmark reference · PCFC11 0.2.25
Windows 11 build 26100, AMD64, MSYS2 UCRT64 GCC 16.2.0. These measurements compare optimization levels and compilers within one run; they are not a release-to-release speedup measurement.
All six benchmark kernels pass their checksum checks. In this Windows run, PCFC11 -O1 has a lower median execution time than -O0 on every kernel. GCC -O2 has a lower median on five kernels. The loop-constants medians are effectively tied and their sample ranges overlap. Unsigned sample ranges also overlap; several O1 timings show noticeable variability.
| Kernel | PCFC11 O0 · s | PCFC11 O1 · s | GCC O2 · s | O0 ÷ O1 | O1 ÷ GCC |
|---|---|---|---|---|---|
| Branches | 0.5108 | 0.2417 | 0.0821 | 2.11× | 2.94× |
| Loop constants | 0.2413 | 0.0747 | 0.0748 | 3.23× | 1.00× |
| PyCForge arithmetic | 0.5125 | 0.1173 | 0.0617 | 4.37× | 1.90× |
| PyCForge division | 1.6201 | 0.0658 | 0.0101 | 24.63× | 6.52× |
| Signed integers | 1.3405 | 0.2507 | 0.0936 | 5.35× | 2.68× |
| Unsigned integers | 0.5681 | 0.0926 | 0.0826 | 6.14× | 1.12× |
Read the ratios: O0 ÷ O1 measures PCFC11’s optimization benefit within this version; a value above 1 means O1 was faster. O1 ÷ GCC compares elapsed time; a value above 1 means PCFC11 took longer. The division kernel’s 24.63× internal ratio still leaves O1 taking 6.52× GCC’s time.
Measurement method
Each kernel uses 250,000 work items per round and equal work across its three variants. A GCC-built timing harness uses Windows QueryPerformanceCounter. Warmups precede five samples, with variant order reversed on alternating samples. PCFC11 compiles its own kernels; the harness is linked separately without link-time optimization.
Calibration targets 0.1 seconds for the fastest variant while bounding estimated slowest-variant samples to two seconds. Several variants remain below the target, especially division, where the slow O0 build caps the common workload. Host load and short-run variation limit strong comparative conclusions.
View workloads and observed sample ranges
| Kernel | Rounds | PCFC11 O0 | PCFC11 O1 | GCC O2 |
|---|---|---|---|---|
| Branches | 120 | 0.4728–0.5251 | 0.2261–0.2576 | 0.0765–0.0837 |
| Loop constants | 100 | 0.2249–0.2628 | 0.0681–0.0877 | 0.0739–0.0767 |
| PyCForge arithmetic | 220 | 0.4519–0.5263 | 0.1060–0.1396 | 0.0616–0.0645 |
| PyCForge division | 60 | 1.6107–1.6822 | 0.0574–0.0720 | 0.0085–0.0117 |
| Signed integers | 100 | 1.2978–1.3805 | 0.2408–0.2791 | 0.0790–0.0968 |
| Unsigned integers | 120 | 0.5543–0.5954 | 0.0871–0.1088 | 0.0763–0.0990 |
Measurement scope. Six bounded kernels, including two PyCForge 1.3.57 workloads, measure this host and configuration. They do not establish general GCC parity, application-wide speed, compiler-throughput superiority or memory-efficiency superiority. Compile-time samples in this run are single observations.
Command and diagnostic contract
PCFC11 uses GCC-compatible assembly/linking tools and the target runtime. The Windows profile uses MinGW-w64 UCRT64. Compiler builds and validation scripts use 64-bit Python 3.11+; Python is not the C parser or code generator. Bundled headers are resolved relative to the compiler executable.
| Option | Behavior |
|---|---|
--version / --info-json | Version and target identity; machine-readable capability schema 1 and process API 1. |
-E / -S / -c | Preprocess, emit assembly or emit an object file. Ordinary compilation can invoke external linking. |
-fsyntax-only | Parse and type-check without code generation. |
-O0 / -O1 | Baseline (default) or conservative optimization. Other optimization levels are rejected. |
--target=TRIPLE | Select the Linux or Windows profile. This does not supply an external cross-toolchain or target runtime. |
-I / -D / -U / -include / -o | Include paths, macro definitions/undefinitions, forced includes and output path. |
--diagnostics-json | JSON Lines diagnostics with schema, severity, source location and message. |
Command examples
pcfc11 --info-json
pcfc11 -std=c11 -O1 -c example.c -o example.o
pcfc11 -std=c11 -O1 -S example.c -o example.s
pcfc11 --diagnostics-json -Wall -Wextra -fsyntax-only example.c
Diagnostics
| Stable warning code | Category | Enabled by |
|---|---|---|
| PCFC11-W0001 | -Wextra-tokens | Default; -Wall |
| PCFC11-W0002 | -Wunused-variable | -Wall |
| PCFC11-W0003 | -Wunused-parameter | -Wextra |
| PCFC11-W0004 | -Wshadow | Explicit option |
| PCFC11-W0005 | -Wsign-compare | -Wextra |
-Werror promotes enabled warnings; category-specific controls override group controls, and equal-specificity controls use the last setting. Unknown warning names are errors. --help-warnings lists the supported subset. This is not the full GCC or Clang warning inventory.
JSON warning records add code, option and promoted. Consumers must tolerate absent category codes on mandatory errors and additive fields. Columns are one-based byte offsets. The tested promoted-warning failures preserve existing outputs, but a multi-file command does not roll back earlier successful translation units.
View the process API and path-handling boundaries
The supplied process adapter launches separate compiler processes, validates schema/process API 1, applies a timeout and supports object or assembly output. It stages output in the destination directory and atomically replaces the requested file after successful compilation. This contract does not imply rollback of an entire multi-file build.
Windows uses wide-character host path/process APIs and stages direct assembler/linker filenames through ASCII temporary paths. Toolchain-installation paths, raw linker-option paths and assembler-internal directives can still require ASCII names. The opt-in PCFC11_UTF8_PATHS=1 generated-program file bridge has a passing UTF-8 I/O regression.
PCFC11_WINDOWS_CC and PCFC11_LINUX_CC select an external GCC executable by path, not by shell command. Accepted compatibility flags including -fno-builtin, -fno-omit-frame-pointer, -fno-stack-protector, -fno-strict-aliasing, -m64 and -mno-red-zone are documented no-ops; they do not enable new optimizer or security behavior.
Generated C compatibility
PCFC11’s compatibility corpus contains 49 pinned C programs generated by PyCForge 1.3.57. The corpus samples Runtime and Typed behavior including calls, closures, inheritance, containers, numeric limits, Unicode, modules and file effects.
PCFC11 O0/O1 and GCC O0/O2 builds are compared with Python execution and the corpus’s explicit runtime contracts. One signed-64 overflow fixture follows PyCForge’s bounded-integer contract rather than Python’s arbitrary-precision result.
Fixture compatibility is scoped to the recorded generated C. It does not establish compatibility with every future converter version or validate a GUI, installer or wheel. Application integration requires its own version-matched qualification.
Limits that affect use
- Optimization: only O0/O1 are implemented. The analysis IR is bounded integer analysis with AST emission; it is not a full SSA backend. There is no general live-range allocator, automatic SIMD, implicit fast math, PGO or LTO.
- Integer IR budgets: at most 64 eligible locals, 512 blocks, 4,095 value/effect instructions, 32,768 scanned AST nodes and depth 256 per function. Copy, constant, known-bit and value-number analyses have bounded work. Failure or an exceeded budget produces no substitutions from that analysis.
- Registers: eligible integer objects can use up to four dedicated callee-saved registers. Pointer, floating, address-exposed, volatile and atomic objects retain their established locations.
- Windows runtime: VLAs, alloca, emitted thread-local objects and local alignment above 16 bytes are unsupported. Runtime headers are a limited UCRT bridge, not an arbitrary Windows SDK implementation.
- Numerics: complete floating-environment, rounding, exceptional-value and external-library coverage is unverified. External BLAS dimension widths must match the actual header/library ABI; standalone 64-bit dimension tests do not qualify an ILP64 library.
- Isolation: process separation does not provide a security sandbox. PCFC11 is not a fully reentrant in-process library or a hardened service for hostile inputs.
Finite passing tests do not prove absence of miscompilation. No full ISO C11 conformance, MISRA compliance, independent certification or safety-critical suitability claim is made.
Standards references and origin
PCFC11 derives from chibicc by Rui Ueyama and contributors and retains MIT licensing and attribution. Upstream chibicc is not claimed to maintain or endorse PCFC11. Separate PyCForge, Csmith and upstream qualification inputs retain their own notices and are not linked into the compiler executable.
These external references describe language and platform contracts. Their inclusion is not certification of PCFC11. This page is a self-contained specification; its content and navigation do not require a source repository or package directory.