diff --git a/Cargo.lock b/Cargo.lock index 92bac995bc6..9fe70870140 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3815,6 +3815,7 @@ dependencies = [ "rustc_query_system", "rustc_resolve", "rustc_session", + "rustc_smir", "rustc_span", "rustc_symbol_mangling", "rustc_target", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index da7c2440faa..545ff32e598 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -43,6 +43,7 @@ rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } rustc_session = { path = "../rustc_session" } +rustc_smir ={ path = "../rustc_smir" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index cc533b9941a..7cd63bc6422 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -9,6 +9,7 @@ use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; +use rustc_smir::rustc_internal::pretty::write_smir_pretty; use rustc_span::symbol::Ident; use rustc_span::FileName; @@ -325,6 +326,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { write_mir_graphviz(ex.tcx(), None, &mut out).unwrap(); String::from_utf8(out).unwrap() } + StableMir => { + let mut out = Vec::new(); + write_smir_pretty(ex.tcx(), &mut out).unwrap(); + String::from_utf8(out).unwrap() + } ThirTree => { let tcx = ex.tcx(); let mut out = String::new(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index add40b83d21..d4f9122e7e3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2926,12 +2926,13 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> "thir-tree" => ThirTree, "thir-flat" => ThirFlat, "mir" => Mir, + "stable-mir" => StableMir, "mir-cfg" => MirCFG, name => handler.early_error(format!( "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ - `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \ + `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \ `mir-cfg`; got {name}" )), }; @@ -3106,6 +3107,8 @@ pub enum PpMode { Mir, /// `-Zunpretty=mir-cfg` MirCFG, + /// `-Zunpretty=stable-mir` + StableMir, } impl PpMode { @@ -3122,7 +3125,8 @@ impl PpMode { | ThirTree | ThirFlat | Mir - | MirCFG => true, + | MirCFG + | StableMir => true, } } pub fn needs_hir(&self) -> bool { @@ -3130,13 +3134,13 @@ impl PpMode { match *self { Source(_) | AstTree | AstTreeExpanded => false, - Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, + Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG | StableMir => true, } } pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat) + matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat) } } diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index c82f948f195..fa75fd3076c 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -21,6 +21,7 @@ use std::hash::Hash; use std::ops::Index; mod internal; +pub mod pretty; pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { with_tables(|tables| item.stable(tables)) diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs new file mode 100644 index 00000000000..3ef2d28ea47 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs @@ -0,0 +1,20 @@ +use std::io; + +use super::run; +use rustc_middle::ty::TyCtxt; + +pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> { + writeln!( + w, + "// WARNING: This is highly experimental output it's intended for stable-mir developers only." + )?; + writeln!( + w, + "// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir." + )?; + let _ = run(tcx, || { + let items = stable_mir::all_local_items(); + let _ = items.iter().map(|item| -> io::Result<()> { item.dump(w) }).collect::>(); + }); + Ok(()) +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 3df09cef1c7..89dbf40c7b4 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,7 +7,7 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::rustc_internal::{IndexMap, RustcInternal}; +use crate::rustc_internal::{internal, IndexMap, RustcInternal}; use crate::rustc_smir::stable_mir::ty::{BoundRegion, Region}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -105,6 +105,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables) } + fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { + internal(cnst).to_string() + } + fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { let mut tables = self.0.borrow_mut(); tables.tcx.def_span(tables[def_id]).stable(&mut *tables) @@ -404,6 +408,7 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { .map(|decl| stable_mir::mir::LocalDecl { ty: decl.ty.stable(tables), span: decl.source_info.span.stable(tables), + mutability: decl.mutability.stable(tables), }) .collect(), self.arg_count, diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 0262fb536e7..79102dcce35 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -19,9 +19,9 @@ use crate::mir::mono::InstanceDef; use crate::mir::Body; -use std::cell::Cell; use std::fmt; use std::fmt::Debug; +use std::{cell::Cell, io}; use self::ty::{ GenericPredicates, Generics, ImplDef, ImplTrait, IndexedVal, LineInfo, Span, TraitDecl, @@ -36,10 +36,12 @@ pub mod mir; pub mod ty; pub mod visitor; +use crate::mir::pretty::function_name; +use crate::mir::Mutability; use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind}; pub use error::*; use mir::mono::Instance; -use ty::{FnDef, GenericArgs}; +use ty::{Const, FnDef, GenericArgs}; /// Use String for now but we should replace it. pub type Symbol = String; @@ -137,6 +139,11 @@ impl CrateItem { pub fn ty(&self) -> Ty { with(|cx| cx.def_ty(self.0)) } + + pub fn dump(&self, w: &mut W) -> io::Result<()> { + writeln!(w, "{}", function_name(*self))?; + self.body().dump(w) + } } /// Return the function where execution starts if the current @@ -223,6 +230,9 @@ pub trait Context { /// Returns the type of given crate item. fn def_ty(&self, item: DefId) -> Ty; + /// Returns literal value of a const as a string. + fn const_literal(&self, cnst: &Const) -> String; + /// `Span` of an item fn span_of_an_item(&self, def_id: DefId) -> Span; diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index 2e1714b49c1..2cbe6eb4ad1 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -1,5 +1,6 @@ mod body; pub mod mono; +pub mod pretty; pub mod visit; pub use body::*; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 351e7bb69c3..fa58a7ffe15 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,7 +1,8 @@ +use crate::mir::pretty::{function_body, pretty_statement}; use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, Ty}; use crate::Opaque; use crate::Span; - +use std::io; /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -56,6 +57,28 @@ impl Body { pub fn locals(&self) -> &[LocalDecl] { &self.locals } + + pub fn dump(&self, w: &mut W) -> io::Result<()> { + writeln!(w, "{}", function_body(self))?; + self.blocks + .iter() + .enumerate() + .map(|(index, block)| -> io::Result<()> { + writeln!(w, " bb{}: {{", index)?; + let _ = block + .statements + .iter() + .map(|statement| -> io::Result<()> { + writeln!(w, "{}", pretty_statement(&statement.kind))?; + Ok(()) + }) + .collect::>(); + writeln!(w, " }}").unwrap(); + Ok(()) + }) + .collect::, _>>()?; + Ok(()) + } } type LocalDecls = Vec; @@ -64,6 +87,7 @@ type LocalDecls = Vec; pub struct LocalDecl { pub ty: Ty, pub span: Span, + pub mutability: Mutability, } #[derive(Clone, Debug)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs new file mode 100644 index 00000000000..e52c3360ce4 --- /dev/null +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -0,0 +1,258 @@ +use crate::mir::{Operand, Rvalue, StatementKind}; +use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; +use crate::{with, Body, CrateItem, Mutability}; + +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()); + } + StatementKind::FakeRead(_, _) => todo!(), + StatementKind::SetDiscriminant { .. } => todo!(), + StatementKind::Deinit(_) => todo!(), + StatementKind::StorageLive(_) => todo!(), + StatementKind::StorageDead(_) => todo!(), + StatementKind::Retag(_, _) => todo!(), + StatementKind::PlaceMention(_) => todo!(), + StatementKind::AscribeUserType { .. } => todo!(), + StatementKind::Coverage(_) => todo!(), + StatementKind::Intrinsic(_) => todo!(), + StatementKind::ConstEvalCounter => (), + StatementKind::Nop => (), + } + pretty +} + +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(_, _) => todo!(), + 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(); + pretty.push_str(""); + 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, _) => 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), + } +} diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index d6304d3ea39..40bedd67352 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -157,7 +157,7 @@ pub trait MirVisitor { fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) { let _ = local; - let LocalDecl { ty, span } = decl; + let LocalDecl { ty, span, .. } = decl; self.visit_ty(ty, Location(*span)); }