Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upmake use of LLVM's scoped noalias metadata #16515
Comments
thestinger
added
I-slow
labels
Aug 15, 2014
This comment has been minimized.
This comment has been minimized.
|
There's already an LLVM pass which converts the |
This comment has been minimized.
This comment has been minimized.
|
I'm aware of that, but we have lots of aliasing information beyond just the outermost pointer in a parameter. |
steveklabnik
added
the
A-LLVM
label
Feb 11, 2015
cmr
self-assigned this
Mar 25, 2015
This comment has been minimized.
This comment has been minimized.
|
In the following code, one would expect #![crate_type = "lib"]
pub unsafe fn a(p: *const usize, g: fn()) -> usize {
let a = *p;
g();
let b = *p;
a ^ b
}
pub unsafe fn b(p: &usize, g: fn()) -> usize {
let a = *p;
g();
let b = *p;
a ^ b
}
pub unsafe fn c(p: *const usize, g: fn()) -> usize {
let p = &*p;
let a = *p;
g();
let b = *p;
a ^ b
}
pub unsafe fn d(p: *const usize, g: fn()) -> usize {
let p = &*p;
b(p, g)
}Applying the information suggested in this issue manually to the IR fixes the issue.
|
cmr
removed their assignment
Jan 5, 2016
aidanhs
referenced this issue
Jan 9, 2017
Open
Missed optimization: references from pointers aren't treated as noalias #38941
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@mahkoh: I'm interested in looking into this — could you provide any more details on what metadata you added to successfully reduce the code generated for |
This comment has been minimized.
This comment has been minimized.
|
Following up on this particular test case, the optimised ( ; a, c
%0 = load i64, i64* %p, align 8
tail call void %g()
%1 = load i64, i64* %p, align 8
%2 = xor i64 %1, %0
ret i64 %2whereas the ideal IR for ; b, d
tail call void %g()
ret i64 0If we manually annotate the IR, so that the body of ; c
%0 = load i64, i64* %p, align 8, !alias.scope !0
tail call void %g(), !noalias !0
%1 = load i64, i64* %p, align 8, !alias.scope !0
%2 = xor i64 %1, %0
ret i64 %2and we add the following domain and scope: !2 = distinct !{!2} ; domain
!1 = distinct !{!1, !2} ; scope
!0 = distinct !{!1} ; scope listthen, after running LLVM's ; c
tail call void %g(), !noalias !0
ret i64 0as we want. |
This comment has been minimized.
This comment has been minimized.
|
Update: the semantics for aliasing guarantees have not by this time been completely well defined — in particular the above transformation is guaranteed (at least now) to be correct. It's probably necessary to wait before implementing any features based on |
This comment has been minimized.
This comment has been minimized.
|
Just in case this is ever useful in the future, I have a branch which optimises the test case using the metadata. Even though it may not be semantically correct, it might be helpful to look at for other alias optimisations in the future. |
This comment has been minimized.
This comment has been minimized.
|
Cc @rust-lang/wg-codegen @rust-lang/compiler This looks like it should be carried to completion by one of us, after @varkor's concern about it being semantically correct or not is addressed. |
This comment has been minimized.
This comment has been minimized.
|
@nox: in particular, we need some examples of test cases that are improved by some |
This comment has been minimized.
This comment has been minimized.
|
IIRC this is blocked on the unsafe code guidelines folks figuring out where aliasing UB starts? cc @RalfJung |
This comment has been minimized.
This comment has been minimized.
|
Sounds reasonable. ;) I'd be hesitant to commit to anything right now though. However, I am fairly close to having a model that (I think) determines some kind of "lower bound" (in the sense of "we want at least this much UB"), so I could try to understand if the examples you have here work under that model. However, longer-term, it'd also be useful for me to actually understand what LLVM's scoped metadata means in general, and how you plan to emit it, so that we can try to get certainty not just for some examples. So, looking at #16515 (comment), we seem to be in agreement that @varkor did you mean to write So, the only "new" example here (that would get optimized now but was not optimized before) is But please hold on with anything related to mutable references. There are some strange corner cases where optimizing within a function is illegal but after moving some code to a separate function it becomes legal: fn legal(x: &mut i32) { unsafe {
let x = x as *mut _ as usize;
let y1 = &mut *(x as *mut i32);
let y2 = &mut *(y1 as *mut i32 as usize as *mut i32);
// these two writes are legal -- y2 is reborrowing from y1, but because
// we went though usize we cannot possibly track where they are "derived from"
*y2 = 4;
*y1 = 3;
// Using y2 again here would be UB
} }
fn illegal(x: &mut i32) { unsafe {
let x = x as *mut _ as usize;
let y1 = &mut *(x as *mut i32);
let y2 = &mut *(y1 as *mut i32 as usize as *mut i32);
bar(y1, y2); // this call must trigger UB
} }
fn bar(y1: &mut i32, y2: &mut i32) {
// we will certainly want to optimize this
*y2 = 4;
*y1 = 3;
}
|
This comment has been minimized.
This comment has been minimized.
pnkfelix
added
T-compiler
WG-codegen
labels
Oct 25, 2018
This was referenced Dec 7, 2018
This comment has been minimized.
This comment has been minimized.
|
It seems that besides the This issue is older than the intrinsic. With the intrinsic now being available, do y'all think that the intrinsic should be better suited than the metadata for Rust's purpose, or is the metadata still preferred? (One of the reasons I am asking is that I hope to start looking at LLVM's |
This comment has been minimized.
This comment has been minimized.
|
@RalfJung The |
This comment has been minimized.
This comment has been minimized.
Oh, seems I misinterpreted the "Accepted" label then. In that case, take my question as the hypothetical "if those patches landed, would Rust prefer that over the metadata?"^^ |
This comment has been minimized.
This comment has been minimized.
|
An RFC has been posted on the LLVM side for extending the support for |
thestinger commentedAug 15, 2014
•
edited by eddyb
Rust could pass along lots of aliasing information to LLVM via the new metadata.
http://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
UPDATE(@eddyb): Currently blocked on an Unsafe Code Guidelines decision, regarding the exact cases we can treat as UB, and optimize - see #16515 (comment) below, and further comments.
While LLVM can and will convert
noaliasattributes in function signatures into scoped!noaliasmetadata on instructions, when inlining, we never emit any such metadata ourselves.Furthermore, the LLVM conversion is conservative (i.e. scoped to the entire callee) in a way that can't easily be generalized intra-function, without deciding on what to define and what to leave as UB.