Tilde, My LLVM Alternative
361 points
14 days ago
| 27 comments
| yasserarg.com
| HN
ksec
12 days ago
[-]
>I'm calling it Tilde (or TB for tilde backend) and the reasons are pretty simple, i believe it's far too slow at compiling and far too big to be fixed from the inside. It's been 20 years and cruft has built up, time for a "redo".

That put a smile on my face because I remember that was how LLVM was born out of frustration with GCC.

I dont know how the modern GCC and LLVM compares, I remember LLVM was fast but resulting binary were not as optimised, once those optimisation added it became slower. While LLVM was a wake up call to modernise GCC and make it faster. In the end competition made both a lot better.

I believe some industry ( Gaming ) used to swear by VS Studio / MS Compiler / Intel Compiler or languages that depends / prefer the Borland ( What ever they are called now ) compiler. Its been very long since I last looked I am wondering if those two are still used or have we all merged mostly into LLVM / GCC?

reply
pjmlp
11 days ago
[-]
It is pretty much Visual Studion on Windows and XBox, Nintendo and Sony have clang forks.

Embarcadero owns Borland, unfortunely stuff like C++ Builder doesn't seem to get much people outside big corps wanting to use it, which is a shame given its RAD capabilities and GUI design tooling for C++.

Also has a standard ABI between Delphi and C++ Builder, which allows to similar development workflows that .NET offered later with C#/VB alongside Managed C++ extensions (later replaced by C++/CLI).

reply
s1gsegv
11 days ago
[-]
Borland as of a few years ago also ships a clang fork for C++ Builder, interestingly enough. It unfortunately does not solve all of the problems you encounter using C++ Builder in the modern age.

I’ve personally watched the enshittification of too many proprietary tools to ever build something I care about on top of one today, especially something which becomes so fundamental to the design of your application like a GUI toolkit.

I know it sounds crazy, like you’d never bother forking your GUI framework anyway even when it’s open source. But I worked on an application built in C++ Builder, at a company with enough engineering talent and willpower that we would’ve forked the compiler internally to fix its problems and limitations had we been granted access to the source. Instead, I got to watch the product get held back by it year after year, hoping that Borland would care.

reply
pjmlp
11 days ago
[-]
Yes, they do, but are still not done adding all the necessary C++ Builder sugar, that makes their tooling great, although almost there as of last year's release.
reply
willvarfar
11 days ago
[-]
Back 20 or more years ago I used to do a lot of rec math competition programming and found that the metrowerks c++ compiler made massively faster programs than gcc, vsstudio, intel and everything else I tried then.

This seemed to be simply down to variable alignment; the programs took more memory but ran much faster, particularly multi-core (which was still high end then).

And this was on x86 where metrowerks weren't really competing, and was probably accidental. But the programs it compiled were fast.

I'd be surprised if anyone even knew that metrowerks had a c++ compiler on x86 on windows. At the time metrowerks were on the tail end of their domination of mac compilers from before mac ran on x86.

reply
bruce343434
11 days ago
[-]
Memory access patterns are everything. Memory delay is almost always the bottleneck anyway. I have the feeling that more and more this is becoming common knowledge, and techniques like "struct of arrays" are becoming more wide spread and talked about.
reply
willvarfar
11 days ago
[-]
Is this perhaps why Build Engine used arrays, rather than arrays of struct? Organising things columnwise rather than rowwise, like an OLAP engine? https://fabiensanglard.net/duke3d/code_legacy.php
reply
TsiCClawOfLight
11 days ago
[-]
Yes. We learned that pattern in University, it is usually worth it unless in a high-level language.
reply
dan_hawkins
11 days ago
[-]
I was using Metrowerks C++ compiler suite to develop code for Dragonball (68000) embedded system 22 years ago!
reply
bbatha
11 days ago
[-]
Intel still has a decent use for compiling math heavy code for intel processors — so it gets a decent amount of use in HPC applications. It has some of the best vectorization passes but they only work with actual intel cpus. So it’s starting to get less traction as AMD takes the performance crown and as vectorized math moves to the gpu.
reply
CUViper
11 days ago
[-]
Intel's compilers are now based on LLVM too.
reply
rurban
11 days ago
[-]
For large C projects, tinycc is invaluable for extremely fast, non-optimized builds. Like 10x faster than gcc or clang builds. In my case I don't wait 10m, when tcc is done with it in 3s
reply
whimsicalism
11 days ago
[-]
msvc is very much in third but it is one of the three that i think of when i think of c++ compilers
reply
melodyogonna
12 days ago
[-]
Chris Lattner seems to have also created an alternative for LLVM - https://mlir.llvm.org/

Because of how the architecture works, LLVM is one of the backends, but it doesn't have to be. Very interesting project, you could do a lot more IR processing before descending to LLVM (if you use that), that way you could give LLVM a lot less to do.

Chris has said LLVM is fast at what it is designed to do - lower IR to machine code. However, because of how convoluted it can get, and the difficulty involved in getting information from some language-specific MIR to LLVM, languages are forced to generate tons upon tons of IR so as to capture every possible detail. Then LLVM is asked to clean up and optimize this IR.

One thing to look out for is the problem of either losing language-specific information when moving from MIR to Low-level IR (be it Tilde or LLVM) or generating too much information, most of it useless.

reply
zellyn
11 days ago
[-]
I wonder if this question can attract any MLIR people to answer my question:

From Chris Lattner's descriptions of LLVM vs MLIR in various podcasts, it seems like LLVM is often used as a backend for MLIR, but only because so much work has been put into optimizing in LLVM. It also seems like MLIR is strictly a superset of LLVM in terms of capabilities.

Here's my question: It seems inevitable that people will eventually port all LLVM's smarts directly into MLIR, and remove the need to shift between the two. Is that right?

reply
marssaxman
11 days ago
[-]
They solve different problems. MLIR is not a backend, but a toolkit for defining intermediate representations ("dialects") and the passes which optimize them or lower from one to another. You can use MLIR to organize everything your compiler does between its front-end and its back-end; MLIR doesn't care where the IR comes from or what you ultimately do with it.

MLIR does include a couple dozen built-in dialects for common tasks - there's an "scf" dialect which defines loops and conditionals, for example, and a "func" dialect with function call and return ops - and it so happens that one of these built-in dialects offers a 1:1 representation of the operations and types found in LLVM IR.

If you choose to structure your compiler so that all of your other dialects are ultimately lowered into this MLIR-LLVM dialect, you can then pass your MLIR-LLVM output through a converter function to get actual LLVM-IR, which you can then provide to LLVM in exchange for machine code; but that is the extent of the interaction between the two projects.

reply
jcranmer
11 days ago
[-]
MLIR is less a specific IR and more a generic framework for expressing your own custom IR (which is itself composed of many pluggable IRs)--except these IRs are renamed "dialects." One of the MLIR dialects is the LLVM dialect, which can be lowered to LLVM IR.

In the future, it's plausible that dialects for hardware ISAs would be added to MLIR, and thus it would be plausible to completely bypass the LLVM IR layer for optimizations. But the final codegen layer of LLVM IR is not a simple thing (I mean, LLVM itself has three different versions of it), and the fact that GlobalISel hasn't taken over SelectionDAG after even a decade of effort should be a sign of how difficult it is to actually replicate that layer in another system to the point of replacing existing work.

reply
CalChris
11 days ago
[-]
Earlier compilers were a pipeline of specialized IRs. I used to think that MLIR was an acknowledgment that this specialization was necessary. Ok, it is necessary. But MLIR's real contribution is, as you say, a generic framework for expressing your own custom IR.
reply
superlopuh
11 days ago
[-]
I know of a few projects looking in that direction, each optimising for different things, and none getting near the capability of LLVM, which is going to take some time. I spoke with some of the core MLIR developers about this, and they're generally open to the notion, but it's going to take a lot of volunteer effort to get there, and it's not clear who the sherpa will be, especially given the major sponsors of the LLVM project aren't in a particular hurry. If you're interested in this feel free to look our paper up in a week or two, we've had a bit of trouble uploading it to arxiv but should be ready soon.

https://2025.cgo.org/details/cgo-2025-papers/39/A-Multi-Leve...

Here's a quick pres from the last dev meeting on how this can be leveraged to compile NNs to a RISC-V-based accelerator core: https://www.youtube.com/watch?v=RSTjn_wA16A&t=1s

reply
fooker
11 days ago
[-]
All the important bits of MLIR are closed source and there’s no indication that’ll change anytime soon.

The big players have their own frontend, dialects, and mostly use LLVM backends. There’s very little common usable infrastructure that is upstreamed. Some of the upstreamed bits are missing large pieces.

reply
ozinenko
10 days ago
[-]
I'd be interested to learn about such closed-source important bits and invite them to MLIR workshop / open developer meeting. Having worked on the project essentially since its inception, I am quite positive that the bits the original MLIR team considered important are completely open source.

Certainly, there are closed-source downstream dialects, that was one of the actual design goals of the project, but they are rarely as useful as one might think. I'd expect every big company with a hardware to have an ISA/intrinsic-level dialect, at least as a prototype, that they won't open source for the same reason they won't open source the ISA.

What I find sad is the lack is that end-to-end flows from, e.g., PyTorch to binaries are usually living outside of the LLVM project, and often in each company's downstream. There is some slow motion to fix that.

reply
marssaxman
11 days ago
[-]
What important bits are those? I can't imagine what you have in mind here; my current job and my previous job have both revolved around MLIR-based compilers, and it has never seemed to me that there is anything missing. I wonder if you might be expecting MLIR to do a job it's not really meant for.
reply
almostgotcaught
11 days ago
[-]
> There’s very little common usable infrastructure that is upstreamed

Hmm I wonder what all that stuff is then that's under mlir/lib?

Like what are you even talking about? First of all there are literally three upstream frontends (flang, ClangIR, and torch-mlir). Most people use PyTorch as a frontend (some people use Jax or Triton). Secondly, downstream users having their own dialects... is basically the whole point of MLIR. Core dialects like linalg, tensor, memref, arith are absolutely generically useful. In addition many (not all) MLIR-based production quality compilers are fully open source (IREE, Triton) even if wholly developed at a for-profit.

reply
ozinenko
10 days ago
[-]
MLIR maintainer here, or however close one can be given that we don't have a clear ownership structure. This has been discussed repeatedly in the community, and it is likely that many things will get eventually ported/reimplemented, but there is no strong push towards that. Lower level parts of the stack, such as register allocation / machine IR / instruction selection are where LLVM has seen a lot of investment are unlikely to move soon. At least not in a generic way.

There was a keynote at the LLVM developer meeting a couple of years ago presenting the differences and the likely evolution from somebody not involved in MLIR that does the lay of the land.

reply
mshockwave
11 days ago
[-]
> Here's my question: It seems inevitable that people will eventually port all LLVM's smarts directly into MLIR, and remove the need to shift between the two. Is that right?

Theoretically, yes -- taking years if not decades for sure. And set aside (middle-end) optimizations, I think people often forgot another big part of LLVM that is (much) more difficult to port: code generation. Again, it's not impossible to port the entire codegen pipeline, it just takes lots of time and you need to try really hard to justify the advantage of moving over to MLIR, which at least needs to show that codegen with MLIR brings X% of performance improvement.

reply
_flux
12 days ago
[-]
I wonder if one solution would be have tighter integration between the layers, so the backend could ask for some IR to be generated? Basically starting from the program entrypoints. This way the frontend wouldn't need to generate all the possible code up-front.

Mind you, I've never written a compiler after that Uni course and touched LLVM IR a long time ago

reply
melodyogonna
11 days ago
[-]
That is how MLIR works. Basically you have multiple levels of IR, you can optimize each level until you get to the last level.

It also has the advantage of being able to parallelize passes

reply
mtlynch
11 days ago
[-]
I saw Yasser present this at Handmade Seattle in 2023.[0] He explained that when he started working on Tilde, he didn't have any special knowledge or interest in compilers. But he was reading discussions in the Handmade forums, and one of the most popular requests was for an alternative to LLVM, so he thought, "Sure, I'll do that."

[0] https://handmadecities.com/media/seattle-2023/tb/

reply
Rochus
14 days ago
[-]
Cool. The author has set himself a huge task if he wants to build something like LLVM. An alternative would be to participate in a project with similar goals that is already quite progressed, such as QBE or Eigen (https://github.com/EigenCompilerSuite/) ; both so far lack of optimizers. I consider Eigen very attractive because it supports much more targets and includes assemblers and linkers for all targets. I see the advantage in having a C implementation; Eigen is unfortunately developed in C++17, but I managed to backport the parts I'm using to a moderate C++11 subset (https://github.com/rochus-keller/Eigen). There are different front-ends available, two C compilers among them. And - as mentioned - an optimizer would be great.

EDIT: just found this podcast where the author gives more informations about the project goals and history (at least the beginning of the podcast is interesting): https://www.youtube.com/watch?v=f2khyLEc-Hw

reply
wffurr
11 days ago
[-]
What’s unfortunate about C++17? It has some nice features that build on C++11’s safety and ergonomic improvements.
reply
Rochus
11 days ago
[-]
You need a large, modern C++ compiler and standard library, which are not available for most older systems, and you're inviting an excess of dependencies because not all compilers support all parts of the newer C++ standards (in the same way), and require a lot more resources and newer versions of APIs and libraries, which further limits their usability on older systems. Furthermore, C89 and C++98 are much easier to bootstrap than a colossus like LLVM and Clang. The few "nice features" are perhaps enticing, but the costs they incur are disproportionate.
reply
o11c
11 days ago
[-]
For reference, GCC 4.7 (released March 2012) was the last build of GCC that is written in C, and supports almost all of the C++11 language (4.8.1, written in C++, finished the last bits) and a fair amount of the library.

If you have to work on a system that hasn't been updated since 2014 or so (since it's fair enough to avoid the .0 releases), getting support for later C++ standards is significantly more complicated.

reply
lerno
9 days ago
[-]
The QBE author has said that good compilation speed was not a design goal. It also outputs asm which then has to be run through GCC or Clang, which nullifies any benefit of being a standalone backend.
reply
Rochus
9 days ago
[-]
> that good compilation speed was not a design goal

Not sure how this relates to my statement. I was talking about an optimizer, not about compilation speed. I'm neither using QBE, but Eigen, for good reasons.

reply
fguerraz
11 days ago
[-]
Looking at the commit history inspires some real confidence!

https://github.com/RealNeGate/Cuik/commits/master/

reply
wild_pointer
11 days ago
[-]
chicken (+558998, -997)
reply
jamil7
11 days ago
[-]
Cursed. I had a coworker once would commit diffs like that but always with the message "Cleanup". The git history was littered with "Cleanup" commits that actually hid all kinds of stuff in them. If you pulled them up on it (or anything else) they went into defensive meltdown mode, so everyone on the team just accepted it and moved on.
reply
tasty_freeze
11 days ago
[-]
Back in 1990 or so I worked at a networking company (Vitalink) that was using whatever source control was popular back then. I forget which one, but the important thing was that rather than allowing multiple check outs followed by resolve, that system would lock a file when it was opened for edit and nobody else could make edits until the file was checked in.

One young developer checked out a couple files to "clean them up" with some refactoring. But because he changed some function interfaces, he needed to check out the files which called those functions. And since he was editing those files he decided to refactor them too. Pretty quickly he had more than half the files locked and everyone was beating on him for doing that. But because he had so many partial edits in progress and things weren't yet compiling and running, he prevented a dozen other people from doing much work for a few days.

reply
pveierland
11 days ago
[-]
Eh, when you're hacking away as a solo developer on something big and new I don't think this matters at all. In my current project I did about 200x commits marked "wip" before having enough structure and stability to bother with proper commit messages. Whatever lets you be productive until more structure is helpful.
reply
pkal
11 days ago
[-]
Perhaps, but I still think it is lazy. A very nice counter example of someone with high commit standards can be seen in this repository: https://github.com/rmyorston/pdpmake/commits/master/
reply
jandrewrogers
11 days ago
[-]
The code base may go through several almost total rewrites before it stabilizes, especially for non-trivial systems that are performance sensitive. Changes to the code may be intrinsically non-modular depending on the type of software. This prior history can be enormous yet have no value, essentially pure noise.

The efficient alternative, which I’ve seen used a few times in these cases, is to retcon a high-quality fake history into the source tree after the design has stabilized. This has proven to be far more useful to other engineers than the true history in cases like this.

Incremental commits are nice but not all types of software development lends itself to that, especially early in the development process. I’ve seen multiple cases where trying to force tidy incremental commit histories early in the process produced significantly worse outcomes than they needed to be.

reply
Aachen
11 days ago
[-]
That doesn't have a commit history going back to what the parent said about the first 200 commits though. It starts off with basically 3 commits all called some variant of "initial public release", after which good commit messages start, so that probably skipped many intermediate WIP states

I agree that one can do good commit messages also early on though. Initial commit can be "project skeleton", then "argument parsing and start of docs", then maybe "implemented basic functionality: it now lists files when run", next "implemented -S flag to sort by size", etc. It's not as specific as "Forbid -H option in POSIX mode" and the commits are going to often be large and touch different components, but I'd say that's expected for young projects with few (concurrent) contributors

reply
jasonjmcghee
11 days ago
[-]
Another example is ghostty
reply
artemonster
11 days ago
[-]
went to write exactly that. Ambitions are great and I dont want to be dissuasive, but monumental tasks require monumental effort and monumental effort requires monumental care. That implies good discipline and certain "beauty" standards that also apply to commit messages. Bad sign :)
reply
KolmogorovComp
11 days ago
[-]
Not really. In the initial phase of a project there is usually so much churn than enforcing proper commit messages is not worth it, until the dust settle down.
reply
apocalypses
11 days ago
[-]
I massively disagree. It would have taken the author approximately 1 minute to write the following high quality hack-n-slash commit message:

``` Big rewrites

* Rewrote X

* Deleted Y

* Refactored Z ```

Done

reply
jandrewrogers
11 days ago
[-]
Many times it is “threw everything out and started over” because the fundamental design and architecture was flawed. Some things have no incremental fix.
reply
fooker
11 days ago
[-]
Different people work differently.

Spending a minute writing commit messages while prototyping something will break my flow and derail whatever I’m doing.

reply
kccqzy
11 days ago
[-]
I am deeply suspicious of anyone who doesn't bother or who is unable to explain this churn. For the right kind of people, this is an excellent opportunity to reflect: why is there churn? Why did the dust not settle down? Why was the initial approach wrong and reworked into a new approach?

I can understand this if you are coding for a corporate. But if it's your own project, you should care about it enough to write good commit messages.

reply
torstenvl
11 days ago
[-]
Is your objection to the inevitable fact that requirements churn early on (regardless whether you're doing agile or waterfall)?

Or is your objection that solo devs code up prototypes and toy with ideas in live code instead of just in their mental VM in grooming sessions?

Or is your objection that you don't think early prototypes and demos should be available in the source tree?

reply
kccqzy
11 days ago
[-]
None of the above. My objection is the lack of explanation.

Churn is okay. Prototypes are okay. Toying with ideas is okay. They should all be in the source tree. But I would want an explanation for the benefit of future readers, including the future author. Earlier in my life I have more than once run blame on a piece of code to find myself writing a line of code where the commit message does not explain it adequately. These days it's much rarer because I ask myself to write good commit messages. Furthermore the act of writing a commit message is also soothing and a nice break from writing for computers.

Explain how requirements have changed. Explain how the prototype didn't work and led to a rewrite. Explain why some idea that was being toyed with turned out to be bad.

Notice that the above are explanations. They do not come with any implied actions. "Why is there churn" is a good question to answer but "how do we avoid churn in the future" is absolutely not. We all know churn is inevitable.

reply
dzaima
11 days ago
[-]
For single-author quickly-changing projects I'd guess that it's quite likely for only like 1% of the commits to be looked at to such extent that the commit message is meaningfully useful. And if each good commit message takes 1 minute to write (incl. overhead from the mental context switching), each of those uses better save 100 minutes compared to just looking at the diff.
reply
kccqzy
9 days ago
[-]
I suspect you have never worked on single-author projects where you fastidiously write good commit messages. If you never got into the habit of writing good commit message, you won't find them valuable at all when you are debugging something or just wondering why something is written in a certain way. Once you consistently write good commit messages you begin to rely on them all the time.
reply
dzaima
8 days ago
[-]
"why something is written in a certain way" most likely doesn't even have an answer while a project is still in the rewrite-large-parts-frequently stage. Sure, you could spend some time conjuring up an explanation, but that's quite possibly gonna end up useless when the code is ruthlessly rewritten anyway.

That said, specific fixes or similar can definitely do with good messaging. Though I'd say such belongs in comments, not commit messages, where it won't get shadowed over time by unrelated changes.

reply
account42
9 days ago
[-]
And for your average backup system it's only like 1% of backups you need to be able to restore, probably much fewer. Trouble is, your won't know which ones ahead of time - same for commits.
reply
dzaima
8 days ago
[-]
Difference being that if you automate backups they're, well, fully automatic, whereas writing good commit messages always continues to take time.
reply
muizelaar
11 days ago
[-]
I thought the sea-of-nodes choice was interesting.

V8 has been moving away from sea-of-nodes. Here's a video where Ben Titzer is talking about V8's reasons for moving away from sea-of-nodes: https://www.youtube.com/watch?v=Vu372dnk2Ak&t=184s. Yasser, the author of Tilde, is is also in the video.

reply
o11c
11 days ago
[-]
TL;DW version: sea of nodes requires a scheduling pass, which was taking 20% of their compilation time. But it sounds like there's a lot of legacy baggage, so ...
reply
negate32
10 days ago
[-]
My GCM doesn't take 20% of my compile times last I checked but even so, V8 is gonna be in a special camp because they're comparing against a compiler that doesn't do much code motion. LLVM does a lot of code motion so that "20%" is still being paid by LLVM during their hoisting and local scheduling passes.
reply
gergo_barany
10 days ago
[-]
> a decent linear scan allocator which will eventually be replaced with graph coloring for optimized builds.

Before setting out to implement 1980s-style graph coloring, I would suggest considering SSA-based register allocation instead: https://compilers.cs.uni-saarland.de/projects/ssara/ , I find the slides at https://compilers.cs.uni-saarland.de/projects/ssara/hack_ssa... especially useful.

Graph coloring is a nice model for the register assignment problem. But that's a relatively easy part of overall register allocation. If your coloring fails, you need to decide what to spill and how. Graph coloring does not help you with this, you will end up having to iterate coloring and spilling until convergence, and you may spill too much as a result.

But if your program is in SSA, the special properties of SSA can be used to properly separate these subphases, do a single spilling pass first (still not easy!) and then do a coloring that is guaranteed to succeed.

I haven't looked at LLVM in a while, but 10-15 years ago it used to transform out of SSA form just before register allocation. If I had to guess, I would guess it still does so. Not destroying SSA too early could actually be a significant differentiator to LLVM's "cruft".

reply
gergo_barany
10 days ago
[-]
Also, for a different notion of "cruft", informally it seems to me like new SSA-based compilers tend to choose an SSA representation with basic block arguments instead of the traditional phi instructions. There are probably reasons for this! I'm not aware of a Sea of Nodes compiler with (some notion corresponding to) block arguments, but it might be fun to explore this when designing a new compiler from the ground up. Might be too late for TB, though.
reply
mungaihaha
12 days ago
[-]
> I believe it's (LLVM) far too slow at compiling and far too big to be fixed from the inside

What are you doing to make sure Tilde does not end up like this?

reply
negate32
11 days ago
[-]
One of the big things which makes LLVM very slow is the abundance of passes, I believe I last counted 75 for an unoptimized function? My solution for this is writing more combined passes, due to the SoN design I'm combining a lot of things which are traditionally separate passes. For instance, my equivalent to "SimplifyCFG" "GVNPass", "InstCombine", "EarlyCSEPass" and "JumpThreadingPass" is one combined peephole solver which runs faster than all of these passes separately. This is for two main reasons:

* Less cache churn, I'm doing more work per cacheline loaded in (rather than rescanning the same function over and over again).

* Combining mutually beneficial optimizations can lead to less phase ordering problems and a better solve (this is why SCCP is better than DCE and constant prop separately).

In a few years when TB is mature, I'd wager I'll have maybe 10-20 real passes for the "-O2 competitive" optimizer pipeline because in practice there's no need to have so many passes.

reply
gergo_barany
10 days ago
[-]
If this is one of the main things you want to demonstrate, wouldn't it be better to focus on this one goal first, instead of the whole pipeline from a C preprocessor to directly linked executables?

Essentially, if you say that LLVM's mid-end in particular is slow, I would expect you to present a drop-in replacement for LLVM's mid-end opt tool. You could leave C-to-LLVM-bitcode to Clang. You could leave LLVM-bitcode-to-machine-code to llc. Just like opt, take unoptimized LLVM bitcode as input and produce optimized LLVM bitcode as output. You would get a much fairer apples to apples comparison of both code quality and mid-end compiler speed (your website already mentions that you aren't measuring apples-to-apples times), and you would duplicate much less work.

Alternatively, look into existing Sea of Nodes compilers and see if you can build your demonstrator into them. LibFIRM is such a C compiler: https://libfirm.github.io/ There may be others.

It just seems like you are mixing two things: On the one hand, you are making some very concrete technical statements that integrated optimizations are good and the Sea of Nodes is a great way to get there. A credible demonstrator for this would be very welcome and of great interest to the wider compiler community. On the other hand, you are doing a rite-of-passage project of writing a self-hosting C compiler. I don't mean this unkindly, but that part is less interesting for anyone besides yourself.

EDIT: I also wanted to mention that the approach I suggest is exactly how LLVM became well-known and popular. It was not because of Clang; Clang did not even exist for the first eight years or so of LLVM's existence. Instead, LLVM focused on what it wanted to demonstrate: a different approach to mid-end optimizations compared to the state of the art at the time. Parsing C code was not part of that, so LLVM left that to an external component (which happened to be GCC).

reply
DannyBee
11 days ago
[-]
I'm very confused what magic you believe will achieve what has not so far been achieved.

I'm also confused why you believe LLVM didn't start out the exact same way?

I say this as one of the main people responsible for working on combined pass replacements in both GCC and LLVM for things that were reasonable to be combined.

I actually love destroying lots of passes in favor of better combined ones. In that sense, i'm the biggest fan in the world of these kinds of efforts.

But the reason these passes exist is not cruft, or 20 years of laziness, - it's because it's very hard to replace them with combined algorithms that are both faster, and achieve the same results.

What exactly do you plan on replacing GVN + Simplify CFG + Jump Threading + correlated value prop with?

It took years of cherrypicking research and significant algorithm development to develop algorithms for this that had reasonable timebounds, were faster, and could do better than all of them combined. The algorithm is quite complex, and it's hard to prove it terminates in all cases, actually. The number of people who understand it is pretty small because of the complexity. That's before you get to applied engineering of putting it in a production compiler.

These days, as the person originally responsible for it, i'd say it's not better enough for the complexity, even though it is definitely faster and more complete and would let you replace these passes.

Meanwhile, you seem to think you will mature everything and get there in a few years.

I could believe you will achieve some percent of GCC or LLVM's performance, but that's not the reason these passes exist. They exist because that is what it reasonably takes to achieve LLVM (and GCC's) performance across a wide variety of code, for some acceptable level of algorithm complexity and maintainability.

So if you told me you were only shooting for 80% across some particular subset code, i could believe 10-20 passes. If you told me you were going to build a different product that targets a different audience, or in a different way, i could maybe believe it.

But for what you say here, I think you vastly underestimate the difficult and vastly underappreciate the effort that goes into these things. This is hundreds of very smart people working on things for decades. It's one thing to have a healthy disrespect for the impossible. It's another to think you will, in a few years, outdo hundreds of smart, capable engineers on pure technical achievement.

That strikes me as somewhere between hubris and insanity.

People also pretty much stopped building and publishing general purpose compiler optimization algorithms a decade ago, moving towards much more specialized algorithms and ML focused things and whatnot.

This is because in large part, there isn't a lot left worth doing.

So unless you've got magic bullets nobody else has, either you won't achieve the same performance level, or it will be slow, or it will take you a significant amount of algorithm development and engineering well beyond "a few years".

I say this not to dissuade you, but to temper your apparent expectations and view.

Honestly - I wish you the best of luck, and hope you succeed at it.

reply
rendaw
11 days ago
[-]
Critical responses from people in the industry are what I come here to read. I have no doubt of your credentials and I'm not at all qualified to judge the technical details here, but your reply comes off as an emotional kneejerk.

I read it a few times and as best I can get this is what you're saying:

- You came up with a similar combined replacement pass for LLVM based on years of personal and external research.

- It's faster and has more functionality.

- It's very complex and you're not comfortable that it's possible to achieve various reliability guarantees, so it is unreleased

- Therefore (?) you think the Tilde author also couldn't possibly succeed

AFAICT you also believe that the Tilde author hasn't completed their replacement pass. From their post my take was that it was already done. The part that will mature is additional passes, or maybe optimizations/bugfixes, but not the MVP development.

Your main arguments seem to be probability and appeal to authority (external research, assigned responsibility, industry association). Pretty much all projects and startups fail, but it's because people attempt them that some succeed.

Is the author betting their career on this? Why do their expectations need to be tempered?

I'd be interested in hearing concrete criticisms of their algorithms (have you looked at the code?) or oversights in the design. Maybe the author would too! If you let the author know, maybe you could think of a solution to reduce the complexity or improve the guarantees together.

reply
DannyBee
11 days ago
[-]
" but your reply comes off as an emotional kneejerk."

Lots of these come by, it gets tiring to try to provide detailed critiques of all of them. Feel free to go through comment history and see the last one of these to come along and the detailed critiques there :)

Meanwhile, let me try to help more:

First, the stuff i'm talking about is released. It's been released for years. It is included in LLVM releases. None of this matter, it was an example of what it actually takes in terms of time and energy to perform some amount of pass combination for real, which the author pays amazingly short shrift to.

I chose the example I did not because i worked on it, because it's in the list of things the author thinks are possible to combine easily!

Second it's not one combined pass they have to make - they think they will turn 75 passes into 20, with equivalent power to LLVM, but somehow much faster, yet still maintainable, mainly because "it's time for a rewrite" and they will avoid 20 years of cruft.

So they don't have to repeat the example i gave once. They have to repeat it 20-30 times. Which they believe they will achieve and reach maturity of in ... a few years.

They give no particular reason this is possible - i explained why it is remarkably difficult - while certainly you can combine some dataflow optimizations in various ways, doing so is not just hacking around.

It's often hard computer science problems to take two optimization passes, combine them in some way, and prove the result even ever terminates, not even that it actually optimizes any better. Here they are literally talking about combining 3 or 4 at a time.

While there are some basic helpful tools we proved a long time ago about things like composability of monotonic dataflow problems, these will not help you that much here.

Solving these hard problems are what it takes to have it work. It's not just cherry picking research papers and implementing them or copying other compiler code or something.

Let's take a concrete example, as you request:

If you want to subsume the various global value numbering passes, which all eliminate slightly different redundancies and prove or otherwise guarantee that you have actually done so, you would need a global value numbering pass you can prove to be complete. Completeness here means that it detects all equivalent values that can be detected.

There is no way around this. Either it subsumes them or it doesn't. If it doesn't, you aren't matching what LLVM's passes do, which the author has stated as the goal. As I said, i could believe a lesser goal, but that's not what we have here.

The limit of value numbering completeness here was proved a long time ago. The best you can do is something called herbrand equivalences. Anything stronger than that can't be proven to be decidable, and to the degree it can, you can't prove it ever terminates.

That has the upside that you only have to achieve this to prove you've done the best you can.

It has the downside that there are very few algorithms that achieve this.

So there are a small number of algorithms that have been proven complete here (about 7) - and all but 3 have exponential worst time.

The three polymonial algorithms are remarkably complicated, and as far as i know, never been implemented in any production compiler, anywhere. Two are N^4, and one is N^3.

One of the N^3 ones has some followup papers where people question whether it really works or terminates in all cases.

These are your existing choices if you try to use existing algorithms to combine these 4 out of the 70 passes, into 1 pass.

Otherwise, you get to make your own, from scratch.

The author seems to believe you can still, somehow, do it, and make the result faster than the existing passes, which, because they do not individually try to be complete, are O(N) and in one case, N^2 in the worst case. So combined, they are N^2.

While it is certainly possible to end up with N^3 algorithms that are faster than N^2 algorithms in practice, here, none of the algorithms have also ever been proven practical or usable in a production compiler, and the fastest one has open questions about whether it works at all.

Given all this, i see the onus as squarely on the author to show this is really possible.

Again, this is just one example of what it takes to subsume 4 passes into 1, along the exact lines the author says they think they will do, and it would have to be repeated 30 more times to get down to 20 passes that are as good as LLVM.

That's without saying anything else about the result being faster, less complex, or having less cruft.

As for whether they've accomplished a combined pass of any kind -I've looked at the code in detail - it implements a fairly basic set of optimization passes that nowhere approaches the functionality of any of the existing LLVM passes in optimization power or capability. It's cool work for one person, for sure, but it's not really that interesting, and there are other attempts i would spend my time on before this one. I don't say that to knock the author - i mean it in the literal sense to answer your question - IE It is not interesting in the sense that there is nothing here that suggests the end result will achieve fundamental improvements over LLVM or GCC, as you would hope to see in a case like this. The choices made so far are a set of tradeoffs that have been chosen before in other compilers, and there is nothing (yet) that suggests it will not end up with similar results to those compilers.

It is any not further along, more well developed, etc, than other attempts have been in the past.

So when I look at it, i view that all as (at least so far) not interesting - nothing here yet suggests a chance of success at the goals given.

As I said, these things come along not infrequently - the ones that are most viable are the ones that have different goals (IE fast compilation even if it does not optimize as well. Or proven correct transforms. or ...). Or those folks who think they can do it, but it will take 10-15 years. Those are believable things.

The rest seem to believe there are magic bullets out there - that's cool - show me them.

As for " Pretty much all projects and startups fail, but it's because people attempt them that some succeed."

This is true, but also tautological, as you know - of course things can only succeed if someone attempts them. It is equally as true that just because people attempt things does not mean anyone will succeed. While it is true nobody will be able to breathe unassisted in space if nobody tries, that does not mean anyone can or will ever succeed at it no matter how many people try.

This case is not like like a startup that succeeds because it built a better product. This is like a startup that succeeds because it proved P=NP.

Those are not the same kind of thing at all, and so the common refrains about startups and such are not really that useful here.

The one you use is useful when arguing that if enough people try to build a better search and outdo Google (or whatever), eventually someone will succeed - this is likely true.

In this case, however, it is closer to arguing that if enough people jump off 500ft cliffs and die, eventually someone will achieve great success at jumping off 500ft cliffs.

reply
snowfarthing
11 days ago
[-]
I just had a random thought: perhaps it would be a good idea to have a project that doesn't do optimizations, but just focuses on fast compiling.

Then again, I now can't help but wonder if LLVM (or even GCC) would be fast, if you just turned off all the optimizations ...

(Of course, at this point, I can't help but think "you don't need to worry about the speed of compilation" in things like Common Lisp or Smalltalk, because everything is compiled incrementally and immediately, so you don't have to wait for the entire project to compile before you could test something ...)

reply
ajross
11 days ago
[-]
> Then again, I now can't help but wonder if LLVM (or even GCC) would be fast, if you just turned off all the optimizations ...

It's not the optimizations really, it's the language front ends. Rust and C++ are extremely analysis-heavy. Try generating a comparable binary in C (or a kernel build, which is likely to be much larger!) and see how fast these compilers can be.

reply
christophilus
11 days ago
[-]
Go’s internal compiler / linker is kind of like that. So is qbe[0] iirc.

https://c9x.me/compile/

reply
fermigier
12 days ago
[-]
"You either die a hero or live long enough to see yourself become the villain".
reply
Ygg2
11 days ago
[-]
You either reinvent the wheel but square or live long enough to make it a circle.
reply
laweijfmvo
11 days ago
[-]

  > It's been 20 years and cruft has built up, time for a "redo".
 
Ah.. is this one of those "I rewrote it and it's better" things, but when people inevitably discover issues that "cruft" was handling the author will blame the user?
reply
rc_mob
11 days ago
[-]
What a strangely pessimistic and negative comment.
reply
snowfarthing
11 days ago
[-]
I think this is more a problem with the nature of technology in general.

If we want simple and fast, we can do that, but sometimes it doesn't cover the corner cases that the slow and complicated stuff does -- and as you fix those things, the "simple and fast" becomes "complicated and slow".

But, as others have observed about GCC vs LLVM (with LLVM having had a similar life cycle), the added competition forced GCC to step up their game, and both projects have benefited from that competition -- even if, as time goes on, they get more and more similar to what each can do.

I think all our efforts suffer from the effects of the Second Law of Thermodynamics: "You can't win. You can't break even. And it's the only game in town."

reply
cfiggers
11 days ago
[-]
Tsoding explored this project on a recent stream: https://youtu.be/aKk_r9ZwXQw?si=dvZAZkOX3xd7yjTw
reply
nurettin
11 days ago
[-]
I got tsoding fatigue after youtube started suggesting him on an hourly basis. He's on ignore.
reply
muke101
11 days ago
[-]
If you're going to rewrite LLVM, you should avoid just trying to 'do it again but less bloated', because that'll end up where LLVM is now once you've added enough features and optimisation to be competitive.

Rewriting LLVM gives you the opportunity to rethink some of its main problems. Of those I think two big ones include Tablegen and peephole optimisations.

The backend code for LLVM is awful, and tablegen only partially addresses the problem. Most LLVM code for defining instruction opcodes amounts to multiple huge switch statements that stuff every opcode into them, its disgusting. This code is begging for a more elegant solution, I think a functional approach would solve a lot of the problems.

The peephole optimisation in the InstCombime pass is a huge collection of handwritten rules that's been accumulated over time. You probably don't want to try and redo this yourself but it will also be a big barrier to achieving competitive optimisation. You could try and solve the problem by using a superoprimisation approach from the beginning. Look into the Souper paper which automatically generates peepholes for LLVM: (https://github.com/google/souper, https://arxiv.org/pdf/1711.04422.pdf).

Lastly as I hate C++ I have to throw in an obligatory suggestion to rewrite using Rust :p

reply
jcranmer
11 days ago
[-]
> The backend code for LLVM is awful, and tablegen only partially addresses the problem. Most LLVM code for defining instruction opcodes amounts to multiple huge switch statements that stuff every opcode into them, its disgusting. This code is begging for a more elegant solution, I think a functional approach would solve a lot of the problems.

So one of the main problems you run into is that your elegant solution only works about 60-80% of the time. The rest of the time, you end up falling back onto near-unmaintainable, horribly inelegant kludges that end up having to exist because gee, real architectures are full of inelegant kludges in the first place.

Recently, I've been working on a decompiler, and I started out with going for a nice, elegant solution that tries as hard as possible to avoid the nasty pile of switch statements. And this is easy mode--I'm not supporting any ugly ISA extensions, I'm only targeting ancient, simple hardware! And still I ran into the limitations of the elegant solution, and had to introduce ugly kludges to make it work.

The saving grace is that I plan to rip out all of this manual work with a fully automatically-generated solution. Except that's only feasible in a decompiler, since the design of that solution starts by completely ignoring compatibility with assembly (ISAs turn out to be simpler if you think of them as "what do these bytes do" rather than "what does this instruction do")... and I'm worried that it's going to end up with inelegant kludges because the problem space more or less mandates it.

> You could try and solve the problem by using a superoprimisation approach from the beginning. Look into the Souper paper which automatically generates peepholes for LLVM:

One of the problems that Souper ran into is that LLVM IR is too abstract for superoptimization to be viable. Rather than the promise of an automatic peephole optimizer, it's instead morphed more into "here's some suggestions for possible peepholes". You need a really accurate cost model for superoptimization to work well, and since LLVM IR gets shoved through instruction selection and instruction scheduling, the link between LLVM instructions and actual instructions is just too tenuous to build the kind of cost model a superoptimizer needs (even if LLVM does have a very good cost model for the actual machine instructions!).

reply
fuhsnn
11 days ago
[-]
>So one of the main problems you run into is that your elegant solution only works about 60-80% of the time. The rest of the time, you end up falling back onto near-unmaintainable, horribly inelegant kludges that end up having to exist

This is generally true, though for small compiler backends they have the luxury to straight up refuse to support such use cases. Take QBE and Cranelift for example, the former lacks x87 support [1], the latter doesn't support varargs[2]; which means either of them support the full x86-64 ABI for C99.

[1]https://github.com/michaelforney/cproc?tab=readme-ov-file#wh...

[2]https://github.com/bytecodealliance/wasmtime/issues/1030

reply
muth02446
11 days ago
[-]
I think you are generally correct but the two examples you gave "triggered" me ;-)

What damaged would there be if gcc or LLVM did decide to not support x87 anymore. It is not much different from dropping an ISA like IA64. You can still use the older compilers if you need to.

Similarly, what is varargs used for? Pretty much only for C and its unfortunate printf, scanf stdlib calls. If a backend decides not support C, all this headache goes away. The problem is, of course, that the first thing every new backend designer does is to write a C frontend.

reply
jcranmer
11 days ago
[-]
> What damaged would there be if gcc or LLVM did decide to not support x87 anymore.

For starters, you'd break every program using long double on x86.

And as far as "complexities of the x86 ISA" goes, x87 isn't really that high on the list. I mean, MMX is definitely more complex (and LLVM recently ripped out support for that). But even more complex than either of those would be anything touching AVX, AVX-512, or now AVX-10 stuff, and all the fun you get trying to build your systems to handle encoding the VEX or EVEX prefixes.

reply
o11c
11 days ago
[-]
"Everything should be as simple as it can be but not simpler!" —Roger Sessions, loosely after Albert Einstein
reply
einpoklum
11 days ago
[-]
I'm not familiar with a lot of the acronyms and catch-phrases already in the first part of the article... let me try to make a bit of sense of this:

  IR = Intermediate Representation
  SSA = Single Static Assignment
  CFG = Control-Flow Graph (not Context-Free Grammar)
And "sea of nodes" is this: https://en.wikipedia.org/wiki/Sea_of_nodes ... IIANM, that means that instead of assuming a global sequence of all program (SSA) instructions, which respects the dependecies - you only have a graph with the partial order defined by the dependencies, i.e. individual instructions are nodes that "float" in the sea.
reply
e4m2
11 days ago
[-]
reply
ThatGuyRaion
11 days ago
[-]
I appreciate several things about this compiler already:

MIT license (the king of licenses, IMHO. That's not an objective statement though)

Written in easy to understand C.

No python required to build it. (GCC requires perl, and I think that Perl is way easier to bootstrap then Python for LLVM)

No Apple. I don't know if you all have seen some of the Apple developers talking with people but some of them are extremely condescending and demeaning towards people of non-formal CS backgrounds. I get it, in a world where you are one of the supreme developers it's easy to be that way but it's also just as bad as having people like Theo or historical Torvalds.

reply
mshockwave
11 days ago
[-]
I’m definitely happy to see this happening. But I would like to point out two ingredients that constitute LLVM’s success beyond academic merits: License and modularity. I’m not a lawyer so can’t say much about the first one, all I can say is that I believe license is one of the main reasons Apple switched to LLVM decades ago. Modularity, on the other hand, is one of the most crucial features of LLVM and something GCC struggles to catch up even nowadays. I really hope Tilde can adopt the modularity philosophy, provide building blocks rather than just tools
reply
pjmlp
11 days ago
[-]
Had it not been for GPL 3, or the resistance to have GCC being more modular, and Apple, followed by Google, would not have sponsored it.

The idea behind LLVM isn't new per se, there have been other similar tools in the past, e.g. Amsterdam Compiler Toolkit.

reply
astrange
11 days ago
[-]
LLVM is not very modular though. For instance there's no backwards/forwards compatibility in the IR.
reply
mshockwave
11 days ago
[-]
modular in terms of using only some of the LLVM libraries without the need to pull the entire compiler into your project. In fact, many of the LLVM libraries have absolutely nothing to do with LLVM IR and have zero dependency on it. For instance, LLVMObject and LLVMDebugInfoDWARF. You can use those libraries to build useful tools, like your own objdump or just use it to read debug info.
reply
muth02446
11 days ago
[-]
Shameless plug for another similar system: http://cwerg.org Less ambitious with a focus on (measurable) simplicity.
reply
Rochus
11 days ago
[-]
Cwerg looks interesting indeed. I had it on my radar for some time. Especially its focus on simplicity and independence (e.g. that it can directly generate ELF executables) are attractive. From my humble point of view, both Python 3 and C++17 are a bit unfortunate as implementation languages. I can understand that the author didn't want to use C, but C++98 would have resolved this issue with less build and dependency complexity than C++17. Last year, I intensively evaluated backends and eventually settled on https://github.com/EigenCompilerSuite/, which supports a large number of targets, has a very powerful IR code generator and also comes with its own linkers. Also Eigen is unfortunately written in C++17, but I managed to port all relevant parts to a very moderate C++11 subset (even C++98 seems feasible in future).

Am I wrong to assume that Cwerg doesn't support x86, or is this just assumed by "X86-64"?

reply
shipp02
11 days ago
[-]
Given how long it takes for compilers to mature, by the time it's ready I didn't think anyone will care about x86. Similarly for c++11 vs 17. No?
reply
Rochus
11 days ago
[-]
Well, for all applications which don't require to addres more than 4 GB memory, a 64 bit machine is overkill. This especially applies to embedded systems (which make up the majority of all systems). This is unlikely to change for the next fifty years.
reply
account42
9 days ago
[-]
Overkill doesn't mean that it won't be the norm. Overspeccing can be much cheaper than keeping niche architectures alive.
reply
Rochus
9 days ago
[-]
Well, if the consumer market thinks that 64 bit architectures are a core benefit (for whatever irrational reason) and are willing to pay for it, industry will/does deliver. It's still overkill for all but a few applications. But I never saw in my more than thrity years in embedded systems that a company did well on a long term when wasting money for non-essential capabilities.
reply
muth02446
11 days ago
[-]
Ultimately, the plan for Cwerg is to be self-hosting, so C++ is just another stepping stone. I am curious about the issues with C++17 (vs say C++11) though.

About using C++:

Cwerg is NOT going "all in" on C++ and tries to use as little STL as possible. There are some warts here and there that C++17 fixes and those are used by Cwerg - nothing major. There is also a lightweight C wrapper for Cwerg Backend.

About not using C:

I do not get the fetishizing of C. String handling is just atrocious, no concept of a span, no namespaces, poorer type system, etc. Cwerg is actually trying to fix these.

If Cwerg was written in C instead of C++, a lot of the constructs would become MACRO-magic.

About Backends:

Currently supported are: 64 bit ARM, 32 bit ARM (no thumb), 64 bit x86 There are no plans to support 32 bit x86

reply
Rochus
11 days ago
[-]
> I am curious about the issues with C++17 (vs say C++11) though.

It's about dependability and bootstrapping. GCC 4.7 was the last version implemented in C, and it supports C++98/03 and a subset of C++11.

> There are some warts here and there that C++17 fixes [..] nothing major

But it's C++17 and thus requires many more bootstrap cycles until we have a compiler. I think a backend which only supports a subset of the features of a C++17 compiler should not depend on C++17, otherwise its usefulness is restricted by the availability of such a compiler.

> I do not get the fetishizing of C. String handling is just atrocious...

C is just a pretty primitive high-level language (with a very strange syntax) a compiler of which exists on almost any system. The next complexity step is C++98 (or the subset supported by cfront), which solves your issues and is even good enough to build something as complex as Qt and KDE.

> There are no plans to support 32 bit x86

Ok, thanks. The support for ARM32 already enables many use cases.

reply
muth02446
11 days ago
[-]
I can commiserate. I did some bootstrapping of gcc 10 years ago and it was the most miserable experience ever. You make a change somewhere. Kick off "make" and 20 min later you get some bizarre error in some artifact that is hard to find, generated by a build system that is impossible to trace.

A self-hosting Cwerg will hopefully be much easier to bootstrap because of its size. But until then, why do you need the (continuous) bootstrapping. You can use a cached version of the bootstrapped C++ compiler or cross compile.

reply
Rochus
11 days ago
[-]
I didn't express a requirement for Cwerg, but just tried to explain why I prefer to implement a compiler in C++98 than C++17.
reply
s3graham
12 days ago
[-]
This looks pretty cool. I've been looking at all the "small" backends recently. It's so much nicer to work with one of them than trying to wrangle LLVM.

QBE, MIR, & IR (php's) are all worth a look too.

Personally I've settled on IR for now because it seemed to match my needs the most closely. It's actively developed, has aarch64 in addition to x64 (looks like TB has just started that?), does x64 Windows ABI, and seems to generate decent code quickly.

reply
sylware
11 days ago
[-]
Again, somebody who comes to the realization something is seriously wrong with ultra-complex languages in the SDK (c++ and similar).

In other words, since this alternative LLVM is coded in plain and simple C, it is shielded against those who are still not seeing that computer languages with an ultra complex syntax are not the right way to go if if want sane software.

You also have QBE, which with cproc will give you ~70% of latest gcc speed (in my benchmarks on AMD zen2 x86_64).

reply
kibwen
11 days ago
[-]
C itself is an ultra-complex language. I do not understand the mindset of the "C is simple" crowd. Is it nostalgia or romanticism for the past? If we want to devise a truly simple language, we need to start by realizing that C is just the Javascript of its day: hacked together in a weekend by someone who wished they were using a different language and then accidentally catapulted into the future by platform effects.
reply
uecker
11 days ago
[-]
While it has its fair share of quirks it is certainly not an "ultra-complex" language.
reply
kibwen
11 days ago
[-]
The sleight of hand here is that by leaving so many things undefined, unspecified, and implementation-defined, C gets to foist complexity off on the implementations and then act as though it's absolved of blame when things go off the rails. The fact that what felt like half of all traffic on Usenet and IRC in the 90s was comprised of people language-lawyering over what is and is not valid C disqualifies it from being considered a simple language. It's as though someone designed a language where the spec is the single sentence "the program does what the user intends it to do" and then held this up pinnacle of simplicity. C has an entire Wikipedia article about how needlessly difficult it is to parse: https://en.m.wikipedia.org/wiki/Lexer_hack . C has an entire website for helping people interpret its type gibberish: https://cdecl.org/ . C's string handling is famously broken. C's formatting machinery is Turing complete! Coercions out the wazoo. Switch fallthrough having exactly the wrong default. The fact that Duff's Device works at all. Delegating all abstraction to an infamously error-prone textual macro language. You could spend an entire career learning this language and still find exciting new ways to blow your leg off. If C is our bar for simplicity, it explains a lot about the state of our profession.
reply
uecker
11 days ago
[-]
I write C every day and wrote C compiler. I know all all the issues it has very well, but it still a relatively simple language. It also not that difficult to parse. The lexer hack is interesting, because you can almost get away with using a context-free lexer, but you need this one hack. But this is not really a problem. People failing to read c declarations is also not the same thing as complexity, although I would agree that those are weird. Null-terminated strings have safety issues, but this is also not the same thing as complexity.
reply
uecker
11 days ago
[-]
I would argue that the problem of C is something else: It does not provide enough functionality out of the box. So instead of using some safe abstraction, people open-code their string manipulation or buffer management. This is then cumbersome and error prone, leading to complexity of the solution and safety issues which would could easily be avoided.
reply
sylware
11 days ago
[-]
I prefer a simple computer language with many real-life alternative compilers, and on the long run: the code will be hardened, where appropriate, because it is not cheap, over time.

And we must not forget that, 100% "safe" high level code should never be trusted to be compiled into 100% safe machine code.

reply
sylware
11 days ago
[-]
And you are right, C syntax is already too complex: integer promotion should go away like implicit casts, 1 loop statement is sufficient, should have had only sized primitive types, etc, etc. Just need a few new inline keywords for modern hardware architecture programming (atomics, barriers, endianness).

C99+ is just the less worse compromise.

reply
Rochus
11 days ago
[-]
What aspects do you consider "ultra-complex"? I agree that it has a very strange syntax, many features of it being unknown to most people; but besides that, it's as easy as Pascal, isn't it?
reply
pjmlp
11 days ago
[-]
Pascal doesn't have half as UB as C, or possibilities to memory corruption.

Pascal here meaning compilers people actually use, not ISO Pascal from 1976, people love their C extensions after all.

A for C's simplicity, one just needs to organise a pub quiz, using ISO, and key extensions as source of inspiration.

reply
Rochus
11 days ago
[-]
When refering to Pascal, I mean something like Turbo, Vax or Apple Pascal, i.e. the version used at the height of popularity. Original Pascal has much less degrees of freedom. And I have no reason to assume that Turbo or Apple Pascal have less possibilities for memory corruption, or are better specified.
reply
pjmlp
11 days ago
[-]
Starts by having proper strings and array types with bounds checking instead of pointers, followed by memory allocation with types instead of sizeof math, less scenarios for implicit conversions, reference parameters reducing the use cases where an invalid pointer might be used instead.
reply
uecker
11 days ago
[-]
UB has nothing to do with complexity. In any case, from about 87 UB in the core language, we eliminated 15 in the last meeting, and already have concrete proposals for 10 more. C2Y will likely not have any trivial UB and hopefully also optional safety modes that eliminate the others.
reply
pjmlp
11 days ago
[-]
It certainly has, as proven by recent talk at BlueHat 2024, on Windows kernel refactorings, as not everyone is knowledgeable of ISO C minutia and how optimisers take advantage of it, and still think they know better than analysers.
reply
uecker
11 days ago
[-]
Maybe you can explain this better. People not knowing about footguns is also not the same complexity, it is just having footguns and people not knowing about them.
reply
pjmlp
11 days ago
[-]
It is a matter of wording, doesn't change the trap is on the path.

Nonetheless, it is good to see efforts to reduce UB on the standard.

My complaints apply to C++ as well, naturally.

reply
lmm
11 days ago
[-]
Just the integer promotion rules are more complex than many languages' entire parser. And undefined behaviour makes the language practically impossible to learn, because there's simply no way to confirm the answer to any question you have about the language (other than "submit a DR and wait a few years for the answer to be published" - even the people who wrote the standard are confidently wrong about what it says, all the time) - you can form a hypothesis about how the language works, write a program to test this hypothesis, observe that the result is what you thought it would be - and you've learnt nothing, because your program was almost certainly undefined behaviour under a strict enough reading of the standard.
reply
Rochus
11 days ago
[-]
I wasn't aware that it is that critical. I have been doing C projects of all sizes and on different platforms and with different toolchains for forty years, including many where the same code runs on different platforms and is built with different toolchains, and I have never come across an undefined behavior for which there was no practical work-around in reasonable time. I have also never seen a language specification that answers all questions, not even Pascal or Ada. I agree that implicit conversions are an unfortunate feature of C, but I think the same about all languages where you can easily assign floating point to integer variables (or vice versa), for example. Cross-toolchain and cross-platform experiments are a constant activity with all the programming languages I use.
reply
lmm
11 days ago
[-]
> I have never come across an undefined behavior for which there was no practical work-around in reasonable time.

How would you know? You don't generally find out until a newer compiler release breaks your code.

> I have also never seen a language specification that answers all questions, not even Pascal or Ada.

Maybe, but I haven't see "upgrade your compiler, get a new security bug" be defended so aggressively in other languages. Probably more cultural than legalistic - obviously "the implementation is the spec" has its problems, but most languages commit to not breaking behaviour that most code relies on, even if that behaviour isn't actually written in the spec, which means that in practice the language (the social artifact) is possible to learn in a way that C isn't.

> I agree that implicit conversions are an unfortunate feature of C, but I think the same about all languages where you can easily assign floating point to integer variables (or vice versa), for example.

So don't use those languages either then?

> Cross-toolchain and cross-platform experiments are a constant activity with all the programming languages I use.

Sounds pretty unpleasant, I practically never need to do that.

reply
uecker
11 days ago
[-]
It is great to see some new C tooling emerge. I will likely make my own C FE public some time but it now uses some toy backend which needs be replaced...
reply
fuhsnn
11 days ago
[-]
There is no shame in simple codegen if it is correct and unsurprising!
reply
sylware
10 days ago
[-]
What's kind of amazing is those people who are "I wrote a small C compiler" and advocating for ultra-complex-syntax computer languages: They know they could _NOT_ have said "I wrote a ultra-complex-syntax computer language compiler"...
reply
pjmlp
11 days ago
[-]
Cough, C23 and C2y roadmp.
reply
Rochus
11 days ago
[-]
We are fortunately free to ignore "C23 and C2y" and stick with C89 (with the common extensions) or C99.
reply
uecker
11 days ago
[-]
What are the specific things you do not like about C23 or the C2y road map (whatever this is, it is more random walk)? I have my own list of course, but overall I still have some hope that C2y does not turn out to be a total disaster.
reply
Rochus
11 days ago
[-]
I've spent too little time with the recent standards/draft to give a specific answer. But I have a general attitude: C89 with extensions or C99 were just perfect for almost any purpuse; newer standards may well correct minor inadequacies or integrate things, that used to be implemented by proven libraries, directly into the language; but the price for these relatively minor improvements is high; people who write supposedly reusable code in the newer standards effectively force all older projects to switch to the newer standard; the costs of this are rarely justifiable. And there is C11 which made mandatory parts of the C99 standard optional, thus breaking backwards compatibility.
reply
pjmlp
11 days ago
[-]
Applies to any programming language, feel free to use C++ARM for example.

Until there is that special library that doesn't care about this target group of developers that want to stay in the past.

reply
IshKebab
11 days ago
[-]
I dunno if "twice as fast as Clang" is very impressive. How fast is it compared to Clang 1.0?

Also starting a new project like this in C is an interesting choice.

reply
oguz-ismail
11 days ago
[-]
> interesting choice

No serious alternative

reply
twic
11 days ago
[-]
Compilation is high-level work, so you could do it in any high-level language.
reply
IshKebab
11 days ago
[-]
Rust? Zig?
reply
lerno
9 days ago
[-]
No, just no
reply
triilman
11 days ago
[-]
I not understand about IR or compiler backend but I know another LLVM alternative like QBE. https://c9x.me/compile/
reply
Night_Thastus
11 days ago
[-]
I'm confused, is this some kind of re-post? I saw this exact same post with the exact same comments on it awhile ago. Could have been more than a couple of weeks. Very strange.
reply
jsnell
11 days ago
[-]
It was posted three days ago, and got re-upped by the mods via the the second chance pool[0].

[0] https://news.ycombinator.com/pool

reply
Ygg2
11 days ago
[-]
Does anyone else experience site disappearing on scroll?
reply
elvircrn
11 days ago
[-]
No benchmarks yet?
reply
bjourne
11 days ago
[-]
Good stuff. Hope they succeed. LLVM support for jit:ed and gc:ed languages is pretty weak so a competitor that addresses those and other shortcomings would be welcome.
reply
pjmlp
11 days ago
[-]
GraalVM, PyPy, naturally the more the merrier.
reply
orliesaurus
11 days ago
[-]
The maintainer said that LLVM has 10M lines of code making it too hard to improve, so he's building its own. That sounds weird to me: but good luck I guess?
reply
ziofill
11 days ago
[-]
Wow, my brain read “my LLM alternative” and I was genuinely confused for a while when reading the blog post :facepalm:
reply
coolThingsFirst
11 days ago
[-]
Is it just me or I find it difficult to believe that 19 year olds can implement the LLVM alternative?
reply
quesera
11 days ago
[-]
Never underestimate adolescents who are not distracted by ordinary teen drama.

They exist, and have truly enviable amounts of time for projects.

Also, don't overestimate compilers (or kernels). They can be much simpler than they might seem! The difficult/tedious parts are optimizations(!) and broad compatibility with bizarre real-world stuff.

reply
astrange
11 days ago
[-]
Compilers aren't that hard. You'll miss out on user requirements by not knowing about them, but getting older isn't a good way to solve that; instead getting more people to work on your project is.

(But you probably need to be older to be a good project manager.)

reply
uecker
11 days ago
[-]
I don't find this difficult to believe.
reply
coolThingsFirst
11 days ago
[-]
Seems far fetched but ok
reply
uecker
11 days ago
[-]
A bit. But Linus Torvalds was not much older when he wrote Linux.
reply
negate32
11 days ago
[-]
It's a game of knowledge and I have time, if you think I don't know what I'm doing please just call it out so I can politely disagree :P
reply
lmm
11 days ago
[-]
Just you. The best programmers I've known were about that age. (Hell, I'm pretty sure my own peak programming years were about that age)
reply
coolThingsFirst
10 days ago
[-]
Same, early 20s.

Why though, it seems with time we learn a LOT more and then there are 100 ways of doing things and get into analysis paralysis. The passion hasn't been the same as well.

reply
mbrubeck
11 days ago
[-]
Chris Lattner was 21 or 22 when he created LLVM.
reply
tester756
11 days ago
[-]
You want to create LLVM alternative and you write it in C?

I'm saying this as someone who uses LLVM daily and wishes that it was written in anything else than C/CPP,

those languages bring so many cons that it is unreal.

Slow compilation, mediocre tooling (cmake), terrible error messages, etc, etc.

What's the point of starting with tech debt?

reply
teleforce
11 days ago
[-]
It will be so much refreshing if someone write LLVM alternative in D language, its compilation speed is much faster than many compiled languages.

Having said that perhaps Tilde can be a good compiler addition for D in addition to the existing GDC (GCC), LCD (LLVM) and the reference compiler DMD.

It's interesting to note that Odin is implementing its compiler alternative in Tilde maybe due to some unresolved issues and bugs in LLVM [1],[2].

[1] A review of the Odin programming language (2022):

https://graphitemaster.github.io/odin_review/

[2] Understanding the Odin Programming Language (97 comments):

https://news.ycombinator.com/item?id=42348655

reply
tester756
10 days ago
[-]
Why not in Go/C#/Rust/Java or Kotlin/etc?
reply
lerno
9 days ago
[-]
1. C is universal, any other language is a dependency.

2. If you're using something like C# or Kotlin or whatever, then you're not serious about compilation speed.

3. You will need to provide a C API anyway.

reply
tester756
8 days ago
[-]
>C is universal, any other language is a dependency.

Executable is executable, there's no magic in C code, it's just frontend for LLVM IR.

>If you're using something like C# or Kotlin or whatever, then you're not serious about compilation speed.

Do you have any good benchmarks about how big the difference is?

reply