4 ms·
It's not a bug, and the answer is provided in the link: "Faster execution time. You may have noticed that in the new compiler pipeline, optimization appears tw
by hacker_9 11y ago
It's not a bug, and the answer is provided in the link:
"Faster execution time. You may have noticed that in the new compiler pipeline, optimization appears twice. That’s no accident: previously, the compiler relied solely on LLVM to perform optimizations, but with MIR, we can do some Rust-specific optimizations before ever hitting LLVM – or, for that matter, before monomorphizing code. Rust’s rich type system should provide fertile ground for going beyond LLVM’s optimizations."
- kibwen 11y agoThere's still an implicit question there, concerning why one would choose to develop a new IR rather than enhancing LLVM (the latter of which the Rust devs (and especially the Swift devs) have had years of experience doing). Though I'm not trying to suggest that Rust made the wrong decision or is suffering from NIH, because MIR is great, and there's no reason to suspect that shoving absolutely everything down into LLVM is necessarily a tractable solution. I'm just curious which Rust-specific and Swift-specific optimizations these IRs enable above and beyond LLVM IR's capabilities, and what that says about each source language in turn (especially if we regard LLVM IR as a proxy for C, being LLVM's original target).
- rayiner 11y agoIt's easiest to do optimizations on an IR that has the appropriate level of granularity. If you're trying to optimize address calculations, it's easier to work with something like LLVM's getelementptr, which represents an address calculation as one IR node, than a C-level IR (where the address calculation would be implicit in an array or structure field access), or an ASM-level IR (where the address calculation might be broken up over several different instructions). LLVM is pretty low-level. It's a bit lower-level than C and has a very simple type system. It has no idea about unique pointers versus references, has no concept of borrowing, etc. I bet you could encode the necessary information for performing say borrow-checking into LLVM IR, but working with that would not necessarily be pleasant. A good example of this is ARC optimization in Swift, which gets rid of unnecessary reference counting operations. That optimization operates on SIL, which has special instructions for reference counting. You could represent those instructions as magic intrinsics in LLVM IR, but you have no way of imposing any structural restrictions on how those intrinsics are used. Moreover, any pass which operated on LLVM IR to optimize uses of those intrinsics, would have to make deep assumptions about the semantics of those operations. Those assumptions, being Swift-specific, would mean the pass could not be used by other languages, which removes a lot of the benefit of making it an LLVM pass in the first place.
- DannyBee 11y agoFor starters, LLVM has a very simple type system. very simple. So pretty much any optimization that relies on type knowledge, unless it's a simple optimization (IE can be expressed as an attribute on lowered types, ...) needs are a higher level IR. Things are also legal in LLVM IR that are not legal in any of the languages it supports, for example, getelementptr can be used with negative indices, etc. Some language rules and optimizations are easy to express in LLVM IR, but there are plenty that are not. You could add metadata, but you'd probably have to extend how metadata works to support a bunch of things, and even then, the community would want metadata designs that multiple language frontends can use, not just yours.
- pklausler 11y ago> Things are also legal in LLVM IR that are not legal in any of the languages it supports, for example, getelementptr can be used with negative indices, etc. Not sure what you're talking about here; what's wrong with negative indices in C?
- kibwen 11y agoI Am Not A Language Lawyer, but there's no way that negative indices aren't UB in C.
- pklausler 11y agoint a[100]; int *p = &a[50]; a[0] = 666; printf("%d\n", p[-50]); Remember that x[y] in C just means *((x)+(y)). You can offset pointers with positive and negative offsets so long as the resulting pointer remains within the bounds of an object. (EDIT: formatting so HN doesn't misinterpret code point U+2A.)
- kibwen 11y agoI'm aware that index notation in C is just sugar for pointer arithmetic, but I'm under the impression that the interpretation of "within the bounds of an object" is less liberal than that demonstrated in your code example. In particular it's not clear to me that a pointer derived from an offset into an existing allocation does not constitute a new object, with its own bounds. Maybe I'm just spoiled by languages with proper slices...