Skip to content

Commit

Permalink
Use let else to reduce indentation
Browse files Browse the repository at this point in the history
  • Loading branch information
tmiasko committed Nov 19, 2023
1 parent d19980e commit 525a64f
Showing 1 changed file with 123 additions and 124 deletions.
247 changes: 123 additions & 124 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,142 +541,141 @@ impl<'tcx> Inliner<'tcx> {
mut callee_body: Body<'tcx>,
) {
let terminator = caller_body[callsite.block].terminator.take().unwrap();
match terminator.kind {
TerminatorKind::Call { args, destination, unwind, .. } => {
// If the call is something like `a[*i] = f(i)`, where
// `i : &mut usize`, then just duplicating the `a[*i]`
// Place could result in two different locations if `f`
// writes to `i`. To prevent this we need to create a temporary
// borrow of the place and pass the destination as `*temp` instead.
fn dest_needs_borrow(place: Place<'_>) -> bool {
for elem in place.projection.iter() {
match elem {
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
_ => {}
}
}
let TerminatorKind::Call { args, destination, unwind, .. } = terminator.kind else {
bug!("unexpected terminator kind {:?}", terminator.kind);
};

false
// If the call is something like `a[*i] = f(i)`, where
// `i : &mut usize`, then just duplicating the `a[*i]`
// Place could result in two different locations if `f`
// writes to `i`. To prevent this we need to create a temporary
// borrow of the place and pass the destination as `*temp` instead.
fn dest_needs_borrow(place: Place<'_>) -> bool {
for elem in place.projection.iter() {
match elem {
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
_ => {}
}
}

let dest = if dest_needs_borrow(destination) {
trace!("creating temp for return destination");
let dest = Rvalue::Ref(
self.tcx.lifetimes.re_erased,
BorrowKind::Mut { kind: MutBorrowKind::Default },
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 {
destination
};
false
}

// Always create a local to hold the destination, as `RETURN_PLACE` may appear
// where a full `Place` is not allowed.
let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
(false, d)
} else {
(
true,
self.new_call_temp(
caller_body,
&callsite,
destination.ty(caller_body, self.tcx).ty,
),
)
};
let dest = if dest_needs_borrow(destination) {
trace!("creating temp for return destination");
let dest = Rvalue::Ref(
self.tcx.lifetimes.re_erased,
BorrowKind::Mut { kind: MutBorrowKind::Default },
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 {
destination
};

// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);

let mut integrator = Integrator {
args: &args,
new_locals: Local::new(caller_body.local_decls.len())..,
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite,
cleanup_block: unwind,
in_cleanup_block: false,
tcx: self.tcx,
always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
};
// Always create a local to hold the destination, as `RETURN_PLACE` may appear
// where a full `Place` is not allowed.
let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
(false, d)
} else {
(
true,
self.new_call_temp(
caller_body,
&callsite,
destination.ty(caller_body, self.tcx).ty,
),
)
};

// Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
// (or existing ones, in a few special cases) in the caller.
integrator.visit_body(&mut callee_body);

// If there are any locals without storage markers, give them storage only for the
// duration of the call.
for local in callee_body.vars_and_temps_iter() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageLive(new_local),
});
}
}
if let Some(block) = callsite.target {
// To avoid repeated O(n) insert, push any new statements to the end and rotate
// the slice once.
let mut n = 0;
if remap_destination {
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((
dest,
Rvalue::Use(Operand::Move(destination_local.into())),
))),
});
n += 1;
}
for local in callee_body.vars_and_temps_iter().rev() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(new_local),
});
n += 1;
}
}
caller_body[block].statements.rotate_right(n);
}
// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);

let mut integrator = Integrator {
args: &args,
new_locals: Local::new(caller_body.local_decls.len())..,
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite,
cleanup_block: unwind,
in_cleanup_block: false,
tcx: self.tcx,
always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
};

// Insert all of the (mapped) parts of the callee body into the caller.
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
// Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
// (or existing ones, in a few special cases) in the caller.
integrator.visit_body(&mut callee_body);

caller_body[callsite.block].terminator = Some(Terminator {
// If there are any locals without storage markers, give them storage only for the
// duration of the call.
for local in callee_body.vars_and_temps_iter() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
kind: StatementKind::StorageLive(new_local),
});

// Copy only unevaluated constants from the callee_body into the caller_body.
// Although we are only pushing `ConstKind::Unevaluated` consts to
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
// because we are calling `instantiate_and_normalize_erasing_regions`.
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ {
Const::Ty(_) => {
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
}
Const::Val(..) | Const::Unevaluated(..) => true,
}),
);
}
kind => bug!("unexpected terminator kind {:?}", kind),
}
if let Some(block) = callsite.target {
// To avoid repeated O(n) insert, push any new statements to the end and rotate
// the slice once.
let mut n = 0;
if remap_destination {
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((
dest,
Rvalue::Use(Operand::Move(destination_local.into())),
))),
});
n += 1;
}
for local in callee_body.vars_and_temps_iter().rev() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(new_local),
});
n += 1;
}
}
caller_body[block].statements.rotate_right(n);
}

// Insert all of the (mapped) parts of the callee body into the caller.
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));

caller_body[callsite.block].terminator = Some(Terminator {
source_info: callsite.source_info,
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
});

// Copy only unevaluated constants from the callee_body into the caller_body.
// Although we are only pushing `ConstKind::Unevaluated` consts to
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
// because we are calling `instantiate_and_normalize_erasing_regions`.
caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter(
|&ct| match ct.const_ {
Const::Ty(_) => {
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
}
Const::Val(..) | Const::Unevaluated(..) => true,
},
));
}

fn make_call_args(
Expand Down

0 comments on commit 525a64f

Please sign in to comment.