-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Emit range metadata on calls returning scalars (fixes #50157) #50164
Conversation
r? @estebank (rust_highfive has picked a reviewer for you, use r? to override) |
@@ -1055,6 +1055,27 @@ impl<'a, 'tcx> FnType<'tcx> { | |||
PassMode::Indirect(ref attrs) => apply(attrs), | |||
_ => {} | |||
} | |||
if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This duplicates https://github.com/rust-lang/rust/blob/master/src/librustc_trans/mir/place.rs#L93:L116 right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partially yes, there are two differences:
- no
nonnull
metadata is ever emitted for calls, because that's illegal; - boolean scalars don't get
range
metadata because they end up asi1
with a!{i1 false, i1 false}
range otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I could make the range extraction and masking its own method on Scalar
, would you prefer that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about nonnull
, but the calculation of the range (and the relevant comments) should still be de-duplicated.
The i1 part confuses me though. Surely the same problem applies to range metadata on loads? If it is a problem at all, that is: the max_next & mask != min & mask
guard should rule that out already, I think? Did something break without the extra check for bools?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the i1
part: https://botbot.me/mozilla/rustc/2018-04-22/?msg=99259759&page=3
I'll add some comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I could make the range extraction and masking its own method on Scalar, would you prefer that?
I still don't know the layout code well enough for my opinion on this to carry much weight, but this is really an LLVM concept, so maybe it should be in rustc_trans. No real clue where, though.
Note that LLVM ranges with max_next & mask == min & mask
are inherently invalid, so the helper function could return Option<Range<_>>
to avoid duplicating that check as well.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
src/librustc_trans/mir/place.rs
Outdated
layout::Int(..) => { | ||
bx.range_metadata(load, range); | ||
} | ||
layout::Pointer if 0 < range.start && range.start < range.end => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure whether this matters, but this comparison changed. range.end
is equal to the old max_next
, not max
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many things can I inadvertently change in a single piece of code? I think this actually disables a bunch of nonnull
metadata by mistake, but it shouldn't be causing that type checking failure. Will fix anyway.
@bors-servo try Let's see if this actually works for LLVM >3.9. |
Emit range metadata on calls returning scalars (fixes #50157)
☀️ Test successful - status-travis |
src/librustc/ty/layout.rs
Outdated
@@ -648,6 +648,25 @@ impl Scalar { | |||
false | |||
} | |||
} | |||
|
|||
/// Returns a range suitable to be passed to LLVM for range metadata. | |||
pub fn range_metadata<C: HasDataLayout>(&self, cx: C) -> Option<Range<u128>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First off, please do not put LLVM special-cases outside of librustc_trans
. Secondly, could the check be performed by having a way to get the full range for the size of the primitive in question?
We should really assert, somewhere, that start & mask == start
and end & mask == end
, because niche computation relies on it - #49981 already fixed an instance of this invariant not being upheld.
Because then you can just go prim.value.full_valid_range(cx) == prim.valid_range
and that's your check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First off, please do not put LLVM special-cases outside of librustc_trans.
Where should I put that in librustc_trans
, and how? A free-standing function? A method on some C
defined in librustc_trans
? A trait implemented for Scalar
?
Secondly, could the check be performed by having a way to get the full range for the size of the primitive in question?
Nope, 0..=255
isn't equal to 1..=0
, so I doubt this is a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, could this function be named valid_range_exclusive
instead, and have the Option
replaced with a r.start == r.end
in rustc_trans
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
src/librustc_trans/abi.rs
Outdated
layout::Int(..) if !scalar.is_bool() => { | ||
if let Some(range) = scalar.range_metadata(bx.cx) { | ||
// FIXME(nox): This causes very weird type errors about | ||
// SHL operators in constants in stage 2 with LLVM 3.9. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really retire LLVM 3.9, sigh.
src/librustc/ty/layout.rs
Outdated
assert!(bits <= 128); | ||
let mask = !0u128 >> (128 - bits); | ||
let start = self.valid_range.start; | ||
let end = self.valid_range.end.wrapping_add(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, wait, this is turning it into an exclusive range. Whereas the storage uses inclusive. I wonder if we could store exclusive ranges throughout, but that sucks for wrap-around ranges because you end up with 0..0
- we should really have some wrap-around range type for layout specifically.
r? @eddyb |
src/librustc/ty/layout.rs
Outdated
/// Returns the valid range as a `x..y` range. | ||
/// | ||
/// If `x` and `y` are equal, the range is full, not empty. | ||
pub fn range_metadata_exclusive<C: HasDataLayout>(&self, cx: C) -> Range<u128> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please name this valid_range_exclusive
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed and squashed everything.
ee049eb
to
d4c8f37
Compare
src/librustc_trans/mir/place.rs
Outdated
} | ||
layout::Pointer if 0 < min && min < max => { | ||
layout::Pointer | ||
if (1..scalar.valid_range.end).contains(&scalar.valid_range.start) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not !scalar.valid_range.contains(&0)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! Fixed.
d4c8f37
to
cc77dc4
Compare
@bors r+ |
📌 Commit cc77dc4 has been approved by |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
@bors r- |
682ef23
to
55d1cf4
Compare
@bors r+ |
📌 Commit 55d1cf4 has been approved by |
☔ The latest upstream changes (presumably #50228) made this pull request unmergeable. Please resolve the merge conflicts. |
55d1cf4
to
9065644
Compare
@bors r+ |
📌 Commit 9065644 has been approved by |
Emit range metadata on calls returning scalars (fixes #50157)
☀️ Test successful - status-appveyor, status-travis |
No description provided.