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

Branch elimination not performed on dead store / failure to introduce a spurious store #114886

Open
SUPERCILEX opened this issue Aug 16, 2023 · 5 comments
Labels
C-bug Category: This is a bug. C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@SUPERCILEX
Copy link
Contributor

I tried this code:

pub fn bar(count: &mut usize, n: usize) {
    for i in 0..n {
        *count = count.wrapping_add(1);
    }
}

I expected to see this happen:

example::bar:
        add     qword ptr [rdi], rsi
        ret

Instead, this happened:

example::bar:
        test    rsi, rsi
        je      .LBB1_2
        add     qword ptr [rdi], rsi
.LBB1_2:
        ret

The missed branch is going to be much more expansive than throwing something in a store buffer. Maybe you could argue the compiler thinks n=0 is going to be common, but I find that unlikely.

I'm pretty sure Rust's ownership system allows inserting stores that didn't exist because an &mut can't be used on another thread.

@SUPERCILEX SUPERCILEX added the C-bug Category: This is a bug. label Aug 16, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 16, 2023
@erikdesjardins
Copy link
Contributor

erikdesjardins commented Aug 16, 2023

I think this may be legal, but we currently don't have any way to tell LLVM about it. The dereferenceable attribute allows introducing reads, but there is no equivalent for writes.

Coincidentally, @nikic just submitted a patch today for a writable attribute...

@SUPERCILEX
Copy link
Contributor Author

Sweet!

cc @RalfJung I assume you've already thought about this case, but I noticed that the PR says tree borrows won't allow this optimization which is a bit of a bummer.

@RalfJung
Copy link
Member

RalfJung commented Aug 17, 2023

I'm pretty sure Rust's ownership system allows inserting stores that didn't exist because an &mut can't be used on another thread.

That's far from clear. Allowing the compiler to introduce such stores has major negative consequences and makes tons of code UB. For instance:

    let mut array = [0, 0];
    std::ptr::copy(array.as_ptr(), array.as_mut_ptr().add(1), 1);

Note that as_mut_ptr takes an &mut rereference. A spurious store to element 0 would make the code UB since it violates immutability of the as_ptr() pointer (which comes from a shared reference, and that's where it gets its immutability from).

We really don't want that code to be UB, so I think we have to disallow spurious stores.

@SUPERCILEX
Copy link
Contributor Author

Ok, the number of issues does seem unpleasant. Do we know what the performance loss is? And is there any way to get it back? I.e. maybe enable stacked borrows locally for some function (with the safety assumption that all code executed within the enabled context must adhere to stacked borrows).

Though this specific issue's optimization is a spurious store which writes the same value that's already there. I agree that the general case where you can write whatever and then undo it as long as that's not visible won't work, but why can't we allow writing the same value as before. Granted, that class of optimizations probably isn't that useful.

@RalfJung
Copy link
Member

RalfJung commented Aug 18, 2023 via email

@RalfJung RalfJung changed the title Branch elimination not performed on dead store Branch elimination not performed on dead store / failure to introduce a spurious store Aug 20, 2023
@Noratrieb Noratrieb added I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 22, 2023
@workingjubilee workingjubilee added the C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such label Oct 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants