summaryrefslogtreecommitdiffstats
path: root/compiler/stable_mir/src/mir/pretty.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/stable_mir/src/mir/pretty.rs
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/stable_mir/src/mir/pretty.rs')
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs483
1 files changed, 483 insertions, 0 deletions
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
new file mode 100644
index 000000000..8b7b488d3
--- /dev/null
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -0,0 +1,483 @@
+use crate::crate_def::CrateDef;
+use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction};
+use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
+use crate::{with, Body, CrateItem, Mutability};
+use std::io::Write;
+use std::{io, iter};
+
+use super::{AssertMessage, BinOp, TerminatorKind};
+
+pub fn function_name(item: CrateItem) -> String {
+ let mut pretty_name = String::new();
+ let body = item.body();
+ pretty_name.push_str("fn ");
+ pretty_name.push_str(item.name().as_str());
+ if body.arg_locals().is_empty() {
+ pretty_name.push_str("()");
+ } else {
+ pretty_name.push_str("(");
+ }
+ body.arg_locals().iter().enumerate().for_each(|(index, local)| {
+ pretty_name.push_str(format!("_{}: ", index).as_str());
+ pretty_name.push_str(&pretty_ty(local.ty.kind()));
+ });
+ if !body.arg_locals().is_empty() {
+ pretty_name.push_str(")");
+ }
+ let return_local = body.ret_local();
+ pretty_name.push_str(" -> ");
+ pretty_name.push_str(&pretty_ty(return_local.ty.kind()));
+ pretty_name.push_str(" {");
+ pretty_name
+}
+
+pub fn function_body(body: &Body) -> String {
+ let mut pretty_body = String::new();
+ body.inner_locals().iter().enumerate().for_each(|(index, local)| {
+ pretty_body.push_str(" ");
+ pretty_body.push_str(format!("let {}", ret_mutability(&local.mutability)).as_str());
+ pretty_body.push_str(format!("_{}: ", index).as_str());
+ pretty_body.push_str(format!("{}", pretty_ty(local.ty.kind())).as_str());
+ pretty_body.push_str(";\n");
+ });
+ pretty_body.push_str("}");
+ pretty_body
+}
+
+pub fn ret_mutability(mutability: &Mutability) -> String {
+ match mutability {
+ Mutability::Not => "".to_string(),
+ Mutability::Mut => "mut ".to_string(),
+ }
+}
+
+pub fn pretty_statement(statement: &StatementKind) -> String {
+ let mut pretty = String::new();
+ match statement {
+ StatementKind::Assign(place, rval) => {
+ pretty.push_str(format!(" _{} = ", place.local).as_str());
+ pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str());
+ }
+ // FIXME: Add rest of the statements
+ StatementKind::FakeRead(_, _) => {
+ return String::from("StatementKind::FakeRead:Unimplemented");
+ }
+ StatementKind::SetDiscriminant { .. } => {
+ return String::from("StatementKind::SetDiscriminant:Unimplemented");
+ }
+ StatementKind::Deinit(_) => return String::from("StatementKind::Deinit:Unimplemented"),
+ StatementKind::StorageLive(_) => {
+ return String::from("StatementKind::StorageLive:Unimplemented");
+ }
+ StatementKind::StorageDead(_) => {
+ return String::from("StatementKind::StorageDead:Unimplemented");
+ }
+ StatementKind::Retag(_, _) => return String::from("StatementKind::Retag:Unimplemented"),
+ StatementKind::PlaceMention(_) => {
+ return String::from("StatementKind::PlaceMention:Unimplemented");
+ }
+ StatementKind::AscribeUserType { .. } => {
+ return String::from("StatementKind::AscribeUserType:Unimplemented");
+ }
+ StatementKind::Coverage(_) => return String::from("StatementKind::Coverage:Unimplemented"),
+ StatementKind::Intrinsic(_) => {
+ return String::from("StatementKind::Intrinsic:Unimplemented");
+ }
+ StatementKind::ConstEvalCounter => {
+ return String::from("StatementKind::ConstEvalCounter:Unimplemented");
+ }
+ StatementKind::Nop => return String::from("StatementKind::Nop:Unimplemented"),
+ }
+ pretty
+}
+
+pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
+ write!(w, "{}", pretty_terminator_head(terminator))?;
+ let successors = terminator.successors();
+ let successor_count = successors.len();
+ 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, " -> {:?}", successors[0])?;
+ Ok(())
+ }
+ _ => {
+ write!(w, " -> [")?;
+ for (i, target) in successors.iter().enumerate() {
+ if i > 0 {
+ write!(w, ", ")?;
+ }
+ write!(w, "{}: bb{:?}", 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 {
+ Goto { .. } => format!(" goto"),
+ SwitchInt { discr, .. } => {
+ format!(" switchInt(_{})", pretty_operand(discr))
+ }
+ 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(&pretty_operand(func));
+ pretty.push_str("(");
+ args.iter().enumerate().for_each(|(i, arg)| {
+ if i > 0 {
+ pretty.push_str(", ");
+ }
+ pretty.push_str(&pretty_operand(arg));
+ });
+ pretty.push_str(")");
+ pretty
+ }
+ Assert { cond, expected, msg, target: _, unwind: _ } => {
+ pretty.push_str(" assert(");
+ if !expected {
+ pretty.push_str("!");
+ }
+ pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str());
+ pretty.push_str(&pretty_assert_message(msg));
+ pretty.push_str(")");
+ pretty
+ }
+ InlineAsm { .. } => todo!(),
+ }
+}
+
+pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
+ use self::TerminatorKind::*;
+ match terminator {
+ Resume | Abort | Return | Unreachable => vec![],
+ Goto { .. } => vec!["".to_string()],
+ SwitchInt { targets, .. } => targets
+ .branches()
+ .map(|(val, _target)| format!("{val}"))
+ .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!(),
+ }
+}
+
+pub fn pretty_assert_message(msg: &AssertMessage) -> String {
+ let mut pretty = String::new();
+ match msg {
+ AssertMessage::BoundsCheck { len, index } => {
+ let pretty_len = pretty_operand(len);
+ let pretty_index = pretty_operand(index);
+ pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Add, l, r) => {
+ let pretty_l = pretty_operand(l);
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Sub, l, r) => {
+ let pretty_l = pretty_operand(l);
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Mul, l, r) => {
+ let pretty_l = pretty_operand(l);
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Div, l, r) => {
+ let pretty_l = pretty_operand(l);
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Rem, l, r) => {
+ let pretty_l = pretty_operand(l);
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Shr, _, r) => {
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(
+ format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
+ .as_str(),
+ );
+ pretty
+ }
+ AssertMessage::Overflow(BinOp::Shl, _, r) => {
+ let pretty_r = pretty_operand(r);
+ pretty.push_str(
+ format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
+ .as_str(),
+ );
+ pretty
+ }
+ AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op),
+ AssertMessage::OverflowNeg(op) => {
+ let pretty_op = pretty_operand(op);
+ pretty.push_str(
+ format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(),
+ );
+ pretty
+ }
+ AssertMessage::DivisionByZero(op) => {
+ let pretty_op = pretty_operand(op);
+ pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str());
+ pretty
+ }
+ AssertMessage::RemainderByZero(op) => {
+ let pretty_op = pretty_operand(op);
+ pretty.push_str(
+ format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(),
+ );
+ pretty
+ }
+ AssertMessage::MisalignedPointerDereference { required, found } => {
+ let pretty_required = pretty_operand(required);
+ let pretty_found = pretty_operand(found);
+ pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str());
+ pretty
+ }
+ AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => {
+ msg.description().unwrap().to_string()
+ }
+ }
+}
+
+pub fn pretty_operand(operand: &Operand) -> String {
+ let mut pretty = String::new();
+ match operand {
+ Operand::Copy(copy) => {
+ pretty.push_str("");
+ pretty.push_str(format!("{}", copy.local).as_str());
+ }
+ Operand::Move(mv) => {
+ pretty.push_str("move ");
+ pretty.push_str(format!("_{}", mv.local).as_str());
+ }
+ Operand::Constant(cnst) => {
+ pretty.push_str("const ");
+ pretty.push_str(with(|cx| cx.const_literal(&cnst.literal)).as_str());
+ }
+ }
+ pretty
+}
+
+pub fn pretty_rvalue(rval: &Rvalue) -> String {
+ let mut pretty = String::new();
+ match rval {
+ Rvalue::AddressOf(muta, addr) => {
+ pretty.push_str("&raw ");
+ pretty.push_str(&ret_mutability(muta));
+ pretty.push_str(format!("(*_{})", addr.local).as_str());
+ }
+ Rvalue::Aggregate(aggregatekind, operands) => {
+ pretty.push_str(format!("{:#?}", aggregatekind).as_str());
+ pretty.push_str("(");
+ operands.iter().enumerate().for_each(|(i, op)| {
+ pretty.push_str(&pretty_operand(op));
+ if i != operands.len() - 1 {
+ pretty.push_str(", ");
+ }
+ });
+ pretty.push_str(")");
+ }
+ Rvalue::BinaryOp(bin, op, op2) => {
+ pretty.push_str(&pretty_operand(op));
+ pretty.push_str(" ");
+ pretty.push_str(format!("{:#?}", bin).as_str());
+ pretty.push_str(" ");
+ pretty.push_str(&pretty_operand(op2));
+ }
+ Rvalue::Cast(_, op, ty) => {
+ pretty.push_str(&pretty_operand(op));
+ pretty.push_str(" as ");
+ pretty.push_str(&pretty_ty(ty.kind()));
+ }
+ Rvalue::CheckedBinaryOp(bin, op1, op2) => {
+ pretty.push_str(&pretty_operand(op1));
+ pretty.push_str(" ");
+ pretty.push_str(format!("{:#?}", bin).as_str());
+ pretty.push_str(" ");
+ pretty.push_str(&pretty_operand(op2));
+ }
+ Rvalue::CopyForDeref(deref) => {
+ pretty.push_str("CopyForDeref");
+ pretty.push_str(format!("{}", deref.local).as_str());
+ }
+ Rvalue::Discriminant(place) => {
+ pretty.push_str("discriminant");
+ pretty.push_str(format!("{}", place.local).as_str());
+ }
+ Rvalue::Len(len) => {
+ pretty.push_str("len");
+ pretty.push_str(format!("{}", len.local).as_str());
+ }
+ Rvalue::Ref(_, borrowkind, place) => {
+ pretty.push_str("ref");
+ pretty.push_str(format!("{:#?}", borrowkind).as_str());
+ pretty.push_str(format!("{}", place.local).as_str());
+ }
+ Rvalue::Repeat(op, cnst) => {
+ pretty.push_str(&pretty_operand(op));
+ pretty.push_str(" ");
+ pretty.push_str(&pretty_ty(cnst.ty().kind()));
+ }
+ Rvalue::ShallowInitBox(_, _) => (),
+ Rvalue::ThreadLocalRef(item) => {
+ pretty.push_str("thread_local_ref");
+ pretty.push_str(format!("{:#?}", item).as_str());
+ }
+ Rvalue::NullaryOp(nul, ty) => {
+ pretty.push_str(format!("{:#?}", nul).as_str());
+ pretty.push_str(&pretty_ty(ty.kind()));
+ pretty.push_str(" ");
+ }
+ Rvalue::UnaryOp(un, op) => {
+ pretty.push_str(&pretty_operand(op));
+ pretty.push_str(" ");
+ pretty.push_str(format!("{:#?}", un).as_str());
+ }
+ Rvalue::Use(op) => pretty.push_str(&pretty_operand(op)),
+ }
+ pretty
+}
+
+pub fn pretty_ty(ty: TyKind) -> String {
+ let mut pretty = String::new();
+ match ty {
+ TyKind::RigidTy(rigid_ty) => match rigid_ty {
+ RigidTy::Bool => "bool".to_string(),
+ RigidTy::Char => "char".to_string(),
+ RigidTy::Int(i) => match i {
+ IntTy::Isize => "isize".to_string(),
+ IntTy::I8 => "i8".to_string(),
+ IntTy::I16 => "i16".to_string(),
+ IntTy::I32 => "i32".to_string(),
+ IntTy::I64 => "i64".to_string(),
+ IntTy::I128 => "i128".to_string(),
+ },
+ RigidTy::Uint(u) => match u {
+ UintTy::Usize => "usize".to_string(),
+ UintTy::U8 => "u8".to_string(),
+ UintTy::U16 => "u16".to_string(),
+ UintTy::U32 => "u32".to_string(),
+ UintTy::U64 => "u64".to_string(),
+ UintTy::U128 => "u128".to_string(),
+ },
+ RigidTy::Float(f) => match f {
+ FloatTy::F32 => "f32".to_string(),
+ FloatTy::F64 => "f64".to_string(),
+ },
+ RigidTy::Adt(def, _) => {
+ format!("{:#?}", with(|cx| cx.def_ty(def.0)))
+ }
+ RigidTy::Str => "str".to_string(),
+ RigidTy::Array(ty, len) => {
+ format!("[{}; {}]", pretty_ty(ty.kind()), with(|cx| cx.const_literal(&len)))
+ }
+ RigidTy::Slice(ty) => {
+ format!("[{}]", pretty_ty(ty.kind()))
+ }
+ RigidTy::RawPtr(ty, mutability) => {
+ pretty.push_str("*");
+ match mutability {
+ Mutability::Not => pretty.push_str("const "),
+ Mutability::Mut => pretty.push_str("mut "),
+ }
+ pretty.push_str(&pretty_ty(ty.kind()));
+ pretty
+ }
+ RigidTy::Ref(_, ty, mutability) => match mutability {
+ Mutability::Not => format!("&{}", pretty_ty(ty.kind())),
+ Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())),
+ },
+ RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
+ RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
+ RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
+ RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty),
+ RigidTy::Dynamic(data, region, repr) => {
+ // FIXME: Fix binder printing, it looks ugly now
+ pretty.push_str("(");
+ match repr {
+ DynKind::Dyn => pretty.push_str("dyn "),
+ DynKind::DynStar => pretty.push_str("dyn* "),
+ }
+ pretty.push_str(format!("{:#?}", data).as_str());
+ pretty.push_str(format!(" + {:#?} )", region).as_str());
+ pretty
+ }
+ RigidTy::Never => "!".to_string(),
+ RigidTy::Tuple(tuple) => {
+ if tuple.is_empty() {
+ "()".to_string()
+ } else {
+ let mut tuple_str = String::new();
+ tuple_str.push_str("(");
+ tuple.iter().enumerate().for_each(|(i, ty)| {
+ tuple_str.push_str(&pretty_ty(ty.kind()));
+ if i != tuple.len() - 1 {
+ tuple_str.push_str(", ");
+ }
+ });
+ tuple_str.push_str(")");
+ tuple_str
+ }
+ }
+ _ => format!("{:#?}", rigid_ty),
+ },
+ TyKind::Alias(_, _) => format!("{:#?}", ty),
+ TyKind::Param(param_ty) => {
+ format!("{:#?}", param_ty.name)
+ }
+ TyKind::Bound(_, _) => format!("{:#?}", ty),
+ }
+}