From 1324363a979924e245f80bc5c386779f95c27936 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 24 Nov 2023 14:34:27 +0300 Subject: [PATCH] add successors and their formatter --- compiler/rustc_smir/src/rustc_smir/mod.rs | 21 +++-- compiler/stable_mir/src/lib.rs | 2 +- compiler/stable_mir/src/mir/body.rs | 76 +++++++++++++-- compiler/stable_mir/src/mir/pretty.rs | 107 +++++++++++++++++++--- 4 files changed, 172 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 2a9f0b4267847..0e5bf797e375a 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -19,8 +19,8 @@ use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; use stable_mir::mir::mono::InstanceDef; use stable_mir::mir::{ - Body, ConstOperand, CopyNonOverlapping, Statement, UserTypeProjection, VarDebugInfoFragment, - VariantIdx, + Body, ConstOperand, CopyNonOverlapping, Statement, Terminator, UserTypeProjection, + VarDebugInfoFragment, VariantIdx, }; use stable_mir::ty::{ AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion, @@ -1171,7 +1171,6 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { type T = stable_mir::mir::Terminator; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use stable_mir::mir::Terminator; Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } } } @@ -1186,13 +1185,15 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { } mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { discr: discr.stable(tables), - targets: targets - .iter() - .map(|(value, target)| stable_mir::mir::SwitchTarget { - value, - target: target.as_usize(), - }) - .collect(), + targets: { + let mut value_vec = Vec::new(); + let mut target_vec = Vec::new(); + targets.iter().for_each(|(value, target)| { + value_vec.push(value); + target_vec.push(target.as_usize()); + }); + stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec } + }, otherwise: targets.otherwise().as_usize(), }, mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index aeaf19128fc41..7f6de7139c3e5 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -16,7 +16,7 @@ //! //! The goal is to eventually be published on //! [crates.io](https://crates.io). - +#![feature(type_alias_impl_trait)] use crate::mir::mono::InstanceDef; use crate::mir::Body; use std::fmt; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 0966f9198a251..02a2868767659 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -3,8 +3,7 @@ use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, }; use crate::{Error, Opaque, Span, Symbol}; -use std::io; - +use std::{io, slice}; /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -83,7 +82,8 @@ impl Body { Ok(()) }) .collect::>(); - writeln!(w, "{}", pretty_terminator(&block.terminator.kind))?; + pretty_terminator(&block.terminator.kind, w)?; + writeln!(w, "").unwrap(); writeln!(w, " }}").unwrap(); Ok(()) }) @@ -101,7 +101,7 @@ pub struct LocalDecl { pub mutability: Mutability, } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct BasicBlock { pub statements: Vec, pub terminator: Terminator, @@ -113,6 +113,14 @@ pub struct Terminator { pub span: Span, } +impl Terminator { + pub fn successors(&self) -> Successors<'_> { + self.kind.successors() + } +} + +pub type Successors<'a> = impl Iterator + 'a; + #[derive(Clone, Debug, Eq, PartialEq)] pub enum TerminatorKind { Goto { @@ -120,7 +128,7 @@ pub enum TerminatorKind { }, SwitchInt { discr: Operand, - targets: Vec, + targets: SwitchTargets, otherwise: usize, }, Resume, @@ -157,6 +165,58 @@ pub enum TerminatorKind { }, } +impl TerminatorKind { + pub fn successors(&self) -> Successors<'_> { + use self::TerminatorKind::*; + match *self { + Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + } + Goto { target: t } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { + Some(t).into_iter().chain((&[]).into_iter().copied()) + } + + CoroutineDrop + | Return + | Resume + | Abort + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { + None.into_iter().chain((&[]).into_iter().copied()) + } + SwitchInt { ref targets, .. } => { + None.into_iter().chain(targets.targets.iter().copied()) + } + } + } + + pub fn unwind(&self) -> Option<&UnwindAction> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::CoroutineDrop + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::SwitchInt { .. } => None, + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct InlineAsmOperand { pub in_value: Option, @@ -603,9 +663,9 @@ pub struct Constant { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SwitchTarget { - pub value: u128, - pub target: usize, +pub struct SwitchTargets { + pub value: Vec, + pub targets: Vec, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index dac024356765b..36eab9994965f 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,4 +1,7 @@ -use crate::mir::{Operand, Rvalue, StatementKind}; +use std::io::Write; +use std::{io, iter}; + +use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction}; use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::{with, Body, CrateItem, Mutability}; @@ -71,21 +74,68 @@ pub fn pretty_statement(statement: &StatementKind) -> String { pretty } -pub fn pretty_terminator(terminator: &TerminatorKind) -> String { +pub fn pretty_terminator(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> { + write!(w, "{}", pretty_terminator_head(terminator))?; + let successor_count = terminator.successors().count(); + let labels = pretty_successor_labels(terminator); + + let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); + let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> { + write!(fmt, "unwind ")?; + match terminator.unwind() { + None | Some(UnwindAction::Cleanup(_)) => unreachable!(), + Some(UnwindAction::Continue) => write!(fmt, "continue"), + Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"), + Some(UnwindAction::Terminate) => write!(fmt, "terminate"), + } + }; + + match (successor_count, show_unwind) { + (0, false) => Ok(()), + (0, true) => { + write!(w, " -> ")?; + fmt_unwind(w)?; + Ok(()) + } + (1, false) => { + write!(w, " -> {:?}", terminator.successors().next().unwrap())?; + Ok(()) + } + _ => { + write!(w, " -> [")?; + for (i, target) in terminator.successors().enumerate() { + if i > 0 { + write!(w, ", ")?; + } + write!(w, "{}: {:?}", labels[i], target)?; + } + if show_unwind { + write!(w, ", ")?; + fmt_unwind(w)?; + } + write!(w, "]") + } + }?; + + Ok(()) +} + +pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { + use self::TerminatorKind::*; let mut pretty = String::new(); match terminator { - TerminatorKind::Goto { .. } => format!(" goto"), - TerminatorKind::SwitchInt { discr, .. } => { + Goto { .. } => format!(" goto"), + SwitchInt { discr, .. } => { format!(" switch({})", pretty_operand(discr)) } - TerminatorKind::Resume => format!(" resume"), - TerminatorKind::Abort => format!(" abort"), - TerminatorKind::Return => format!(" return"), - TerminatorKind::Unreachable => format!(" unreachable"), - TerminatorKind::Drop { place, .. } => format!(" drop({:?})", place.local), - TerminatorKind::Call { func, args, destination, .. } => { + Resume => format!(" resume"), + Abort => format!(" abort"), + Return => format!(" return"), + Unreachable => format!(" unreachable"), + Drop { place, .. } => format!(" drop(_{:?})", place.local), + Call { func, args, destination, .. } => { pretty.push_str(" "); - pretty.push_str(format!("{} = ", destination.local).as_str()); + pretty.push_str(format!("_{} = ", destination.local).as_str()); pretty.push_str(&pretty_operand(func)); pretty.push_str("("); args.iter().enumerate().for_each(|(i, arg)| { @@ -97,18 +147,45 @@ pub fn pretty_terminator(terminator: &TerminatorKind) -> String { pretty.push_str(")"); pretty } - TerminatorKind::Assert { cond, expected, msg, target: _, unwind: _ } => { + Assert { cond, expected, msg, target: _, unwind: _ } => { pretty.push_str(" assert("); if !expected { pretty.push_str("!"); } - pretty.push_str(&pretty_operand(cond)); + pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str()); pretty.push_str(&pretty_assert_message(msg)); pretty.push_str(")"); pretty } - TerminatorKind::CoroutineDrop => format!(" coroutine_drop"), - TerminatorKind::InlineAsm { .. } => todo!(), + CoroutineDrop => format!(" coroutine_drop"), + InlineAsm { .. } => todo!(), + } +} + +pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { + use self::TerminatorKind::*; + match terminator { + Resume | Abort | Return | Unreachable | CoroutineDrop => vec![], + Goto { .. } => vec!["".to_string()], + SwitchInt { targets, .. } => targets + .value + .iter() + .map(|target| format!("{}", target)) + .chain(iter::once("otherwise".into())) + .collect(), + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: _, .. } => vec!["return".into()], + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()], + Call { target: None, unwind: _, .. } => vec![], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] + } + Assert { unwind: _, .. } => vec!["success".into()], + InlineAsm { .. } => todo!(), } }