Man I can't wait for tcc to be reposted for the 4th time this week with the license scrubbed and the comment of "The Latest AI just zero-shotted an entire C compiler in 5 minutes!"
The code of TCC (0.9.26) is kind hard to compile, I have discovered in the past year, while developing a minimal C compiler to compile the TCC sources [1]. For that reason, I have concluded that TCC is its own test set. It uses the constant 0x80000000, which is an edge case for if you want to print it as a signed integer only using 32-bit operators. There is a switch statement with an post-increment operator in the switch expression. There are also switch statements with fall throughs and with goto statements in the cases. It uses the ## operator where the result is the name of a macro. Just to name a few.
Anyone know a good resource for getting started writing a compiler? I'm not trying to write a new LLVM, but being a "software engineer" writing web-based APIs for a living is leaving me wanting more.
TCC supports 32 (and I think 64?) bit chips, SDCC only targets 8 and 16, so their use cases don't overlap at all as far as I can tell from their homepages...
One of the coolest tricks is using tcc to compile "on demand." This allows you to use a compiled language like Nim for scripting, with almost no noticeable performance difference compared to interpreted languages.
#!/usr/bin/env -S nim r --cc:tcc -d:useMalloc --verbosity:0 --hints:off --tlsEmulation:on --passL:-lm
echo "Hello from Nim via TCC!"
Here's a comparison (bash script at [1]) of a minimal binary compiled this way with different interpreters. First line is the noise. Measured by tim[2] written by @cb321.
1.151 +- 0.028 ms (AlreadySubtracted)Overhead
1.219 +- 0.037 ms bash -c exit
2.498 +- 0.040 ms fish --no-config --private -c exit
1.682 +- 0.058 ms perl -e 'exit 0'
1.621 +- 0.043 ms gawk 'BEGIN{exit 0}'
15.8 +- 2.2 ms python3 -c 'exit(0)'
20.0 +- 5.7 ms node -e 'process.exit(0)'
-2.384 +- 0.041 ms tcc -run x.c
153.2 +- 4.6 ms nim r --cc:tcc x.nim
164.5 +- 1.2 ms nim r --cc:tcc -d:release x.nim
Measured on a laptop without any care to clean the environment, except turning the performance governor. Even with `-d:release` compiling nim code is comparable.
The fact that tcc compilation cycle measures negative here is a nice punchline.
It's worth pointing out that Nim is going to cache all of the compilation up to the linking step. If you want to include the full compilation time, you'd need to add --forceBuild to the Nim compiler.
(Since a lot of the stuff you'd use this for doesn't change often, I don't think this invalidates the "point", since it makes "nim r" run very quickly, but still)
There's also the Nim interpreter built into the compiler, "NimScript", which can be invoked like:
#!/usr/bin/env -S nim e --hints:off
echo "Hello from Nim!"
The cool thing is that, without --forceBuild, Nim + TCC (as a linker) has a faster startup time than NimScript. But if you include compile time, NimScript wins.
No, the coolest thing about tcc is that it is developed successfully wiki-style. Everybody can commit to the main branch (called mob). And it only gets better. No cooperation would allow that.
TCC is my go-to for keeping builds lean. on windows specifically, you get a functional C compiler in a few hundred KB, whereas the standard alternatives require gigabytes of disk space (that I don't have to spare) and complex environment setups
What's the quality of the generated code like? Does it use explicit stack frames and all local variables live there? Does it move loop-invariant operations out of a loop? Does it store variables in registers?
28 comments
[ 2.8 ms ] story [ 51.2 ms ] threadSad but not surprised to see it's no longer maintained (8 years ago!).
Even in the era of terabyte NVMe drives my eyes water when I install MSVC (and that's usually just for the linker!)
https://repo.or.cz/w/tinycc.git
https://github.com/TinyCC/tinycc
https://github.com/TinyCC/tinycc
https://guix.gnu.org/manual/1.5.0/en/html_node/Full_002dSour...
https://repo.or.cz/tinycc.git
Tiny C, Small C are names I seem to recall, buts its very fuzzy - Not sure if they were compilers, may have been interpreters....
[1] https://github.com/FransFaase/MES-replacement
Goto is easier to implement than an if statement. Postincrement behaves no differently in a switch statement than elsewhere.
The fact that tcc compilation cycle measures negative here is a nice punchline.
[1]: https://gist.github.com/ZoomRmc/58743a34d3bb222aa5ec02a5e2b6...
[2]: https://github.com/c-blake/bu/blob/main/doc/tim.md
(Since a lot of the stuff you'd use this for doesn't change often, I don't think this invalidates the "point", since it makes "nim r" run very quickly, but still)
There's also the Nim interpreter built into the compiler, "NimScript", which can be invoked like:
The cool thing is that, without --forceBuild, Nim + TCC (as a linker) has a faster startup time than NimScript. But if you include compile time, NimScript wins.