Skip to content

Commit

Permalink
Auto merge of #117330 - tmiasko:custom-mir-cleanup-blocks, r=cjgillot
Browse files Browse the repository at this point in the history
Custom MIR: Support cleanup blocks

Cleanup blocks are declared with `bb (cleanup) = { ... }`.

`Call` and `Drop` terminators take an additional argument describing the unwind action, which is one of the following:

* `UnwindContinue()`
* `UnwindUnreachable()`
* `UnwindTerminate(reason)`, where reason is `ReasonAbi` or `ReasonInCleanup`
* `UnwindCleanup(block)`

Also support unwind resume and unwind terminate terminators:

* `UnwindResume()`
* `UnwindTerminate(reason)`
  • Loading branch information
bors committed Nov 14, 2023
2 parents 173b6e6 + 78da577 commit 5526682
Show file tree
Hide file tree
Showing 38 changed files with 428 additions and 107 deletions.
13 changes: 13 additions & 0 deletions compiler/rustc_mir_build/src/build/custom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
expected: expected.to_string(),
}
}

fn stmt_error(&self, stmt: StmtId, expected: &'static str) -> ParseError {
let stmt = &self.thir[stmt];
let span = match stmt.kind {
StmtKind::Expr { expr, .. } => self.thir[expr].span,
StmtKind::Let { span, .. } => span,
};
ParseError {
span,
item_description: format!("{:?}", stmt.kind),
expected: expected.to_string(),
}
}
}

type PResult<T> = Result<T, ParseError>;
48 changes: 36 additions & 12 deletions compiler/rustc_mir_build/src/build/custom/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ macro_rules! parse_by_kind {
$expr_name:pat,
$expected:literal,
$(
@call($name:literal, $args:ident) => $call_expr:expr,
@call($name:ident, $args:ident) => $call_expr:expr,
)*
$(
$pat:pat => $expr:expr,
@variant($adt:ident, $variant:ident) => $variant_expr:expr,
)*
$(
$pat:pat $(if $guard:expr)? => $expr:expr,
)*
) => {{
let expr_id = $self.preparse($expr_id);
Expand All @@ -42,14 +45,20 @@ macro_rules! parse_by_kind {
ExprKind::Call { ty, fun: _, args: $args, .. } if {
match ty.kind() {
ty::FnDef(did, _) => {
$self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
$self.tcx.is_diagnostic_item(rustc_span::sym::$name, *did)
}
_ => false,
}
} => $call_expr,
)*
$(
$pat => $expr,
ExprKind::Adt(box AdtExpr { adt_def, variant_index, .. }) if {
$self.tcx.is_diagnostic_item(rustc_span::sym::$adt, adt_def.did()) &&
adt_def.variants()[*variant_index].name == rustc_span::sym::$variant
} => $variant_expr,
)*
$(
$pat $(if $guard)? => $expr,
)*
#[allow(unreachable_patterns)]
_ => return Err($self.expr_error(expr_id, $expected))
Expand Down Expand Up @@ -172,7 +181,8 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
ExprKind::Block { block } => &self.thir[*block].stmts,
);
for (i, block_def) in block_defs.iter().enumerate() {
let block = self.parse_block_def(self.statement_as_expr(*block_def)?)?;
let is_cleanup = self.body.basic_blocks_mut()[BasicBlock::from_usize(i)].is_cleanup;
let block = self.parse_block_def(self.statement_as_expr(*block_def)?, is_cleanup)?;
self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
}

Expand All @@ -181,15 +191,28 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {

fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
for stmt in stmts {
let (var, _, _) = self.parse_let_statement(stmt)?;
let data = BasicBlockData::new(None);
let block = self.body.basic_blocks_mut().push(data);
self.block_map.insert(var, block);
self.parse_basic_block_decl(stmt)?;
}

Ok(())
}

fn parse_basic_block_decl(&mut self, stmt: StmtId) -> PResult<()> {
match &self.thir[stmt].kind {
StmtKind::Let { pattern, initializer: Some(initializer), .. } => {
let (var, ..) = self.parse_var(pattern)?;
let mut data = BasicBlockData::new(None);
data.is_cleanup = parse_by_kind!(self, *initializer, _, "basic block declaration",
@variant(mir_basic_block, Normal) => false,
@variant(mir_basic_block, Cleanup) => true,
);
let block = self.body.basic_blocks_mut().push(data);
self.block_map.insert(var, block);
Ok(())
}
_ => Err(self.stmt_error(stmt, "let statement with an initializer")),
}
}

fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
self.local_map.insert(ret_var, Local::from_u32(0));
Expand Down Expand Up @@ -219,7 +242,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
};
let span = self.thir[expr].span;
let (name, operand) = parse_by_kind!(self, expr, _, "debuginfo",
@call("mir_debuginfo", args) => {
@call(mir_debuginfo, args) => {
(args[0], args[1])
},
);
Expand Down Expand Up @@ -281,12 +304,13 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
}
}

fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
fn parse_block_def(&self, expr_id: ExprId, is_cleanup: bool) -> PResult<BasicBlockData<'tcx>> {
let block = parse_by_kind!(self, expr_id, _, "basic block",
ExprKind::Block { block } => &self.thir[*block],
);

let mut data = BasicBlockData::new(None);
data.is_cleanup = is_cleanup;
for stmt_id in &*block.stmts {
let stmt = self.statement_as_expr(*stmt_id)?;
let span = self.thir[stmt].span;
Expand Down
83 changes: 59 additions & 24 deletions compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ use super::{parse_by_kind, PResult, ParseCtxt};
impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
parse_by_kind!(self, expr_id, _, "statement",
@call("mir_storage_live", args) => {
@call(mir_storage_live, args) => {
Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
},
@call("mir_storage_dead", args) => {
@call(mir_storage_dead, args) => {
Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
},
@call("mir_deinit", args) => {
@call(mir_deinit, args) => {
Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
},
@call("mir_retag", args) => {
@call(mir_retag, args) => {
Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
},
@call("mir_set_discriminant", args) => {
@call(mir_set_discriminant, args) => {
let place = self.parse_place(args[0])?;
let var = self.parse_integer_literal(args[1])? as u32;
Ok(StatementKind::SetDiscriminant {
Expand All @@ -43,24 +43,30 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {

pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
parse_by_kind!(self, expr_id, expr, "terminator",
@call("mir_return", _args) => {
@call(mir_return, _args) => {
Ok(TerminatorKind::Return)
},
@call("mir_goto", args) => {
@call(mir_goto, args) => {
Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
},
@call("mir_unreachable", _args) => {
@call(mir_unreachable, _args) => {
Ok(TerminatorKind::Unreachable)
},
@call("mir_drop", args) => {
@call(mir_unwind_resume, _args) => {
Ok(TerminatorKind::UnwindResume)
},
@call(mir_unwind_terminate, args) => {
Ok(TerminatorKind::UnwindTerminate(self.parse_unwind_terminate_reason(args[0])?))
},
@call(mir_drop, args) => {
Ok(TerminatorKind::Drop {
place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?,
unwind: UnwindAction::Continue,
unwind: self.parse_unwind_action(args[2])?,
replace: false,
})
},
@call("mir_call", args) => {
@call(mir_call, args) => {
self.parse_call(args)
},
ExprKind::Match { scrutinee, arms, .. } => {
Expand All @@ -70,6 +76,34 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
)
}

fn parse_unwind_terminate_reason(&self, expr_id: ExprId) -> PResult<UnwindTerminateReason> {
parse_by_kind!(self, expr_id, _, "unwind terminate reason",
@variant(mir_unwind_terminate_reason, Abi) => {
Ok(UnwindTerminateReason::Abi)
},
@variant(mir_unwind_terminate_reason, InCleanup) => {
Ok(UnwindTerminateReason::InCleanup)
},
)
}

fn parse_unwind_action(&self, expr_id: ExprId) -> PResult<UnwindAction> {
parse_by_kind!(self, expr_id, _, "unwind action",
@call(mir_unwind_continue, _args) => {
Ok(UnwindAction::Continue)
},
@call(mir_unwind_unreachable, _args) => {
Ok(UnwindAction::Unreachable)
},
@call(mir_unwind_terminate, args) => {
Ok(UnwindAction::Terminate(self.parse_unwind_terminate_reason(args[0])?))
},
@call(mir_unwind_cleanup, args) => {
Ok(UnwindAction::Cleanup(self.parse_block(args[0])?))
},
)
}

fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
let Some((otherwise, rest)) = arms.split_last() else {
return Err(ParseError {
Expand Down Expand Up @@ -113,6 +147,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
);
let destination = self.parse_place(destination)?;
let target = self.parse_block(args[1])?;
let unwind = self.parse_unwind_action(args[2])?;

parse_by_kind!(self, call, _, "function call",
ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
Expand All @@ -126,7 +161,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
args,
destination,
target: Some(target),
unwind: UnwindAction::Continue,
unwind,
call_source: if *from_hir_call { CallSource::Normal } else {
CallSource::OverloadedOperator
},
Expand All @@ -138,25 +173,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {

fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
parse_by_kind!(self, expr_id, expr, "rvalue",
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
@call("mir_cast_transmute", args) => {
@call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
@call(mir_cast_transmute, args) => {
let source = self.parse_operand(args[0])?;
Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
},
@call("mir_checked", args) => {
@call(mir_checked, args) => {
parse_by_kind!(self, args[0], _, "binary op",
ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
)),
)
},
@call("mir_offset", args) => {
@call(mir_offset, args) => {
let ptr = self.parse_operand(args[0])?;
let offset = self.parse_operand(args[1])?;
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
},
@call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
@call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
ExprKind::Borrow { borrow_kind, arg } => Ok(
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
),
Expand Down Expand Up @@ -206,9 +241,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {

pub fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
parse_by_kind!(self, expr_id, expr, "operand",
@call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
@call("mir_static", args) => self.parse_static(args[0]),
@call("mir_static_mut", args) => self.parse_static(args[0]),
@call(mir_move, args) => self.parse_place(args[0]).map(Operand::Move),
@call(mir_static, args) => self.parse_static(args[0]),
@call(mir_static_mut, args) => self.parse_static(args[0]),
ExprKind::Literal { .. }
| ExprKind::NamedConst { .. }
| ExprKind::NonHirLiteral { .. }
Expand All @@ -229,23 +264,23 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {

fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
@call("mir_field", args) => {
@call(mir_field, args) => {
let (parent, ty) = self.parse_place_inner(args[0])?;
let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
let field_ty = ty.field_ty(self.tcx, field);
let proj = PlaceElem::Field(field, field_ty);
let place = parent.project_deeper(&[proj], self.tcx);
return Ok((place, PlaceTy::from_ty(field_ty)));
},
@call("mir_variant", args) => {
@call(mir_variant, args) => {
(args[0], PlaceElem::Downcast(
None,
VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
))
},
ExprKind::Deref { arg } => {
parse_by_kind!(self, *arg, _, "does not matter",
@call("mir_make_place", args) => return self.parse_place_inner(args[0]),
@call(mir_make_place, args) => return self.parse_place_inner(args[0]),
_ => (*arg, PlaceElem::Deref),
)
},
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ symbols! {
// There is currently no checking that all symbols are used; that would be
// nice to have.
Symbols {
Abi,
AcqRel,
Acquire,
AddToDiagnostic,
Expand Down Expand Up @@ -166,6 +167,7 @@ symbols! {
CString,
Capture,
Center,
Cleanup,
Clone,
Command,
ConstParamTy,
Expand Down Expand Up @@ -215,6 +217,7 @@ symbols! {
HashSet,
Hasher,
Implied,
InCleanup,
IndexOutput,
Input,
Instant,
Expand Down Expand Up @@ -258,6 +261,7 @@ symbols! {
NonZeroU8,
NonZeroUsize,
None,
Normal,
Ok,
Option,
Ord,
Expand Down Expand Up @@ -1023,6 +1027,36 @@ symbols! {
minnumf32,
minnumf64,
mips_target_feature,
mir_basic_block,
mir_call,
mir_cast_transmute,
mir_checked,
mir_copy_for_deref,
mir_debuginfo,
mir_deinit,
mir_discriminant,
mir_drop,
mir_field,
mir_goto,
mir_len,
mir_make_place,
mir_move,
mir_offset,
mir_retag,
mir_return,
mir_set_discriminant,
mir_static,
mir_static_mut,
mir_storage_dead,
mir_storage_live,
mir_unreachable,
mir_unwind_cleanup,
mir_unwind_continue,
mir_unwind_resume,
mir_unwind_terminate,
mir_unwind_terminate_reason,
mir_unwind_unreachable,
mir_variant,
miri,
misc,
mmx_reg,
Expand Down
Loading

0 comments on commit 5526682

Please sign in to comment.