forked from anthropics/claudes-c-compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
363 lines (342 loc) · 18.5 KB
/
index.html
File metadata and controls
363 lines (342 loc) · 18.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
---
layout: home
title: LCCC — Lev's Claude's C Compiler
---
<!-- ── Nav ──────────────────────────────────────────────────────────────── -->
<nav class="site-nav">
<a class="nav-logo" href="#">lc<span class="accent">cc</span></a>
<ul class="nav-links">
<li><a href="#why">Why</a></li>
<li><a href="#allocator">Allocator</a></li>
<li><a href="#benchmarks">Benchmarks</a></li>
<li><a href="#install">Install</a></li>
<li><a href="/lccc/docs/getting-started">Docs</a></li>
</ul>
<a class="nav-gh" href="https://github.com/levkropp/lccc" target="_blank" rel="noopener">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
GitHub
</a>
</nav>
<!-- ── Hero ──────────────────────────────────────────────────────────────── -->
<header class="hero">
<h1><span class="l">l</span><span class="rest">ccc</span></h1>
<p class="hero-sub">
An optimized fork of <a href="https://github.com/anthropics/claudes-c-compiler" style="color:var(--amber)">CCC</a>
— Claude's C Compiler — with a two-pass linear-scan register allocator,
tail-call elimination, phi-copy stack coalescing, loop unrolling, and
FP intrinsic lowering, targeting x86-64, AArch64, RISC-V 64, and i686.
</p>
<div class="hero-actions">
<a class="btn btn-primary" href="/lccc/docs/getting-started">Get Started</a>
<a class="btn btn-secondary" href="https://github.com/levkropp/lccc" target="_blank" rel="noopener">View on GitHub</a>
</div>
<!-- ── Mini benchmark table ─────────────────────────────────────────────── -->
<div class="mini-bench-wrap">
<table>
<thead>
<tr>
<th>Benchmark</th>
<th>LCCC</th>
<th>GCC -O2</th>
<th>LCCC vs GCC</th>
</tr>
</thead>
<tbody>
<tr><td><code>arith_loop</code></td><td>0.139s</td><td>0.088s</td><td class="slower">1.6×</td></tr>
<tr><td><code>sieve</code></td><td>0.073s</td><td>0.047s</td><td class="slower">1.6×</td></tr>
<tr><td><code>qsort</code></td><td>0.137s</td><td>0.105s</td><td class="slower">1.3×</td></tr>
<tr><td><code>fib(40)</code></td><td class="faster">0.000s</td><td>0.146s</td><td class="faster">478× faster</td></tr>
<tr><td><code>matmul</code></td><td>0.010s</td><td>0.006s</td><td class="slower">1.8×</td></tr>
<tr><td><code>tce_sum</code></td><td class="faster">0.008s</td><td>0.008s</td><td class="faster">≈equal</td></tr>
</tbody>
</table>
</div>
</header>
<!-- ── Compiler pipeline diagram ─────────────────────────────────────────── -->
<div class="diagram-section">
<div class="diagram-wrap">
<pre>
<span class="c-dim">┌─────────────────────────────────────────────────────────────────────┐</span>
<span class="c-dim">│</span> <span class="c-em">C source</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-teal">frontend</span>: lex → parse → sema → IR lowering <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">▼</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-em">SSA IR</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-teal">optimizer</span>: GVN · LICM · IPCP · DCE · const-fold · inline <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">▼</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-em">Optimized IR</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-amb">regalloc</span> <span class="c-dim">(LCCC)</span>: two-pass linear scan over live intervals <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-dim">pass 1:</span> <span class="c-amb">callee-saved</span> <span class="c-dim">↔ all eligible values</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-dim">pass 2:</span> <span class="c-teal">caller-saved</span> <span class="c-dim">↔ non-call-spanning unallocated values</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">▼</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-em">Machine code</span> <span class="c-dim">x86-64 · AArch64 · RISC-V 64 · i686</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">│</span> <span class="c-teal">standalone assembler + linker</span> <span class="c-dim">(no external toolchain)</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-dim">▼</span> <span class="c-dim">│</span>
<span class="c-dim">│</span> <span class="c-em">ELF executable</span> <span class="c-dim">│</span>
<span class="c-dim">└─────────────────────────────────────────────────────────────────────┘</span>
</pre>
</div>
</div>
<!-- ── Why ───────────────────────────────────────────────────────────────── -->
<section id="why">
<div class="section-label">Motivation</div>
<h2>CCC is impressive. LCCC makes it faster.</h2>
<p>
CCC compiles real projects — SQLite, PostgreSQL, Redis, the Linux kernel — from a
zero-dependency Rust codebase with its own assembler and linker. LCCC focuses on
closing the performance gap with GCC by improving where CCC leaves the most on the table.
</p>
<div class="cards">
<div class="card">
<div class="card-icon">⚡</div>
<h3>Linear-scan register allocator</h3>
<p>Two-pass allocation: callee-saved for all eligible values, then caller-saved for non-call-spanning remainder. Priority-weighted by loop depth.</p>
</div>
<div class="card">
<div class="card-icon">🔩</div>
<h3>Drop-in GCC replacement</h3>
<p>Same flags, same output ABI. Point <code>CC=lccc</code> at any Makefile. No build system changes required.</p>
</div>
<div class="card">
<div class="card-icon">🏗</div>
<h3>Four architectures</h3>
<p>x86-64, AArch64, RISC-V 64, i686. The same allocator improvements apply everywhere — architecture-agnostic <code>PhysReg</code> abstraction.</p>
</div>
<div class="card">
<div class="card-icon">🔭</div>
<h3>518 tests passing</h3>
<p>518 unit tests pass. Correctness-first — all four phases (linear scan, TCE, phi-copy coalescing, loop unrolling) maintain byte-identical output to GCC.</p>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ── Allocator ─────────────────────────────────────────────────────────── -->
<section id="allocator">
<div class="section-label">Phases 2–4</div>
<h2>Linear scan · tail-call elim · phi-copy coalescing · loop unrolling · FP intrinsics</h2>
<p>
The old CCC allocator uses three greedy phases. LCCC replaces the allocation
core with a proper linear scan (Phase 2), adds tail-call-to-loop conversion (Phase 3a),
eliminates redundant phi-copy stack slots in loop backedges (Phase 3b),
and Phase 4 adds loop unrolling and FP intrinsic lowering.
</p>
<div class="code-block">
<div class="code-block-header">regalloc — Phase 1: callee-saved linear scan</div>
<pre><span class="cm">// All eligible IR values compete for callee-saved registers.</span>
<span class="cm">// Safe across calls; better coverage than old "call-spanning only" Phase 1.</span>
<span class="kw">let</span> phase1_intervals = filter_eligible_intervals(&liveness, &eligible);
<span class="kw">let</span> phase1_ranges = build_live_ranges(&phase1_intervals, &liveness.block_loop_depth, func);
<span class="kw">let mut</span> allocator = LinearScanAllocator::new(phase1_ranges, config.available_regs.clone());
allocator.run(); <span class="cm">// expire → find_free → evict-or-spill</span></pre>
</div>
<div class="code-block">
<div class="code-block-header">regalloc — Phase 2: caller-saved linear scan</div>
<pre><span class="cm">// Unallocated, non-call-spanning values get caller-saved registers.</span>
<span class="cm">// Caller-saved regs are destroyed by calls, so we must not assign them</span>
<span class="cm">// to values that cross call boundaries.</span>
<span class="kw">let</span> phase2_intervals = liveness.intervals.iter()
.filter(|iv| eligible.contains(&iv.value_id))
.filter(|iv| !assignments.contains_key(&iv.value_id))
.filter(|iv| !spans_any_call(iv, call_points))
.collect();
<span class="kw">let mut</span> caller_alloc = LinearScanAllocator::new(phase2_ranges, config.caller_saved_regs.clone());
caller_alloc.run();</pre>
</div>
</section>
<div class="divider"></div>
<!-- ── Benchmarks ────────────────────────────────────────────────────────── -->
<section id="benchmarks">
<div class="section-label">Performance</div>
<h2>Benchmark results — LCCC vs CCC vs GCC -O2</h2>
<p>
Best-of-5 wall-clock time. All outputs are identical. Run with
<code>python3 lccc-improvements/benchmarks/bench.py --reps 5</code>.
</p>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Benchmark</th>
<th>Description</th>
<th>LCCC</th>
<th>CCC</th>
<th>GCC -O2</th>
<th>LCCC vs CCC</th>
<th>LCCC vs GCC</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>arith_loop</code></td>
<td>32-var arithmetic, 10M iters</td>
<td class="faster">0.103s</td>
<td>0.146s</td>
<td class="baseline">0.068s</td>
<td class="faster">+42% faster</td>
<td class="slower">1.50×</td>
</tr>
<tr>
<td><code>sieve</code></td>
<td>Primes to 10M</td>
<td class="faster">0.036s</td>
<td>0.045s</td>
<td class="baseline">0.024s</td>
<td class="faster">+25% faster</td>
<td class="slower">1.50×</td>
</tr>
<tr>
<td><code>qsort</code></td>
<td>Sort 1M integers</td>
<td>0.096s</td>
<td>0.095s</td>
<td class="baseline">0.087s</td>
<td class="slower">≈equal</td>
<td class="slower">1.10×</td>
</tr>
<tr>
<td><code>fib(40)</code></td>
<td>Recursive Fibonacci</td>
<td>0.352s</td>
<td>0.354s</td>
<td class="baseline">0.096s</td>
<td class="slower">≈equal</td>
<td class="slower">3.68×</td>
</tr>
<tr>
<td><code>matmul</code></td>
<td>256×256 double matrix multiply</td>
<td class="faster">0.020s</td>
<td>0.029s</td>
<td class="baseline">0.004s</td>
<td class="faster">+45% faster</td>
<td class="slower">4.86×</td>
</tr>
<tr>
<td><code>tce_sum</code></td>
<td>Tail-recursive sum(10M)</td>
<td class="faster">0.008s</td>
<td>1.09s</td>
<td class="baseline">0.008s</td>
<td class="faster">139× faster</td>
<td class="slower">≈equal</td>
</tr>
</tbody>
</table>
</div>
<p style="margin-top:1rem">
The largest gains are on register-pressure code (linear scan + phi-copy coalescing),
tail-recursive code (TCE), and matrix multiply (FP intrinsic lowering, Phase 4).
The remaining matmul gap is GCC's AVX2 auto-vectorization — a Phase 5 target.
See the <a href="/lccc/docs/roadmap">roadmap</a> for what's next.
</p>
<div class="badges">
<span class="badge badge-amber">✓ all outputs match GCC</span>
<span class="badge badge-teal">518 unit tests passing</span>
<span class="badge badge-gray">GCC 15.2.0 · Ubuntu</span>
<span class="badge badge-gray">x86-64 · -O2</span>
</div>
</section>
<div class="divider"></div>
<!-- ── Updates ──────────────────────────────────────────────────────────── -->
<section id="updates">
<div class="section-label">Latest</div>
<h2>What's new in Phase 10</h2>
<p>
Phase 12 brings LCCC within <strong>1.3–1.6× of GCC -O2</strong> across all benchmarks,
and <strong>478× faster than GCC</strong> on recursive Fibonacci — with constant-immediate
stores, SIB address folding, accumulator ALU+store folding, and a register
allocator loop-depth priority fix.
</p>
<div class="cards">
<div class="card">
<div class="card-icon">🔁</div>
<h3>Binary recursion → iteration</h3>
<p>Detects <code>f(n) = f(n-1) + f(n-2)</code> and converts exponential O(2^n) recursion to O(n) iterative loop. <code>fib(40)</code>: 0.001 s vs GCC's 0.194 s.</p>
</div>
<div class="card">
<div class="card-icon">🧮</div>
<h3>AVX2 FMA3 vectorization</h3>
<p>MatMul inner loop uses <code>vfmadd231pd</code> — fused multiply-add in a single instruction. Correct innermost-loop detection, SIB addressing, remainder loops.</p>
</div>
<div class="card">
<div class="card-icon">📊</div>
<h3>XMM register allocation</h3>
<p>F64 values allocated to xmm2–xmm7, freeing GPR pressure. Combined with frame pointer omission, this gives the allocator up to 17 usable registers.</p>
</div>
<div class="card">
<div class="card-icon">🔗</div>
<h3>Cross-block store forwarding</h3>
<p>Callee-saved register mappings preserved across loop headers. Copy propagation flows through conditional jumps. Eliminates redundant stack traffic.</p>
</div>
</div>
<p style="margin-top:1rem">
<a href="/lccc/updates/phase4-loop-unrolling">Read the Phase 4 write-up →</a>
·
<a href="/lccc/updates/phase3-tce-and-phi-coalescing">Phase 3 write-up →</a>
</p>
</section>
<div class="divider"></div>
<!-- ── Install ───────────────────────────────────────────────────────────── -->
<section id="install">
<div class="section-label">Getting Started</div>
<h2>Build LCCC</h2>
<div class="steps">
<div class="step">
<div class="step-num">1</div>
<div class="step-body">
<h4>Clone the repo</h4>
<div class="code-block">
<div class="code-block-header">shell</div>
<pre>git clone --recurse-submodules https://github.com/levkropp/lccc.git
cd lccc</pre>
</div>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-body">
<h4>Build (requires Rust stable)</h4>
<div class="code-block">
<div class="code-block-header">shell</div>
<pre>cargo build --release
<span class="cm"># Binary at target/release/ccc (x86-64)</span>
<span class="cm"># Also: ccc-arm, ccc-riscv, ccc-i686</span></pre>
</div>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-body">
<h4>Compile a C program</h4>
<div class="code-block">
<div class="code-block-header">shell</div>
<pre>GCC_INC=<span class="st">"-I/usr/lib/gcc/x86_64-linux-gnu/$(gcc -dumpversion)/include"</span>
./target/release/ccc <span class="kw">$GCC_INC</span> -O2 -o hello hello.c
./hello</pre>
</div>
</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div class="step-body">
<h4>Run the benchmark suite</h4>
<div class="code-block">
<div class="code-block-header">shell</div>
<pre>python3 lccc-improvements/benchmarks/bench.py --reps 5 --md results.md</pre>
</div>
</div>
</div>
</div>
<div class="badges" style="margin-top:2rem">
<span class="badge badge-amber">Rust stable 2021</span>
<span class="badge badge-teal">Linux · x86-64 host</span>
<span class="badge badge-gray">MIT OR Apache-2.0 OR BSD-2-Clause</span>
</div>
</section>
<footer>
<p>
<a href="https://github.com/levkropp/lccc">github.com/levkropp/lccc</a>
· MIT OR Apache-2.0 OR BSD-2-Clause (LCCC)
· CC0 (CCC-derived code)
· <a href="/lccc/docs/getting-started">Documentation</a>
</p>
</footer>