[HN Gopher] Tree Borrows
___________________________________________________________________
Tree Borrows
Author : zdw
Score : 376 points
Date : 2025-07-09 14:40 UTC (8 hours ago)
(HTM) web link (plf.inf.ethz.ch)
(TXT) w3m dump (plf.inf.ethz.ch)
| pvg wrote:
| The Stacked Borrows mentioned had threads in 2020 and 2018
|
| https://news.ycombinator.com/item?id=22281205
|
| https://news.ycombinator.com/item?id=17715399
| kibwen wrote:
| Recent blog post from Ralf Jung providing some extra context:
| https://www.ralfj.de/blog/2025/07/07/tree-borrows-paper.html
|
| Bonus: recent talk from Ralf Jung on his group's efforts to
| precisely specify Rust's operational semantics in executable form
| in a dialect of Rust: https://youtube.com/watch?v=yoeuW_dSe0o
| wavemode wrote:
| From the paper:
|
| > The problem with unsafe code is that it can do things like
| this: fn main() { let mut x = 42;
| let ptr = &mut x as *mut i32; let val = unsafe {
| write_both(&mut *ptr, &mut *ptr) };
| println!("{val}"); }
|
| No it can't? Using pointers to coexist multiple mutable
| references to the same variable is undefined behavior. Unless I'm
| just misunderstanding the point they're trying to make here.
| seritools wrote:
| "can do things" in this case doesn't mean "is allowed to do
| things".
|
| "Unsafe code allows to express the following, which is UB:"
| ehsanu1 wrote:
| I believe that's exactly the point: it's too easy to violate
| constraints like not allowing multiple mutable references.
| Unsafe is meant for cases where the validity of the code is
| difficult to prove with rust's lifetime analysis, but can be
| abused to do much more than that.
| pavpanchekha wrote:
| The point of this work is to pin down the exact boundaries of
| undefined behavior. Certainly the code above is _accepted by
| the Rust compiler_ , but it also _breaks rules_. What rules? In
| essence, we know that:
|
| - Anything accepted by the borrow checker is legal
|
| - Unsafe can express illegal / undefined behavior
|
| - There's some set of rules, broader than what the borrow
| checker can check, that is still legal / defined behavior
|
| The goal of this line of work is to precisely specify that set
| of rules. The outlines are clear (basically, no writable
| pointers should alias) but the details (interior pointers,
| invalidation of iterators, is it _creating_ or _using_ bad
| pointers that 's bad, etc) are really hard. The previous paper
| in this series, on Stacked Borrows, was simpler but more
| restrictive, and real-world unsafe code often failed its rules
| (while still seeming correct). Tree Borrows is broader and
| allows more while still being provably safe.
| ralfj wrote:
| > allows more while still being provably safe.
|
| Note that we have not yet proven this. :) I hope to one day
| prove that every program accepted by the borrow checker is
| compatible with TB, but right now, that is only a (very well-
| tested) conjecture.
| sunshowers wrote:
| Hi Ralf! Congrats to you all for the PLDI distinguished
| paper award.
| ralfj wrote:
| Thanks :-)
| oconnor663 wrote:
| You're already getting a lot of replies, and I don't want to
| pile on, but I think the clearest way to see the intent there
| is at the start of the following paragraph:
|
| > Given that aliasing optimizations are something that the Rust
| compiler developers clearly want to support, we need some way
| of "ruling out" counterexamples like the one above from
| consideration.
| ralfj wrote:
| > Using pointers to coexist multiple mutable references to the
| same variable is undefined behavior.
|
| Yes, but which exact rule does it violate? What is the exact
| definition that says that it is UB? Tree Borrows is a proposal
| for exactly such a definition.
|
| "code can do things like this" here means "you can write this
| code and compile it and run it and it will do something, and
| unless we have something like Tree Borrows we have no argument
| for why there would be anything wrong with this code".
|
| You seem to have already accepted that we need something like
| Tree Borrows (i.e., we should say code like this is UB). This
| part of the paper is arguing why we need something like Tree
| Borrows. :)
| GolDDranks wrote:
| > Unless I'm just misunderstanding the point they're trying to
| make here.
|
| You misunderstand the word "can". Yes, you can, in unsafe code,
| do that. And yes, that is undefined behaviour ;)
|
| https://play.rust-lang.org/?version=stable&mode=debug&editio...
| pil0u wrote:
| Just realised that one of the author, Neven Villani, is Cedric
| Villani's (Fields Medal 2010) son. Apples don't fall far from the
| tree, indeed.
| tandr wrote:
| > Apples don't fall far from the tree, indeed.
|
| And one could say that they borrow from the tree some of their
| qualities. Sorry, couldn't resist.
| Yoric wrote:
| Hey, I used to have an office close to the dad's :)
|
| That's before he went into politics, though.
| fuhsnn wrote:
| I wonder if Rust or future PL would evolve into allowing multiple
| borrow checker implementations with varying characteristics
| (compile speed, runtime speed, algorithm flexibility, etc.) that
| projects can choose from.
| speed_spread wrote:
| I cannot imagine how that would work. You couldn't combine code
| that expect different borrowing rules to be applied. You'd
| effectively be creating as many sub-dialects as there are
| borrow checker implementations.
| vlovich123 wrote:
| FWIW technically the rules are the same. How they go about
| proving that the rules are upheld for a program is what would
| be different.
| umanwizard wrote:
| What's wrong with the compile or runtime speed of the current
| one?
| pjmlp wrote:
| We already have that by having multiple approaches via affine
| types (what Rust uses), linear types, effects, dependent types,
| formal proofs.
|
| All have different costs and capabilities across
| implementation, performance and developer experience.
|
| Then we have what everyone else besides Rust is actually going
| for, the productivity of automatic resource management
| (regardless of how), coupled with one of the type systems
| above, only for performance critical code paths.
| LelouBil wrote:
| I would love some sort of affine types in languages like
| Kotlin, it just makes cleaner code organization in my
| opinion.
|
| Doesn't matter if it's purely "syntaxical" because the
| language is garbage collected, just the fact of specifying
| what owns what and be explicit about multiple references is
| great imo.
|
| Some sort of effects systems can already be simulated with
| Kotlin features too.
|
| Programming language theory is so interesting!
| ChadNauseam wrote:
| > affine types (what Rust uses)
|
| I'd just like to interject for a moment. What you're
| referring to as "affine types", is in fact, Uniqueness Types.
| The difference has to do with how they interact with
| unrestricted types. In Rust, these "unrestricted types" are
| references (which can be used multiple times due to
| implementing Copy).
|
| Uniqueness types allow functions to place a constraint on the
| caller ("this argument cannot be aliased when you pass it to
| me"), but places no restriction on the callee. This is useful
| for Rust, because (among other reasons) if a value is not
| aliased you can free it and be sure that you're not leaving
| behind references to freed data.
|
| Affine types are the opposite - they allow the caller to
| place a restriction on the callee ("I'm passing you this
| value, but you may use it at most once"), which is not
| something possible to express in Rust's type system, because
| the callee is always free to create a reference from its
| argument and pass that reference to multiple functions..
| ralfj wrote:
| I would say it is perfectly accurate to call Rust's type
| system affine. At its core, "affine" means that the type
| system has exchange and weakening but not contraction, and
| that exactly characterizes Rust's type system. See <https:/
| /math.stackexchange.com/questions/3356302/substructur...>
| for an explanation of what those terms mean (that's in the
| context of a logic, but it's the same for type systems via
| the Curry-Howard correspondence).
|
| This is often explained via the "do not use more than once
| rule", but that's not the actual definition, and as your
| example shows, following that simplified explanation to the
| letter can cause confusion.
|
| > because the callee is always free to create a reference
| from its argument and pass that reference to multiple
| functions..
|
| Passing a reference is not the same thing as passing the
| actual value, so this does not contradict affinity.
| ChadNauseam wrote:
| > Passing a reference is not the same thing as passing
| the actual value, so this does not contradict affinity.
|
| I agree that passing a reference is not the same thing as
| passing the actual value. If it were, there would really
| be no point to references. However, it does contradict
| affinity. Specifically, the fact that multiple references
| can be created from the same value, combined with the
| properties of references, contradicts affinity.
|
| > At its core, "affine" means that the type system has
| exchange and weakening but not contraction, and that
| exactly characterizes Rust's type system.
|
| Well, the rust type system certainly does support
| contraction, as I can use a reference multiple times. So
| what is that if not contraction? It seems like rust at
| least does support contraction for references.
|
| But in practice, having absolutely no contraction is not
| a very useful definition of affine, because no practical
| programming language would ever satisfy it. It prohibits
| too much and the language would not even be turing
| complete. Instead, there is usually an "affine world" and
| an "exponential world". (Exponential meaning
| "unrestricted" values that you can do whatever you want
| with). And the convention is that values can go from the
| exponential world to the affine world, but not back. So a
| function taking an affine value can be passed any value,
| but must use in in an affine way, and meanwhile but a
| function taking an exponential (unrestricted) value can
| only be passed exponential and not an affine value.
|
| If you don't believe me, you can try using linear
| haskell, and notice that a function taking a linear
| argument can be passed a non-linear argument, but not the
| other way around.
|
| If you interpret Rust's type system this way, it's
| natural to interpret references as exponentials. But
| references have the opposite convention. You can go from
| owned values to references, but not the other way around,
| which is precisely the opposite situation as the
| convention around linear/affine type systems. Because
| these systems feel very different to use and enforce very
| different properties, I do think it's important that we
| have separate names for them rather than referring to
| both as "affine". And the usual name for the rust-like
| system is "uniqueness types", see https://docs.idris-
| lang.org/en/latest/reference/uniqueness-t... or
| https://en.wikipedia.org/wiki/Uniqueness_type .
| ralfj wrote:
| > Well, the rust type system certainly does support
| contraction, as I can use a reference multiple times. So
| what is that if not contraction? It seems like rust at
| least does support contraction for references.
|
| Good question! For shared references, the answer is that
| they are `Copy`, so they indeed have contraction.
| Affinity just means that contraction is not a universal
| property, but some types/propositions may still have
| contraction. For mutable references, you can't _actually_
| use them multiple times. However, there is a desugaring
| phase going on before affinity gets checked, so uses of
| mutable references `r` get replaced by ` &mut *r`
| everywhere. That's not using contraction, it's not
| literally passing `r` somewhere, it is calling a
| particular (and interesting) operating on `r`
| ("reborrowing").
|
| Rust is not just an affine system, it is an affine system
| extended with borrowing. But I think it is still entirely
| fair to call it an affine system, for the simple fact
| that the language will prevent you from "using" a
| variable twice. "reborrowing" is just not a case of
| "using", it is its own special case with its own rules.
|
| > But in practice, having absolutely no contraction is
| not a very useful definition of affine,
|
| Obviously Rust has a class of "duplicable" types, called
| `Copy`. That's besides the point though.
|
| > If you interpret Rust's type system this way, it's
| natural to interpret references as exponentials.
|
| Why would that be natural? Mutable references are not
| even duplicable, so what you say makes little sense for
| references in general. Maybe you mean shared references
| -- those are just an example of a duplicable type.
|
| Rust doesn't have a modality in its type system that
| would make every type duplicable, so there is no
| equivalent to exponentials. (In particular, `&T` isn't a
| modality around `T`. It's a different type, with a
| different representation. And as you noted, even if it
| were a modality, it wouldn't correspond to exponentials.)
|
| But a type system can be affine/linear without having
| exponentials so I don't understand the point of this
| remark.
|
| Uniqueness types seem to be all about how many references
| there are to a value. You can use linear/affine types to
| enforce such a uniqueness property (and that is indeed
| what Rust does), but that doesn't take away from the fact
| that you have a linear/affine type system.
|
| > Because these systems feel very different to use and
| enforce very different properties,
|
| I can't talk about the "feel" as I never programmed in an
| affine language (other than Rust ;), but in terms of the
| properties, what Rust does is extremely closely related
| to affine logics: the core property being enforced is
| that things do not get duplicated. My model of Rust,
| RustBelt, uses an affine separation logic to encode the
| properties of the Rust type system, and there's a lot of
| overlap between separation logic and linear logic. So we
| have further strong evidence here that it makes perfect
| sense to call Rust an affine language.
| caim wrote:
| The main point of Affine logic is that it doesn't allow
| contraction, and the Rust type system does allow
| different forms of contraction. How exactly is Rust an
| "affine language"?
|
| Also, the claims about Curry-Howard correspondence are
| wrong. It does not prove that rust is an affine language:
| https://liamoc.net/forest/loc-000S/index.xml
|
| But Swift DOES have affine types with the "Non copyable"
| types that doesn't allow contraction.
| hollerith wrote:
| Rust has types that don't allow contraction (i.e., being
| used twice), too: e.g., String, vectors and boxes.
|
| Their being that way is essential for the borrow checker
| to provide the memory-safety guarantees it provides.
| caim wrote:
| Yep, that's true. But multiple immutable shared
| references are a form of contraction, while mutable
| references are actually affine.
|
| Swift doesn't have references like Rust, and you can't
| even have unsafe raw pointers to variables without
| producing a dangling pointer, but this makes Swift more
| restrictive and less powerful than Rust.
| caim wrote:
| Yeah, that makes sense. The Rust type system isn't "affine"
| as in affine logic. Rust allows different forms of
| contraction, which affine logic strictly prohibits.
|
| And some people like to claim that the Curry-Howard
| correspondence proves something about their type system,
| but this is only true for dependently typed languages.
|
| And the proofs aren't about program behavior.
|
| See, https://liamoc.net/forest/loc-000S/index.xml
| 0x000xca0xfe wrote:
| As I understand it the borrow checker only has false negatives
| but no false positives, correct?
|
| Maybe a dumb question but couldn't you just run multiple
| implementations in parallel threads and whichever finishes
| first with a positive result wins?
| vlovich123 wrote:
| This presumes that checking composes which may not if you
| have orthogonal checker implementations. You might end up
| risking accepting an invalid program because part of it is
| valid under one checker, part under another, but the
| combination isn't actually valid. But maybe that's not
| actually possible in practice.
| afdbcreid wrote:
| Borrow checking is function-local, so if the opsem model is
| the same and you run the different checkers per-function,
| there is no such risk.
| sunshowers wrote:
| That would result in ecosystem splitting, which isn't great.
| pornel wrote:
| Rust already supports switching between borrow checker
| implementations.
|
| It has migrated from a scope-based borrow checker to non-
| lexical borrow checker, and has next experimental Polonius
| implementation as an option. However, once the new
| implementation becomes production-ready, the old one gets
| discarded, because there's no reason to choose it. Borrow
| checking is fast, and the newer ones accept strictly more
| (correct) programs.
|
| You also have Rc and RefCell types which give you greater
| flexibility at cost of some runtime checks.
| Ericson2314 wrote:
| What you actually want is the underlying separation logic, so
| you can precisely specify function preconditions and prove mid-
| function conditions, and the the optomizer can take all those
| "lemmas" and go hog-wiled, right up to but _not past_ what is
| allowed by the explicitly stated invariants.
|
| "Rust", in this context, is "merely" "the usual invariants that
| people want" and "a suite of optimizations that assume those
| usual invariants, but not more or less".
| Voultapher wrote:
| Amazing work, I remember reading the Tree Borrows spec? on
| Nevin's website a couple years ago and being thoroughly impressed
| by how it solves some pretty gnarly issue quite elegantly. And in
| my experience [1] [2] it does indeed allow for sensible code that
| is illegal under Stacked Borrows.
|
| [1] https://github.com/Voultapher/sort-research-
| rs/blob/main/wri... Miri column
|
| [2] https://github.com/rust-
| lang/rust/blob/6b3ae3f6e45a33c2d95fa...
| vollbrecht wrote:
| Hmm i just tested out the claim that the following rust code
| would be rejected ( Example 4 in the paper).
|
| And it seams to not be the case on the stable compiler version?
| fn write(x: &mut i32) {*x = 10} fn main() {
| let x = &mut 0; let y = x as *mut i32;
| //write(x); // this should use the mention implicit twophase
| borrow *x = 10; // this should not and therefore be
| rejected by the compiler unsafe {*y = 15 }; }
| Arnavion wrote:
| Stacked borrows is miri's runtime model. Run it under miri and
| you will see the error reported for the `*x = 10;` version but
| not the `write(x);` version - "Undefined Behavior: attempting a
| write access using [...] but that tag does not exist in the
| borrow stack for this location".
|
| rustc itself has no reason to reject either version, because y
| is a *mut and thus has no borrow/lifetime relation to the &mut
| that x is, from a compile-time/typesystem perspective.
| vollbrecht wrote:
| Ah that make sense. Thanks for clarifying.
| jcalvinowens wrote:
| > On the one hand, compilers would like to exploit the strong
| guarantees of the type system--particularly those pertaining to
| aliasing of pointers--in order to unlock powerful intraprocedural
| optimizations.
|
| How true is this really?
|
| Torvalds has argued for a long time that strict aliasing rules in
| C are more trouble than they're worth, I find his arguments
| compelling. Here's one of many examples:
| https://lore.kernel.org/all/CAHk-=wgq1DvgNVoodk7JKc6BuU1m9Un...
| (the entire thread worth reading if you find this sort of thing
| interesting)
|
| Is Rust somehow fundamentally different? Based on limited
| experience, it seems not (at least, when unsafe is involved...).
| ralfj wrote:
| I would agree that C's strict aliasing rules are terrible. The
| rules we are proposing for Rust are very different. They are
| both more useful for compilers and, in my opinion, less onerous
| for programmers. We also have an actual in-language opt-out:
| use raw pointers. And finally, we have a tool you can use to
| check your code.
|
| But in the end, it's a trade-off, like everything in language
| design. (In life, really. ;) We think that in Rust we may have
| found a new sweet spot for this kind of optimizations. Time
| will tell whether we are right.
| kookamamie wrote:
| Agreed about C's aliasing rules. Fortran had a better set of
| defaults.
| NobodyNada wrote:
| As someone who has been writing a lot of unsafe Rust (mostly
| in an embedded context), I'm thrilled about and thankful for
| the work that you, your students, and the opsem team are
| doing.
|
| When you're working with anything below the application
| level, C's confusing and underspecified rules about UB are
| almost impossible to keep track of, especially when it comes
| to aliasing and volatile/MMIO. The spec is so difficult to
| read and full of complicated cross-references that to
| actually get a practical answer you have to look for a random
| Stack Overflow post that may or may not have a correct
| interpretation of the spec, and may or may not address your
| specific problem.
|
| Rust right now feels a lot harder to work with, because the
| spec isn't done. When you have a concrete question about a
| piece of code, like "is this conversion from an &mut to a
| *mut and back sound", and you try to look for documentation
| on it, you get either "Nobody knows, Rust aliasing model
| isn't defined"; a hand-wavy explanation that is not rigorous
| or specific; or a model like Stack Borrows or Tree Borrows
| that's defined a little too formally for easy digestion :)
|
| But when I really started digging, I realized just how much
| _cleaner_ Rust 's semantics are. References aren't actually
| _hard_ , Tree Borrows basically boils down to "while an &mut
| reference is live, you can only access the value through
| pointers or references derived from that reference". Pointer
| operations have straightforward semantics, there's no
| confusing notions of typed memory, and no UB "just because"
| for random things like integer overflow. It's just so much
| less complicated to understand than C's abstract machine.
|
| I'm really looking forward to things like MiniRust, and to an
| aliasing model making it into the Reference / other
| documentation, because at that point I feel like unsafe Rust
| will be _way_ easier to write confidently and correctly than
| C.
|
| Congrats on the publication, and thanks again for the work
| you all have put into this.
| Asooka wrote:
| While I can't name the product I work on, we also use -fno-
| strict-aliasing. The problem with these optimisations is that
| they can only be done safely if you can prove aliasing never
| happens, which is equivalent to solving the halting problem in
| C++. In Rust I suspect the stronger type system can actually
| prove that aliasing doesn't happen in select cases. In any
| case, I can always manually do the optimisations enabled by
| strict aliasing in hot code, but I can never undo a customer
| losing data due to miscompilation.
| pornel wrote:
| > actually prove that aliasing doesn't happen in select cases
|
| In the safe subset of Rust it's guaranteed in _all_ cases.
| Even across libraries. Even in multi-threaded code.
| oconnor663 wrote:
| To elaborate on that some more, safe Rust can guarantee
| that mutable aliasing never happens, without solving the
| halting program, because it forbids some programs that
| could've been considered legal. Here's an example of a
| function that's allowed: fn foo() {
| let mut x = 42; let mut mutable_references =
| Vec::new(); let test: bool = rand::random();
| if test { mutable_references.push(&mut x);
| } else { mutable_references.push(&mut x);
| } }
|
| Because only one if/else branch is ever allowed to execute,
| the compiler can see "lexically" that only one mutable
| reference to `x` is created, and `foo` compiles. But this
| other function that's "obviously" equivalent doesn't
| compile: fn bar() { let mut x
| = 42; let mut mutable_references = Vec::new();
| let test: bool = rand::random(); if test {
| mutable_references.push(&mut x); }
| if !test { mutable_references.push(&mut x);
| // error: cannot borrow `x` as mutable more than once at a
| time } }
|
| The Rust compiler doesn't do the analysis necessary to see
| that only one of those branches can execute, so it
| conservatively assumes that both of them can, and it
| refuses to compile `bar`. To do things like `bar`, you have
| to either refactor them to look more like `foo`, or else
| you have to use `unsafe` code.
| steveklabnik wrote:
| While both involve aliasing, C's strict aliasing and Rust's
| aliasing are two different things. Rust pretty explicitly did
| not adopt the C style.
|
| C's aliasing is based on type alone, hence its other name "type
| based alias analysis" or TBAA.
| dzaima wrote:
| Rust's aliasing rules are very different from C's.
|
| In C you have a nuclear `restrict` that in my experience does
| anything only when applied to function arguments across clang &
| gcc, and type-based aliasing which is both not a generally-
| usable thing (don't have infinite different copies of the
| int64_t type (and probably wouldn't want such either)), and
| annoying (forces using memcpy if you want to reinterpret to a
| different type).
|
| Whereas with Rust references you have finely-bounded lifetimes
| and spans and mutability, and it doesn't actually care about
| the "physical" types, so it is possible to reinterpret memory
| as both `&mut i32`/`&i32` and `&mut i64`/`&i64` and switch
| between the two for the same memory, writing/reading halves
| of/multiple values by the most bog standard Rust safe reads &
| writes, as long as the unsafe abstraction never gives you
| overlapping `&mut` references at the same time, or split a
| `&mut` into multiple non-overlapping `&mut`s.
| jandrewrogers wrote:
| Strict aliasing rules are useful conditional on them being
| sufficiently expressive and sensible, otherwise they just
| create pointless headaches that require kludgy workarounds or
| they are just disabled altogether. I don't think there is much
| disagreement that C strict aliasing rules are pretty broken.
| There is no reason a language like Rust can't be designed with
| much more sensible strict aliasing rules. Even C++ has invested
| in providing paths to more flexibility around strict aliasing
| than C provides.
|
| But like Linus, I've noticed it doesn't seem to make much
| difference outside of obvious narrow cases.
| ivanbakel wrote:
| >How true is this really?
|
| I'd be interested to see a more thorough analysis, but there is
| a simple way to gauge this - rip out all the parts of the
| compiler where aliasing information is propagated to LLVM, and
| see what happens to performance.
|
| I found a claim that noalias contributes about 5% performance
| improvement in terms of runtimes[0], though the data is
| obviously very old.
|
| https://github.com/rust-lang/rust/issues/54878#issuecomment-...
| jcranmer wrote:
| Take anything Linus says about compilers with a grain of salt--
| he writes OS kernels, not compilers, and those are pretty
| different domains.
|
| Alias analysis is _extremely_ important for getting good
| performance these days--but it should also be remembered that
| the biggest benefits accrue from the simplest heuristics (like
| two loads that use the same SSA value as the pointer must alias
| each other). In LLVM terms, that 's BasicAA: a collection of
| very simple heuristics that primarily amounts to "if we can
| track down the allocation sites of objects, we can definitively
| resolve these alias queries; otherwise, we don't know."
|
| The real question that you're trying to ask, though, is what is
| the value of alias analyses that go beyond the most basic,
| obvious tests. At the point where the alias queries are no
| longer trivial to solve, then it's generally the case that what
| you can do as a result of those queries also shrinks
| dramatically, pretty much to looking for code motion hazards,
| and the benefits you get from that are much reduced. One of the
| experiments I would like to do is measure the total speedup
| you'd get from a theoretically perfect alias analysis, and my
| guess is that it's somewhere in the 20% range even on non-HPC
| code like the Linux kernel [1].
|
| [1] This doesn't account for the heroic optimizations, such as
| data-layout transformations, that you wouldn't attempt to write
| without a very high-quality alias analysis. But since we
| already know that alias analysis doesn't exist in practice,
| we're not going to attempt those optimizations anyways, so it's
| not worth including such stuff in prospective speed gains.
| oconnor663 wrote:
| Here's another data point: https://lobste.rs/s/yubalv/pointer
| s_are_complicated_ii_we_ne...
|
| > I spoke to Apple folks when their compiler team switched
| the default to strict aliasing. They reported that it made
| key workloads 5-10% faster and the fixes were much easier to
| do and upstream than I would have expected. My view of
| -fstrict-aliasing at the time was that it was a flag that let
| you generate incorrect code that ran slightly faster. They
| had actual data that convinced me otherwise.
| tliltocatl wrote:
| It is mostly useful on arrays/numeric code, probably next to
| useless otherwise. Numerics people was the ones who sponsored
| much of compiler/optimization work in the first place, that's
| how strict aliasing came to be.
| dzaima wrote:
| I don't think the usefulness is that skewed towards numerics?
|
| Both clang/llvm and gcc can do alias checking at runtime if
| they can't at compile-time, which makes loops vectorizable
| without alias info, at the cost of a bit of constant overhead
| for checking aliasing. (there's the exception of gather loads
| though, where compile-time aliasing info is basically
| required)
|
| And on the other hand there's good potential for benefit to
| normal code (esp. code with layers of abstractions) - if you
| have a `&i32`, or any other immutable reference, it's pretty
| useful for compiler to be able to deduplicate/CSE
| loads/computations from it from across the whole function
| regardless of what intermediate writes to potentially-other
| things there are.
| gavinhoward wrote:
| This looks excellent. I will probably implement this model for my
| own language.
| Nurbek-F wrote:
| It can't be a dejavu. I keep seeing this post every 2-3 months...
| steveklabnik wrote:
| The paper is years in the making. This is it finally being
| published.
| olddustytrail wrote:
| _Tree Borrows_
|
| "I want my fuckin' money back."
|
| "Hoom, hmm, let us not be hasty!"
|
| "You got 48 hours to deliver or the sapling gets it, Treebeard."
___________________________________________________________________
(page generated 2025-07-09 23:00 UTC)