In this way, IR would fullfil the same role Macro-32/64 did for porting VMS to Alpha and beyond. However, it appears to my understanding (sorry, I was still crawling when VAXes were on the way out), that the benefit was retaining "VAX" syntax to avoid massive rewrites.
If you're starting from a clean slate, what's the benefit of writing IR? Why not use C? After all, IR won't really give you complete control over generated code, and it's still an abstract VM (albeit that obviously allows writing IR that will only sensibly compile on a specific arch - e.g. system register acceses and so on).
Why the hell are people down-voting this? It's a purely technical comment. Seriously people, someone making an argument against a technology you like shouldn't make you reach for the down-vote button. I've noticed I get down-voted too if I make something critical of certain technologies, and it's really sad . Make a response or an argument.
(Replying here, so my upvote on the parent doesn't get lost...)
Working in C means you get restricted to only doing things which C can do, and you're out of luck if you want to do things that C can't do: unaligned accesses, tail calls, saturating arithmetic, overflow detection, exceptions, stuff like that. IR allows you to do all this, at the expense of being considerably more complex and painful to use.
Of course, if your compiler don't want to do any of this, then C is a perfectly valid choice, as it doesn't tie you to the LLVM toolchain --- see Nim, for example. But as soon as you venture outside C's comfort zone, working in IR starts paying off.
But LLVM-C (i.e. C + llvm extensions) does do all the things you just described, plus it's a stable interface for programming. IR is unstable, and therefore unsuitable as a source language for most projects. I say this as someone who writes an enormous amount of both assembly and llvm-c, and has considered and dismissed IR for exactly this reason.
That's all fair and correct, but the amount written for, say, an OS, in assembly - native or IR - is quite minimal and well-controlled, usually written in assembly because of a good reason (exception handlers, for example). At that point, it's just more obvious to write in native assembly, given that you're writing architectural code, and for a different architecture, that code would be sufficiently different.
So again, I see all the value in IR for compilers. Can someone give me at least a reasonable use case for beginning to write in IR, or even using IR for optimizing cerain code paths?
LLVM IR can detect overflow, has exceptions, tail call optimisations etc? I thought it was lower level than C itself. I have kind of a strict hierarchy of abstraction in my head, with LLVM IR sitting a bit below C, but maybe it's not that simple.
Sitting below C is exactly what you want in this case. It's not about tail calls as an automatic optimization - it's about having a tailcall opcode of some sort, that guarantees a tail call when used (but you're responsible for lifetimes etc). That is inherently a low-level facility - lower than what the C standard provides. C implementations can do tail calls, but because this behavior isn't actually guaranteed and is purely a quality-of-implementation issue, a language that needs tail calls for its idiomatic code to not blow up the stack cannot target portable C, unless it redoes the stack itself.
If you're starting from a clean slate, what's the benefit of writing IR? Why not use C? After all, IR won't really give you complete control over generated code, and it's still an abstract VM (albeit that obviously allows writing IR that will only sensibly compile on a specific arch - e.g. system register acceses and so on).