5 ms·
LLVM is basically a resource pool for C++ compiler development. As such, it is highly C++ specific and leaks C++ semantics everywhere. It's especially funny wh
by tw061023 1y ago
LLVM is basically a resource pool for C++ compiler development. As such, it is highly C++ specific and leaks C++ semantics everywhere.
It's especially funny when this happens in Rust, which is marketed as a "safer" alternative.
Would you like a segfault out of nowhere in safe Rust? The issue is still open after two years by the way: https://github.com/rust-lang/rust/issues/107975 https://github.com/rust-lang/rust/issues/107975
- pjmlp 1y agoWhich is why nowadays most frontends have been migrating to MLIR, and there is also ongoing work for clang as well.
- AndyKelley 1y agoHow does migrating to MLIR address the problem?
- pjmlp 1y agoThe higher abstraction level it provides over the LLVM IR, making language frontends and compiler passes less dependent on its semantics.
- AndyKelley 1y agoHuh?? That can only make frontends' jobs more tricky.
- pjmlp 1y agoYet is being embraced by everyone since its introduction in 2019, with its own organization and conference talks. So maybe all those universities, companies and the LLVM project know kind of what they are doing. - https://mlir.llvm.org/ https://mlir.llvm.org/ - https://llvm.github.io/clangir/ https://llvm.github.io/clangir/ - https://mlir.llvm.org/talks/ https://mlir.llvm.org/talks/
- AndyKelley 1y agoNo need to make a weird appeal to authority. Can you just explain the answer to my question in your own words?
- marcelroed 1y agoI am only familiar with MLIR for accelerator-specific compilation, but my understanding is that by describing operations at a higher level, you don’t need the frontend to know what LLVM IR will lead to the best final performance. For instance you could say "perform tiled matrix multiplication" instead of "multiply and add while looping in this arbitrary indexing pattern", and an MLIR pass can reason about what pattern to use and take whatever hints you’ve given it. This is especially helpful when some implementations should be different depending on previous/next ops and what your target hardware is. I think there’s no reason Zig can’t do something like this internally, but MLIR is an existing way to build primitives at several different levels of abstraction. From what I’ve heard it’s far from ergonomic for compiler devs, though…
- pjmlp 1y agoYou see it as appeal to authority, I see it as the community of frontend developers, based on Swift and Rust integration experience, and work done by Chris Lattner, while working at Google, feedbacking into what the evolution of LLVM IR is supposed to look like. Mojo and Flang, were designed from scratch using MLIR, as there are many other newer languages on the LLVM ecosystem. I see it as the field experience of folks that know a little bit more than I ever will about compiler design.
- alexrp 1y agoAs the guy currently handling Zig's LLVM upgrades, I do not see this as an advantage at all. The more IR layers I have to go through to diagnose miscompilations, the more of a miserable experience it becomes. I don't know that I would have the motivation to continue doing the upgrades if I also had to deal with MLIR.
- pjmlp 1y agoLLVM project sees that otherwise, and the adoption across the LLVM community is quite telling where they stand.
- alexrp 1y agoThat doesn't seem like a good argument for why Zig ought to target MLIR instead of LLVM IR. I think I'd like to see some real-world examples of compilers for general-purpose programming languages using MLIR (ClangIR is still far from complete) before I entertain this particular argument.
- pjmlp 1y agoWould Flang do it? Fortran was once general purpose. https://github.com/llvm/llvm-project/blob/main/flang/docs/HighLevelFIR.md https://github.com/llvm/llvm-project/blob/main/flang/docs/Hi... Maybe the work in Swift (SIL), Rust (MIR), Julia (SSAIR) that were partially the inspiration for MLIR, alongside work done at Google designing Tensorflow compiler? The main goal being an IR that would accomodate all use cases of those high level IRs. Here are the presentation talk slides at European LLVM Developers Meeting back in 2019, https://llvm.org/devmtg/2019-04/slides/Keynote-ShpeismanLattner-MLIR.pdf https://llvm.org/devmtg/2019-04/slides/Keynote-ShpeismanLatt... Also you can find many general purpose enough users around this listing, https://mlir.llvm.org/users/ https://mlir.llvm.org/users/
- pklausler 1y agoAre you saying that Fortran was once a general purpose programming language, but somehow changed to no longer be one?
- saghm 1y agoIt's not clear to me what you mean by default with regards to that issue. As far as I can tell, there's not really any indication that this is undefined behavior. Yes, there seems to be to a bug of some sort in the code being generated, but it seems like a stretch to me to imply that any bug that generates incorrect code is necessarily a risk of UB. Maybe I'm missing some assumption being made about what the pointers not being equal implies, but given that you can't actually dereference `*const T` in safe Rust, I don't really see where you're able to draw the conclusion that having two of them incorrectly not compare as equal could lead to unsafety.
- tux3 1y agoIf you read the Github issue, this one was weaponized fairly straightforwardly by taking the difference between the two pointers. The difference is zero, but the compiler thinks it is non-zero because it thinks they are unequal. From there you turn it into type confusion through an array, and then whatever you want. Almost any wrong compiler assumption can be exploited. This particular way to do it has also been used several times to exploit bugs in Javscript engines.
- saghm 1y agoI did read through the issue, and reading through it again, I still see nothing about how a segfault can be generated from safe Rust. I'm not saying it can't happen from this bug, but it's not obvious to me what exact code I could write that could cause this to happen, because none of the examples in that issue seem to be doing that.
- tux3 1y agoHere it is extracted for you: https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=bce23162d56467806fac8f0b4ad91b81 https://play.rust-lang.org/?version=stable&mode=release&edit... https://github.com/rust-lang/rust/issues/107975#issuecomment-1431996745 https://github.com/rust-lang/rust/issues/107975#issuecomment...
- ncruces 1y agoYeah, using LLVM for anything trying to avoid UB is crazy. I got involved in a discussion with a Rust guy when trying to get C with SIMD intrinsics into wasi-libc where something that the C standard explicitly state is “implementation defined” (and so, sane, as we're targeting a single implementation - LLVM) can't be trusted, because LLVM may turn it back into UB because “reasons.” At this point Go and Zig made the right choice to dump it. I don't know about Rust. https://github.com/WebAssembly/wasi-libc/pull/593 https://github.com/WebAssembly/wasi-libc/pull/593
- AndyKelley 1y agoIt sounds like you have a fundamental misunderstanding about undefined behavior. It's easy to emit LLVM IR that avoids undefined behavior. The language reference makes it quite clear what constitutes undefined behavior and what does not. The issue is that frontends want to emit code that is as optimizeable as possible, so they opt into the complexity of specifying additional constraints, attributes, and guarantees, each of which risks triggering undefined behavior if the frontend has a bug and emits wrong information.
- ncruces 1y agoHi Andy. Did you read the linked thread? I was not the one making this claim: > However, I believe that currently, there is no well-defined way to actually achieve this on the LLVM IR level. Using plain loads for this is UB (even if it may usually work out in practice, and I'm sure plenty of C code just does that). My claim is that the below snippet is implemention defined (not UB): // Casting through uintptr_t makes this implementation-defined, // rather than undefined behavior. uintptr_t align = (uintptr_t)s % sizeof(v128_t); const v128_t *v = (v128_t *)((uintptr_t)s - align); Further, that this is actually defined by the implementation to do the correct thing, by any good faith reading of the standard: > The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment. I further suggested laundering the pointer with something like the below, but was told it would amount to nothing, again the blame being put on LLVM: asm ("" : "+r"(v)) I honestly don't know if LLVM or clang should be to blame. I was told LLVM IR and took it in good faith.