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

Mark &mut pointers as noalias once LLVM no longer miscompiles them #31681

Closed
bstrie opened this Issue Feb 15, 2016 · 26 comments

Comments

Projects
None yet
@bstrie
Contributor

bstrie commented Feb 15, 2016

This issue tracks the undoing of the workaround introduced in #31545 on account of a bug in LLVM. cc @dotdash

@jplatte

This comment has been minimized.

Show comment
Hide comment
@jplatte

jplatte Feb 18, 2016

Contributor

Was just reading about this, and it was a little hard to find the LLVM bug report, so for reference, here it is.

Contributor

jplatte commented Feb 18, 2016

Was just reading about this, and it was a little hard to find the LLVM bug report, so for reference, here it is.

@eefriedman

This comment has been minimized.

Show comment
Hide comment
@eefriedman

eefriedman May 31, 2016

Contributor

I've been working through the LLVM optimization passes to find noalias-related bugs. Known issues:

Some of these are less important because they can't caused a wrong value, only a segfault.

There are probably a few more lurking issues, but hopefully I've found most of them.


(Edited by bluss 2016-12-15 to strike out fixed bug)
(Edited by mbrubeck 2017-03-30 to link to new LLVM bugzilla domain)
(Edited by scottmcm 2018-03-29 to strike out fixed bug)

Contributor

eefriedman commented May 31, 2016

I've been working through the LLVM optimization passes to find noalias-related bugs. Known issues:

Some of these are less important because they can't caused a wrong value, only a segfault.

There are probably a few more lurking issues, but hopefully I've found most of them.


(Edited by bluss 2016-12-15 to strike out fixed bug)
(Edited by mbrubeck 2017-03-30 to link to new LLVM bugzilla domain)
(Edited by scottmcm 2018-03-29 to strike out fixed bug)

@mrhota

This comment has been minimized.

Show comment
Hide comment
@mrhota

mrhota Aug 6, 2016

Contributor

@eefriedman LLVM bug 27859 is closed.

Contributor

mrhota commented Aug 6, 2016

@eefriedman LLVM bug 27859 is closed.

bluss added a commit to bluss/rust that referenced this issue Sep 8, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bluss added a commit to bluss/rust that referenced this issue Sep 8, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bluss added a commit to bluss/rust that referenced this issue Sep 8, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bluss added a commit to bluss/rust that referenced this issue Sep 8, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bluss added a commit to bluss/rust that referenced this issue Sep 8, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bluss added a commit to bluss/rust that referenced this issue Sep 9, 2016

Work around pointer aliasing issue in Vec::extend_from_slice, extend_…
…with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

bors added a commit that referenced this issue Sep 12, 2016

Auto merge of #36355 - bluss:vec-extend-from-slice-aliasing-workaroun…
…d, r=alexcrichton

Work around pointer aliasing issue in Vec::extend_from_slice, extend_with_element

Due to missing noalias annotations for &mut T in general (issue #31681),
in larger programs extend_from_slice and extend_with_element may both
compile very poorly. What is observed is that the .set_len() calls are
not lifted out of the loop, even for `Vec<u8>`.

Use a local length variable for the Vec length instead, and use a scope
guard to write this value back to self.len when the scope ends or on
panic. Then the alias analysis is easy.

This affects extend_from_slice, extend_with_element, the vec![x; n]
macro, Write impls for Vec<u8>, BufWriter, etc (but may / may not
have triggered since inlining can be enough for the compiler to get it right).

Fixes #32155
Fixes #33518
Closes #17844
@gnzlbg

This comment has been minimized.

Show comment
Hide comment
@gnzlbg

gnzlbg Sep 15, 2016

Contributor

@eefriedman bug 25422 should be fixed.

Any progress on bug 27860 ?


(Edited by mbrubeck 2017-03-30 to link to new LLVM bugzilla domain)

Contributor

gnzlbg commented Sep 15, 2016

@eefriedman bug 25422 should be fixed.

Any progress on bug 27860 ?


(Edited by mbrubeck 2017-03-30 to link to new LLVM bugzilla domain)

@pmarcelll

This comment has been minimized.

Show comment
Hide comment
@pmarcelll

pmarcelll Jan 16, 2017

Contributor

NewGVN was recently merged into LLVM (still experimental), it's a rewrite of the global value numbering algorithm. The last remaining bug on our list is bug in the old gvn implementation. I compiled the example codes in the bug report with the new gvn algorithm, and they work fine, so hopefully LLVM 5.0 will stabilize NewGVN and we can turn this optimization back on.
EDIT: NewGVN integration into LLVM tracked here

Contributor

pmarcelll commented Jan 16, 2017

NewGVN was recently merged into LLVM (still experimental), it's a rewrite of the global value numbering algorithm. The last remaining bug on our list is bug in the old gvn implementation. I compiled the example codes in the bug report with the new gvn algorithm, and they work fine, so hopefully LLVM 5.0 will stabilize NewGVN and we can turn this optimization back on.
EDIT: NewGVN integration into LLVM tracked here

@jrmuizel

This comment has been minimized.

Show comment
Hide comment
@jrmuizel

jrmuizel Jul 20, 2017

Contributor

I talked with Davide Italiano from LLVM and the goal is for NewGVN to be turned on in LLVM 6.0.
Given that and the fact that https://bugs.llvm.org//show_bug.cgi?id=27860 also affects code that doesn't use restrict/noalias I wonder if we could try turning this on? Even if we could only use this when compiling in panic=abort mode (as it seems many of the codegen issues were related to exceptions).

#42047 is a reduced test case of a real performance problem that's helped by this that we're running into with WebRender so it would be nice to fix this sooner rather than later.

Contributor

jrmuizel commented Jul 20, 2017

I talked with Davide Italiano from LLVM and the goal is for NewGVN to be turned on in LLVM 6.0.
Given that and the fact that https://bugs.llvm.org//show_bug.cgi?id=27860 also affects code that doesn't use restrict/noalias I wonder if we could try turning this on? Even if we could only use this when compiling in panic=abort mode (as it seems many of the codegen issues were related to exceptions).

#42047 is a reduced test case of a real performance problem that's helped by this that we're running into with WebRender so it would be nice to fix this sooner rather than later.

@Vurich

This comment has been minimized.

Show comment
Hide comment
@Vurich

Vurich Aug 2, 2017

I support enabling this if and only if panic = "abort". Even if having the codegen be different depending on panic mode is not currently supported it would be something deserving of an RFC in my opinion, since there are a bunch of possible optimisations that this could enable, like removing zeroing when initialising an array.

Maybe if "treat function calls as possible branch point" is a function-level annotation in LLVM the only difference would be emitting/not emitting that.

Vurich commented Aug 2, 2017

I support enabling this if and only if panic = "abort". Even if having the codegen be different depending on panic mode is not currently supported it would be something deserving of an RFC in my opinion, since there are a bunch of possible optimisations that this could enable, like removing zeroing when initialising an array.

Maybe if "treat function calls as possible branch point" is a function-level annotation in LLVM the only difference would be emitting/not emitting that.

@jrmuizel

This comment has been minimized.

Show comment
Hide comment
@jrmuizel

jrmuizel Aug 4, 2017

Contributor

Is it possible for us to get a cargobomb run with the patch reverted to see if we trigger any bad codegen?

Contributor

jrmuizel commented Aug 4, 2017

Is it possible for us to get a cargobomb run with the patch reverted to see if we trigger any bad codegen?

@dpc

This comment has been minimized.

Show comment
Hide comment
@dpc

dpc Aug 5, 2017

Contributor

Any best guesses when this improvement would be available in Rust nightly (with and without panic = "abort")? It would affect the design and implementation of performance critical crates I'm working on. If it's couple of months, it might be worth waiting. If it's a year, it might be worth to workaround in the code.

Contributor

dpc commented Aug 5, 2017

Any best guesses when this improvement would be available in Rust nightly (with and without panic = "abort")? It would affect the design and implementation of performance critical crates I'm working on. If it's couple of months, it might be worth waiting. If it's a year, it might be worth to workaround in the code.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Aug 6, 2017

Contributor

@eefriedman

Is PR27860 actually a problem for Rust? I think every time we emit noalias we also emit dereferencable. Unless LLVM considers every GEP of the pointer as dereferencable, even in the presence of e.g. bounds checks (oops).

Contributor

arielb1 commented Aug 6, 2017

@eefriedman

Is PR27860 actually a problem for Rust? I think every time we emit noalias we also emit dereferencable. Unless LLVM considers every GEP of the pointer as dereferencable, even in the presence of e.g. bounds checks (oops).

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Aug 6, 2017

Contributor

PR27860 is actually a problem even with &-references - this segfaults:

#![feature(test)]

extern crate test;

extern "C" {
    fn abort();
}

#[no_mangle]
#[inline(never)]
pub fn abuseme(x: &[u8]) -> u8 {
    if x.len() > 0x10000000000 {
        test::black_box(x[0x10000000000]);
    }
    unsafe { abort(); }
    unsafe { *x.get_unchecked(0x10000000000) }
}

fn main() {
    abuseme(&[]);
}
Contributor

arielb1 commented Aug 6, 2017

PR27860 is actually a problem even with &-references - this segfaults:

#![feature(test)]

extern crate test;

extern "C" {
    fn abort();
}

#[no_mangle]
#[inline(never)]
pub fn abuseme(x: &[u8]) -> u8 {
    if x.len() > 0x10000000000 {
        test::black_box(x[0x10000000000]);
    }
    unsafe { abort(); }
    unsafe { *x.get_unchecked(0x10000000000) }
}

fn main() {
    abuseme(&[]);
}
@Vurich

This comment has been minimized.

Show comment
Hide comment
@Vurich

Vurich Aug 8, 2017

@arielb1 Does that violate Rust's guarantees though? I don't know that there's any guarantees about reordering when it comes to calling extern functions. What happens if you explicitly annotate the type as fn abort() -> !?

Vurich commented Aug 8, 2017

@arielb1 Does that violate Rust's guarantees though? I don't know that there's any guarantees about reordering when it comes to calling extern functions. What happens if you explicitly annotate the type as fn abort() -> !?

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Aug 9, 2017

Contributor

@Vurich

Of course there are guarantees about reordering about extern functions - otherwise read etc. would never work. You could also replace the abort with a read of a forever-empty pipe or something to avoid it needing to be annotated with !.

Contributor

arielb1 commented Aug 9, 2017

@Vurich

Of course there are guarantees about reordering about extern functions - otherwise read etc. would never work. You could also replace the abort with a read of a forever-empty pipe or something to avoid it needing to be annotated with !.

@arielb1 arielb1 closed this Aug 9, 2017

@arielb1 arielb1 reopened this Aug 9, 2017

@oyvindln

This comment has been minimized.

Show comment
Hide comment
@oyvindln

oyvindln Aug 9, 2017

Contributor

I support enabling this if and only if panic = "abort".

Maybe a -Z enable-noalias or similar option could be added as a start to make it easier to test where the lack of noalias makes a difference.

Contributor

oyvindln commented Aug 9, 2017

I support enabling this if and only if panic = "abort".

Maybe a -Z enable-noalias or similar option could be added as a start to make it easier to test where the lack of noalias makes a difference.

@bstrie bstrie added the I-slow label Sep 15, 2017

@matthiaskrgr

This comment has been minimized.

Show comment
Hide comment
@matthiaskrgr

matthiaskrgr Sep 15, 2017

Contributor

@oyvindln if you want to turn on newgvn to compare things, RUSTFLAGS="-C llvm-args=-enable-newgvn" might work.

Contributor

matthiaskrgr commented Sep 15, 2017

@oyvindln if you want to turn on newgvn to compare things, RUSTFLAGS="-C llvm-args=-enable-newgvn" might work.

@pcwalton

This comment has been minimized.

Show comment
Hide comment
@pcwalton

pcwalton Sep 28, 2017

Contributor

It's unclear from reading this what the state of this bug is. Do we still believe that NewGVN will fix this issue?

Contributor

pcwalton commented Sep 28, 2017

It's unclear from reading this what the state of this bug is. Do we still believe that NewGVN will fix this issue?

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Sep 28, 2017

Contributor

@pcwalton

I think all "noalias-exclusive" bugs are fixed, so it might be worth giving it a try and opening a PR.

Contributor

arielb1 commented Sep 28, 2017

@pcwalton

I think all "noalias-exclusive" bugs are fixed, so it might be worth giving it a try and opening a PR.

@cuviper

This comment has been minimized.

Show comment
Hide comment
@cuviper

cuviper Sep 28, 2017

Member

Does that enablement need to be conditional on LLVM version?

Member

cuviper commented Sep 28, 2017

Does that enablement need to be conditional on LLVM version?

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Sep 28, 2017

Contributor

I think. 4.0 should be fine.

Contributor

arielb1 commented Sep 28, 2017

I think. 4.0 should be fine.

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Oct 20, 2017

Contributor

Update: there's now a -Z flag for opting-in to this on an experimental basis: #45012. It also seems as though the behavior is enabled by default for panic=abort builds. However, I think this might be worth keeping open until we concretely determine whether or not we'll be able to turn this on for panic=unwind builds (see #45029 ).

Contributor

bstrie commented Oct 20, 2017

Update: there's now a -Z flag for opting-in to this on an experimental basis: #45012. It also seems as though the behavior is enabled by default for panic=abort builds. However, I think this might be worth keeping open until we concretely determine whether or not we'll be able to turn this on for panic=unwind builds (see #45029 ).

@alexbool

This comment has been minimized.

Show comment
Hide comment
@alexbool

alexbool Feb 11, 2018

Contributor

What's the state of this given that LLVM has been upgraded to 6.0?

Contributor

alexbool commented Feb 11, 2018

What's the state of this given that LLVM has been upgraded to 6.0?

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Mar 3, 2018

Member

To help finding this issue: the -Z flag is mutable_noalias.

Member

scottmcm commented Mar 3, 2018

To help finding this issue: the -Z flag is mutable_noalias.

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Mar 30, 2018

Member

Looks like the last part of the checklist above landed with https://reviews.llvm.org/D38619#937247

Member

scottmcm commented Mar 30, 2018

Looks like the last part of the checklist above landed with https://reviews.llvm.org/D38619#937247

@nox

This comment has been minimized.

Show comment
Hide comment
@nox

nox Apr 2, 2018

Contributor

Should we make a PR to always enable mutable_noalias and see what happens on the CI and Crater?

Cc @rust-lang/wg-codegen

Contributor

nox commented Apr 2, 2018

Should we make a PR to always enable mutable_noalias and see what happens on the CI and Crater?

Cc @rust-lang/wg-codegen

nikic added a commit to nikic/rust that referenced this issue May 14, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.

nikic added a commit to nikic/rust that referenced this issue May 14, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.

nikic added a commit to nikic/rust that referenced this issue May 14, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.

nikic added a commit to nikic/rust that referenced this issue May 14, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.

nikic added a commit to nikic/rust that referenced this issue May 17, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

Noalias annotations will not be emitted by default if either
-C panic=abort (as previously) or LLVM >= 6.0 (new).

-Z mutable-noalias=no is left as an escape-hatch to allow
debugging problems suspected to stem from this change.

nikic added a commit to nikic/rust that referenced this issue May 17, 2018

Emit noalias on &mut parameters by default
This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

Noalias annotations will not be emitted by default if either
-C panic=abort (as previously) or LLVM >= 6.0 (new).

-Z mutable-noalias=no is left as an escape-hatch to allow
debugging problems suspected to stem from this change.

bors added a commit that referenced this issue May 19, 2018

Auto merge of #50744 - nikic:mutable-noalias, r=alexcrichton
Emit noalias on &mut parameters by default

This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.

bors added a commit that referenced this issue May 19, 2018

Auto merge of #50744 - nikic:mutable-noalias, r=alexcrichton
Emit noalias on &mut parameters by default

This used to be disabled due to LLVM bugs in the handling of
noalias information in conjunction with unwinding. However,
according to #31681 all known LLVM bugs have been fixed by
LLVM 6.0, so it's probably time to reenable this optimization.

-Z no-mutable-noalias is left as an escape-hatch to debug problems
suspected to stem from this change.
@nikic

This comment has been minimized.

Show comment
Hide comment
@nikic

nikic May 21, 2018

Contributor

As #50744 has landed, this can be closed.

Contributor

nikic commented May 21, 2018

As #50744 has landed, this can be closed.

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton
Member

alexcrichton commented May 21, 2018

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment