4 ms·
Note that the language independence of the middle layer(s) is often incomplete. Language-level constructs sometimes get smuggled through the intermediate layer
by sfink 4y ago
Note 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...