# llvm816

LLVM/Clang C compiler for the WDC 65816 / Apple IIgs.

Compiles C (and a minimal subset of C++) to native 65816 machine code,
links to a relocatable OMF binary, and runs under MAME's apple2gs.
Speed-tuned: matches or beats hand-written 65816 assembly on the
tight loops in benchmarks like sumOfSquares, popcount, and strcpy.

## What you get

- **`clang --target=w65816`** — full C99 + parts of C11, optimized at
  `-O2` by default. Soft-float and soft-double included.
- **C standard library subset** — `stdio.h`, `stdlib.h`, `string.h`,
  `math.h`, `time.h`, `setjmp.h`, etc. See
  [`runtime/include/`](runtime/include/) for the complete list.
- **C++ via `clang++`** — single + multiple inheritance, virtual base
  diamonds, RTTI, `dynamic_cast`, `new` / `delete` / `new[]` / `delete[]`,
  Meyers singletons (`__cxa_guard_*`), global ctors via `.init_array`,
  global / static-local dtors actually run at exit (`__cxa_atexit` +
  `__run_cxa_atexit`), SJLJ exceptions.  Backed by `runtime/libcxxabi.o`
  + `libcxxabiSjlj.o`.
- **ETL** — vendored [Embedded Template Library](https://www.etlcpp.com/)
  at `runtime/include/c++/etl/` (MIT, header-only).  Fixed-capacity
  `etl::vector<T,N>`, `etl::string<N>`, `etl::map<K,V,N>`,
  `etl::optional`, `etl::delegate`, etc. — no malloc, no exceptions,
  fits the IIgs memory model.
- **`link816`** — relocating linker producing GS/OS-loadable OMF
  binaries (single- or multi-segment).
- **MAME integration scripts** — compile, link, and run a program
  under MAME's apple2gs with one command.
- **Apple IIgs Toolbox bindings** — `<iigs/toolbox_full.h>` exposes
  ~1300 toolbox routines from 35 tool sets.

## Quick start

After installation (see [docs/INSTALL.md](docs/INSTALL.md)):

```bash
# Write a tiny C program that computes 1+2+...+10 = 55 and stores it.
cat > hello.c <<'EOF'
int main(void) {
    unsigned short x = 0;
    for (int i = 1; i <= 10; i++) x += i;        // x = 55 = 0x37
    // Write to a known 24-bit absolute address.  The compiler lowers
    // this to `sta long $025000` — no bank switching needed.  The MAME
    // test harness reads this cell to verify the program ran.
    *(volatile unsigned short *)0x025000 = x;
    while (1) {}
}
EOF

# Compile, link, run under MAME, check the result.
./tools/llvm-mos-build/bin/clang --target=w65816 -O2 -c hello.c -o hello.o
./tools/link816 -o hello.bin --text-base 0x1000 \
    runtime/crt0.o runtime/libc.o runtime/libgcc.o hello.o
bash scripts/runInMame.sh hello.bin --check 0x025000=0037
```

See [docs/USAGE.md](docs/USAGE.md) for a full walkthrough including
multi-segment builds and the Apple IIgs Toolbox.

### Register-heavy code and the regalloc fallback

The 65816 has a single accumulator, so a few unusually register-heavy
functions exceed what LLVM's default `greedy` allocator can place and
abort with `ran out of registers during register allocation`.  This is a
hardware constraint, not a miscompile; LLVM's `basic` allocator handles
those functions correctly (greedy stays the default everywhere else
because its codegen is smaller and faster).

The project build scripts handle this automatically via
`scripts/ccRegallocFallback.sh`, which compiles with greedy and silently
retries the affected translation unit with `-mllvm -regalloc=basic` only
when it hits that error.  `tests/lua/build.sh`, `tests/coremark/build.sh`,
and `runtime/build.sh` route their compiles through it.

If you invoke `clang` directly and hit the error on your own
register-heavy code, either compile that file through the wrapper:

```bash
./scripts/ccRegallocFallback.sh ./tools/llvm-mos-build/bin/clang \
    --target=w65816 -O2 -c heavy.c -o heavy.o
```

or just add `-mllvm -regalloc=basic` to that one compile.

## Project layout

```
runtime/         C standard library + crt0 startup
  src/           sources (C and .s)
  include/       headers
  *.o            built object files
src/             our LLVM/Clang sources (W65816 target backend)
  clang/         clang patches
  llvm/          LLVM patches + W65816 target
  link816/       relocating linker
patches/         patches against vanilla llvm-mos
scripts/         install scripts, MAME runners, benchmarks
tools/           installed compilers, MAME, ROMs, Calypsi (reference)
benchmarks/      cycle-count and instruction-count benchmarks
compare/         side-by-side asm vs Calypsi
docs/            this directory — INSTALL.md, USAGE.md, design notes
```

## Status

Stable enough to build real programs.  Per-call cycle measurements
against commercial Calypsi 5.16, measured under MAME via `emu.time()`
(IIgs slow-mode 1.023 MHz, `-mllvm -w65816-dbr-safe-ptrs` enabled):

| Benchmark | Ours | Calypsi | Ratio |
|---|---:|---:|---:|
| dotProduct | 1,534 | 5,712 | **0.27×** ✓ |
| bsearch | 682 | 2,387 | **0.29×** ✓ |
| sumOfSquares | 6,820 | 16,368 | **0.42×** ✓ |
| bubbleSort | 11,594 | 17,050 | **0.68×** ✓ |
| strLen | 767 | 1,023 | **0.75×** ✓ |
| djb2Hash | 2,046 | 2,643 | **0.77×** ✓ |
| popcount | 1,194 | 1,534 | **0.78×** ✓ |
| strcpy | 1,108 | 1,194 | **0.93×** ✓ |
| memcmp | 682 | 716 | **0.95×** ✓ |
| fib | 11,594 | 10,912 | 1.06× |

**Geomean: 0.62× Calypsi** across this suite.  Nine of ten benches beat
Calypsi outright; only fib trails at 1.06×.  Run
`scripts/benchCyclesPrecise.sh` (ours, with
`W65816_CC_EXTRA="-mllvm -w65816-dbr-safe-ptrs"`) and
`scripts/benchCyclesCalypsi.sh` (Calypsi) to reproduce.

On real programs:
- **Lua 5.1.5** (17K LoC, 24 source files) compiles + links clean.
  Object total 0.93× Calypsi.
- **CoreMark 1.0** (EEMBC standard benchmark) compiles + links clean.
  Linked binary 39.6 KB (0.73× Calypsi's 54.5 KB).
- **ETL** containers (vector, string, map, optional, delegate) — full
  end-to-end probe in `demos/etlProbe.cpp`, ~20 KB total under GNO.

See [STATUS.md](STATUS.md) for full language and runtime feature
coverage, and [LLVM_65816_DESIGN.md](LLVM_65816_DESIGN.md) for
backend internals.

## Documentation

- [docs/INSTALL.md](docs/INSTALL.md) — system requirements and install
  steps
- [docs/USAGE.md](docs/USAGE.md) — compile, link, run, debug
- [STATUS.md](STATUS.md) — current language/runtime support matrix
- [LLVM_65816_DESIGN.md](LLVM_65816_DESIGN.md) — backend design notes

## License

Apache 2.0 (matching the LLVM project's license). See
`tools/llvm-mos/LICENSE.TXT` after install.
