Refactor call terminator to always hold a destination place

This commit is contained in:
Jakob Degen 2022-04-16 09:27:54 -04:00
parent 222c5724ec
commit 09b0936db2
67 changed files with 422 additions and 412 deletions

View file

@ -50,12 +50,7 @@ impl AddCallGuards {
for block in body.basic_blocks_mut() {
match block.terminator {
Some(Terminator {
kind:
TerminatorKind::Call {
destination: Some((_, ref mut destination)),
cleanup,
..
},
kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. },
source_info,
}) if pred_count[*destination] > 1
&& (cleanup.is_some() || self == &AllCallEdges) =>

View file

@ -130,11 +130,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
.iter_mut()
.filter_map(|block_data| {
match block_data.terminator().kind {
TerminatorKind::Call { destination: Some(ref destination), .. }
if needs_retag(&destination.0) =>
TerminatorKind::Call { target: Some(target), destination, .. }
if needs_retag(&destination) =>
{
// Remember the return destination for later
Some((block_data.terminator().source_info, destination.0, destination.1))
Some((block_data.terminator().source_info, destination, target))
}
// `Drop` is also a call, but it doesn't return anything so we are good.

View file

@ -200,7 +200,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
_instance: ty::Instance<'tcx>,
_abi: Abi,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_destination: &PlaceTy<'tcx>,
_target: Option<BasicBlock>,
_unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
Ok(None)
@ -210,7 +211,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_destination: &PlaceTy<'tcx>,
_target: Option<BasicBlock>,
_unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@ -384,24 +386,22 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
);
let ret = ecx
let ret_layout = ecx
.layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
.ok()
// Don't bother allocating memory for ZST types which have no values
// or for large values.
.filter(|ret_layout| {
!ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
})
.map(|ret_layout| {
ecx.allocate(ret_layout, MemoryKind::Stack)
.expect("couldn't perform small allocation")
.into()
});
// Don't bother allocating memory for large values.
.filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
.unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
let ret = ecx
.allocate(ret_layout, MemoryKind::Stack)
.expect("couldn't perform small allocation")
.into();
ecx.push_stack_frame(
Instance::new(def_id, substs),
dummy_body,
ret.as_ref(),
&ret,
StackPopCleanup::Root { cleanup: false },
)
.expect("failed to push initial stack frame");

View file

@ -192,7 +192,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
_instance: ty::Instance<'tcx>,
_abi: Abi,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_destination: &PlaceTy<'tcx>,
_target: Option<BasicBlock>,
_unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
Ok(None)
@ -202,7 +203,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_destination: &PlaceTy<'tcx>,
_target: Option<BasicBlock>,
_unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@ -377,24 +379,22 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
);
let ret = ecx
let ret_layout = ecx
.layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
.ok()
// Don't bother allocating memory for ZST types which have no values
// or for large values.
.filter(|ret_layout| {
!ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
})
.map(|ret_layout| {
ecx.allocate(ret_layout, MemoryKind::Stack)
.expect("couldn't perform small allocation")
.into()
});
// Don't bother allocating memory for large values.
.filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
.unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
let ret = ecx
.allocate(ret_layout, MemoryKind::Stack)
.expect("couldn't perform small allocation")
.into();
ecx.push_stack_frame(
Instance::new(def_id, substs),
dummy_body,
ret.as_ref(),
&ret,
StackPopCleanup::Root { cleanup: false },
)
.expect("failed to push initial stack frame");

View file

@ -84,7 +84,7 @@ impl<'tcx> MockBlocks<'tcx> {
fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) {
match self.blocks[from_block].terminator_mut().kind {
TerminatorKind::Assert { ref mut target, .. }
| TerminatorKind::Call { destination: Some((_, ref mut target)), .. }
| TerminatorKind::Call { target: Some(ref mut target), .. }
| TerminatorKind::Drop { ref mut target, .. }
| TerminatorKind::DropAndReplace { ref mut target, .. }
| TerminatorKind::FalseEdge { real_target: ref mut target, .. }
@ -139,7 +139,8 @@ impl<'tcx> MockBlocks<'tcx> {
TerminatorKind::Call {
func: Operand::Copy(self.dummy_place.clone()),
args: vec![],
destination: Some((self.dummy_place.clone(), TEMP_BLOCK)),
destination: self.dummy_place.clone(),
target: Some(TEMP_BLOCK),
cleanup: None,
from_hir_call: false,
fn_span: DUMMY_SP,
@ -182,7 +183,7 @@ fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String {
let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32());
match kind {
TerminatorKind::Assert { target, .. }
| TerminatorKind::Call { destination: Some((_, target)), .. }
| TerminatorKind::Call { target: Some(target), .. }
| TerminatorKind::Drop { target, .. }
| TerminatorKind::DropAndReplace { target, .. }
| TerminatorKind::FalseEdge { real_target: target, .. }

View file

@ -575,7 +575,8 @@ impl<'a> Conflicts<'a> {
TerminatorKind::Call {
func,
args,
destination: Some((dest_place, _)),
destination,
target: _,
cleanup: _,
from_hir_call: _,
fn_span: _,
@ -583,9 +584,9 @@ impl<'a> Conflicts<'a> {
// No arguments may overlap with the destination.
for arg in args.iter().chain(Some(func)) {
if let Some(place) = arg.place() {
if !place.is_indirect() && !dest_place.is_indirect() {
if !place.is_indirect() && !destination.is_indirect() {
self.record_local_conflict(
dest_place.local,
destination.local,
place.local,
"call dest/arg overlap",
);
@ -691,7 +692,6 @@ impl<'a> Conflicts<'a> {
}
TerminatorKind::Goto { .. }
| TerminatorKind::Call { destination: None, .. }
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Resume
| TerminatorKind::Abort

View file

@ -494,15 +494,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn drop_flags_for_fn_rets(&mut self) {
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
if let TerminatorKind::Call {
destination: Some((ref place, tgt)),
cleanup: Some(_),
..
destination, target: Some(tgt), cleanup: Some(_), ..
} = data.terminator().kind
{
assert!(!self.patch.is_patched(bb));
let loc = Location { block: tgt, statement_index: 0 };
let path = self.move_data().rev_lookup.find(place.as_ref());
let path = self.move_data().rev_lookup.find(destination.as_ref());
on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
self.set_drop_flag(loc, child, DropFlagState::Present)
});
@ -576,14 +574,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
// There may be a critical edge after this call,
// so mark the return as initialized *before* the
// call.
if let TerminatorKind::Call {
destination: Some((ref place, _)), cleanup: None, ..
} = data.terminator().kind
if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } =
data.terminator().kind
{
assert!(!self.patch.is_patched(bb));
let loc = Location { block: bb, statement_index: data.statements.len() };
let path = self.move_data().rev_lookup.find(place.as_ref());
let path = self.move_data().rev_lookup.find(destination.as_ref());
on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
self.set_drop_flag(loc, child, DropFlagState::Present)
});

View file

@ -37,6 +37,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
func,
args,
destination: _,
target: _,
cleanup: _,
from_hir_call: _,
fn_span: _,

View file

@ -1459,12 +1459,13 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
TerminatorKind::Call {
func,
args,
destination: Some((dest, _)),
destination,
target: Some(_),
cleanup: _,
from_hir_call: _,
fn_span: _,
} => {
self.check_assigned_place(*dest, |this| {
self.check_assigned_place(*destination, |this| {
this.visit_operand(func, location);
for arg in args {
this.visit_operand(arg, location);

View file

@ -248,7 +248,7 @@ impl<'tcx> Inliner<'tcx> {
) -> Option<CallSite<'tcx>> {
// Only consider direct calls to functions
let terminator = bb_data.terminator();
if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind {
if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
let func_ty = func.ty(caller_body, self.tcx);
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
// To resolve an instance its substs have to be fully normalized.
@ -266,7 +266,7 @@ impl<'tcx> Inliner<'tcx> {
callee,
fn_sig,
block: bb,
target: destination.map(|(_, target)| target),
target,
source_info: terminator.source_info,
});
}
@ -395,7 +395,7 @@ impl<'tcx> Inliner<'tcx> {
}
}
TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. }
TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. }
if first_block =>
{
// If the function always diverges, don't inline
@ -512,27 +512,22 @@ impl<'tcx> Inliner<'tcx> {
false
}
let dest = if let Some((destination_place, _)) = destination {
if dest_needs_borrow(destination_place) {
trace!("creating temp for return destination");
let dest = Rvalue::Ref(
self.tcx.lifetimes.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false },
destination_place,
);
let dest_ty = dest.ty(caller_body, self.tcx);
let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((temp, dest))),
});
self.tcx.mk_place_deref(temp)
} else {
destination_place
}
let dest = if dest_needs_borrow(destination) {
trace!("creating temp for return destination");
let dest = Rvalue::Ref(
self.tcx.lifetimes.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false },
destination,
);
let dest_ty = dest.ty(caller_body, self.tcx);
let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((temp, dest))),
});
self.tcx.mk_place_deref(temp)
} else {
trace!("creating temp for return place");
Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty()))
destination
};
// Copy the arguments if needed.
@ -914,8 +909,8 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
*unwind = self.cleanup_block;
}
}
TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
if let Some((_, ref mut tgt)) = *destination {
TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => {
if let Some(ref mut tgt) = *target {
*tgt = self.map_block(*tgt);
}
if let Some(tgt) = *cleanup {

View file

@ -141,7 +141,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
terminator: &mut Terminator<'tcx>,
statements: &mut Vec<Statement<'tcx>>,
) {
let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind
let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind
else { return };
// It's definitely not a clone if there are multiple arguments
@ -149,7 +149,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
return;
}
let Some((destination_place, destination_block)) = *destination
let Some(destination_block) = *target
else { return };
// Only bother looking more if it's easy to know what we're calling
@ -193,7 +193,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
destination_place,
*destination,
Rvalue::Use(Operand::Copy(
arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
)),

View file

@ -14,7 +14,9 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks {
let terminator = block.terminator.as_mut().unwrap();
if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
if let TerminatorKind::Call { func, args, destination, target, .. } =
&mut terminator.kind
{
let func_ty = func.ty(local_decls, tcx);
let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(tcx, func_ty) else {
continue;
@ -24,11 +26,11 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Unreachable;
}
sym::forget => {
if let Some((destination, target)) = *destination {
if let Some(target) = *target {
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
destination,
*destination,
Rvalue::Use(Operand::Constant(Box::new(Constant {
span: terminator.source_info.span,
user_ty: None,
@ -40,7 +42,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
}
}
sym::copy_nonoverlapping => {
let target = destination.unwrap().1;
let target = target.unwrap();
let mut args = args.drain(..);
block.statements.push(Statement {
source_info: terminator.source_info,
@ -61,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Goto { target };
}
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
if let Some((destination, target)) = *destination {
if let Some(target) = *target {
let lhs;
let rhs;
{
@ -78,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
destination,
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
))),
});
@ -91,7 +93,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
// during codegen. Issue #35310.
}
sym::size_of | sym::min_align_of => {
if let Some((destination, target)) = *destination {
if let Some(target) = *target {
let tp_ty = substs.type_at(0);
let null_op = match intrinsic_name {
sym::size_of => NullOp::SizeOf,
@ -101,7 +103,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
destination,
*destination,
Rvalue::NullaryOp(null_op, tp_ty),
))),
});
@ -109,14 +111,12 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
}
}
sym::discriminant_value => {
if let (Some((destination, target)), Some(arg)) =
(*destination, args[0].place())
{
if let (Some(target), Some(arg)) = (*target, args[0].place()) {
let arg = tcx.mk_place_deref(arg);
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
destination,
*destination,
Rvalue::Discriminant(arg),
))),
});

View file

@ -52,7 +52,8 @@ fn lower_slice_len_call<'tcx>(
TerminatorKind::Call {
func,
args,
destination: Some((dest, bb)),
destination,
target: Some(bb),
cleanup: None,
from_hir_call: true,
..
@ -73,7 +74,8 @@ fn lower_slice_len_call<'tcx>(
// make new RValue for Len
let deref_arg = tcx.mk_place_deref(arg);
let r_value = Rvalue::Len(deref_arg);
let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value)));
let len_statement_kind =
StatementKind::Assign(Box::new((*destination, r_value)));
let add_statement =
Statement { kind: len_statement_kind, source_info: terminator.source_info };

View file

@ -450,7 +450,8 @@ impl<'tcx> CloneShimBuilder<'tcx> {
TerminatorKind::Call {
func,
args: vec![Operand::Move(ref_loc)],
destination: Some((dest, next)),
destination: dest,
target: Some(next),
cleanup: Some(cleanup),
from_hir_call: true,
fn_span: self.span,
@ -676,7 +677,8 @@ fn build_call_shim<'tcx>(
TerminatorKind::Call {
func: callee,
args,
destination: Some((Place::return_place(), BasicBlock::new(1))),
destination: Place::return_place(),
target: Some(BasicBlock::new(1)),
cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
Some(BasicBlock::new(3))
} else {