mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 13:05:18 +03:00
Rollup merge of #155184 - scottmcm:intercept-array-drop-shim, r=WaffleLapkin
Have arrays' `drop_glue` just unsize and call the slice version It's silly to emit two loops (because of the drop ladder -- just one in panic=abort) for every array length that's dropped when we can just polymorphize to the slice version. Built atop rust-lang/rust#154327 to avoid conflicts later, so draft for now. r? @WaffleLapkin
This commit is contained in:
@@ -292,7 +292,7 @@ pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
let def_id = match *self {
|
||||
ty::InstanceKind::Item(def) => def,
|
||||
ty::InstanceKind::DropGlue(_, Some(_)) => return false,
|
||||
ty::InstanceKind::DropGlue(_, Some(ty)) => return ty.is_array(),
|
||||
ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => return ty.is_coroutine(),
|
||||
ty::InstanceKind::FutureDropPollShim(_, _, _) => return false,
|
||||
ty::InstanceKind::AsyncDropGlue(_, _) => return false,
|
||||
|
||||
@@ -317,16 +317,56 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
||||
let block = |blocks: &mut IndexVec<_, _>, kind| {
|
||||
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
|
||||
};
|
||||
block(&mut blocks, TerminatorKind::Goto { target: return_block });
|
||||
if ty.is_some() {
|
||||
block(&mut blocks, TerminatorKind::Goto { target: return_block });
|
||||
}
|
||||
block(&mut blocks, TerminatorKind::Return);
|
||||
|
||||
let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty));
|
||||
let mut body =
|
||||
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
|
||||
|
||||
let Some(ty) = ty else {
|
||||
return body;
|
||||
};
|
||||
|
||||
let dropee_ptr = Place::from(Local::arg(0));
|
||||
|
||||
if ty.is_some() {
|
||||
if let ty::Array(ety, _len) = *ty.kind() {
|
||||
// Don't write out the elaboration for each array type.
|
||||
// Instead, just delegate to the slice version.
|
||||
let slice_ty = Ty::new_slice(tcx, ety);
|
||||
let mut_slice_ty = Ty::new_ref(tcx, tcx.lifetimes.re_erased, slice_ty, ty::Mutability::Mut);
|
||||
let erased_local = body.local_decls.push(LocalDecl::new(mut_slice_ty, span));
|
||||
|
||||
let start = &mut body.basic_blocks_mut()[START_BLOCK];
|
||||
start.statements.push(Statement::new(
|
||||
source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
Place::from(erased_local),
|
||||
Rvalue::Cast(
|
||||
CastKind::PointerCoercion(
|
||||
ty::adjustment::PointerCoercion::Unsize,
|
||||
CoercionSource::Implicit,
|
||||
),
|
||||
Operand::Move(dropee_ptr),
|
||||
mut_slice_ty,
|
||||
),
|
||||
))),
|
||||
));
|
||||
start.terminator = Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, def_id, [ty::GenericArg::from(slice_ty)], span),
|
||||
args: Box::new([Spanned { span, node: Operand::Move(Place::from(erased_local)) }]),
|
||||
destination: Place::from(RETURN_PLACE),
|
||||
target: Some(return_block),
|
||||
unwind: UnwindAction::Continue,
|
||||
call_source: CallSource::Misc,
|
||||
fn_span: span,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
let patch = {
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
|
||||
let mut elaborator = DropShimElaborator {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
//@ revisions: RAW OPT
|
||||
//@ compile-flags: -C opt-level=z -C panic=abort
|
||||
//@[RAW] compile-flags: -C no-prepopulate-passes -Z inline-mir
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Ensure all the different array drop_glue functions just delegate to the slice one,
|
||||
// rather than emitting two loops in each of the three.
|
||||
|
||||
// When this test was first written, the array drop glues came out in the
|
||||
// seemingly-arbitrary order of 42, then 7, then 13, so to avoid potential
|
||||
// fragility from that changing we don't check any particular order.
|
||||
|
||||
// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]>
|
||||
// RAW-NEXT: inlinehint
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// RAW-NEXT: noundef [[N]])
|
||||
// RAW: }
|
||||
|
||||
// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]>
|
||||
// RAW-NEXT: inlinehint
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// RAW-NEXT: noundef [[N]])
|
||||
// RAW: }
|
||||
|
||||
// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]>
|
||||
// RAW-NEXT: inlinehint
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// RAW-NEXT: noundef [[N]])
|
||||
// RAW: }
|
||||
|
||||
// CHECK-LABEL: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// CHECK-NOT: inlinehint
|
||||
// OPT: add nuw nsw {{.+}} 1
|
||||
// CHECK: }
|
||||
|
||||
#[no_mangle]
|
||||
// CHECK-LABEL: @drop_arrays
|
||||
pub fn drop_arrays(x: [NeedsDrop; 7], y: [NeedsDrop; 13], z: [NeedsDrop; 42]) {
|
||||
// I don't remember the parameter drop order, so write out the order the test expects.
|
||||
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 7]>
|
||||
// OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// OPT-NEXT: noundef 7)
|
||||
drop(x);
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 13]>
|
||||
// OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// OPT-NEXT: noundef 13)
|
||||
drop(y);
|
||||
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 42]>
|
||||
// OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
|
||||
// OPT-NEXT: noundef 42)
|
||||
drop(z);
|
||||
}
|
||||
|
||||
struct NeedsDrop(u32);
|
||||
|
||||
impl Drop for NeedsDrop {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
do_the_drop(self);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "Rust" {
|
||||
safe fn do_the_drop(_: &mut NeedsDrop);
|
||||
}
|
||||
+3
-51
@@ -2,62 +2,14 @@
|
||||
|
||||
fn std::ptr::drop_glue(_1: &mut [String; 42]) -> () {
|
||||
let mut _0: ();
|
||||
let mut _2: *mut [std::string::String; 42];
|
||||
let mut _3: *mut [std::string::String];
|
||||
let mut _4: usize;
|
||||
let mut _5: usize;
|
||||
let mut _6: *mut std::string::String;
|
||||
let mut _7: bool;
|
||||
let mut _8: *mut std::string::String;
|
||||
let mut _9: bool;
|
||||
let mut _2: &mut [std::string::String];
|
||||
|
||||
bb0: {
|
||||
goto -> bb9;
|
||||
_2 = move _1 as &mut [std::string::String] (PointerCoercion(Unsize, Implicit));
|
||||
_0 = std::ptr::drop_glue::<[String]>(move _2) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb2 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
_6 = &raw mut (*_3)[_5];
|
||||
_5 = Add(move _5, const 1_usize);
|
||||
drop((*_6)) -> [return: bb4, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
_7 = Eq(copy _5, copy _4);
|
||||
switchInt(move _7) -> [0: bb3, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_8 = &raw mut (*_3)[_5];
|
||||
_5 = Add(move _5, const 1_usize);
|
||||
drop((*_8)) -> [return: bb6, unwind: bb4];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_9 = Eq(copy _5, copy _4);
|
||||
switchInt(move _9) -> [0: bb5, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_4 = PtrMetadata(copy _3);
|
||||
_5 = const 0_usize;
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb9: {
|
||||
_2 = &raw mut (*_1);
|
||||
_3 = move _2 as *mut [std::string::String] (PointerCoercion(Unsize, Implicit));
|
||||
goto -> bb8;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user