Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc_codegen_ssa: Use llvm.invariant intrinsics on arguments that are immutable references; off by default. #103070

Closed
wants to merge 1 commit into from

Commits on Oct 15, 2022

  1. rustc_codegen_ssa: Use llvm.invariant intrinsics on arguments that are

    immutable references; off by default.
    
    Optimization failures around reloads and memcpy optimizations are frequently
    traceable to LLVM's failure to prove that memory can't be mutated by a call or
    store. This problem is especially acute in Rust, where large values tend to be
    memcpy'd more often than in C++. Thankfully, Rust has stronger guarantees on
    mutability available than C++ does, via the strong immutability of `&`
    references. This should allow LLVM to prove that memory can't be modified by
    stores and calls in more cases.
    
    We're already using LLVM's `readonly` parameter attribute on such calls.
    However, the semantics of `readonly` are akin to `const` in C++, in that they
    only promise to LLVM that the function won't mutate the parameter *through that
    pointer*, not that the pointed-to memory is immutable for the entire duration
    of the function. These weak semantics limit the applicability of `readonly` to
    LLVM's alias analysis. Instead of `readonly`, the correct way to express strong
    immutability guarantees on memory is through the `llvm.invariant.start` and
    `llvm.invariant.end` intrinsics. These enable a frontend like `rustc` to
    describe immutability of memory regions in an expressive, flow-sensitive
    manner.
    
    Unfortunately, LLVM doesn't use the `llvm.invariant.start` and
    `llvm.invariant.end` intrinsics for much at the moment. It's only used in one
    optimization in loop-invariant code motion at this time. Follow-up work will
    need to be done in LLVM to integrate these intrinsics into alias analysis.
    Possibly there will need to be some sort of "MemoryInvarianceAnalysis" that
    uses graph reachability algorithms to analyze the extent of the guarantees
    provided by these intrinsics to the control flow graph.
    
    Regardless, this front-end work needs to happen as a prerequisite for any LLVM
    work, so that the improvements to LLVM can be measured and tested. So this
    commit makes `rustc` use `llvm.invariant` in a minimal way: on immutable
    references to "freeze" types (i.e. not transitively containing UnsafeCell)
    passed directly as parameters to functions. This is off by default, gated
    behind the non-default `-Z emit-invariant-markers=yes` flag.
    
    Obviously, a lot more can be done to use `llvm.invariant` more liberally in the
    future, but this can be added over time, especially once more LLVM optimization
    passes use that infrastructure. This is simply the bare minimum for now. Once
    LLVM uses those intrinsics for more optimizations, the effects of more
    `llvm.invariant` use can be measured more precisely.
    pcwalton committed Oct 15, 2022
    Configuration menu
    Copy the full SHA
    5327e78 View commit details
    Browse the repository at this point in the history