The last few months, I've been spending a considerable portion of my off hours hacking away on snippets of code generated by LLVM-MOS, trying to make them less weird. LLVM-MOS still emits weird code, despite my best efforts. I had a long list of TODO items before the first release, "make this weird thing never happen," and it seemed like the list was getting perpetually longer.
Well, that list isn't empty, and LLVM-MOS still emits weird code. If you open up any large compiled binary, there will be some weird code in it. But this is my perfectionism speaking. LLVM can emit great code, and it does emit great code often enough to be very useful. I can and will spend the next N years playing wackamole with the code generator until there aren't any moles left, but that personal vendetta isn't a good reason to hold up releasing the thing.
I've been using LLVM-MOS to build a C64 dots-and-boxes game in C++. Despite my best efforts to write horrible, inoptimal, modern C++11, as naively as possible, the thing has been hovering around 2K, which is way way under my code budget. The compiler is tremendously usable; it has great error messages, modern features, it's easy to invoke, relatively fast, etc. It's now fairly silly that we don't have a binary release.
So, without further ado, I'd like to announce the first LLVM-MOS compiler and SDK release, v0.1.0.
A huge thanks to everyone who contributed to this project. Without you, it wouldn't be anywhere near where it is today.
https://github.com/llvm-mos/llvm-mos-sdk/releases/tag/v0.1.0Documentation for getting started.
What you get
- Code generation for the Commodore 64, Atari 800, and an included 6502 simulator.
- The high and low-level optimizations expected of a young-ish LLVM backend
- Sophisticated register allocation over A, X, Y, and a field of 16 2-byte zero-page (imaginary) registers
- The imaginary registers can be placed anywhere and need not be contiguous.
- The calling convention passes through registers whenever possible.
- Loop optimizations to select 6502 addressing modes
- Whole program "static stack" optimization
- Automatically identifies non-reentrant functions and allocates their frames as static globals
- Programs without recursion or complex function pointers may not need a soft stack at all.
- No manual annotations required
- Link time inlining and optimization across the whole program
- Includes SDK libraries. Library calls can be often optimized away completely!
- Broad C99 and C++11 freestanding standards compatibility
- Interrupt handling
- C++ templates
- C++ virtual functions
- C++ new/delete
- C++ Run-Time Type Information (dynamic_cast, typeid)
- C++ static constructors/destructors (run before and after main)
- C++ "magic" function local static constructors/destructors
- Excellent compiler usability
- Clang's world-class error messages
- IDE integration through the included custom clangd's Language Server Protocol
- Straigtforward invocations to compile for various targets: mos-c64-clang++ -Os -o game.prg game.cc
- A small standard library sufficient to provide the above and a few extras
- Simple printf
- Simple malloc/free
- exit, _Exit, and atexit
- An ELF file format implementation
- All the usual POSIX tools for working with object files: readelf, nm, etc.
- A GAS-compatible assembler for the 6502 with a complete macro system
- A lld linker implementation for the 6502
- Link-time garbage collection
- Symbol map exports
- Linker scripts
- GCC ld compatibility
What you don't get
- C99 requires supporting 64KiB locals, sorry, no can do.
- A hosted C with all the standard library bells and whistles.
- Float/double
- C++ Exceptions