From ae179a04b64d56fa4d648fccf3db661301550797 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?O=C4=9Fuz=20A=C4=9Fcayaz=C4=B1?= <ouz.agz@gmail.com>
Date: Wed, 8 Nov 2023 12:37:26 +0300
Subject: [PATCH] emit basic smir

---
 compiler/rustc_driver_impl/Cargo.toml         |   1 +
 compiler/rustc_driver_impl/src/pretty.rs      |   6 +
 compiler/rustc_session/src/config.rs          |  10 +-
 compiler/rustc_smir/src/rustc_internal/mod.rs |   7 +
 .../rustc_smir/src/rustc_internal/pretty.rs   | 133 ++++++++++++++++++
 compiler/rustc_smir/src/rustc_smir/mod.rs     |   6 +-
 compiler/stable_mir/src/mir/body.rs           |   2 +
 7 files changed, 160 insertions(+), 5 deletions(-)
 create mode 100644 compiler/rustc_smir/src/rustc_internal/pretty.rs

diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index da7c2440faa..e9b5a328422 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -44,6 +44,7 @@ rustc_query_system = { path = "../rustc_query_system" }
 rustc_resolve = { path = "../rustc_resolve" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_smir ={ path = "../rustc_smir" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index cc533b9941a..84f8941ff66 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()
         }
+        Smir => {
+            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..54335645e43 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2926,6 +2926,7 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) ->
         "thir-tree" => ThirTree,
         "thir-flat" => ThirFlat,
         "mir" => Mir,
+        "smir" => Smir,
         "mir-cfg" => MirCFG,
         name => handler.early_error(format!(
             "argument to `unpretty` must be one of `normal`, `identified`, \
@@ -3106,6 +3107,8 @@ pub enum PpMode {
     Mir,
     /// `-Zunpretty=mir-cfg`
     MirCFG,
+    /// `-Zunpretty=smir`
+    Smir,
 }
 
 impl PpMode {
@@ -3122,7 +3125,8 @@ impl PpMode {
             | ThirTree
             | ThirFlat
             | Mir
-            | MirCFG => true,
+            | MirCFG
+            | Smir => 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 | Smir => true,
         }
     }
 
     pub fn needs_analysis(&self) -> bool {
         use PpMode::*;
-        matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat)
+        matches!(*self, Hir(PpHirMode::Typed) | Mir | Smir | 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..7957c3ce617 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))
@@ -299,4 +300,10 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
 pub trait RustcInternal<'tcx> {
     type T;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
+
+    /// Use this when you want to convert to a rustc counterpart in user-code.
+    /// Do not use this within the smir crates themselves.
+    fn internal_via_tls(&self) -> Self::T {
+        with_tables(|tables| self.internal(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..e9af5081353
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs
@@ -0,0 +1,133 @@
+use std::io;
+
+use rustc_middle::ty::TyCtxt;
+use stable_mir::{
+    ty::{RigidTy, TyKind},
+    CrateItem, mir::Mutability,
+};
+
+
+use super::{run, RustcInternal};
+
+pub fn write_smir_pretty<'tcx>(tcx: TyCtxt<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { 
+    run(tcx, || {
+        let items = stable_mir::all_local_items();
+        items.iter().for_each(|item| {
+            // Because we can't return a Result from a closure, we have to unwrap here.
+            writeln!(w, "{}", function_name(*item,tcx)).unwrap();
+            writeln!(w, "{}", function_body(*item,tcx)).unwrap();
+        })
+    });
+    Ok(())
+}
+
+pub fn function_name(item: CrateItem,tcx: TyCtxt<'_>) -> String {
+    let mut name = String::new();
+    let body  = item.body();
+    name.push_str("fn ");
+    name.push_str(item.name().as_str());
+    if body.arg_locals().is_empty() {
+        name.push_str("()");
+    }else{
+        name.push_str("(");
+    }
+    body.arg_locals().iter().for_each(|local| {
+        name.push_str(format!("_{}: ",local.local).as_str());
+        name.push_str(&pretty_ty(local.ty.kind(), tcx));
+    });
+    if !body.arg_locals().is_empty() {
+        name.push_str(")");
+    }
+    let return_local = body.ret_local();
+    name.push_str(" -> ");
+    name.push_str(&pretty_ty(return_local.ty.kind(), tcx));
+    name.push_str(" {");
+    name
+}
+
+pub fn function_body(item: CrateItem,_tcx: TyCtxt<'_>) -> String {
+    let mut body_str = String::new();
+    let body  = item.body();
+    body.inner_locals().iter().for_each(|local| {
+        body_str.push_str("    ");
+        body_str.push_str(format!("let {}",ret_mutability(&local.mutability)).as_str());
+        body_str.push_str(format!("_{}: ",local.local).as_str());
+        body_str.push_str(format!("{}",pretty_ty(local.ty.kind(), _tcx)).as_str());
+        body_str.push_str(";\n");
+
+    });
+    body_str.push_str("}");
+    body_str
+
+}
+
+pub fn ret_mutability(mutability: &Mutability) -> String {
+    match mutability {
+        Mutability::Not => "".to_string(),
+        Mutability::Mut => "mut ".to_string(),
+    }
+}
+
+pub fn pretty_ty<'tcx>(ty: TyKind,tcx: TyCtxt<'tcx>) -> 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 {
+                stable_mir::ty::IntTy::Isize => "isize".to_string(),
+                stable_mir::ty::IntTy::I8 => "i8".to_string(),
+                stable_mir::ty::IntTy::I16 => "i16".to_string(),
+                stable_mir::ty::IntTy::I32 => "i32".to_string(),
+                stable_mir::ty::IntTy::I64 => "i64".to_string(),
+                stable_mir::ty::IntTy::I128 => "i128".to_string(),
+            },
+            RigidTy::Uint(u) => match u {
+                stable_mir::ty::UintTy::Usize => "usize".to_string(),
+                stable_mir::ty::UintTy::U8 => "u8".to_string(),
+                stable_mir::ty::UintTy::U16 => "u16".to_string(),
+                stable_mir::ty::UintTy::U32 => "u32".to_string(),
+                stable_mir::ty::UintTy::U64 => "u64".to_string(),
+                stable_mir::ty::UintTy::U128 => "u128".to_string(),
+            },
+            RigidTy::Float(f) => match f {
+                stable_mir::ty::FloatTy::F32 => "f32".to_string(),
+                stable_mir::ty::FloatTy::F64 => "f64".to_string(),
+            },
+            RigidTy::Adt(def, _) => format!("{:#?}", tcx.type_of(def.0.internal_via_tls()).instantiate_identity()),
+            RigidTy::Foreign(_) => format!("{:#?}", rigid_ty),
+            RigidTy::Str => "str".to_string(),
+            RigidTy::Array(_ty, len) => {
+                format!("[{};{:#?}]", 1,len.internal_via_tls())},
+            RigidTy::Slice(ty) => pretty_ty(ty.kind(),tcx),
+            RigidTy::RawPtr(_, _) => format!("{:#?}", rigid_ty),
+            RigidTy::Ref(_, ty, _) => pretty_ty(ty.kind(),tcx),
+            RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
+            RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
+            RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
+            RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty),
+            RigidTy::Dynamic(_, _, _) => format!("{:#?}", rigid_ty),
+            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(),tcx));
+                        if i != tuple.len() - 1 {
+                            tuple_str.push_str(", ");
+                        }
+                    });
+                    tuple_str.push_str(")");
+                    tuple_str
+                }
+            },
+        },
+        TyKind::Alias(_, _) => format!("{:#?}", ty),
+        TyKind::Param(_) => format!("{:#?}", ty),
+        TyKind::Bound(_, _) => format!("{:#?}", ty),
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 3df09cef1c7..69b0c0bb80d 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -400,10 +400,12 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
                 })
                 .collect(),
             self.local_decls
-                .iter()
-                .map(|decl| stable_mir::mir::LocalDecl {
+                .iter_enumerated()
+                .map(|(local, decl)| stable_mir::mir::LocalDecl {
                     ty: decl.ty.stable(tables),
                     span: decl.source_info.span.stable(tables),
+                    local: local.as_usize(),
+                    mutability: decl.mutability.stable(tables),
                 })
                 .collect(),
             self.arg_count,
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 351e7bb69c3..2981d6a8bb5 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -64,6 +64,8 @@ type LocalDecls = Vec<LocalDecl>;
 pub struct LocalDecl {
     pub ty: Ty,
     pub span: Span,
+    pub local: Local,
+    pub mutability: Mutability,
 }
 
 #[derive(Clone, Debug)]