Skip to content

Commit

Permalink
Fuse gen blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Oct 27, 2023
1 parent b8bfd08 commit eb66d10
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 35 deletions.
5 changes: 3 additions & 2 deletions compiler/rustc_middle/src/mir/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,9 @@ impl<O> AssertKind<O> {
DivisionByZero(_) => middle_assert_divide_by_zero,
RemainderByZero(_) => middle_assert_remainder_by_zero,
ResumedAfterReturn(CoroutineKind::Async(_)) => middle_assert_async_resume_after_return,
// FIXME(gen_blocks): custom error message for `gen` blocks
ResumedAfterReturn(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_return,
ResumedAfterReturn(CoroutineKind::Gen(_)) => {
bug!("gen blocks can be resumed after they return and will keep returning `None`")
}
ResumedAfterReturn(CoroutineKind::Coroutine) => {
middle_assert_coroutine_resume_after_return
}
Expand Down
63 changes: 49 additions & 14 deletions compiler/rustc_mir_transform/src/coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,34 @@ struct TransformVisitor<'tcx> {
}

impl<'tcx> TransformVisitor<'tcx> {
// Make a `CoroutineState` or `Poll` variant assignment.
//
// `core::ops::CoroutineState` only has single element tuple variants,
// so we can just write to the downcasted first field and then set the
// discriminant to the appropriate variant.
fn make_state(
fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
let block = BasicBlock::new(body.basic_blocks.len());

let source_info = SourceInfo::outermost(body.span);

let (kind, idx) = self.coroutine_state_adt_and_variant_idx(true);
assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 0);
let statements = vec![Statement {
kind: StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::Aggregate(Box::new(kind), IndexVec::new()),
))),
source_info,
}];

body.basic_blocks_mut().push(BasicBlockData {
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});

block
}

fn coroutine_state_adt_and_variant_idx(
&self,
val: Operand<'tcx>,
source_info: SourceInfo,
is_return: bool,
statements: &mut Vec<Statement<'tcx>>,
) {
) -> (AggregateKind<'tcx>, VariantIdx) {
let idx = VariantIdx::new(match (is_return, self.coroutine_kind) {
(true, hir::CoroutineKind::Coroutine) => 1, // CoroutineState::Complete
(false, hir::CoroutineKind::Coroutine) => 0, // CoroutineState::Yielded
Expand All @@ -271,6 +287,22 @@ impl<'tcx> TransformVisitor<'tcx> {
});

let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_args, None, None);
(kind, idx)
}

// Make a `CoroutineState` or `Poll` variant assignment.
//
// `core::ops::CoroutineState` only has single element tuple variants,
// so we can just write to the downcasted first field and then set the
// discriminant to the appropriate variant.
fn make_state(
&self,
val: Operand<'tcx>,
source_info: SourceInfo,
is_return: bool,
statements: &mut Vec<Statement<'tcx>>,
) {
let (kind, idx) = self.coroutine_state_adt_and_variant_idx(is_return);

match self.coroutine_kind {
// `Poll::Pending`
Expand Down Expand Up @@ -1285,10 +1317,13 @@ fn create_coroutine_resume_function<'tcx>(
}

if can_return {
cases.insert(
1,
(RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))),
);
let block = match coroutine_kind {
CoroutineKind::Async(_) | CoroutineKind::Coroutine => {
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
}
CoroutineKind::Gen(_) => transform.insert_none_ret_block(body),
};
cases.insert(1, (RETURNED, block));
}

insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/coroutine/gen_block_iterate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ fn main() {
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next(), None);
// `gen` blocks are fused
assert_eq!(iter.next(), None);

let mut iter = moved();
assert_eq!(iter.next(), Some(42));
Expand Down
19 changes: 0 additions & 19 deletions tests/ui/coroutine/gen_block_iterate_fused.rs

This file was deleted.

0 comments on commit eb66d10

Please sign in to comment.