-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Get rid of the Scalar
and ScalarPair
variants of ConstValue
...
#55260
Conversation
@bors try for perf run |
Get rid of the `Scalar` and `ScalarPair` variants of `ConstValue`... ... by always using `ByRef` and reading the scalars from the backing `Allocation` where desired Oh god this uncovered so many bugs and bugs-just-waiting-to-happen. I'm still not fully done, but I don't want to grow this PR any further. It is in a sane state except for the `const_field` function, which was hacky to begin with. fixes #54738 r? @RalfJung
@rust-timer build f3100df |
Bors try commit f3100df unexpectedly has 1 parents. |
💔 Test failed - status-travis |
Your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem. 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 |
@rust-timer build 621ca4e (Need to give the merge commit.) |
Success: Queued 621ca4e with parent a66dc8a, comparison URL. |
@bors try (checkout failure, I don't think perfbot has anything to run perf on) |
Your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem. 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 |
Everything seems stuck, not sure what to do, cycling the PR |
I'd be more confident that all this code actually does the right thing if it was used by memory, and if you verified that miri still works on top of it. |
/// if this is ByRef, return the same thing but with the offset increased by `n` | ||
pub fn try_offset(&self, n: Size) -> Option<Self> { | ||
let (id, alloc, offset) = self.try_as_by_ref()?; | ||
Some(ConstValue::ByRef(id, alloc, offset + n)) |
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 have complex and subtle code to do overflow-aware (which is architecture-dependent) pointer arithmetic. We surely shouldn't just do plain addition here.
} | ||
|
||
#[inline] | ||
pub fn try_get_bytes(&self, hdl: impl HasDataLayout, n: Size, align: Align) -> Option<&[u8]> { |
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.
hdl
? We usually called this cx
, didn't we?
tcx.data_layout().endian, | ||
&mut alloc.bytes[i..j], | ||
int.into(), | ||
).unwrap(); |
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.
Uh, so here we are duplicating write_sclar
? Not good. You moved so many methods here, including read_scalar
, why not also write_scalar
?
ty::tls::with(|tcx| { | ||
let (s, o) = { | ||
let map = tcx.alloc_map.lock(); | ||
(map.get(*self), map.get(*other)) |
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.
Uh, wait, what? That doesn't seem right to me.
Certainly, ptr comparison in miri should compare the actual IDs, the the content that's stored behind these IDs. What is the type of s
and o
here?
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 only applies to AllocId
s that refer to global allocations. Comparing by id is inherently wrong. We never ran into any trouble, because we never used a ConstValue
containing an AllocId
in comparisons that mattered. Now that everything is ByRef
, pattern match exhaustiveness checks failed because they couldn't figure out that two const patterns are the same if their AllocId
differs.
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 only applies to AllocIds that refer to global allocations.
It is still grossly wrong in the context of the miri engine. Ptr equality wants to compare the IDs, not the allocations they point to, and the IDs should be newtyped to not mix them up with other integers.
pattern match exhaustiveness checks failed because they couldn't figure out that two const patterns are the same if their AllocId differs.
Then it shouldn't use the same equality as the miri engine. If you want to overwrite equality and hashing for ConstValue
, I can support that, but doing it for a type used inside the engine makes me really nervous.
fn cmp(&self, other: &Self) -> cmp::Ordering { | ||
match self.partial_cmp(other) { | ||
Some(ord) => ord, | ||
None => self.0.cmp(&other.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.
Why is it okay to fall back to comparing the integers here?
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 happens only for non-interned allocations
@@ -440,7 +488,7 @@ pub enum AllocType<'tcx, M> { | |||
|
|||
pub struct AllocMap<'tcx, M> { | |||
/// Lets you know what an AllocId refers to | |||
id_to_type: FxHashMap<AllocId, AllocType<'tcx, M>>, | |||
id_to_type: FxHashMap<u64, AllocType<'tcx, M>>, |
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.
Now we lose the newtype protection for not mixing up IDs.
I don't understand the purpose of this entire commit, at all. It also suffers from an astute lack of comments :)
@@ -736,22 +736,23 @@ impl<Tag: Copy, Extra: Default> Allocation<Tag, Extra> { | |||
&self, | |||
hdl: impl HasDataLayout, | |||
offset: Size, | |||
size: Size, | |||
align: Align, | |||
) -> EvalResult<'tcx, Scalar<Tag>> { |
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.
Wait, why does get_bytes
return a Scalar<Tag>
? That doesn't make any sense, a method of that name should return a &[u8]
. Now I am even more puzzled about what it does.
(See, a doc comment would have been useful. ;)
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 function is called read_scalar
?
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.
Hm did the diff view fool me? Yes it did.
I am still quite confused why this looks so different from what we do in memory.rs?
); | ||
OperandValue::Immediate(llval) | ||
}, | ||
layout::Abi::ScalarPair(ref a_scalar, ref b_scalar) => { |
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 is a duplicate of... read_value
, I guess? Why can't we use that instead?
// we produce a weird dummy layout with somewhat sane values | ||
let mut layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); | ||
layout.ty = ty.value; | ||
layout |
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.
Woah.
Your comment consists of two sentences, right, despite there not being a .
nor the first word of the second sentence being capitalized? I am not sure but so far I haven't found another way to parse these sentences. Please add punctuation :)
And also please add that delay_span_bug
. I mean I have no clue when and where and how this method is used, but just using u128
clearly cannot be right. Maybe add a comment saying why this even remotely makes sense -- i.e., is the result of this method unused in the error case, or so?
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 read it as one sentence. "weird" and "dummy" are adjectives modifying "layout", and "with somewhat sane values" is also attached to "layout.")
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.
GitHub cut away half the comment. I cannot parse the following as one sentence:
add delay_span_bug call, we can only get here if there are errors we produce a weird dummy layout with somewhat sane values
@@ -359,7 +359,7 @@ pub(super) fn from_known_layout<'tcx>( | |||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { | |||
/// Try reading a value in memory; this is interesting particularily for ScalarPair. | |||
/// Return None if the layout does not permit loading this as a value. | |||
pub(super) fn try_read_value_from_mplace( | |||
pub(crate) fn try_read_value_from_mplace( |
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.
These were meant to be internal to the engine :(
"could not evaluate constant", | ||
); | ||
None | ||
let error = match self.ecx.const_to_mplace(c.literal) { |
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 use read_value
?
☀️ Test successful - status-travis |
src/librustc_mir/const_eval.rs
Outdated
// as this function is essentially copying the value | ||
// out of the larger allocation, so we lose all information about | ||
// potential surrounding types with different alignment. | ||
alloc.align = mplace.layout.align; |
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 looks very wrong. Couldn't there still be other ConstValue
around that refer to the same allocation?
We should never, ever change the align
of an existing allocation. Even making a copy seems more sane, and that's already a rather insane option.^^
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 yea, this code was broken to begin with. That's one of the uncovered bugs I was talking about.
A few commits down I'm actually creating a new Allocation from scratch instead of this wrongness. I can't make it not copy right now, that would need large changes to ByRef
that I didn't want to do in this PR
@@ -50,6 +50,7 @@ impl<'tcx> ConstValue<'tcx> { | |||
#[inline] | |||
pub fn try_get_bytes(&self, hdl: impl HasDataLayout, n: Size, align: Align) -> Option<&[u8]> { | |||
let (_, alloc, offset) = self.try_as_by_ref()?; | |||
trace!("{:?}", alloc.get_bytes(hdl, offset, n, align)); |
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 add the function name to this, or it'll flood my screen one day and I won't even know where it comes from.
@@ -2008,12 +2008,12 @@ impl<'tcx> Const<'tcx> { | |||
|
|||
#[inline] | |||
pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { | |||
Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) | |||
Self::from_bits(tcx, v as u128, ParamEnv::reveal_all().and(tcx.types.bool)) |
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.
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 can change it back. But it's actually irrelevant here, since it gets used in layout_of
which (I checked) directly turns any ParamEnv
into a reveal_all
.
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.
directly turns any ParamEnv into a reveal_all.
Oh. Is there a way to make it not take a ParamEnv
then if it gets ignored anway?
// out of the larger allocation, so we lose all information about | ||
// potential surrounding types with different alignment. | ||
align: mplace.layout.align, | ||
}; |
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.
All this memory-modifying code outside of memory.rs
makes me really sad. :( The (subtle and correctness-critical!) relocations invariant was already scattered across that entire file, can we avoid scattering it over the entire rustc codebase?
@bors try something went wrong with the previous try commit build so we'll want to re-queue perf with a new one |
I thought I already did that with #55260 (comment) which went through fine |
Finished benchmarking try commit 3e4570cd5f53a5ad28f9a74e7ea1599cd22e5470 |
OOOOKAY: avg: 33219.2% | min: 22801.4% | max: 62508.3% I really need to rethink this strategy |
I created a separate PR for the memory -> allocation function moves: #55293 I'll split out things of this PR until it becomes manageable. Next up: removing only |
Ping from triage! If I understand correctly, this PR won't be merged in its current state, so I'm closing it for the time being. Feel free to re-open if you want to merge it in the future. |
... by always using
ByRef
and reading the scalars from the backingAllocation
where desiredOh god this uncovered so many bugs and bugs-just-waiting-to-happen. I'm still not fully done, but I don't want to grow this PR any further. It is in a sane state except for the
const_field
function, which was hacky to begin with.fixes #54738
r? @RalfJung