Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 165f1dd

Browse files
committed
Auto merge of rust-lang#141406 - RalfJung:less-force-allocate, r=<try>
interpret: do not force_allocate all return places A while ago I cleaned up our `PlaceTy` a little, but as a side-effect of that, return places had to always be force-allocated. That turns out to cause quite a few extra allocations, and for a project we are doing where we marry Miri with a model checker, that means a lot of extra work -- local variables are just so much easier to reason about than allocations. So, this PR brings back the ability to have the return place be just a local of the caller. To make this work cleanly I had to rework stack pop handling a bit, which also changes the output of Miri in some cases as the span for errors occurring during a particular phase of stack pop changed. With these changes, a no-std binary with a function of functions that just take and return scalar types and that uses no pointers now does not move *any* local variables into memory. :) r? `@oli-obk`
2 parents e3892a4 + 2480c47 commit 165f1dd

File tree

18 files changed

+138
-141
lines changed

18 files changed

+138
-141
lines changed

compiler/rustc_const_eval/src/const_eval/dummy_machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
9090
_instance: ty::Instance<'tcx>,
9191
_abi: &FnAbi<'tcx, Ty<'tcx>>,
9292
_args: &[interpret::FnArg<'tcx, Self::Provenance>],
93-
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
93+
_destination: &interpret::PlaceTy<'tcx, Self::Provenance>,
9494
_target: Option<BasicBlock>,
9595
_unwind: UnwindAction,
9696
) -> interpret::InterpResult<'tcx, Option<(&'tcx Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -108,7 +108,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
108108
_ecx: &mut InterpCx<'tcx, Self>,
109109
_instance: ty::Instance<'tcx>,
110110
_args: &[interpret::OpTy<'tcx, Self::Provenance>],
111-
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
111+
_destination: &interpret::PlaceTy<'tcx, Self::Provenance>,
112112
_target: Option<BasicBlock>,
113113
_unwind: UnwindAction,
114114
) -> interpret::InterpResult<'tcx, Option<ty::Instance<'tcx>>> {

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
7171

7272
// This can't use `init_stack_frame` since `body` is not a function,
7373
// so computing its ABI would fail. It's also not worth it since there are no arguments to pass.
74-
ecx.push_stack_frame_raw(cid.instance, body, &ret, StackPopCleanup::Root { cleanup: false })?;
74+
ecx.push_stack_frame_raw(
75+
cid.instance,
76+
body,
77+
&ret.clone().into(),
78+
StackPopCleanup::Root { cleanup: false },
79+
)?;
7580
ecx.storage_live_for_always_live_locals()?;
7681

7782
// The main interpreter loop.

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn};
2222
use crate::fluent_generated as fluent;
2323
use crate::interpret::{
2424
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
25-
GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar,
25+
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
2626
compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom,
2727
throw_unsup, throw_unsup_format,
2828
};
@@ -226,7 +226,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
226226
&mut self,
227227
instance: ty::Instance<'tcx>,
228228
args: &[FnArg<'tcx>],
229-
_dest: &MPlaceTy<'tcx>,
229+
_dest: &PlaceTy<'tcx>,
230230
_ret: Option<mir::BasicBlock>,
231231
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
232232
let def_id = instance.def_id();
@@ -343,7 +343,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
343343
orig_instance: ty::Instance<'tcx>,
344344
_abi: &FnAbi<'tcx, Ty<'tcx>>,
345345
args: &[FnArg<'tcx>],
346-
dest: &MPlaceTy<'tcx>,
346+
dest: &PlaceTy<'tcx>,
347347
ret: Option<mir::BasicBlock>,
348348
_unwind: mir::UnwindAction, // unwinding is not supported in consts
349349
) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -385,7 +385,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
385385
ecx: &mut InterpCx<'tcx, Self>,
386386
instance: ty::Instance<'tcx>,
387387
args: &[OpTy<'tcx>],
388-
dest: &MPlaceTy<'tcx, Self::Provenance>,
388+
dest: &PlaceTy<'tcx, Self::Provenance>,
389389
target: Option<mir::BasicBlock>,
390390
_unwind: mir::UnwindAction,
391391
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
339339
caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
340340
args: &[FnArg<'tcx, M::Provenance>],
341341
with_caller_location: bool,
342-
destination: &MPlaceTy<'tcx, M::Provenance>,
342+
destination: &PlaceTy<'tcx, M::Provenance>,
343343
mut stack_pop: StackPopCleanup,
344344
) -> InterpResult<'tcx> {
345345
// Compute callee information.
@@ -487,7 +487,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
487487
}
488488

489489
// Protect return place for in-place return value passing.
490-
M::protect_in_place_function_argument(self, &destination)?;
490+
// We only need to protect anything if this is actually an in-memory place.
491+
if let Left(mplace) = destination.as_mplace_or_local() {
492+
M::protect_in_place_function_argument(self, &mplace)?;
493+
}
491494

492495
// Don't forget to mark "initially live" locals as live.
493496
self.storage_live_for_always_live_locals()?;
@@ -512,7 +515,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
512515
(caller_abi, caller_fn_abi): (ExternAbi, &FnAbi<'tcx, Ty<'tcx>>),
513516
args: &[FnArg<'tcx, M::Provenance>],
514517
with_caller_location: bool,
515-
destination: &MPlaceTy<'tcx, M::Provenance>,
518+
destination: &PlaceTy<'tcx, M::Provenance>,
516519
target: Option<mir::BasicBlock>,
517520
unwind: mir::UnwindAction,
518521
) -> InterpResult<'tcx> {
@@ -776,10 +779,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
776779
// Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
777780
// as the latter "executes" the goto to the return block, but we don't want to,
778781
// only the tail called function should return to the current return block.
779-
M::before_stack_pop(self, self.frame())?;
780-
781-
let StackPopInfo { return_action, return_to_block, return_place } =
782-
self.pop_stack_frame_raw(false)?;
782+
let StackPopInfo { return_action, return_to_block, return_place } = self
783+
.pop_stack_frame_raw(false, |_this, _return_place| {
784+
// This function's return value is just discarded, the tail-callee will fill in the return place instead.
785+
interp_ok(())
786+
})?;
783787

784788
assert_eq!(return_action, ReturnAction::Normal);
785789

@@ -850,7 +854,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
850854
(ExternAbi::Rust, fn_abi),
851855
&[FnArg::Copy(arg.into())],
852856
false,
853-
&ret,
857+
&ret.into(),
854858
Some(target),
855859
unwind,
856860
)
@@ -891,28 +895,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
891895
throw_ub_custom!(fluent::const_eval_unwind_past_top);
892896
}
893897

894-
M::before_stack_pop(self, self.frame())?;
895-
896-
// Copy return value. Must of course happen *before* we deallocate the locals.
897-
// Must be *after* `before_stack_pop` as otherwise the return place might still be protected.
898-
let copy_ret_result = if !unwinding {
899-
let op = self
900-
.local_to_op(mir::RETURN_PLACE, None)
901-
.expect("return place should always be live");
902-
let dest = self.frame().return_place.clone();
903-
let res = self.copy_op_allow_transmute(&op, &dest);
904-
trace!("return value: {:?}", self.dump_place(&dest.into()));
905-
// We delay actually short-circuiting on this error until *after* the stack frame is
906-
// popped, since we want this error to be attributed to the caller, whose type defines
907-
// this transmute.
908-
res
909-
} else {
898+
// Get out the return value. Must happen *before* the frame is popped as we have to get the
899+
// local's value out.
900+
let return_op =
901+
self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live");
902+
// Do the actual pop + copy.
903+
let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| {
904+
this.copy_op_allow_transmute(&return_op, return_place)?;
905+
trace!("return value: {:?}", this.dump_place(return_place));
910906
interp_ok(())
911-
};
912-
913-
// All right, now it is time to actually pop the frame.
914-
// An error here takes precedence over the copy error.
915-
let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?;
907+
})?;
916908

917909
match stack_pop_info.return_action {
918910
ReturnAction::Normal => {}
@@ -924,7 +916,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
924916
// If we are not doing cleanup, also skip everything else.
925917
assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
926918
assert!(!unwinding, "tried to skip cleanup during unwinding");
927-
// Skip machine hook.
919+
// Don't jump anywhere.
928920
return interp_ok(());
929921
}
930922
}

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use tracing::trace;
1717
use super::memory::MemoryKind;
1818
use super::util::ensure_monomorphic_enough;
1919
use super::{
20-
Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult,
21-
MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval,
22-
err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
20+
Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine,
21+
OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
22+
err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
2323
};
2424
use crate::fluent_generated as fluent;
2525

@@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
112112
&mut self,
113113
instance: ty::Instance<'tcx>,
114114
args: &[OpTy<'tcx, M::Provenance>],
115-
dest: &MPlaceTy<'tcx, M::Provenance>,
115+
dest: &PlaceTy<'tcx, M::Provenance>,
116116
ret: Option<mir::BasicBlock>,
117117
) -> InterpResult<'tcx, bool> {
118118
let instance_args = instance.args;
@@ -587,7 +587,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
587587
&mut self,
588588
a: &ImmTy<'tcx, M::Provenance>,
589589
b: &ImmTy<'tcx, M::Provenance>,
590-
dest: &MPlaceTy<'tcx, M::Provenance>,
590+
dest: &PlaceTy<'tcx, M::Provenance>,
591591
) -> InterpResult<'tcx> {
592592
assert_eq!(a.layout.ty, b.layout.ty);
593593
assert_matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..));
@@ -801,7 +801,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
801801
fn float_min_intrinsic<F>(
802802
&mut self,
803803
args: &[OpTy<'tcx, M::Provenance>],
804-
dest: &MPlaceTy<'tcx, M::Provenance>,
804+
dest: &PlaceTy<'tcx, M::Provenance>,
805805
) -> InterpResult<'tcx, ()>
806806
where
807807
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
@@ -822,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
822822
fn float_max_intrinsic<F>(
823823
&mut self,
824824
args: &[OpTy<'tcx, M::Provenance>],
825-
dest: &MPlaceTy<'tcx, M::Provenance>,
825+
dest: &PlaceTy<'tcx, M::Provenance>,
826826
) -> InterpResult<'tcx, ()>
827827
where
828828
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
@@ -843,7 +843,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
843843
fn float_minimum_intrinsic<F>(
844844
&mut self,
845845
args: &[OpTy<'tcx, M::Provenance>],
846-
dest: &MPlaceTy<'tcx, M::Provenance>,
846+
dest: &PlaceTy<'tcx, M::Provenance>,
847847
) -> InterpResult<'tcx, ()>
848848
where
849849
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
@@ -859,7 +859,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
859859
fn float_maximum_intrinsic<F>(
860860
&mut self,
861861
args: &[OpTy<'tcx, M::Provenance>],
862-
dest: &MPlaceTy<'tcx, M::Provenance>,
862+
dest: &PlaceTy<'tcx, M::Provenance>,
863863
) -> InterpResult<'tcx, ()>
864864
where
865865
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
@@ -875,7 +875,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
875875
fn float_copysign_intrinsic<F>(
876876
&mut self,
877877
args: &[OpTy<'tcx, M::Provenance>],
878-
dest: &MPlaceTy<'tcx, M::Provenance>,
878+
dest: &PlaceTy<'tcx, M::Provenance>,
879879
) -> InterpResult<'tcx, ()>
880880
where
881881
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
@@ -890,7 +890,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
890890
fn float_abs_intrinsic<F>(
891891
&mut self,
892892
args: &[OpTy<'tcx, M::Provenance>],
893-
dest: &MPlaceTy<'tcx, M::Provenance>,
893+
dest: &PlaceTy<'tcx, M::Provenance>,
894894
) -> InterpResult<'tcx, ()>
895895
where
896896
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub trait Machine<'tcx>: Sized {
208208
instance: ty::Instance<'tcx>,
209209
abi: &FnAbi<'tcx, Ty<'tcx>>,
210210
args: &[FnArg<'tcx, Self::Provenance>],
211-
destination: &MPlaceTy<'tcx, Self::Provenance>,
211+
destination: &PlaceTy<'tcx, Self::Provenance>,
212212
target: Option<mir::BasicBlock>,
213213
unwind: mir::UnwindAction,
214214
) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>>;
@@ -220,7 +220,7 @@ pub trait Machine<'tcx>: Sized {
220220
fn_val: Self::ExtraFnVal,
221221
abi: &FnAbi<'tcx, Ty<'tcx>>,
222222
args: &[FnArg<'tcx, Self::Provenance>],
223-
destination: &MPlaceTy<'tcx, Self::Provenance>,
223+
destination: &PlaceTy<'tcx, Self::Provenance>,
224224
target: Option<mir::BasicBlock>,
225225
unwind: mir::UnwindAction,
226226
) -> InterpResult<'tcx>;
@@ -234,7 +234,7 @@ pub trait Machine<'tcx>: Sized {
234234
ecx: &mut InterpCx<'tcx, Self>,
235235
instance: ty::Instance<'tcx>,
236236
args: &[OpTy<'tcx, Self::Provenance>],
237-
destination: &MPlaceTy<'tcx, Self::Provenance>,
237+
destination: &PlaceTy<'tcx, Self::Provenance>,
238238
target: Option<mir::BasicBlock>,
239239
unwind: mir::UnwindAction,
240240
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>;
@@ -536,11 +536,9 @@ pub trait Machine<'tcx>: Sized {
536536
interp_ok(())
537537
}
538538

539-
/// Called just before the return value is copied to the caller-provided return place.
540-
fn before_stack_pop(
541-
_ecx: &InterpCx<'tcx, Self>,
542-
_frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>,
543-
) -> InterpResult<'tcx> {
539+
/// Called just before the frame is removed from the stack (followed by return value copy and
540+
/// local cleanup).
541+
fn before_stack_pop(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
544542
interp_ok(())
545543
}
546544

@@ -675,7 +673,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
675673
fn_val: !,
676674
_abi: &FnAbi<$tcx, Ty<$tcx>>,
677675
_args: &[FnArg<$tcx>],
678-
_destination: &MPlaceTy<$tcx, Self::Provenance>,
676+
_destination: &PlaceTy<$tcx, Self::Provenance>,
679677
_target: Option<mir::BasicBlock>,
680678
_unwind: mir::UnwindAction,
681679
) -> InterpResult<$tcx> {

0 commit comments

Comments
 (0)