Skip to content

Commit 162bc51

Browse files
committed
use a pointer-based array drop loop for non-zero-sized types
1 parent 6548aef commit 162bc51

File tree

1 file changed

+136
-53
lines changed

1 file changed

+136
-53
lines changed

src/librustc_mir/util/elaborate_drops.rs

Lines changed: 136 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
493493
let discr_ty = adt.repr.discr_type().to_ty(self.tcx());
494494
let discr = Lvalue::Local(self.new_temp(discr_ty));
495495
let discr_rv = Rvalue::Discriminant(self.lvalue.clone());
496-
let switch_block = self.elaborator.patch().new_block(BasicBlockData {
497-
statements: vec![
498-
Statement {
499-
source_info: self.source_info,
500-
kind: StatementKind::Assign(discr.clone(), discr_rv),
501-
}
502-
],
496+
let switch_block = BasicBlockData {
497+
statements: vec![self.assign(&discr, discr_rv)],
503498
terminator: Some(Terminator {
504499
source_info: self.source_info,
505500
kind: TerminatorKind::SwitchInt {
@@ -510,7 +505,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
510505
}
511506
}),
512507
is_cleanup: unwind.is_cleanup(),
513-
});
508+
};
509+
let switch_block = self.elaborator.patch().new_block(switch_block);
514510
self.drop_flag_test_block(switch_block, succ, unwind)
515511
}
516512

@@ -531,14 +527,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
531527
let ref_lvalue = self.new_temp(ref_ty);
532528
let unit_temp = Lvalue::Local(self.new_temp(tcx.mk_nil()));
533529

534-
self.elaborator.patch().new_block(BasicBlockData {
535-
statements: vec![Statement {
536-
source_info: self.source_info,
537-
kind: StatementKind::Assign(
538-
Lvalue::Local(ref_lvalue),
539-
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone())
540-
)
541-
}],
530+
let result = BasicBlockData {
531+
statements: vec![self.assign(
532+
&Lvalue::Local(ref_lvalue),
533+
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone())
534+
)],
542535
terminator: Some(Terminator {
543536
kind: TerminatorKind::Call {
544537
func: Operand::function_handle(tcx, drop_fn.def_id, substs,
@@ -550,24 +543,33 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
550543
source_info: self.source_info
551544
}),
552545
is_cleanup: unwind.is_cleanup(),
553-
})
546+
};
547+
self.elaborator.patch().new_block(result)
554548
}
555549

556550
/// create a loop that drops an array:
551+
///
552+
557553
///
558554
/// loop-block:
559-
/// can_go = index == len
555+
/// can_go = cur == length_or_end
560556
/// if can_go then succ else drop-block
561557
/// drop-block:
562-
/// ptr = &mut LV[index]
563-
/// index = index + 1
558+
/// if ptr_based {
559+
/// ptr = cur
560+
/// cur = cur.offset(1)
561+
/// } else {
562+
/// ptr = &mut LV[cur]
563+
/// cur = cur + 1
564+
/// }
564565
/// drop(ptr)
565566
fn drop_loop(&mut self,
566567
succ: BasicBlock,
567-
index: &Lvalue<'tcx>,
568-
length: &Lvalue<'tcx>,
568+
cur: &Lvalue<'tcx>,
569+
length_or_end: &Lvalue<'tcx>,
569570
ety: Ty<'tcx>,
570-
unwind: Unwind)
571+
unwind: Unwind,
572+
ptr_based: bool)
571573
-> BasicBlock
572574
{
573575
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
@@ -581,38 +583,44 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
581583
let can_go = &Lvalue::Local(self.new_temp(tcx.types.bool));
582584

583585
let one = self.constant_usize(1);
584-
let drop_block = self.elaborator.patch().new_block(BasicBlockData {
586+
let (ptr_next, cur_next) = if ptr_based {
587+
(Rvalue::Use(use_(cur)),
588+
Rvalue::BinaryOp(BinOp::Offset, use_(cur), one))
589+
} else {
590+
(Rvalue::Ref(
591+
tcx.types.re_erased,
592+
BorrowKind::Mut,
593+
self.lvalue.clone().index(use_(cur))),
594+
Rvalue::BinaryOp(BinOp::Add, use_(cur), one))
595+
};
596+
597+
let drop_block = BasicBlockData {
585598
statements: vec![
586-
Statement { source_info: self.source_info, kind: StatementKind::Assign(
587-
ptr.clone(), Rvalue::Ref(
588-
tcx.types.re_erased, BorrowKind::Mut,
589-
self.lvalue.clone().index(use_(index))
590-
),
591-
)},
592-
Statement { source_info: self.source_info, kind: StatementKind::Assign(
593-
index.clone(), Rvalue::BinaryOp(BinOp::Add, use_(index), one)
594-
)},
599+
self.assign(ptr, ptr_next),
600+
self.assign(cur, cur_next)
595601
],
596602
is_cleanup: unwind.is_cleanup(),
597603
terminator: Some(Terminator {
598604
source_info: self.source_info,
599605
// this gets overwritten by drop elaboration.
600606
kind: TerminatorKind::Unreachable,
601607
})
602-
});
608+
};
609+
let drop_block = self.elaborator.patch().new_block(drop_block);
603610

604-
let loop_block = self.elaborator.patch().new_block(BasicBlockData {
611+
let loop_block = BasicBlockData {
605612
statements: vec![
606-
Statement { source_info: self.source_info, kind: StatementKind::Assign(
607-
can_go.clone(), Rvalue::BinaryOp(BinOp::Eq, use_(index), use_(length))
608-
)},
613+
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
614+
use_(cur),
615+
use_(length_or_end)))
609616
],
610617
is_cleanup: unwind.is_cleanup(),
611618
terminator: Some(Terminator {
612619
source_info: self.source_info,
613620
kind: TerminatorKind::if_(tcx, use_(can_go), succ, drop_block)
614621
})
615-
});
622+
};
623+
let loop_block = self.elaborator.patch().new_block(loop_block);
616624

617625
self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop {
618626
location: ptr.clone().deref(),
@@ -625,29 +633,97 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
625633

626634
fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
627635
debug!("open_drop_for_array({:?})", ety);
628-
// FIXME: using an index instead of a pointer to avoid
629-
// special-casing ZSTs.
636+
637+
// if size_of::<ety>() == 0 {
638+
// index_based_loop
639+
// } else {
640+
// ptr_based_loop
641+
// }
642+
643+
let tcx = self.tcx();
644+
645+
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
646+
let size = &Lvalue::Local(self.new_temp(tcx.types.usize));
647+
let size_is_zero = &Lvalue::Local(self.new_temp(tcx.types.bool));
648+
let base_block = BasicBlockData {
649+
statements: vec![
650+
self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
651+
self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq,
652+
use_(size),
653+
self.constant_usize(0)))
654+
],
655+
is_cleanup: self.unwind.is_cleanup(),
656+
terminator: Some(Terminator {
657+
source_info: self.source_info,
658+
kind: TerminatorKind::if_(
659+
tcx,
660+
use_(size_is_zero),
661+
self.drop_loop_pair(ety, false),
662+
self.drop_loop_pair(ety, true)
663+
)
664+
})
665+
};
666+
self.elaborator.patch().new_block(base_block)
667+
}
668+
669+
// create a pair of drop-loops of `lvalue`, which drops its contents
670+
// even in the case of 1 panic. If `ptr_based`, create a pointer loop,
671+
// otherwise create an index loop.
672+
fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock {
673+
debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based);
630674
let tcx = self.tcx();
631-
let index = &Lvalue::Local(self.new_temp(tcx.types.usize));
632-
let length = &Lvalue::Local(self.new_temp(tcx.types.usize));
675+
let iter_ty = if ptr_based {
676+
tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::MutMutable })
677+
} else {
678+
tcx.types.usize
679+
};
680+
681+
let cur = Lvalue::Local(self.new_temp(iter_ty));
682+
let length = Lvalue::Local(self.new_temp(tcx.types.usize));
683+
let length_or_end = if ptr_based {
684+
Lvalue::Local(self.new_temp(iter_ty))
685+
} else {
686+
length.clone()
687+
};
633688

634689
let unwind = self.unwind.map(|unwind| {
635-
self.drop_loop(unwind, index, length, ety, Unwind::InCleanup)
690+
self.drop_loop(unwind,
691+
&cur,
692+
&length_or_end,
693+
ety,
694+
Unwind::InCleanup,
695+
ptr_based)
636696
});
637697

638698
let succ = self.succ; // FIXME(#6393)
639-
let loop_block = self.drop_loop(succ, index, length, ety, unwind);
699+
let loop_block = self.drop_loop(
700+
succ,
701+
&cur,
702+
&length_or_end,
703+
ety,
704+
unwind,
705+
ptr_based);
640706

641707
let zero = self.constant_usize(0);
708+
let mut drop_block_stmts = vec![];
709+
drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.lvalue.clone())));
710+
if ptr_based {
711+
// cur = &LV[0];
712+
// end = &LV[len];
713+
drop_block_stmts.push(self.assign(&cur, Rvalue::Ref(
714+
tcx.types.re_erased, BorrowKind::Mut,
715+
self.lvalue.clone().index(zero.clone())
716+
)));
717+
drop_block_stmts.push(self.assign(&length_or_end, Rvalue::Ref(
718+
tcx.types.re_erased, BorrowKind::Mut,
719+
self.lvalue.clone().index(Operand::Consume(length.clone()))
720+
)));
721+
} else {
722+
// index = 0 (length already pushed)
723+
drop_block_stmts.push(self.assign(&cur, Rvalue::Use(zero)));
724+
}
642725
let drop_block = self.elaborator.patch().new_block(BasicBlockData {
643-
statements: vec![
644-
Statement { source_info: self.source_info, kind: StatementKind::Assign(
645-
length.clone(), Rvalue::Len(self.lvalue.clone())
646-
)},
647-
Statement { source_info: self.source_info, kind: StatementKind::Assign(
648-
index.clone(), Rvalue::Use(zero),
649-
)},
650-
],
726+
statements: drop_block_stmts,
651727
is_cleanup: unwind.is_cleanup(),
652728
terminator: Some(Terminator {
653729
source_info: self.source_info,
@@ -836,4 +912,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
836912
literal: Literal::Value { value: ConstVal::Integral(self.tcx().const_usize(val)) }
837913
})
838914
}
915+
916+
fn assign(&self, lhs: &Lvalue<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
917+
Statement {
918+
source_info: self.source_info,
919+
kind: StatementKind::Assign(lhs.clone(), rhs)
920+
}
921+
}
839922
}

0 commit comments

Comments
 (0)