> [in C] It's very difficult to avoid undefined behavior,
True, but LLVM IR and other IRs have undefined behavior as well.
> you won't be able to modify the compiler backend (and you will want to as you start optimizing),
Not all languages need backend changes. And you can still add IR optimizations or backend changes that help your language, if you do. Yes, this might not be as easy, but then if you compile to LLVM IR, you might need IR changes for your special things anyhow.
> you can't add new language intrinsics, good GC is pretty much incompatible with that,
Good point, for most GC languages compiling to C is not a good option, which makes sense since C has no GC support.
> and precise control over debug info is impossible.
Yes, but using the C preprocessor you can get pretty far.
> Compile to LLVM IR and/or GCC IR instead.
More power that way, sure, but
1. It limits you to one compiler, while C has many.
2. LLVM IR changes over time (and recently had plenty of examples of this), so you'll need to track that. Whereas C is extremely stable, so long-term, it's much less work.
3. Emitting C is very easy (for those familiar with C), and also very easy to debug.
I think compiling to C is an excellent option. Sometimes better, sometimes worse.
> True, but LLVM IR and other IRs have undefined behavior
> as well.
LLVM IR has less undefined behavior than C, and even despite the reduced surface area frontends have still historically wrestled with taming its UB (both PNaCL and Rust have documented their struggles). > It limits you to one compiler, while C has many.
To quote Walter Bright on this topic (which I've linked elsewhere in this thread, but here it is again: http://forum.dlang.org/post/n1vbos$11ov$1@digitalmars.com): > 1. You're at the mercy of bugs in the C compiler you
> cannot fix.
> 2. C leaves quite a lot as "implementation defined",
> causing endless compatibility issues with various C
> compilers.
> [...]
> 6. You'll suffer from endless bug reports caused by a
> mismatch between your compiler and the user's C
> compiler, whatever that might be.
> [...]
> 10. The order of evaluation of C code expressions is
> implementation defined.
> 11. Installation problems, again, because you don't
> control the user's C compiler.And there are also non-semantic differences that end up being important, like one browser running certain things too slowly or taking too much memory.
Multiple implementations is always more complicated ;) But in many cases it's better than a monoculture, in my opinion.
Meanwhile, the only thing that you gain from all this extra effort is the ability to target platforms that GCC and LLVM don't already support, but these platforms are all likely to be obscure resource-constrained devices, and I just can't see developers on these platforms flocking to such a thoroughly-dynamic language as the OP is envisioning.
But yes, I agree that in the context of a really dynamic language, it might not be what the author wants anyhow.
The very amount of tests in the LLVM source tree ensures that nobody will be motivated to do any significant change unless it is really, really needed, otherwise you'd be forced to do a lot of painful work to update all the tests.
Also, compiling to C pretty much rules out having a REPL for free and all the other fun, while with LLVM it's trivial.
* the removal of pointer types (still happening)
* the use/user flip
In my experience these have been significant in the amount of work it takes to track.
In fact, there isn't any dialect of C, standard or not, that I'm aware of that allows you to do this in a fashion that works with precise, moving GC. (Mostly-copying doesn't count.) Maybe C++/CLI, but the object model you're opting into with that brings you so far from C as to barely be considered "compiling to C".
The problem is not so much the spilling and reloading (though that is a large issue) as what that is going to do to the ability of the optimizer to reason about the code.
(If you're curious how I'm so sure it's a huge performance penalty, I have been spending a fair amount of time of the last month working with others to debug large performance problems caused by a variant of exactly this technique used in Servo.) :)
The LLVM GC interface is controlled through intrinsics, so you can access it through the human-readable IR representation just as you can with the API.
The obvious one is not having a giant build time dependency that might change and be at different versions on different platforms. The text interface is far more stable.
The problem I had with doing this is how picky llvm is when it comes to ordering your temporary registers.
We have some macros and a bunch of functions then that make emitting LLVM IR simpler. For example, the "ins--iterate" and "ins--if" / "ins--else" macros in this code handle phi nodes and so on:
https://github.com/dylan-lang/opendylan/blob/05271f6fec9da05...
This library is currently in the process of being updated from LLVM 3.5 to current HEAD as debug info has changed significantly upstream. After that, we will be landing some documentation for it as well.
If you're interested in learning or hearing more about this, we're typically around on #dylan on freenode IRC.