6 ms·
What does a "front-end" mean exactly, in this context?
by sdfhdhjdw3 4y ago
What does a "front-end" mean exactly, in this context?
- stevewatson301 4y agoThe part of a compiler that handles tokenization, parsing, AST generation and IR emission, as opposed to the backend which is responsible for conversion of IR to a target-compatible executable.
- colejohnson66 4y agoAt a high level, GCC and LLVM are divided into two ends: the front and the back. The front end takes the source code and turns it into some form that's language agnostic (e.g. LLVM bitcode). The back end takes those structures and turns it into machine code. This allows the compiler to be modular. Old compilers didn't use this concept. So a C->x86 compiler and a Fortran->x86 one couldn't share code as easily. And if you wanted to expand to, say, ARM, Alpha, etc. targets, it gets worse. You end up needing O(l*t) compilers[a] to be homogenous. It gets even worse if you want to add optimization. With this model, the whole system is working on an AST, and therefore, the optimizers are tailored to the individual compiler varient, so they end up being just as unportable. However, with a modular design (front and back end), you can have C->IR and Fortran->IR front ends, then a single back end for each target: IR->x86 and IR->ARM. If you want to add, say, Ada support, you only need to write an Ada->IR module, and the back ends handle the rest. In the end, you only need O(l+t) modules. You also get the benefit of agnostic optimizers as they only need to support your internal IR. [a]: 'l' is languages and 't' is targets
- bombcar 4y agoWould it ever make sense to build a chip/vm (something like the JVM) designed to run the intermediate code directly?
- Blackthorn 4y agoAt some point in history there was a jvm chip like that. It's long gone, not sure for what reason.
- mcronce 4y agoYou actually can - https://llvm.org/docs/CommandGuide/lli.html https://llvm.org/docs/CommandGuide/lli.html LLVM's original purpose was something analogous to the JVM, but it's obviously evolved to be more of a compiler platform, debugging toolchain, etc these days (No direct hardware support, though, as cool as that sounds)
- gpm 4y agoProbably not a chip, since the intermediate language is optimized for optimizing and compiling, not for executing quickly. Meanwhile normal instruction sets are just a bytecode optimized to run quickly. LLVM-IR at least also isn't stable, so not a good thing to bake into a chip - but you could conceivably make a stable intermediate language.
- jcranmer 4y agoGenerally not. There are cases where something akin to intermediate code is shipped (e.g., SPIR-V or PTX for GPU code), but even then, the intent is that it is converted to a binary machine code in the driver. Intermediate code tends to have downsides that make it hard to work with in an actual hardware implementation. Infinite registers, for example, which makes encoding instructions challenging.
- 1980phipsi 4y agoI would be worried about the intermediate code not being stable over time.
- pjmlp 4y agoUnless one keeps it stable, like Apple did for watchOS. However they apparently don't want to keep fixing upstream changes and is now deprecated going forward.
- jerf 4y agoGenerally, no. The IR will be tuned for compiler purposes, not execution purposes. It can be possible but it won't be optimal. For instance, the IR will probably retain type information that generally CPUs don't care about, since they live in a world of bits. The IR will have been designed knowing it is upstream of optimization code, so it won't be something that is already optimal, it'll be something designed to be easily made optimal in many different ways. As Blackthorn mentioned, specifically it can be done. There was a chip that ran JVM bytecode directly. There was an entire Lisp Machine which was very influential... but not because of its high performance. Wikipedia has a page on this: https://en.wikipedia.org/wiki/High-level_language_computer_architecture https://en.wikipedia.org/wiki/High-level_language_computer_a... Many people decry the lack of innovation in computer architecture over the past 50-60 years. There is a legitimate reason for that, though: Any such innovation had to outrun the exponential increases conventional architecture was experiencing. We had it for so long we could take it for granted, but while computing wasn't the first and won't be the last to see periods of exponential growth, I can't think of anything else that had the length of run that computer chips had. (And even now, it's only slowed down. There's still multiplicative advances rather than additive ones every year. The base on the exponent is just smaller than it used to be.) There's been a number of architectures based on running IR (or an equivalent directly) that didn't pan out, but there's also some that did run OK, but they just couldn't keep up with the exponentially accelerating behemoth. I think if silicon continues to plateau, there is some hope that this could change. However, a new challenger has appeared! Now it's not good enough to just outrun what a "conventional" architecture can do with CPU and RAM and peripherals... now you also need outrun what a GPU-based architecture can do! This sucks up a lot of the oxygen. For instance, right now you see some tentative steps towards special-purpose AI silicon, but it has to do something amazing to beat out a GPU, and you also have to be really, really sure that the AI technique you are committing to silicon will still be the state-of-the-art in the couple of years it'll take you to bring it to market. AI hasn't been moving as fast as, say, JS front-end frameworks, but it's still moving fast enough that I'd be nervous in investing in that vs. the same amount of effort poured into optimizing a GPU algorithm on GPUs that are still advancing a lot every year.
- cogman10 4y agoI don't think these limitations are ones that really impact hardware all that much. It wouldn't be impossible to create hardware with the concept of "infinite registers" that ultimately gets optimized away. (see: Mill CPU) The bigger issue (IMO) is that the IR for compilers tends to evolve rapidly while hardware is stuck in the mud. Moving the problem of finalizing the IR into the hardware will effectively make it so you'd change your compiler to emit IR that targets old IR. This is why, for example, x86 will get a new instruction which will effectively go unused for 5 to 10 years (except in extreme cases where the performance gains are worth the cost of writing code to detect and use those new instructions... For example, FMA). Those who compile code want it to be able to run most anywhere in not so surprising fashions, so they'll target the LCD. Now, imagine someone was building a JVM bytecode chip today. The JVM is on a 6 month release schedule. That's incredibly hard for a hardware manufacturer to want to keep updating their chips at that rate. Further, even if they targeted "LTS" versions, they've moved that to a 2 year cycle. Again, hard to really expect customers to want a new JVM chip every 2 years. The likes of GCC and LLVM IR change and expand just as rapidly (if not moreso) than than JVM. There is the option of something like FPGA or programmable hardware leaking into more places, but IMO, the HDLs and their tools simply suck too bad to expect FPGA on an ASIC to really take off. We need a first mover here and after that happens, I expect at least 5 to 10 years before the tools get to a level that doesn't completely suck. Even then, while access to GPGPUs is now pretty much universal, GPGPU programming still feels like it is in the stone ages. Despite being a thing for over 10 years. So how can we expect HDLs to evolve at a faster pace?
- tendstofortytwo 4y agoFor a chip, I think you would run into the same problems as Intel iAPX if you did that: https://en.wikipedia.org/wiki/Intel_iAPX_432 https://en.wikipedia.org/wiki/Intel_iAPX_432
- kergonath 4y agoSomething like a Low-Level Virtual Machine? Short answer, it’s feasible in theory, but usually suboptimal.
- Twirrim 4y agoBeen there, done that! https://en.wikipedia.org/wiki/Jazelle https://en.wikipedia.org/wiki/Jazelle Jazelle was an instruction set extension to allow natively running java bytecode on Arm processors. Arm never seemed to give it any proper care and attention necessary for it to make any actual market impact, they didn't even publish the ABI. Transmeta, that used to employ Linus Torvalds at one stage, had Code Morphing Software: https://en.wikipedia.org/wiki/Transmeta#Code_Morphing_Software https://en.wikipedia.org/wiki/Transmeta#Code_Morphing_Softwa... It was built in to the silicon, that essentially operated as a full JIT for x86 software, translating to back-end VLIW instruction set. Transmeta seemed heavy on the marketing and buzz (hiring Linus was very much a marketing move), light on the actual execution. Crusoe didn't even remotely live up to their own buzz and it just about killed off their chances of success.
- pjmlp 4y agoVery very old compilers like in the early 70's, given that PL.8 and Amsterdam Compiler Toolkit are two well known approaches to this design.
- sfink 4y agoNote that the language independence of the middle layer(s) is often incomplete. Language-level constructs sometimes get smuggled through the intermediate layer and get translated in code generation. Or the middle layer is theoretically generic but valid variants that haven't been used before are buggy or unimplemented. I think Rust on LLVM has a major example of this? IIUC, it's a big problem to turn on strict aliasing because LLVM doesn't actually implement it correctly, it just works well enough for C/C++ etc.? (But I'm no expert.) Still, the frontend/backend split gets you a lot closer to supporting all of the l*t pairs than the all-in-one approach. Porting is a matter of fixing bugs and filling in missing parts rather than starting from scratch.
- colejohnson66 4y agoFor sure, leaky abstractions will get through; Rust has had quite a few issues LLVM (you mention one), but it's still a lot better than the all-in-one system we had before.
- stouset 4y agoThe issue was that LLVM codegen produced buggy output with strict aliasing, but this wasn't really caught until Rust since Rust can use it several orders of magnitude more frequently than C / C++ frontends would. AIUI, the solution wasn't that Rust smuggled the language-level construct through the intermediate layer, but that they simply held off on expressing these constraints until bugfixes could be merged upstream into LLVM. The only downside to disabling this was simply that compiled code would potentially be a bit less optimal than otherwise, so such tactics weren't really necessary.
- jcranmer 4y ago> I think Rust on LLVM has a major example of this? IIUC, it's a big problem to turn on strict aliasing because LLVM doesn't actually implement it correctly, it just works well enough for C/C++ etc.? (But I'm no expert.) It's noalias (C99's restrict code, in essence), that you're thinking of, not C/C++ strict aliasing rules.
- tialaramex 4y agoWorse than not being completely "language independent" sometimes LLVM's Intermediate Representation is not well defined at all. This is most common where C++ (as the main consumer of these semantics) doesn't define certain semantics, or, the semantics it standardises are just impossible to optimise so nobody really delivers them (ie they don't always work in your C++ programs when you compile them with actual modern C++ programs) As I understand it an example when it comes to aliasing would be what happens if somebody typed a bunch of ASCII into a prompt and then the program... uudecodes the ASCII to get an integer, and begins just using that as a pointer to rummage around in some data structure. Is that... OK? Obviously you can't do this in safe Rust, but even unsafe Rust says er, no, that's definitely not allowed (it might actually work but it isn't OK). But the ISO C++ standard says that so long as the ASCII string happened, by some cosmic accident, to be a "valid" address for a pointer after this transformation this works fine even if it now magically aliases a pointer we otherwise had no reason to believe could be aliased. If we allow this, many optimisation opportunities vanish. So, LLVM doesn't allow it. Our "correct" C++ pointer uudecoding program doesn't work. However, a blanket prohibition blows up real tricks that people actually do, such as hiding flag bits in address values (unlike uudecoding ASCII inputs to make pointers). So LLVM provides behaviour that's not formally standardised anywhere but can be thought of as something akin to PNVI-ae (Provenance Not Via Integers - Address Exposed). If the program "exposes" addresses from pointers, then the compiler assumes it could see those addresses "magically" appear from somewhere else (e.g. a uuencoded string) and so it must choose optimisations accordingly. One day perhaps C++ will actually document PNVI-ae or some similar scheme in the ISO standard. That day is not today (nor next year, this will not happen in C++ 23) but meanwhile you've got the problem that, in unsafe Rust you actually get whatever arbitrary semantics that were delivered by LLVM. Since they're not just "This is what C++ does" but only "This is how C++ works in Clang" that's even less portable. As I wrote, this only burns unsafe Rust. If you don't write unsafe and just depend on other people's stuff to use that as necessary (e.g. obviously the standard library is full of unsafety) then it's not your problem to fix this when it breaks. But it sure would be nice if the people writing unsafe code would have more certainty on this sort of topic. Rust is experimenting with "Strict Provenance" rules to see what happens if, instead, it makes its own provenance rules and dispenses with waiting for C and C++ programmers to actually decide what the rules are in their languages. https://doc.rust-lang.org/std/ptr/index.html#strict-provenance https://doc.rust-lang.org/std/ptr/index.html#strict-provenan...
- rayiner 4y agoHow “old” are we talking about here? Multiple language front ends sharing a common IR is a concept that dates to the 50s: https://academic.oup.com/comjnl/article/22/3/226/408542 https://academic.oup.com/comjnl/article/22/3/226/408542 (click through to the pdf)
- lalaithion 4y agoLink is broken
- whimsicalism 4y agoYour link does not work
- rayiner 4y agoThanks. Fixed. (It's not my fault young people broke direct linking on the web.)
- colejohnson66 4y agoBeing a concept and having papers written about it doesn't imply an actual implementation
- dtech 4y agoGCC has an intermediary format, which then compiles to machine code. So the front-end is similar to the main Rust compiler that compiles to LLVM bytecode.
- nrclark 4y agoCompilers are often implemented as a front-end/back-end split. The front-end compiles your input language (C, C++, Rust, etc) down to a low-level language called an Intermediate Representation. Then the back-end of the compiler optimizes the IR and compiles it into object code. A family of compilers will usually share the back-end. This kind of split allows for deduplication across different compilers in the same family, and also makes it easier to design a new language without having to fully re-implement everything about the compiler yourself. In GCC, these are bundled together as a common project afaik. In Clang/LLVM, these are split into the front-end (clang) and the back-end (LLVM).
- FrankHB 4y agoIn some stricter sense, back-end is for target-depending stuff like ISA-dependent code generation. A great deal of work in both GCC and LLVM is in the so-called mid-end. Both have more than one IRs in the pipeline after the front-end.
- sdfhdhjdw3 4y agoOh damn, THIS is what the "intermediate representation" i keep hearing about is. I knew that Julia uses LLVM. I also knew that Julia has something called IR, but i didn't know what it was. So Julia's IR is probably LLVM's IR...
- borodi 4y agoJulia has an IR called Julia IR that is used before compiling to LLVM IR, it's a bit higher level than LLVM ir
- jcranmer 4y agoI suspect Julia has its own IR that is later lowered into LLVM IR. One of the aspects of multiple compilers is that it's basically a massive tower of IRs that get progressively lowered into lower- and lower-level IRs.
- ChrisRackauckas 4y ago