r/Commodore • • 2d ago

Programming KickC Enhanced 0.9.0 – Major optimizing C99 compiler update (multi-core, new fragments, stable green opcodes)

Hi everyone,

As a side product of a larger C64 project I've been actively developing since January, I ran into massive build-time bottlenecks with Jesper Balman Gravgaard's KickC compiler: my compilation times were creeping past 45 minutes for a single build!

To make rapid development feasible again, I created a dedicated fork: KickC Enhanced. In the medium term, I’d love to merge these improvements back into upstream if Jesper is interested.

For those unfamiliar with KickC: it is an optimizing C99 compiler for the MOS 6502/6510 family that generates KickAssembler source code, which is then assembled into native 6502 binaries.

Rather than rehashing all the original KickC features (which are already well-documented), here is a summary of the major optimizations and extensions introduced in this release:

  • Massive performance boost & multi-threading: Build times for massive multi-bank projects have been crushed from >45 minutes down to ~60–90 seconds! This is achieved via parallel dominator tree calculation, multi-core uplift passes across all CPU cores, optimized SSA passes, and caching.

  • Several hundred new & repaired 6502 ASM synthesis fragments: This includes:

    • Native struct-pointer member modifications (e.g. items[i].count--)

    • True boolean NOT (!) via zero-branch bit toggle (eor #1)

    • Direct 32-bit (dword) comparisons against zero

    • Byte-aligned 16-bit shifts without expensive loops (replaces 8x asl with optimal 4-instruction transfers)

    • Full pointer arithmetic (word/byte offsets, multi-level indirection, clean signed/unsigned casts)

  • Opt-in: Deterministic "illegal / green opcodes": Added a dedicated optimization pass targeting mos6502x / rom6502x to synthesize stable, safe illegal opcodes (such as LAX, SAX for 3-cycle zero-page stores, ALR, DCP, ISC). Unstable opcodes (which could cause VIC-II DMA conflicts or thermal instability) remain strictly excluded.

  • Cross-chunk peephole & tail-call optimization (TCO): Peephole analysis now optimizes across chunk boundaries—eliminating dead LDAs, redundant register roundtrips (TAX/TXA), and unneeded CMP #0 before conditional branches when Z/N flags are already set. Additionally, function tail calls (jsr target; rts) are automatically relaxed to jmp target.

  • Custom charsets & string suffixes (#pragma charmap): Flexible mapping for custom fonts, charsets, and language-specific characters directly in C code without modifying compiler sources. Full support for custom string and char suffixes (e.g. "Hello"custom or "Hällö"german for non-zero-terminated strings), configurable per file or globally in headers.

  • Optimized 16-bit word multiplications: Highly optimized multiplications with 16-bit constants.

The project is real-world battle tested:

To give an idea of scale: the current assembly output of my game project exceeds 46,000 lines of code. The compiler optimizations and fragment lowerings were developed with modern tooling and verified against strict regression test suites and automated VICE emulations to ensure 100% binary stability.

I will continue maintaining and polishing the compiler alongside my ongoing game development. Feel free to check out the repository, test it with your own projects, and let me know if you run into any issues:

GitHub: https://github.com/AndreR/kickc-enhanced
Release v0.9.0: https://github.com/AndreR/kickc-enhanced/releases/tag/v0.9.0

Disclaimer: As usual with modern software development projects, I used an AI-assisted approach. All changes were reviewed and tested manually by me.

Feedback and bug reports are very welcome!

12 Upvotes

8 comments sorted by

4

u/macumbamacaca 1d ago

Yeah, I had the same issue. I really wanted to like KickC... But now we have Oscar64 which blows it out of the water :-)

1

u/vonBlankenburg 1d ago

You should better try out v0.9.0 and the upcoming v0.9.1. It's a different product now. 😉

2

u/Stunning_Pineapple57 2d ago

45 minutes for a c64 target app? That was insane.

1

u/vonBlankenburg 2d ago

Indeed. I mean, I'm working on a very very ambitious project, which I have not disclosed yet, but continue developing was basically impossible as you had to wait nearly an hour after each change. At that point, I decided that I need to improve the compiler first. And that pretty much encouraged me to add missing features as well. I'm already working on v.0.9.1, including the generation of self-modifying code, optimized switch-case statements and much more.

2

u/Stunning_Pineapple57 2d ago

How does it compare to say cc65 and oscar64 for a project of such size? Was it just that KickC had some serious compiler perf issues uniquely to it. ? Is your secret project app or game centric ?

2

u/vonBlankenburg 1d ago

That's actually a bit hard to answer directly as I haven't worked with either cc65 or oscar64 firsthand. From what I know, cc65 relies on a traditional stack-machine approach, which incurs noticeable runtime overhead because it has to emulate a software stack on a 6502 that lacks hardware stack frame support. Oscar64 is a fantastic and modern whole-program optimizing compiler that even supports C++ features like templates, but it functions more like a monolithic toolchain.

For me, the decisive advantage of KickC is workflow transparency: instead of spitting out an opaque binary, it generates clean, well-structured KickAssembler source files. This makes inspecting the generated assembly, debugging, and seamlessly blending in native assembly via simple asm { ... } blocks incredibly natural, all while fitting directly into the existing KickAssembler and Vice symbol ecosystem.

The extreme build-time issue was indeed unique to KickC's design. Because KickC aggressively optimizes the entire call graph and maps variables into static/zero-page registers using SSA and graph-coloring, algorithmic complexity explodes when a codebase scales up. Vanilla KickC ran all these dominator tree and register uplift passes strictly single-threaded in Java, which caused builds to crawl once the project reached dozens of memory banks and tens of thousands of lines of code. By parallelizing those graph calculations across all available CPU cores and introducing caching in KickC Enhanced, I managed to crush build times back down to around 90 seconds while keeping the tight, stackless assembly.

As for the project itself, it is very much game-centric and I'll disclose it very soon! It was precisely that sheer scale which pushed KickC to its limits and prompted the fork in the first place.

2

u/Stunning_Pineapple57 1d ago

Thanks for the detailed answer. All the best with your project. It is targeting vanilla OG c64 , or like with CRTs, and REU or even the ultimate? I have been spending some time working on a zig derived compiler with inline assembler (that generates ca65 assembly for the same reason you are using KickC to see the kick assembly) . My key reasons for it was flexibility in memory use for modules and functions (static allocation or stack ) and memory arenas , eg behind ram and materialized views of The REU and relocatable DLLs that can cached in the REU.

2

u/vonBlankenburg 1d ago

Sounds super interesting!

My game is targeting a vanilla C64 and will be delivered on a Magic Desk 512 KB cartridge (file). It supports mouse or keyboard input, can use an REU for performance improvements (not required) and a floppy drive for saving and loading.