Conceptio › Archive › arXiv CS
arXiv CSopen access

CPL: A Compact C-like Systems Language with Explicit Low-Level Control

· arxiv_cs
arXiv CS · Papers · License: Open Access
Open Source ↗Direct PDF ↓
software-architecturesoftware-engineeringtesting
software engineering, software architecture, testing

CPL: A Compact C-like Systems Language with Explicit Low-Level Control Nikolai Fot Alexander Vinarsky Compiler Technology Department, Ivannikov Institute for System Programming of the Russian Academy of Sciences (ISP RAS)

arXiv:2609.04904v1 [cs.PL] 4 Sep 2026

Abstract

or create misleading expectations that the rest of the language should also be supported. The design instead favors a compact parser-friendly grammar, explicit syntax for functions and pointer-like operations, and compiler-supported low-level constructs. The central research problem is the trade-off between implementation compactness and systems-level adequacy. Reducing a language and compiler makes experimentation and inspection easier, but can remove the layout controls, ABI mechanisms, analyses, and backend structure needed for realistic low-level programs. This article studies CPL as a C-like language design that keeps the directness of C while experimenting with a smaller grammar and selected modern conveniences.

This paper presents Cordell Programming Language (CPL), a compact C-like systems language that retains C’s direct access to memory, layout, and machine interfaces while experimenting with a smaller grammar and selected conveniences from newer languages. Also this paper studies whether C-like are more convenient to use for compiler experiments than modern approaches and paradigms. While the language and compiler provide primitive values, pointers, arrays, containers with methods, unions, generic functions, overloads, entry-point and section control, system calls, and inline assembly, they do not provide high-level constructs such as classes, built-in methods, a standard library, or memory protection. The article describes the language design, compiler pipeline, target backends, static-analysis architecture, and OS-facing use cases, then evaluates the prototype backend with reproducible x86_64 and i386 microbenchmarks against C compiler baselines. The obtained results suggest that the compiler can produce code comparable to that produced by production compilers such as GCC and Clang, as well as by small compilers such as TinyC and SmallerC.

1

2

Language Overview

The language remains close to assembly and C by exposing pointers, explicit dereferencing, C-like structures, direct system calls, inline assembly, manual entry points, and annotations for placement and control. It deliberately avoids reproducing the full C grammar and semantics. The compiler includes enough phase separation to study SSA-form construction [3], diagnostics, scalar optimization, low-level selection, register allocation, and peephole rewriting.

Introduction

2.1

Systems programming languages expose machine-level details while attempting to keep programs tractable. Mature languages such as C [13, 7], C++ [14, 15], Rust [8, 6], and Zig [18] provide large ecosystems, but the full syntactic and semantic complexity makes them expensive targets for compiler experiments. Conversely, many teaching compilers are intentionally small but do not expose enough low-level mechanisms for studying system-oriented code generation, platform-specific interfaces, and optimization under realistic constraints. To address this issue building a new small compiler (and a language) is a promising approach to create a convenient testbed for learning and experiments. A new compiler provides more opportunities for experimentation, given the nature of optimizations, and a new language can reflect modern syntax common among languages such as Rust, C, C++, and Zig. The motivation for a new grammar lays in a fact, that a faithful C-like, Rust-like or Zig-like subset would either require a substantially more complex parser and semantic model,

Program Entry

A program can use a start block as its static entry point. The entry block does not return a value with return; it must terminate through exit. An ordinary function can also become an entry point through the @[entry] annotation. The start structure was chosen as the basic name of a function, which is an entry point during the standard linker process with the ld tool on Linux. In most cases, it is more convenient to use the @[entry] annotation rather than explicit start function. :/ The final name depends on the architecture /: start() { exit 0; } :/ ’main’ is the name in the final assembly file /: @[entry("main")] function main() { }

Listing 1: Minimal CPL entry point. 1

Table 1: Type size on x86_64 GNU.

The entry point may accept arguments, such as argc and argv, and can be annotated for platform-specific entry behavior. The naked annotation disables default entry and exit routines, which is useful for systemlevel code that must manage its own prologue and epilogue. On i386 this also affects how stack arguments are addressed, as discussed in Section 3.4.

2.2

Size (bytes)

u8, i8 u16, i16 u32, i32, f32 u64, i64, f64

1 2 4 8

By default, container fields use the target architecture’s default maximum alignment policy. A container can override this with the align annotation. For example, @[align(1)] requests a packed layout, which is useful when a byte-exact representation is required.

Types

CPL uses permissive static typing. Variables do not dynamically change type, widening conversions may be inserted implicitly, and narrowing conversions require an explicit as cast. The primitive integer and floatingpoint types include i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, and the void-like function return type i0. Boolean-like logic follows the C convention: zero is false and non-zero is true. The sizes can be seen in the Table 1. The largest type size depends on the target system.

2.3

Type

@[align(1)] container packed_value { i8 a; i16 b; i32 c; } :/ packed, occupies 7 bytes on the stack /:

Listing 5: Packed container layout. In addition to fields, a container may declare functions. These functions are ordinary CPL functions attached syntactically to the container definition. They do not make the container a class, and they do not introduce implicit constructors or destructors.

Pointers, Strings, and Arrays

The language exposes pointer types through the ptr modifier. In contrast to the asterisk used in C, the explicit ptr keyword makes the pointers more distinct and imposes the uniform declaration style. The ref keyword obtains a pointer to an object or string literal, and dref reads or writes through a pointer.

container counter { @[inline(always)] function default_value() -> i32; }

i32 x = 123; ptr i32 p = ref x; :/ While C supports int* p; int *p; int * p; /: i32 y = dref p; dref p = y + 1;

function counter::default_value() -> i32 { return 100; } counter c; c.default_value();

Listing 2: Pointer operations in CPL.

Listing 6: Container function. Strings and arrays are distinct built-in containers. arr[0, i8] allocates a terminated byte sequence, while arr declares a fixed-size array. String literals placed independently in code reside in a read-only section-like area and must be referenced explicitly.

The self annotation marks a container function whose first explicit argument is the receiver pointer. Calls to such functions may use method-like syntax, and the parser can pass the container pointer automatically. This is purely syntactic sugar only: a self function must still declare its receiver argument explicitly.

arr msg[0, i8] = "Hello world!"; :/ Compiler sets the size by itself, which means we can provide ’0’ /: arr xs[4, i32] = { 1, 2, 3, 4 }; :/ We can set the exact size for an array /: ptr i8 p = ref "Hello, World!\n";

container counter { i32 val; @[self] function init(ptr counter self) -> i0 { self.val = 100; }

Listing 3: Strings and arrays. }

2.4

Containers

counter c; c.init(); c.val; :/ 100 /:

CPL containers are lightweight C-like aggregate types. They group fields of different types in one named layout and are intended for explicit systems code rather than for object-oriented programming.

Listing 7: A self container function. Containers should therefore be treated as modified C structures with optional attached functions. Initialization, cleanup, and ownership-like behavior must be written explicitly by the programmer. Containers may also represent unions. With @[union], all fields share offset zero and the aggregate size is determined by the largest field together

container pair { i32 first; i32 second; }

Listing 4: A simple CPL container.

2

with the selected alignment policy. The annotation composes with @[align] and @[like_c].

use glob when their symbol name must be preserved for external linkage.

@[like_c] @[union] container device_value { i8 size_8; i16 size_16; i32 size_32; i64 size_64; }

function add(i32 a, i32 b = 1) -> i32 { return a + b; } glob function exported(i32 x) -> i32;

Listing 12: Function forms.

Listing 8: Union container with C-compatible layout.

2.7

Container values can be array elements, and array element types may themselves be arrays. These forms permit arrays of records and statically sized matrices without introducing a separate aggregate system.

System-Level Facilities

CPL provides two built-in low-level mechanisms: syscall and asm. A syscall expression is targetdependent and accepts a platform-specific argument list. Inline assembly supports argument substitution through numbered placeholders.

container string_view { ptr i8 data; i32 length; }

i32 a = 0; i32 ret; asm(a, ret) { "push rax", "mov rax, %0", "syscall", "mov %1, rax", "pop rax" }

arr views[10, string_view]; arr matrix[10, arr[10, i32]];

Listing 9: Arrays of containers and nested arrays. A container method may be declared in the container and defined separately with the :: qualifier. This form avoids emitting the same implementation in every translation unit while retaining container-qualified lookup.

Listing 13: Inline assembly with placeholders. Inline assembly is intentionally powerful and fragile. It is copied with minimal changes into the generated assembly after placeholder substitution, therefore, the programmer must preserve registers and match the selected target syntax. The compiler does not optimize inside inline assembly blocks.

container math { glob function add(i32 a, i32 b) -> i32; } function math::add(i32 a, i32 b) -> i32 { return a + b; }

Listing 10: Out-of-container method definition.

2.8 2.5

Annotations extend the small grammar with low-level behavior. Table 2 summarizes the system-oriented annotations available in the implementation. The maturity column separates stable annotations from annotations whose behavior is target-dependent or experimental. These annotations expose system-level control without introducing an object-oriented runtime model. The like_c annotation is relevant for containers that cross a C ABI boundary because it specifies C-compatible padding assumptions. The section annotation accepts an optional alignment argument, for example @[section(".bss", 16)]; this is distinct from aligning an individual declaration because the emitted section directive itself carries the alignment constraint. The only_body annotation supports target directives or instruction sequences that must appear without a generated function label, while preserving the function body as an optimizable compiler object before emission.

Control Flow

CPL provides if, while, loop, and switch. A semicolon separates the condition from the body in conditional constructs. The loop construct represents an infinite loop unless terminated with break or annotated with @[counter(n)]. The switch construct supports fallthrough by default, while @[no_fall] inserts breaklike behavior into cases. if x > 0; x -= 1; else x = 0; @[counter(10)] loop { x += 1; }

Listing 11: Control flow.

2.6

Annotations

Functions

Functions are declared with the function keyword. CPL supports prototypes, default arguments, local functions, function overloading with restrictions, generic functions, function pointers, lambdas without capturing closures, and variadic arguments. Global functions

2.9

Core Static and Dynamic Model

The complete language is defined by the implementation, but the safety-relevant core used in this article 3

Table 2: Selected CPL annotations. Annotation

Purpose

Example

Maturity

naked align section nosection

Disable default entry and exit routines. Align a local or global object. Place code or data in a target section. Emit a declaration without an explicit section directive. Mark a function as an entry point. Insert break-like behavior in switch cases. Use linear switch selection. Generate a counted loop. Influence branch layout. Bind a primitive variable to a register index. Mark a container method whose explicit receiver pointer can be passed through method-like syntax. Influence argument popping at a low-level call boundary. Request C-ABI-like padding and layout behavior for a container. Give all fields of a container offset zero.

@[naked] start() @[align(16)] glob i32 a; @[section(".data")] @[nosection] glob function f() @[entry("_start")] @[no_fall] switch x; @[straight] switch x; @[counter(100)] loop @[cold] if cond; @[register(RAX)] i32 x; @[self] function init(ptr T self) @[poparg]

stable stable stable stable

entry no_fall straight counter hot/cold register self poparg like_c union abi weak only_body

Mark an external function declaration as ABIcompatible. Emit a weak linker symbol for a function. Emit only the lowered body of a function, without its symbol label or ordinary wrapper.

can be stated independently. Let primitive types be b ∈ {i8, . . . , u64, f32, f64, i0}, and let

where C is a container type. A typing environment Γ maps identifiers to types, a container environment ∆ maps field pairs C.f to field types, and Γ ⊢ e : τ denotes expression typing. Γ ⊢ e : ptr τ , Γ ⊢ dref e : τ

stable implemented implemented implemented experimental

3

Compiler Architecture

3.1

Pipeline

Figure 1 presents the compiler architecture. The frontend performs preprocessing, tokenization, AST construction, and early semantic checking. The middle-end constructs HIR, converts it to SSA [3], runs SSA-level semantic checking with a Z3-backed symbolic layer [4], and applies HIR-level optimizations. The backend lowers the program to LIR, performs LIR data-flow and copy-propagation passes, selects target-sensitive instructions, allocates registers, applies late peephole cleanup, and finally emits assembly for an external assembler/linker toolchain. This organization deliberately separates source-level analysis, SSA construction, symbolic checking, highlevel optimization, lowering, instruction selection, register allocation, and late cleanup. The separation makes the implementation suitable for code generation, as well as for experiments with IR design, pass placement, and target-specific transformations.

Γ⊢e:C ∆(C, f ) = τ . Γ ⊢ e.f : τ Widening numeric conversions may be inserted by the compiler; narrowing conversions require an explicit as expression. Pointer dereference is type-correct when its operand has a pointer type, but typing does not establish allocation validity or non-nullness. This distinction motivates the separate SSA/SMT diagnostic layer. A small-step memory model uses a store σ from addresses to typed values and locations ℓ: ⟨σ, ref x⟩ → ⟨σ, ℓx ⟩,

stable

and target annotations are modeled as externally defined transitions because their behavior depends on the selected ABI and machine. These rules define the article’s core reasoning model, not a mechanized semantics or a proof that every compiler pass preserves it.

τ ::= b | ptr τ | arr[n, τ ] | C,

Γ⊢x:τ Γ ⊢ ref x : ptr τ

@[like_c] container T {...} @[union] container U {...} @[abi] extern function f(...) @[weak] function f() @[only_body] function h()

stable stable stable stable stable stable stable

σ(ℓ) = v . ⟨σ, dref ℓ⟩ → ⟨σ, v⟩

For assignment through a pointer,

3.2

⟨σ, dref ℓ = v⟩ → ⟨σ[ℓ 7→ v], v⟩.

Worked Example

Listing 14 presents a minimal program used to illustrate the compiler forms.

Container field access is computed by adding the targetdependent field offset to the base location; union fields have a zero offset. Function calls evaluate arguments, establish parameter bindings, execute the body, and yield the explicit return value. Inline assembly, syscalls,

start() { i32 a = 1; i32 b = 2; exit a + b;

4

Frontend Source *.cpl

Preprocessing

Tokenizer

AST Parser

AST Semantic Checker

SSA Construction

HIR Generation

Middle-end LIR Lowering

SSA/HIR Optimizations

SSA-Level Semantic Checker (Z3)

Backend LIR Data-Flow Passes

Copy Propagation

Instruction Selection

Peephole & Copy Prop.

Register Allocation

Assembly

Linker / Binary

Figure 1: Graphical overview of the CPL compiler architecture. The pipeline is arranged in three phases to preserve readability in a two-column layout while retaining the execution order. Table 3: Backend maturity in the CPL compiler prototype.

}

Listing 14: Input CPL program. The corresponding HIR uses stack variables with an s suffix and temporaries with a t suffix. fn _main0() { i32s %0 = alloc; i32t %2 = i8n 1 as i32; i32s %0 = i32t %2; i32s %1 = alloc; i32t %3 = i8n 2 as i32; i32s %1 = i32t %3; i32t %5 = i32s %0 + i32s %1; u8t %4 = i32t %5 as u8; exit u8t %4; }

Target

Assembler format

Status

x86-64 Mach-O

macho64

x86-64 Linux

elf64

i386 Linux

elf32

default; broadest coverage implemented; targeted tests implemented; kernel examples

The final optimized Mach-O assembly for this example collapses the computation to a short sequence. section .text global _main _main: mov al, 1 add al, 2 mov dil, al mov rax, 0x2000001 ; Exit syscall on MACHO64 syscall

Listing 15: High IR (HIR) form for Listing 14. After lowering to LIR, the program is represented as a basic-block sequence. BB1: start { %2 = $1 as i32; %0 = %2; %3 = $2 as i32; %1 = %3; %5 = %0 + %1; %4 = %5 as u8; exit %4; } BB2: send

Listing 18: Generated assembly.

3.3

Backends and Target Status

The implemented backends are x86_64 MachO/NASM, x86_64 GNU/Linux NASM, and i386 GNU/Linux NASM. Each path includes instruction selection, memory selection, caller-saving logic, and assembly generation. Mach-O is the default configuration and has the broadest test coverage. Linux x86_64 and i386 are exercised by dedicated compiler and assemblygeneration tests; the i386 path additionally supports kernel-oriented examples. Other architectures and system options exposed by configuration code are outside the evaluated target set. The compiler can invoke ld, clang, or gcc for linking.

Listing 16: LIR form before target-sensitive selection. A later selected LIR form contains target-dependent register choices. BB1: start rcx = $1; rcx = rcx; rdx = $2; rdx = rdx; rax = rcx; rax = rax + rdx; rcx = rax; rcx = rcx; rdi = rcx; exit rdi; BB2: send

3.4

i386 ABI Notes

The i386 backend follows a simple C-style stack ABI for exported functions and extern declarations. Primitive

Listing 17: Selected LIR form.

5

arguments are passed through the caller’s stack frame, return values use the target return-register convention, and extern declarations describe symbols implemented outside the CPL module. Global CPL functions are emitted as externally visible symbols and can be called from C support code when matching prototypes are used. The naked annotation is the main exception to the ordinary function-frame shape. In a normal i386 function, the compiler may establish an ebp-based frame: [ebp + 4] contains the return address, [ebp + 8] the first argument, and [ebp + 12] the second. A naked function suppresses the generated prologue and epilogue, so the corresponding locations are [esp], [esp + 4], and [esp + 8]. Figure 2 presents this difference.

and makes the generated constraints easier to relate to compiler variables. The analysis is diagnostic rather than protective. It does not implement memory safety, ownership, or aliasing restrictions, and it does not prevent undefined behavior caused by dangling pointers, unsafe inline assembly, invalid external interfaces, or target-specific misuse. start() { function foo(ptr i32 p) -> i32 { return dref p; :/ Dereference of NULL /: } ptr i32 a = 0; foo(a); }

Listing 20: Example that triggers SSA-level nulldereference diagnostics.

@[nosection] @[naked] glob function i386_switch2user(u32 eip, u32 esp) -> i0 { asm(eip, esp) { "cli", "push 0x23", "push %1", "push 0x202", "push 0x1b", "push %0", "iretd" } }

A representative diagnostic sequence for this example reports both that the return value of foo(a) is ignored and that p may be dereferenced while equal to null. More complex inputs additionally trigger path-sensitive reports, for example, when one branch makes a pointer definitely null while another makes it only conditionally null.

4.1

Listing 19: A naked i386 helper whose arguments are addressed from esp.

The SSA-level checker is implemented as a symbolic layer over the HIR control-flow graph. The analyzer prepares HIR expressions as Z3 formulas, preserves symbolic names for compiler variables, and augments path conditions with phi-node constraints when controlflow edges enter SSA merge points. This design makes it possible to ask local reachability and value questions over the same representation that the optimizer sees. The wrapper accepts either parsed JSON or textual HIR dumps, can select a particular function, builds a CFG, and then dispatches solver-backed queries. Two query modes are especially useful for development: label, which checks whether a label can be reached under satisfiable path conditions, and var-eq, which checks whether a selected variable can, must, or cannot equal a given value. The wrapper also supports initial assignments, pointer-width configuration, strict parsing modes, and cached parsing/analysis artifacts. These features keep the solver path useful for compiler diagnostics, as well as for investigating IR examples during pass development.

For Listing 19, the backend must materialize the CPL parameters from [esp + 4] and [esp + 8] before expanding inline-assembly placeholders. Once the assembly body pushes interrupt-frame words, esp changes normally; subsequent hand-written instructions must account for that movement.

4

Z3-Backed Symbolic Layer

Static Diagnostics

CPL contains a two-level diagnostic subsystem. The first level operates on the AST and targets sourcestructure issues such as read-only variable updates, declaration problems, return mismatches, wrong argument counts, incompatible argument types, unused return values, illegal array access, duplicated branches, invalid function names, dead code, lossy implicit conversions, inefficient infinite loops, invalid exit usage, break statements without legal targets, invalid use of i0, unused expressions, invalid references, and suspicious alignment requests. The second level is intentionally placed after SSA construction [3]. At this point, the compiler has explicit use-definition chains and phi nodes, so the checker can reason about values and path conditions in a more structured form than in the original HIR. Z3-backed symbolic execution [4] is applied to SSA-form HIR to detect definite null dereferences, null values passed to dereferencing functions, possible null dereferences under path-dependent conditions, and constant branches. This ordering is important: the solver-facing analysis works on SSA-form HIR rather than on pre-SSA HIR, because SSA simplifies symbolic value tracking

analyze-hir --function entry --pointer-width 64 variable-equals temporary_7 0

Listing 21: Representative interface to the symbolic query layer. This subsystem should be understood as an experimental symbolic analysis component, not as a formal verification framework. Z3 is used to answer bounded path and value questions that are helpful for diagnostics such as null-dereference detection and unreachablecode reasoning. It does not by itself provide a complete semantic proof of CPL programs or of compiler transformations [4]. 6

Normal i386 function after prologue

Naked i386 function at entry

[ebp + 12] second argument

[esp + 8] second argument

[ebp + 8] first argument

[esp + 4] first argument esp

[ebp + 4] return address ebp

[ebp] saved ebp

esp

locals / spills

[esp] return address caller stack

Figure 2: i386 stack view for ordinary and naked CPL functions. In this target, ordinary functions use 32-bit registers such as eax, ebx, ecx, edx, esp, and ebp; without push ebp; mov ebp, esp, the backend addresses arguments from esp rather than from ebp.

4.2

Scalability

branch sequences, and can replace zero materialization with xor-style idioms where applicable.

The present evaluation does not isolate solver time or characterize its growth with function size and path count. It also does not use a labeled defect corpus from which false-positive and false-negative rates could be computed. Consequently, the evaluation of the symbolic diagnostic layer remains architectural: SSA-form HIR can drive path-conditioned Z3 queries, but the speed and diagnostic accuracy of this design remain unestablished. A quantitative answer requires functions stratified by HIR size and path count, seeded null defects with known ground truth, and separate measurements of solver and total compilation time.

5

Before: rax = rcx; rax = rax - 1; rcx = rax; rdx = rcx; cmp rdx, 0; je lb11; jne lb9; After: rcx = rcx - 1; jne lb10;

Listing 23: Peephole effect on a counted empty loop.

Optimization Passes

5.3

Table 4 summarizes the passes included in the evaluated optimization profiles. The driver uses -O0 as the default, enables LICM, constant optimization, and peephole cleanup at -O2, and additionally enables LIR copy propagation and tail-recursion elimination at -O3. Experimental function inlining is excluded from the evaluated pass set because known correctness defects prevent an interpretable performance claim.

5.1

In addition to handwritten rewrites, the late peephole pass also uses PTRN, a small domain-specific language for generating peephole optimization patterns. The motivation is practical: low-level instruction cleanup often consists of many small local rewrites, and encoding them in C by hand makes the pass difficult to extend. PTRN provides a declarative syntax for matching short Low LIR instruction sequences and replacing them with simpler or more efficient sequences. A PTRN file consists of rewrite rules separated by /. The left-hand side describes a sequence to match; the right-hand side after -> describes the replacement. Pattern objects abstract over concrete Low LIR operands: areg_N tracks a repeated abstract register, aconst_N tracks a repeated abstract constant, mem_N matches memory locations, and obj can match an arbitrary object. Conditions such as [if:equals], [if:arg2:zero], or [if:arg2:mod2] restrict a match, while actions can transform matched constants in the replacement.

Loop-Invariant Code Motion

LICM operates on SSA High IR. A loop body that repeatedly computes a constant expression such as 10 + 10 can have this computation moved before the loop, with phi nodes preserving loop-carried values. start() { i32 d = 0; loop { i32 c = 10 + 10; d += c; } }

; Remove a jump that immediately targets the next label. jmp label_1 mklb label_1 -> mklb label_1 /

Listing 22: LICM source pattern.

5.2

PTRN: A Peephole Pattern DSL

Peephole Optimization

Peephole optimization runs late, after instruction selection and register allocation. It removes redundant register-to-itself moves, simplifies decrement-and-

; Remove redundant self-copy. mov obj_1, obj_2 [if:equals] ->

7

Table 4: Optimization passes implemented in the CPL compiler prototype. Pass

IR level and role

Level

LICM

Works on SSA HIR; hoists loop-invariant expressions after loop canonicalization. Works on selected LIR after instruction selection, register allocation, memory selection, and caller-saving insertion. Works on HIR via DAG generation and CFG rebuild before lowering to LIR. Builds and applies a call graph before later HIR transformations. Rewrites propagated LIR operands and removes unused variable writes. Works on HIR and rewrites tail self-calls to loops before SSA construction. Implemented during AST-to-HIR generation as annotation-driven branch layout.

-O2 and above

Peephole DAG rebuild and sparse constant propagation Dead-function elimination LIR copy propagation and unused-variable dropping Tail-recursion elimination Hot/cold placement

; Prefer xor-zeroing over moving an immediate zero. mov areg_1, const 0 -> xor areg_1, areg_1 /

default pipeline -O3 -O3 default pipeline

Table 5: Representative CPL programs. Program

What it demonstrates

Hello World

Strings, pointers to string literals, strlen, inline assembly, direct syscall use, and entry-point termination. Global arrays, indexed memory acCRC8 cess, loops, pointer arguments, integer operations, and exit-code calculation. Brainfuck in- Arrays, argument access, switch terpreter dispatch, no_fall, straight, loops, function calls, and bytelevel tape manipulation. Memory and Header-style declarations, syscall file helpers wrappers, pointer arithmetic, and low-level I/O abstractions. OS kernel i386 extern boundaries, interrupthelpers related routines, keyboard-driver logic, and C ABI integration. Multiboot Packed header layout, aligned seckernel entry tions, linker-visible entry points, register binding, stack construction, and transfer to a higher-level kernel routine.

Listing 24: Examples of PTRN peephole rules. The generated C code is then used by the low-level peephole pass. This keeps the compiler backend extensible: adding a new local simplification can be implemented by adding a pattern rule rather than modifying the peephole engine directly. The approach is intentionally modest; PTRN does not replace global optimization or data-flow analysis. Its role is to make late instruction cleanup explicit, testable, and easier to maintain. This article does not attribute an independent performance improvement to PTRN because the available benchmark data measures the complete optimization pipeline. PTRN is therefore evaluated here as an implementation mechanism for declarative and generated local rewrites, rather than as an isolated source of speedup.

Excluded Experimental Passes

The implementation contains heuristic and modelguided function-inlining experiments. They are not part of the evaluated -O0/-O2/-O3 evidence in this article. Known call-site rewriting defects and the absence of model, dataset, and accuracy documentation make performance results involving these modes not interpretable. They are therefore treated as implementation prototypes rather than research results.

6

-O2 and above

shortened to isolate the language mechanisms relevant to each case.

delete /

5.4

-O2 and above

Listing 25 presents a compact Hello World excerpt using a direct syscall wrapper. The complete version includes the full strlen implementation and register preservation sequence. function puts(ptr i8 s) -> i0 { asm (s, strlen(s)) { "mov rax, 33554436", "mov rdi, 1", "mov rsi, %0", "mov rdx, %1", "syscall" } }

Examples and Use Cases

The evaluated examples exercise core low-level features rather than large application workloads. Listings are 8

u32 flags; u32 checksum; arr reserved[5, u32]; u32 mode; u32 width; u32 height; u32 depth;

Listing 25: Shortened Hello World with explicit syscall wrapper. }

6.1

@[section(".multiboot", 4)] glob multiboot_header header = { 0x1BADB002, 7, 3830599671, 0, 0, 0, 0, 0, 0, 640, 480, 32 };

Operating-System Code on i386

container kernel_stack { arr storage[16384, u8]; }

A practical use case for CPL is small freestanding routines used by an operating-system kernel. The i386 backend was added to support this style of code: globally visible routines can be emitted as NASMcompatible 32-bit assembly, while extern declarations make it possible to integrate CPL modules with C kernel code. Listing 26 presents a shortened PS/2 keyboard driver excerpt. The complete example additionally contains scancode tables, polling helpers, initialization code, and an exported C boundary.

@[section(".bss", 16)] glob kernel_stack stack; @[section(".text")] function kmain(u32 info, u32 magic, u32 stack_top) -> i0; @[section(".text")] @[entry("_start")] @[naked] function main() -> i0 { @[register(4)] u32 magic; @[register(5)] u32 info; asm(magic, info) { "mov %0, eax", "mov %1, ebx" } asm(ref stack + sizeof(kernel_stack)) { "mov esp, %0", "cli", "xor ebp, ebp" }

extern function i386_inb(u16 port) -> i8; extern function i386_outb(u16 port, u8 data) -> i0; extern function i386_irq_registerHandler(i32 irq, ptr i0 handler) -> i0;

u32 stack_top = 0; asm(stack_top) { "mov %0, esp" } kmain(info, magic, stack_top); asm() { ".hang: hlt", "jmp .hang" } }

glob arr _key_pressed[128, u8] = { 0 };

Listing 27: Abridged Multiboot-compatible i386 entry unit.

function i386_keyboard_handler(ptr i0 _) -> i0 { i8 character = i386_inb(0x60); if character < 0 || character >= 128; return; _key_pressed[character as i32] = 1; }

The case study does not eliminate assembly semantically; privileged and register-specific operations remain explicit. Instead, it narrows handwritten assembly to the target operations that require it, while representing binary layout, symbol placement, initialization, and control transfer in a typed source language. This division is useful for boot code because layout constraints remain auditable without forcing the complete entry path into an untyped assembly file.

Listing 26: Shortened i386 PS/2 keyboard driver excerpt using C externs. Imported and exported symbols form ordinary lowlevel ABI boundaries. In this organization, CPL expresses driver control flow and data structures, while C or platform support code supplies target-specific primitives.

7 6.2

Multiboot Kernel Bootstrap

Testing Infrastructure

The compiler is tested with a phase-oriented framework rather than only through end-to-end examples. The central principle is phase observability: tests can inspect preprocessing, tokenization, AST construction, semantic analysis, HIR generation, SSA construction, DAG construction, constant-folding analysis, LIR construction, instruction selection, register allocation, peephole optimization, assembly generation, or assembly-level constant folding. This makes regressions easier to localize than in a purely black-box compiler test. CPL tests use an OUTPUT oracle embedded in source files. The oracle can match runtime output, exit codes, and selected compiler dumps. It also supports tolerant matching for unstable compiler-generated identifiers, so tests can focus on semantically important output instead of incidental temporary names. Runtime tests can run generated assembly and can use multiple argument cases inside one file. Two flags are especially important for this workflow. BUG marks an expected failing test and keeps known defects visible without making the entire test run unusable. LEAK_TRACE enables memory-operation logging for leak localization in compiler-internal tests. Together

A second i386 use case is replacement of a conventional assembly bootstrap with a mostly typed CPL translation unit. Multiboot version 0.6.96 requires a 32-bit-aligned header within the first 8192 bytes of the operating-system image. The header begins with the magic value 0x1BADB002; its magic, flags, and checksum fields must sum to zero modulo 232 . At transfer of control, EAX contains the Multiboot boot-loader magic, EBX points to the boot-information structure, and the operating system must establish its own stack [5]. Listing 27 expresses these requirements through packed containers, explicit section placement and alignment, a linker-visible entry symbol, and register-bound source variables. Inline assembly remains necessary for instructions whose effects are not represented by ordinary CPL expressions, including loading esp, disabling interrupts, and halting the processor. The header layout, static storage, and call into the kernel routine remain visible to the type system and normal compiler pipeline. @[align(1)] container multiboot_header { u32 magic;

9

with phase observability, these mechanisms support regression tracking across frontend, middle-end, backend, and runtime behavior. The regression corpus covers simple output programs, counted loops, CRC-style table traversal, arithmetic and function-call kernels, Fibonacci, switch dispatch, and a larger Brainfuck interpreter. It also includes OS-oriented i386 examples. This testing setup is not a proof of correctness, but it checks internal forms and executable behavior and provides a practical mechanism for detecting pass-level regressions.

8

pointer string scanning, where the C compilers appear to perform stronger loop and memory simplification. These explanations remain hypotheses until validated with decoded instruction counts and hardware counters.

8.3

Figure 4 presents the effect of CPL optimization alone by comparing -O0 and -O3 on both evaluated architectures. CPL -O3 improves most measured kernels, but i386 Fibonacci is a counterexample in these measurements. Within CPL, LICM affects loop-invariant HIR expressions, peephole cleanup removes redundant selected-LIR instructions, and copy propagation reduces low-level temporary traffic after lowering. Because no pass-by-pass ablation was performed, the observed improvement cannot be assigned to an individual optimization. Generated-code size was not measured in object bytes or decoded instruction counts. Source-level or assemblyline counts are omitted because directives, labels, and formatting make them an unreliable proxy for machinecode size.

Experimental Evaluation

The evaluation combines a qualitative systems case study with a microbenchmark study. Table 7 summarizes the evidence for the evaluated aspects and separates measured behavior from properties that are only supported by the implementation design. The chosen kernels expose loop overhead, arithmetic recurrence, predictable branching, function-call overhead, global table traversal, pointer-heavy string traversal, and a short Fibonacci dependency chain. They are useful for identifying workload-specific behavior but are not a substitute for a standard benchmark suite or kernel-level performance comparison. The microbenchmarks compare CPL with GCC and Clang C baselines on x86_64 Linux and i386 Linux targets. GCC, Clang, and CPL are tested at -O0 and -O3. CPL sources are emitted as NASM assembly, assembled with nasm, and linked with ld -e _main. The C baselines use freestanding _main entry points to avoid libc and CRT-startup differences. Each reported runtime is the arithmetic mean of ten executions of one produced binary. The harness and raw repetitions are stored in specs/run_compiler_microbenches.py and specs/compiler_microbench_results.json. The empty-loop benchmark is a loop-overhead test: the C baseline uses asm volatile to prevent deletion of the loop.

8.1

9

Limitations and Threats to Validity

The results are subject to the following limitations. Partial formalization only. Section 2.9 defines typing and reduction rules for a small pointer-andcontainer core. It does not cover the complete grammar, target annotations, inline assembly, or every controlflow construct, and it is not mechanized. The compiler has no semantic-preservation proof or translation validation. No memory safety. The static analyzer can find selected problems, but CPL intentionally does not implement an ownership or borrowing discipline.

Benchmarked Kernels

Table 8 lists the benchmark snippets. The benchmark harness extracts the executable CPL block from each file before the OUTPUT test-runner section.

8.2

Effect of Optimization within CPL

Limited target validation. The most exercised path is x86_64 Mach-O/NASM. x86_64 GNU/Linux NASM is implemented but less tested. The i386 GNU/Linux NASM backend has dedicated assemblygeneration tests and real operating-system helper examples, but it is newer and has not yet been evaluated with the same breadth as the Mach-O path. Other architecture and system-type options exposed by the driver should be treated as planned or partial support unless backed by dedicated tests.

Optimized Runtimes

Table 9 reports the optimized and unoptimized runtimes. Figure 3 visualizes the optimized measurements. In the runtime comparison, CPL is effectively tied with GCC and Clang on the preserved empty counted loop on both x86_64 and i386. On x86_64, CPL is also within the same millisecond-scale range on Fibonacci, but GCC and Clang are faster on the other optimized kernels. On i386, CPL slows down more strongly on 64bit arithmetic, function calls, pointer-string traversal, and Fibonacci, which is consistent with higher pressure from 32-bit register allocation and 64-bit operation lowering. The largest gaps remain table traversal and

Excluded function-inlining prototypes. Heuristic and model-guided inlining modes exist in the implementation but are excluded from the evaluated optimization profiles and contribution claims because their correctness and effectiveness have not been established. 10

Table 6: Compiler phases exposed by the integration testing framework. Frontend

HIR / SSA

LIR / backend

Assembly

preproc prep ast sem

hir hir_ssa hir_dag hir_constfold

lir lir_constfold lir_selector lir_instplan lir_regalloc lir_peephole

asm asm_constfold

Table 7: Evaluation evidence and limitations for the evaluated aspects. Aspect

Evidence

Supported conclusion

Status

Systems suitability

Multiboot entry unit and i386 kernel helpers

partially answered

Runtime performance

Seven ten-run microbenchmarks against GCC and Clang on Linux x86_64 and i386

Symbolic diagnostics

Implemented SSA-to-Z3 query layer and diagnostic examples

Typed CPL represents layout, sections, symbols, stack storage, and higher-level control transfer; machine-register and privileged operations still require assembly. CPL is close on the empty counted loop, but mature C optimizers are substantially faster on arithmetic, branch, call, table, and pointer-string kernels. i386 increases pressure on CPL’s lowering and register allocation. The representation supports pathconditioned null and reachability queries; precision and cost are unknown. Optimization profiles affect runtime, but individual pass contributions and codesize effects cannot be identified.

Optimization -O0/-O3 aggregate comparison effects

Small benchmark suite. The benchmark suite consists of microbenchmarks. It does not include large applications, compiler self-hosting, SPEC-style workloads, kernel compilation workloads, broad target comparisons, or enough kernels to characterize general performance.

preliminary answer

architectural only

unanswered

Evaluation scope. The benchmark data should be treated as prototype evidence for the implementation direction rather than as a complete evaluation of every backend and optimization combination. Inline assembly opacity. Inline assembly is copied into the output after placeholder substitution and is not optimized by the compiler. This can invalidate assumptions made by surrounding optimization passes if the programmer uses labels, jumps, or unpreserved registers in fragile ways.

Single-machine measurements. Measurements were performed on a single Linux x86_64 host while targeting both x86_64 and i386 binaries. Results may vary across processors, operating systems, assemblers, linkers, and timing wrappers.

10 No cache or memory-hierarchy analysis. The evaluation does not include cache-miss counters, branchmisprediction counters, memory-bandwidth measurements, or other memory-hierarchy analysis. Pointerheavy results such as string traversal should therefore be interpreted cautiously.

Related Work

Table 10 compares CPL with projects that represent distinct points in the design space: LLVM [9], QBE [1], TinyCC [2], Zig [18], CompCert [10, 16], Cogent [11], and Low* [12]. The comparison separates language scope, primary objective, low-level access, formal assurance, and backend maturity rather than treating all systems as interchangeable compiler projects. The closest implementation-scale comparators are QBE and TinyCC, but each leaves a different gap. QBE provides a compact backend rather than a source language with typed OS-facing constructs. TinyCC provides practical C compatibility, but inherits the full complexity and expectations of C and is not organized as a small SSA/SMT experimentation platform. Zig

No differential fuzzing campaign. The phaseoriented regression suite checks known examples and internal representations, but it does not provide randomized differential validation against a reference interpreter or a semantically equivalent C subset. Compiler reliability beyond the covered tests is therefore not quantified. 11

Table 8: Microbenchmark kernels. Kernel

CPL source

Main behavior

Empty counted loop Arithmetic recurrence Hot branch loop Hot function call Global table traversal Pointer string scan Fibonacci recurrence

02_count_to_billion.cpl 04_arith_mix.cpl 05_branch_hot.cpl 06_function_call_hot.cpl 07_table_sum_hot.cpl 08_pointer_string_scan.cpl 09_fibonacci.cpl

preserved one-billion-iteration counter loop repeated byte-masked integer recurrence predictable branch in a 200M-iteration loop small function called in a 100M-iteration loop repeated scan of a global byte table repeated pointer walk over a string literal short loop-carried arithmetic dependency

Table 9: Mean benchmark runtimes in seconds over ten runs. Lower is better. Target

Benchmark

CPL -O3

GCC -O3

Clang -O3

CPL -O0

GCC -O0

Clang -O0

x86_64 x86_64 x86_64 x86_64 x86_64 x86_64 x86_64 i386 i386 i386 i386 i386 i386 i386

Empty loop Arithmetic Branch Function call Table traversal String scan Fibonacci Empty loop Arithmetic Branch Function call Table traversal String scan Fibonacci

0.261887 0.319541 0.263617 0.151619 0.091685 0.084198 0.000938 0.261450 0.474456 0.381038 0.330364 0.112236 0.142074 0.002809

0.260706 0.264630 0.080978 0.105209 0.002133 0.004427 0.000467 0.261913 0.327300 0.150469 0.163568 0.009064 0.030128 0.000456

0.261217 0.021762 0.056354 0.026664 0.002328 0.000176 0.000470 0.261629 0.021911 0.072008 0.026601 0.002387 0.000196 0.000479

0.943493 0.420121 0.469712 0.286096 0.143158 0.135586 0.001268 0.951507 0.540225 0.464537 0.399027 0.194468 0.191890 0.002066

2.732771 0.472506 0.522766 0.286031 0.119041 0.095225 0.002113 2.744684 0.535768 0.470560 0.396996 0.121796 0.094678 0.002117

2.743791 0.426030 0.520616 0.315833 0.140017 0.106931 0.002122 2.751128 0.433954 0.415575 0.374836 0.132445 0.106399 0.002140

provides substantially stronger language and ecosystem support, while CompCert, Cogent, and Low* provide assurance that CPL does not claim. The resulting niche is narrow: CPL combines an inspectable source language, explicit boot- and kernelfacing controls, a multi-stage optimizing pipeline, and an experimental SSA/SMT diagnostic layer in one compact implementation. This is a research gap only in the sense of an engineering combination, not evidence of superiority. CPL lacks the formal assurance of verified systems, the validation methodology exemplified by Csmith [17], and the benchmark breadth and backend maturity of production compilers. The article’s contribution is therefore the design and feasibility evidence for that combination. Classes, enums, constructors, destructors, inheritance, and ownership-oriented aggregate models remain outside the core language by design. Containers provide a deliberately small C-like aggregate mechanism, but richer user-defined type systems may be studied separately. This article treats that restriction as part of CPL’s deliberate language model rather than as an accidental omission.

11

and labeled diagnostic evaluation specified in the futurework program.

A

Abridged BNF Grammar of CPL

This appendix gives an abridged grammar reconstructed from the parser implementation. It documents principal forms rather than a complete formal operational semantics. program ::= top_item* top_item ::= annotation* (start_decl | function_decl | container_decl | extern_decl | import_decl | section_decl | align_decl | var_decl | pp_directive | block) start_decl ::= "start" "(" param_list? ")" block function_decl ::= "function" ident generic_params? "(" param_list? ")" ("->" type)? (";" | block) extern_decl ::= "extern" (function_decl | type ident ";") import_decl ::= "from" string "import" ident ("," ident)* ";"? container_decl ::= "container" ident "{" container_item* "}" container_item ::= annotation* (field_decl | method_decl | pp_directive) field_decl ::= storage_mod* annotation* type ident ("=" expr)? stmt_end method_decl ::= "function" ident generic_params? "(" param_list? ")" ("->" type)? (";" | block)

Conclusion

The article establishes feasibility of a compact C-like source language that combines OS-facing controls with a conventional optimizing pipeline and SSA/SMT analysis. It does not establish compiler correctness, memory safety, general performance competitiveness, backend maturity, or diagnostic effectiveness. Those claims require the formalization, differential validation, expanded benchmarks, hardware-counter measurements,

param_list ::= param ("," param)* param ::= annotation* ("..." type? ident? | "self" | type annotation* ident ("=" expr)?) generic_params ::= "<" ident ("," ident)* ">"

12

0.35 0.32

0.3 0.26 0.26 0.26

0.26

0.26

Runtime (s)

0.25 0.2 0.15

0.15

0.11

0.1

8.1 · 10−2

9.17 · 10−2

8.42 · 10−2

5.64 · 10−2

5 · 10−2

2.67 · 10−2

2.18 · 10−2

−3

· 10· 10−4 2.33 10−3 4.43 2.13 · 10·−3 9.38 · 10 4.7 · −4 10−4 4.67 ·−4 10 1.76

0

pty

h

Arit

Em

Bra

nch

Cal

CPL -O3

l

le Tab

GCC -O3

ng

Stri

Fib

Clang -O3

Figure 3: x86_64 optimized runtimes for the benchmark kernels. The full x86_64/i386 table is reported in Table 9.

Runtime (s)

1

if_stmt ::= "if" expr ";" statement ("else" statement)? while_stmt ::= "while" expr? ";" statement loop_stmt ::= "loop" statement switch_stmt ::= "switch" expr ";" "{" case_clause* default_clause? "}" case_clause ::= "case" literal ";" block default_clause ::= "default" ";"? block

0.94 0.95

0.8 0.6

0.54 0.47 0.47 0.46 0.42 0.380.4 0.33 0.32 0.29 0.26 0.26 0.26 0.19 0.19 0.15 0.14 0.14 0.14 0.11 9.17 · 8.42 10−2 · 10−2

0.4 0.2

var_decl ::= storage_mod* annotation* ( array_decl | type ident ("=" expr)? stmt_end) array_decl ::= "arr" ident "[" const_len "," type "]" ("=" array_init)? stmt_end | type ident "[" const_len "]" ("=" array_init)? stmt_end

2.81 10−3 10·−3 1.27 · 2.07 10·−3 9.38 10·−4

0 E

y mpt

all

h h C Arit Branc

le ng Tab Stri

Fib

x86_64 CPL -O0

x86_64 CPL -O3

i386 CPL -O0

i386 CPL -O3

annotation ::= "@" "[" annotation_text "]" pp_directive ::= "#" ("line" | "include" | "define" | "undef" | "ifdef" | "ifndef" | "endif") ... line_end stmt_end ::= ";" | end_of_line

Figure 4: Optimization effect within CPL.

Listing 28: Abridged CPL grammar. storage_mod ::= "glob" | "ro" type ::= prim_type | "ptr" type | "arr" "[" const_len "," type "]" | "(" type_list? ")" "=>" type | ident prim_type ::= "f64" | "f32" | "i64" | "i32" | " i16" | "i8" | "u64" | "u32" | "u16" | "u8" | "i0 " | "str" const_len ::= int | numeric_macro

The keyword set is: start, exit, function, container, return, if, else, while, loop, switch, case, default, glob, ro, dref, ref, ptr, lis, break, extern, from, import, syscall, asm, as, f64, f32, i64, i32, i16, i8, u64, u32, u16, u8, i0, str, arr, not, neg, poparg, sizeof, section, align, line, include, define, undef, ifdef, ifndef, and endif. Containers may contain scalar fields, pointer fields, and array fields; method-like calls are supported through explicit receiver parameters marked with @[self]. The @[like_c] annotation is used to document C-ABI-like container padding and layout intent.

statement ::= block | function_decl | align_decl | start_decl | if_stmt | while_stmt | loop_stmt | switch_stmt | return_stmt | exit_stmt | break_stmt | lis_stmt | syscall_stmt | asm_stmt | var_decl | expr ";" block ::= "{" statement* "}"

13

Table 10: Positioning of CPL relative to representative systems languages and compiler infrastructures. Project

Scope

Primary objective

Low-level facilities

Formal assurance

Backend rity

matu-

LLVM

reusable compiler in- broad optimization and tar- low-level IR; frontend- no general fron- production, many frastructure get support dependent source facil- tend correctness targets ities proof QBE compact SSA backend simple reusable code gener- low-level IR, not a sys- none claimed small but estabation tems source language lished backend TinyCC compact C compiler fast compilation and C C pointers, ABI and none claimed practical multicompatibility system interfaces platform C compiler Zig full systems language production systems devel- explicit memory, language safety productionopment ABI, inline assembly, checks, no verified oriented, broad compile-time facilities compiler claim targets CompCert C compiler semantic preservation C-level systems facili- machine-checked mature verified ties compiler proof target set Cogent/Low* restricted verified sys- proof-oriented low-level controlled memory and mechanized seman- specialized veritems languages software C interoperability tics and proofs fied toolchains CPL compact source lan- inspectable OS/compiler pointers, layout, sec- partial paper three x86-family guage and compiler experiments tions, entry points, model; no proof formats, uneven syscalls, inline assemvalidation bly

References

[10] Xavier Leroy. Formal verification of a realistic compiler. Communications of the ACM, 52(7):107– 115, 2009.

[1] Quentin Carbonneaux Babiak and contributors. QBE: A Quick Backend, 2026. Accessed 2026-0530.

[11] Liam O’Connor, Christine Rizkallah, Zilin Chen, Sidney Amani, Japheth Lim, Yutaka Nagashima, Thomas Sewell, Alex Hixon, Gabriele Keller, Toby Murray, and Gerwin Klein. COGENT: Certified compilation for a functional systems language, 2016.

[2] Fabrice Bellard and TinyCC contributors. TinyCC: Tiny C Compiler, 2026. Accessed 2026-05-30. [3] Ron Cytron, Jeanne Ferrante, Barry K. Rosen, Mark N. Wegman, and F. Kenneth Zadeck. Efficiently computing static single assignment form and the control dependence graph. ACM Transactions on Programming Languages and Systems, 13(4):451–490, 1991.

[12] Jonathan Protzenko, Jean-Karim Zinzindohoué, Aseem Rastogi, Tahina Ramananandro, Peng Wang, Santiago Zanella-Béguelin, Antoine Delignat-Lavaud, Cătălin Hriţcu, Karthikeyan Bhargavan, Cédric Fournet, and Nikhil Swamy. Verified low-level programming embedded in F*. Proceedings of the ACM on Programming Languages, 1(ICFP):17:1–17:29, 2017.

[4] Leonardo de Moura and Nikolaj Bjørner. Z3: An efficient SMT solver. In Tools and Algorithms for the Construction and Analysis of Systems, pages 337–340. Springer, 2008. [5] Bryan Ford, Erich Stefan Boleyn, and Free Software Foundation. Multiboot Specification, Version 0.6.96. GNU Project, 2010. Accessed 2026-06-13.

[13] D. M. Ritchie, S. C. Johnson, M. E. Lesk, and B. W. Kernighan. UNIX time-sharing system: The C programming language. The Bell System Technical Journal, 57(6):1991–2019, 1978.

[6] Ralf Jung, Jacques-Henri Jourdan, Robbert Krebbers, and Derek Dreyer. RustBelt: Securing the foundations of the Rust programming language. Proceedings of the ACM on Programming Languages, 2(POPL):66:1–66:34, 2018.

[14] Bjarne Stroustrup. Evolving a language in and for the real world: C++ 1991–2006. In Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages, HOPL III, pages 4–1– 4–59. ACM, 2007.

[7] Brian W. Kernighan and Dennis M. Ritchie. The C Programming Language. Prentice Hall, 2 edition, 1988.

[15] Bjarne Stroustrup. The C++ Programming Language. Addison-Wesley, 4 edition, 2013.

[8] Steve Klabnik, Carol Nichols, and Chris Krycho. The Rust Programming Language. No Starch Press, 2 edition, 2023.

[16] The CompCert Project. The CompCert Verified Compiler, 2026. Accessed 2026-05-12.

[9] Chris Lattner and Vikram Adve. LLVM: A compilation framework for lifelong program analysis and transformation. In Proceedings of the International Symposium on Code Generation and Optimization, pages 75–88, 2004.

[17] Xuejun Yang, Yang Chen, Eric Eide, and John Regehr. Finding and understanding bugs in C compilers. In Proceedings of the 32nd ACM SIGPLAN Conference on Programming Language Design and Implementation, pages 283–294. ACM, 2011. 14

[18] Zig Software Foundation. The Zig Programming Language Reference, 2026. Accessed 2026-05-12.

15

Record · ID 660883 · SHA-256 8951df38a84446a9
Retrieved via Conceptio — every document is proof-bundled with source, license, and retrieval metadata.