Change SwitchTarget representation
The new structure encodes its invariant, which reduces the likelihood of having an inconsistent representation. It is also more intuitive and user friendly. I encapsulated the structure for now in case we decide to change it back.
This commit is contained in:
parent
07921b50ba
commit
3e0b2fac5d
@ -579,13 +579,12 @@ fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
|||||||
mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
|
mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
|
||||||
discr: discr.stable(tables),
|
discr: discr.stable(tables),
|
||||||
targets: {
|
targets: {
|
||||||
let (value_vec, mut target_vec): (Vec<_>, Vec<_>) =
|
let branches = targets.iter().map(|(val, target)| (val, target.as_usize()));
|
||||||
targets.iter().map(|(value, target)| (value, target.as_usize())).unzip();
|
stable_mir::mir::SwitchTargets::new(
|
||||||
// We need to push otherwise as last element to ensure it's same as in MIR.
|
branches.collect(),
|
||||||
target_vec.push(targets.otherwise().as_usize());
|
targets.otherwise().as_usize(),
|
||||||
stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec }
|
)
|
||||||
},
|
},
|
||||||
otherwise: targets.otherwise().as_usize(),
|
|
||||||
},
|
},
|
||||||
mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
|
mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
|
||||||
mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
|
mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
|
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
|
||||||
};
|
};
|
||||||
use crate::{Error, Opaque, Span, Symbol};
|
use crate::{Error, Opaque, Span, Symbol};
|
||||||
use std::{io, slice};
|
use std::io;
|
||||||
/// The SMIR representation of a single function.
|
/// The SMIR representation of a single function.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
@ -23,6 +23,8 @@ pub struct Body {
|
|||||||
pub(super) var_debug_info: Vec<VarDebugInfo>,
|
pub(super) var_debug_info: Vec<VarDebugInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BasicBlockIdx = usize;
|
||||||
|
|
||||||
impl Body {
|
impl Body {
|
||||||
/// Constructs a `Body`.
|
/// Constructs a `Body`.
|
||||||
///
|
///
|
||||||
@ -114,22 +116,21 @@ pub struct Terminator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Terminator {
|
impl Terminator {
|
||||||
pub fn successors(&self) -> Successors<'_> {
|
pub fn successors(&self) -> Successors {
|
||||||
self.kind.successors()
|
self.kind.successors()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Successors<'a> = impl Iterator<Item = usize> + 'a;
|
pub type Successors = Vec<BasicBlockIdx>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum TerminatorKind {
|
pub enum TerminatorKind {
|
||||||
Goto {
|
Goto {
|
||||||
target: usize,
|
target: BasicBlockIdx,
|
||||||
},
|
},
|
||||||
SwitchInt {
|
SwitchInt {
|
||||||
discr: Operand,
|
discr: Operand,
|
||||||
targets: SwitchTargets,
|
targets: SwitchTargets,
|
||||||
otherwise: usize,
|
|
||||||
},
|
},
|
||||||
Resume,
|
Resume,
|
||||||
Abort,
|
Abort,
|
||||||
@ -137,43 +138,42 @@ pub enum TerminatorKind {
|
|||||||
Unreachable,
|
Unreachable,
|
||||||
Drop {
|
Drop {
|
||||||
place: Place,
|
place: Place,
|
||||||
target: usize,
|
target: BasicBlockIdx,
|
||||||
unwind: UnwindAction,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
func: Operand,
|
func: Operand,
|
||||||
args: Vec<Operand>,
|
args: Vec<Operand>,
|
||||||
destination: Place,
|
destination: Place,
|
||||||
target: Option<usize>,
|
target: Option<BasicBlockIdx>,
|
||||||
unwind: UnwindAction,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
Assert {
|
Assert {
|
||||||
cond: Operand,
|
cond: Operand,
|
||||||
expected: bool,
|
expected: bool,
|
||||||
msg: AssertMessage,
|
msg: AssertMessage,
|
||||||
target: usize,
|
target: BasicBlockIdx,
|
||||||
unwind: UnwindAction,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
CoroutineDrop,
|
|
||||||
InlineAsm {
|
InlineAsm {
|
||||||
template: String,
|
template: String,
|
||||||
operands: Vec<InlineAsmOperand>,
|
operands: Vec<InlineAsmOperand>,
|
||||||
options: String,
|
options: String,
|
||||||
line_spans: String,
|
line_spans: String,
|
||||||
destination: Option<usize>,
|
destination: Option<BasicBlockIdx>,
|
||||||
unwind: UnwindAction,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminatorKind {
|
impl TerminatorKind {
|
||||||
pub fn successors(&self) -> Successors<'_> {
|
pub fn successors(&self) -> Successors {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
|
Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
| Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
| Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
|
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
|
||||||
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
vec![t, u]
|
||||||
}
|
}
|
||||||
Goto { target: t }
|
Goto { target: t }
|
||||||
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
@ -182,21 +182,18 @@ pub fn successors(&self) -> Successors<'_> {
|
|||||||
| Assert { target: t, unwind: _, .. }
|
| Assert { target: t, unwind: _, .. }
|
||||||
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
||||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
vec![t]
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineDrop
|
Return
|
||||||
| Return
|
|
||||||
| Resume
|
| Resume
|
||||||
| Abort
|
| Abort
|
||||||
| Unreachable
|
| Unreachable
|
||||||
| Call { target: None, unwind: _, .. }
|
| Call { target: None, unwind: _, .. }
|
||||||
| InlineAsm { destination: None, unwind: _, .. } => {
|
| InlineAsm { destination: None, unwind: _, .. } => {
|
||||||
None.into_iter().chain((&[]).into_iter().copied())
|
vec![]
|
||||||
}
|
|
||||||
SwitchInt { ref targets, .. } => {
|
|
||||||
None.into_iter().chain(targets.targets.iter().copied())
|
|
||||||
}
|
}
|
||||||
|
SwitchInt { ref targets, .. } => targets.all_targets(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +202,6 @@ pub fn unwind(&self) -> Option<&UnwindAction> {
|
|||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::CoroutineDrop
|
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Abort
|
||||||
| TerminatorKind::SwitchInt { .. } => None,
|
| TerminatorKind::SwitchInt { .. } => None,
|
||||||
@ -231,7 +227,7 @@ pub enum UnwindAction {
|
|||||||
Continue,
|
Continue,
|
||||||
Unreachable,
|
Unreachable,
|
||||||
Terminate,
|
Terminate,
|
||||||
Cleanup(usize),
|
Cleanup(BasicBlockIdx),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@ -662,10 +658,45 @@ pub struct Constant {
|
|||||||
pub literal: Const,
|
pub literal: Const,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The possible branch sites of a [TerminatorKind::SwitchInt].
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct SwitchTargets {
|
pub struct SwitchTargets {
|
||||||
pub value: Vec<u128>,
|
/// The conditional branches where the first element represents the value that guards this
|
||||||
pub targets: Vec<usize>,
|
/// branch, and the second element is the branch target.
|
||||||
|
branches: Vec<(u128, BasicBlockIdx)>,
|
||||||
|
/// The `otherwise` branch which will be taken in case none of the conditional branches are
|
||||||
|
/// satisfied.
|
||||||
|
otherwise: BasicBlockIdx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SwitchTargets {
|
||||||
|
/// All possible targets including the `otherwise` target.
|
||||||
|
pub fn all_targets(&self) -> Successors {
|
||||||
|
Some(self.otherwise)
|
||||||
|
.into_iter()
|
||||||
|
.chain(self.branches.iter().map(|(_, target)| *target))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `otherwise` branch target.
|
||||||
|
pub fn otherwise(&self) -> BasicBlockIdx {
|
||||||
|
self.otherwise
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The conditional targets which are only taken if the pattern matches the given value.
|
||||||
|
pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> + '_ {
|
||||||
|
self.branches.iter().copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of targets including `otherwise`.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.branches.len() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new SwitchTargets from the given branches and `otherwise` target.
|
||||||
|
pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
|
||||||
|
SwitchTargets { branches, otherwise }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -76,7 +76,8 @@ pub fn pretty_statement(statement: &StatementKind) -> String {
|
|||||||
|
|
||||||
pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
|
pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
|
||||||
write!(w, "{}", pretty_terminator_head(terminator))?;
|
write!(w, "{}", pretty_terminator_head(terminator))?;
|
||||||
let successor_count = terminator.successors().count();
|
let successors = terminator.successors();
|
||||||
|
let successor_count = successors.len();
|
||||||
let labels = pretty_successor_labels(terminator);
|
let labels = pretty_successor_labels(terminator);
|
||||||
|
|
||||||
let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
||||||
@ -98,12 +99,12 @@ pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(1, false) => {
|
(1, false) => {
|
||||||
write!(w, " -> {:?}", terminator.successors().next().unwrap())?;
|
write!(w, " -> {:?}", successors[0])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
write!(w, " -> [")?;
|
write!(w, " -> [")?;
|
||||||
for (i, target) in terminator.successors().enumerate() {
|
for (i, target) in successors.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write!(w, ", ")?;
|
write!(w, ", ")?;
|
||||||
}
|
}
|
||||||
@ -157,7 +158,6 @@ pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
|
|||||||
pretty.push_str(")");
|
pretty.push_str(")");
|
||||||
pretty
|
pretty
|
||||||
}
|
}
|
||||||
CoroutineDrop => format!(" coroutine_drop"),
|
|
||||||
InlineAsm { .. } => todo!(),
|
InlineAsm { .. } => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,12 +165,11 @@ pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
|
|||||||
pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match terminator {
|
match terminator {
|
||||||
Resume | Abort | Return | Unreachable | CoroutineDrop => vec![],
|
Resume | Abort | Return | Unreachable => vec![],
|
||||||
Goto { .. } => vec!["".to_string()],
|
Goto { .. } => vec!["".to_string()],
|
||||||
SwitchInt { targets, .. } => targets
|
SwitchInt { targets, .. } => targets
|
||||||
.value
|
.branches()
|
||||||
.iter()
|
.map(|(val, _target)| format!("{val}"))
|
||||||
.map(|target| format!("{}", target))
|
|
||||||
.chain(iter::once("otherwise".into()))
|
.chain(iter::once("otherwise".into()))
|
||||||
.collect(),
|
.collect(),
|
||||||
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
|
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
|
||||||
|
@ -237,8 +237,7 @@ fn super_terminator(&mut self, term: &Terminator, location: Location) {
|
|||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Abort
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable => {}
|
||||||
| TerminatorKind::CoroutineDrop => {}
|
|
||||||
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
||||||
self.visit_operand(cond, location);
|
self.visit_operand(cond, location);
|
||||||
self.visit_assert_msg(msg, location);
|
self.visit_assert_msg(msg, location);
|
||||||
@ -268,7 +267,7 @@ fn super_terminator(&mut self, term: &Terminator, location: Location) {
|
|||||||
let local = RETURN_LOCAL;
|
let local = RETURN_LOCAL;
|
||||||
self.visit_local(&local, PlaceContext::NON_MUTATING, location);
|
self.visit_local(&local, PlaceContext::NON_MUTATING, location);
|
||||||
}
|
}
|
||||||
TerminatorKind::SwitchInt { discr, targets: _, otherwise: _ } => {
|
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||||
self.visit_operand(discr, location);
|
self.visit_operand(discr, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user