-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Const prop: erase all block-only locals at the end of every block #73757
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -131,6 +131,10 @@ pub enum LocalValue<Tag = ()> { | |||||
} | ||||||
|
||||||
impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { | ||||||
/// Read the local's value or error if the local is not yet live or not live anymore. | ||||||
/// | ||||||
/// Note: This may only be invoked from the `Machine::access_local` hook and not from | ||||||
/// anywhere else. You may be invalidating machine invariants if you do! | ||||||
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> { | ||||||
match self.value { | ||||||
LocalValue::Dead => throw_ub!(DeadLocal), | ||||||
|
@@ -143,6 +147,9 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { | |||||
|
||||||
/// Overwrite the local. If the local can be overwritten in place, return a reference | ||||||
/// to do so; otherwise return the `MemPlace` to consult instead. | ||||||
/// | ||||||
/// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// anywhere else. You may be invalidating machine invariants if you do! | ||||||
pub fn access_mut( | ||||||
&mut self, | ||||||
) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> { | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ use rustc_span::def_id::DefId; | |
|
||
use super::{ | ||
AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, | ||
Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, | ||
LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, | ||
}; | ||
|
||
/// Data returned by Machine::stack_pop, | ||
|
@@ -192,6 +192,8 @@ pub trait Machine<'mir, 'tcx>: Sized { | |
) -> InterpResult<'tcx>; | ||
|
||
/// Called to read the specified `local` from the `frame`. | ||
/// Since reading a ZST is not actually accessing memory or locals, this is never invoked | ||
/// for ZST reads. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear, this was already the case before but now is documented better? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes |
||
#[inline] | ||
fn access_local( | ||
_ecx: &InterpCx<'mir, 'tcx, Self>, | ||
|
@@ -201,6 +203,21 @@ pub trait Machine<'mir, 'tcx>: Sized { | |
frame.locals[local].access() | ||
} | ||
|
||
/// Called to write the specified `local` from the `frame`. | ||
/// Since writing a ZST is not actually accessing memory or locals, this is never invoked | ||
/// for ZST reads. | ||
#[inline] | ||
fn access_local_mut<'a>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @RalfJung some miri engine and machine extensions happen in this PR. They don't change anything, they just allow the const propagator to hook into accessing a local mutably and run some extra code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the heads-up! |
||
ecx: &'a mut InterpCx<'mir, 'tcx, Self>, | ||
frame: usize, | ||
local: mir::Local, | ||
) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>> | ||
where | ||
'tcx: 'mir, | ||
{ | ||
ecx.stack_mut()[frame].locals[local].access_mut() | ||
} | ||
|
||
/// Called before a basic block terminator is executed. | ||
/// You can use this to detect endlessly running programs. | ||
#[inline] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -740,7 +740,7 @@ where | |
// but not factored as a separate function. | ||
let mplace = match dest.place { | ||
Place::Local { frame, local } => { | ||
match self.stack_mut()[frame].locals[local].access_mut()? { | ||
match M::access_local_mut(self, frame, local)? { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a risk here of accidentally using the frame method instead of the hook. Is there anything we can do about that? I think there should at least be a comment at the frame method saying to not call it (except when implementing the hook). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll investigate whether we can have something static and otherwise document it properly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I documented it. I don't think it's realistic to statically prevent it being called except by introducing some appropriately named token types. |
||
Ok(local) => { | ||
// Local can be updated in-place. | ||
*local = LocalValue::Live(Operand::Immediate(src)); | ||
|
@@ -973,7 +973,7 @@ where | |
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> { | ||
let (mplace, size) = match place.place { | ||
Place::Local { frame, local } => { | ||
match self.stack_mut()[frame].locals[local].access_mut()? { | ||
match M::access_local_mut(self, frame, local)? { | ||
Ok(&mut local_val) => { | ||
// We need to make an allocation. | ||
|
||
|
@@ -997,7 +997,7 @@ where | |
} | ||
// Now we can call `access_mut` again, asserting it goes well, | ||
// and actually overwrite things. | ||
*self.stack_mut()[frame].locals[local].access_mut().unwrap().unwrap() = | ||
*M::access_local_mut(self, frame, local).unwrap().unwrap() = | ||
LocalValue::Live(Operand::Indirect(mplace)); | ||
(mplace, Some(size)) | ||
} | ||
|
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 had
must
before 😆 I thinkmay
is correct here.