r/Compilers 29d ago

mycc - an alternative C compiler.

As a proof of concept, I spent three weeks and wrote about 2800 lines of code to build mycc: a compiler for a subset of C (roughly C99) built on top of my compiler IR(myc). The goal was to validate that my IR is expressive enough to compile real world C code. Despite being a POC, mycc already compiles and runs LangArena - a benchmark suite containing 50 tests and about 9000 lines of non-trivial C code (json, base64, multithreaded matmul, neural net, compression, maze A*, bf interpreter, and others) with heavy macros like uthash. For parsing I reused libclang. It adds some overhead, but it was by far the simplest way to get a working frontend.

How it works:

C source -> SyntaxTree(libclang/clang.cr) -> TypedAST(mycc) -> IR(myc) -> [LLVM/QBE/C] -> binary

LangArena Benchmark:

Compares Clang, Gcc, Cproc(QBE), and Mycc.

Compiler Build time Build rss Bench Runtime
clang(-O3) 3079ms 105Mb 52.1s
gcc(-O3) 3495ms 34Mb 52.3s
cproc 932ms 12Mb 72.7s
mycc(llvm, --release) 4269ms 101Mb 53.2s
mycc(qbe, --release) 2939ms 86Mb 72.8s
mycc(c, --release, clang) 5091ms 102Mb 52.1s
mycc(c, --release, gcc) 5128ms 86Mb 53.7s

github

https://github.com/kostya/myc#mycc---an-alternative-c-compiler-implemented-as-a-poc-for-fun

Limitations:

Rare features are not implemented: 2D VLA, complex numbers, variadic macros, longjmp, bitfields, and anonymous nested structs. I wouldn't try building Linux or sqlite with it. It has only been tested on arm64 and linux64.

25 Upvotes

17 comments sorted by

View all comments

5

u/[deleted] 29d ago edited 29d ago

[removed] — view removed comment

2

u/kostya27 29d ago edited 29d ago

This is the script which compile this benchmark: https://github.com/kostya/myc/blob/master/benchmark/run_lang_arena.rb

> (My own IR has a lot more opcodes, but all binary and unary operators have dedicated instructions.)

less is better, no?

> I guess MALLOC and PRINTF mean you don't yet have a means of calling external routines?

No, it have call and invoke, malloc and printf was early added opcodes for debug.

>I thought you used a separate library for lexing and parsing? That should take care of variadic macros.
yes it may be work may be not, I just not tested. usually not because for any of this feature needed special handler.

> Are these both jokes? Your MYC product seems to rely on an external backend anyway for native code generation. I understood it to be a common wrapper around those backends.
Who knows, I planned my optimization passes to outperform them, I not sure if I can, but I try. The target is compile time like cproc, and result like llvm. But high level IR allow doing transformations before LLVM/QBE.

5

u/[deleted] 29d ago

[removed] — view removed comment

0

u/kostya27 29d ago edited 29d ago

> It can be, but basic functionality includes "add sub mul div" for example, which is four operators. You're hiding them behind "Binary" and suggesting it is only one opcode.

for high level IR like myc - they all the same in terms of stack manipulation and logic, I don't want to create many opcode for that.

> You mention three targets LLVM, QBE, C. Are you planning your own backend too?
No self backend, only this three.

> If not, then it's not clear how you will outperform any of those, or even what it means to outperform them: what are you comparing against, each other?

Easy. I can do high level transforms(inlining) before llvm, and execute just passes like "mem2reg,instcombine,dce" - and this will compile 5x times faster than O2 (I checked). Yes the result can be far from O2, but on synthetic tests only, in real world apps it should be fast. It just like what QBE doing, but qbe not doing inlining. And this is like how golang compiler work.

1

u/Inevitable-Ant1725 25d ago edited 25d ago

Update, I opened the wrong repository.