(Really like that LLVM IR. Does anyone code in it directly? Was also thinking it would be interesting to port Knuth's MMIX examples to it.)
(Really like that LLVM IR. Does anyone code in it directly? Was also thinking it would be interesting to port Knuth's MMIX examples to it.)
If you looked at, just for an example, the IR used in the dmd d compiler, using (Walter Bright's) Digital Mars backend then you'd notice that the IR is not trivial to access at all. Last time I checked, you had to actually dive into the backend code (I'm pretty sure there's an undocumented flag/switch that I'm missing somewhere) to get the IR out of the compiler. In fairly sharp contrast to this, getting the IR (in a textual format!) is normally as simple as using -emit-llvm when compiling. This is part of the revolution (~Slight~ exaggeration) that LLVM brought about in compiler design: Compared to most other compilers, LLVM is designed to be very portable. The only compiler, of similar stature, like it is GCC. GCC is much better than it was, I'd imagine because of the competition from LLVM/Clang.
Tangent Aside: The LLVM IR textual format is not guaranteed to be stable at all. It's also not particularly nice to program in, and also it uses SSA form so it's not suitable for humane consumption. It looks like a high level programming language, but it really isn't. IR is designed to be generated, bullied and discard by the compiler.
If you want to punish yourself, the LLVM project does contain interpreters and compilers just for IR in a file. If I remember correctly, Clang will compile anything with a ?.ll? file as IR.
You can see all the optimisation passes in action here: https://godbolt.org/g/uZH3UD
It's called LISP. It is a niche style, I'll give you. ;)
Then the folk whom build the processors/architecture/assembly languages (and open source advocates when businesses ultimately ignore LLVM for a bit) will be writing the conversion from IR down to some specific machine code. This allows Intel to convert the IR line "COMPLICATEDFUNCTION $r2 5" to some advanced x86 call that has some significant speed or memory increase and is only one line while TI can still call the 26 lines of MIPS they need to call and both will be semantically equivalent.
That way you can, from the the software side, be relatively agnostic with how you're writing code and the chipset side is able to get every ounce of optimization using advanced functionality (if available). More importantly, software side is then able to ignore any processor features (be they speed ups or slowdowns) because every chipset manufacturer should have some toolset to convert your IR down to the best machine code they've got based on some desires (speed, space, power, etc). Inevitably, there will still be differences in performance between chipsets but being able to build down to IR (even with performance issues for some chipsets while everyone gets on board) and not some large set of assembly languages should be very nice.
Most mainframe architectures since the early 60's, didn't really used pure Assembly, rather bytecodes that were processed by microcode on the CPUs.
Hence why many old papers tend to mix both terms, bytecodes vs assembly.
This tradition carried on to mainframe architectures like the AS/400, nowadays IBM i, where the user space is pure bytecode (even C), called TIMI, and a kernel level JIT is used at installation time to convert the application into the actual machine code.
IBM i Java takes advantage of this, where the JVM bytecodes are converted into TIMI bytecodes.
It also provides some kind of common language runtime called ILE (Integrated Language Environment).
So the trend of using LLVM bitcode on iDevices, Dalvik on Android or MSIL on .NET, JavaScript/WebAssembly on browsers, is similarly with containers, modern computing catching up with mainframe ideas.
> Most mainframe architectures since the early 60's, didn't really used pure Assembly, rather bytecodes that were processed by microcode on the CPUs.
And was that microcode typed SSA-based IR with alias metadata and so forth?
You can't just lump all "bytecodes" together. x86 machine code is a bytecode that is processed by the microcode on the CPUs too.
Even if not, I see it as a very interesting Msc or PhD to implement a FPGA to execute LLVM bitcode.
I am not the one lumping all bytecodes together CS papers since the dawn of our industry are. Just go dig a random paper about computer architectures in the 50 and 60's, for example.
Some of them even use bytecode and assembly interchangeably on the same document.
I guess we could eventually consider it a form of bytecode, given its CISC nature.
And when bytecode gets a pure hardware implementation, without any form of microcode support, is it still bytecode or has it become assembly?
Although it is not really what you are describing.
You could make an ISA which is similar to LLVM IR, but there'd be little point when RISC-V (or even AArch64) already exists.
* JVM bytecode is stack-based, whereas LLVM uses "infinite registers" in SSA form
* being in SSA form makes it convenient to consume in compiler passes, but comes with quirks that mean you don't really want to write in that style manually: the mind-bending phi instructions, definitions must dominate uses, simple ops like incrementing a variable really means creating a new variable, etc.
* JVM bytecode carries a lot of Java-level information, for instance if you have N classes with M methods each in source, you will typically find N classes with M methods in bytecode too. A lot of keywords in Java have an equivalent in bytecode (e.g. private, protected, public, switch, new...)
* in contrast, LLVM IR feels closer to C (it only knows about globals, arrays, structs and functions). It exposes lower level constructs like vector instructions, intrinsics like memcpy
* JVM bytecode is well specified: anyone armed with the pdf [1] can implement a full JVM. LLVM IR is somewhat loosely defined and evolves based on the needs of the various targets
* JVM bytecode is truly portable, whereas target ABI details leak into LLVM IR. A biggie is 32 bit vs 64 bit LLVM IR.
From a few LLVM meetings and Apple's work on bitcode packaging, I think there is some work to make LLVM IR actually architecture independent.
The biggest problem with GCJ was that most people left the project when OpenJDK was made available, and decided to work on it instead.
On text format: "The textual format is not backwards compatible. We don't change it too often, but there are no specific promises." On C API: "The C API is, in general, a "best effort" for stability. This means that we make every attempt to keep the C API stable, but that stability will be limited by the abstractness of the interface and the stability of the C++ API that it wraps."
There is confusion because C++ API is unstable (very unstable). But C API is stable. And C API is more stable than text format. (In my experience, policy is accurate description of actual practice and not empty promise.)
It's a bit of a thought experiment but it's not totally insane. Let's just say that humanoids writing in IR makes more sense than humanoids writing in asm.js Ultimately, IR is an assembly language. By contrast, web assembly is not an assembly language.
https://idea.popcount.org/2013-07-24-ir-is-better-than-assem...