about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-30 02:59:25 +0000
committerbors <bors@rust-lang.org>2023-03-30 02:59:25 +0000
commit82bfda848e28d7616c7045d7ced8cee88d2d1a8f (patch)
tree616c98d4020a1d6355cecba28f62d3b307ebca30
parent10338571cfa7c2be0aeed309141ced91454d41e1 (diff)
parent480e042097573ad518e43cf2ee8f17ecb755693a (diff)
downloadrust-82bfda848e28d7616c7045d7ced8cee88d2d1a8f.tar.gz
rust-82bfda848e28d7616c7045d7ced8cee88d2d1a8f.zip
Auto merge of #109224 - oli-obk:smir, r=pnkfelix
Stable MIR: Add basic MIR body datastructures

At this point it will panic on most useful MIR, but you can do basic assignments

r? `@pnkfelix`
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs19
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs118
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir.rs3
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/body.rs69
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs10
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs31
6 files changed, 239 insertions, 11 deletions
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 3eaff9c051f..5998c8b6500 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,11 +3,28 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
+use std::sync::RwLock;
+
 use crate::stable_mir;
 pub use rustc_span::def_id::{CrateNum, DefId};
 
+static DEF_ID_MAP: RwLock<Vec<DefId>> = RwLock::new(Vec::new());
+
 pub fn item_def_id(item: &stable_mir::CrateItem) -> DefId {
-    item.0
+    DEF_ID_MAP.read().unwrap()[item.0]
+}
+
+pub fn crate_item(did: DefId) -> stable_mir::CrateItem {
+    // FIXME: this becomes inefficient when we have too many ids
+    let mut map = DEF_ID_MAP.write().unwrap();
+    for (i, &d) in map.iter().enumerate() {
+        if d == did {
+            return stable_mir::CrateItem(i);
+        }
+    }
+    let id = map.len();
+    map.push(did);
+    stable_mir::CrateItem(id)
 }
 
 pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index d956f0ac802..86e30dd0f6a 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,7 +7,10 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
-use crate::stable_mir::{self};
+use crate::{
+    rustc_internal::{crate_item, item_def_id},
+    stable_mir::{self},
+};
 use rustc_middle::ty::{tls::with, TyCtxt};
 use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
 use tracing::debug;
@@ -34,9 +37,7 @@ pub fn find_crate(name: &str) -> Option<stable_mir::Crate> {
 
 /// Retrieve all items of the local crate that have a MIR associated with them.
 pub fn all_local_items() -> stable_mir::CrateItems {
-    with(|tcx| {
-        tcx.mir_keys(()).iter().map(|item| stable_mir::CrateItem(item.to_def_id())).collect()
-    })
+    with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
 }
 
 /// Build a stable mir crate from a given crate number.
@@ -46,3 +47,112 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
     debug!(?crate_name, ?crate_num, "smir_crate");
     stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
 }
+
+pub fn mir_body(item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
+    with(|tcx| {
+        let def_id = item_def_id(item);
+        let mir = tcx.optimized_mir(def_id);
+        stable_mir::mir::Body {
+            blocks: mir
+                .basic_blocks
+                .iter()
+                .map(|block| stable_mir::mir::BasicBlock {
+                    terminator: rustc_terminator_to_terminator(block.terminator()),
+                    statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
+                })
+                .collect(),
+        }
+    })
+}
+
+fn rustc_statement_to_statement(
+    s: &rustc_middle::mir::Statement<'_>,
+) -> stable_mir::mir::Statement {
+    use rustc_middle::mir::StatementKind::*;
+    match &s.kind {
+        Assign(assign) => stable_mir::mir::Statement::Assign(
+            rustc_place_to_place(&assign.0),
+            rustc_rvalue_to_rvalue(&assign.1),
+        ),
+        FakeRead(_) => todo!(),
+        SetDiscriminant { .. } => todo!(),
+        Deinit(_) => todo!(),
+        StorageLive(_) => todo!(),
+        StorageDead(_) => todo!(),
+        Retag(_, _) => todo!(),
+        PlaceMention(_) => todo!(),
+        AscribeUserType(_, _) => todo!(),
+        Coverage(_) => todo!(),
+        Intrinsic(_) => todo!(),
+        ConstEvalCounter => todo!(),
+        Nop => stable_mir::mir::Statement::Nop,
+    }
+}
+
+fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Operand {
+    use rustc_middle::mir::Rvalue::*;
+    match rvalue {
+        Use(op) => rustc_op_to_op(op),
+        Repeat(_, _) => todo!(),
+        Ref(_, _, _) => todo!(),
+        ThreadLocalRef(_) => todo!(),
+        AddressOf(_, _) => todo!(),
+        Len(_) => todo!(),
+        Cast(_, _, _) => todo!(),
+        BinaryOp(_, _) => todo!(),
+        CheckedBinaryOp(_, _) => todo!(),
+        NullaryOp(_, _) => todo!(),
+        UnaryOp(_, _) => todo!(),
+        Discriminant(_) => todo!(),
+        Aggregate(_, _) => todo!(),
+        ShallowInitBox(_, _) => todo!(),
+        CopyForDeref(_) => todo!(),
+    }
+}
+
+fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Operand {
+    use rustc_middle::mir::Operand::*;
+    match op {
+        Copy(place) => stable_mir::mir::Operand::Copy(rustc_place_to_place(place)),
+        Move(place) => stable_mir::mir::Operand::Move(rustc_place_to_place(place)),
+        Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()),
+    }
+}
+
+fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
+    assert_eq!(&place.projection[..], &[]);
+    stable_mir::mir::Place { local: place.local.as_usize() }
+}
+
+fn rustc_terminator_to_terminator(
+    terminator: &rustc_middle::mir::Terminator<'_>,
+) -> stable_mir::mir::Terminator {
+    use rustc_middle::mir::TerminatorKind::*;
+    use stable_mir::mir::Terminator;
+    match &terminator.kind {
+        Goto { target } => Terminator::Goto { target: target.as_usize() },
+        SwitchInt { discr, targets } => Terminator::SwitchInt {
+            discr: rustc_op_to_op(discr),
+            targets: targets
+                .iter()
+                .map(|(value, target)| stable_mir::mir::SwitchTarget {
+                    value,
+                    target: target.as_usize(),
+                })
+                .collect(),
+            otherwise: targets.otherwise().as_usize(),
+        },
+        Resume => Terminator::Resume,
+        Abort => Terminator::Abort,
+        Return => Terminator::Return,
+        Unreachable => Terminator::Unreachable,
+        Drop { .. } => todo!(),
+        Call { .. } => todo!(),
+        Assert { .. } => todo!(),
+        Yield { .. } => todo!(),
+        GeneratorDrop => todo!(),
+        FalseEdge { .. } => todo!(),
+        FalseUnwind { .. } => todo!(),
+        InlineAsm { .. } => todo!(),
+    }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/mir.rs b/compiler/rustc_smir/src/stable_mir/mir.rs
new file mode 100644
index 00000000000..a9dbc3463f8
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/mir.rs
@@ -0,0 +1,3 @@
+mod body;
+
+pub use body::*;
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
new file mode 100644
index 00000000000..c504065c993
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -0,0 +1,69 @@
+#[derive(Clone, Debug)]
+pub struct Body {
+    pub blocks: Vec<BasicBlock>,
+}
+
+#[derive(Clone, Debug)]
+pub struct BasicBlock {
+    pub statements: Vec<Statement>,
+    pub terminator: Terminator,
+}
+
+#[derive(Clone, Debug)]
+pub enum Terminator {
+    Goto {
+        target: usize,
+    },
+    SwitchInt {
+        discr: Operand,
+        targets: Vec<SwitchTarget>,
+        otherwise: usize,
+    },
+    Resume,
+    Abort,
+    Return,
+    Unreachable,
+    Drop {
+        place: Place,
+        target: usize,
+        unwind: Option<usize>,
+    },
+    Call {
+        func: Operand,
+        args: Vec<Operand>,
+        destination: Place,
+        target: Option<usize>,
+        cleanup: Option<usize>,
+    },
+    Assert {
+        cond: Operand,
+        expected: bool,
+        msg: String,
+        target: usize,
+        cleanup: Option<usize>,
+    },
+}
+
+#[derive(Clone, Debug)]
+pub enum Statement {
+    Assign(Place, Operand),
+    Nop,
+}
+
+#[derive(Clone, Debug)]
+pub enum Operand {
+    Copy(Place),
+    Move(Place),
+    Constant(String),
+}
+
+#[derive(Clone, Debug)]
+pub struct Place {
+    pub local: usize,
+}
+
+#[derive(Clone, Debug)]
+pub struct SwitchTarget {
+    pub value: u128,
+    pub target: usize,
+}
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index cbf52e691fb..ba23186224a 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -11,7 +11,7 @@
 //! There shouldn't be any direct references to internal compiler constructs in this module.
 //! If you need an internal construct, consider using `rustc_internal` or `rustc_smir`.
 
-use crate::rustc_internal;
+pub mod mir;
 
 /// Use String for now but we should replace it.
 pub type Symbol = String;
@@ -37,7 +37,13 @@ pub struct Crate {
 /// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to
 /// use this item.
 #[derive(Clone, PartialEq, Eq, Debug)]
-pub struct CrateItem(pub(crate) rustc_internal::DefId);
+pub struct CrateItem(pub(crate) DefId);
+
+impl CrateItem {
+    pub fn body(&self) -> mir::Body {
+        crate::rustc_smir::mir_body(self)
+    }
+}
 
 /// Access to the local crate.
 pub fn local_crate() -> Crate {
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 4458ab0162e..99b653f20b6 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -4,6 +4,7 @@
 // ignore-stage-1
 // ignore-cross-compile
 // ignore-remote
+// edition: 2021
 
 #![feature(rustc_private)]
 
@@ -30,16 +31,34 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
 
     // Find items in the local crate.
     let items = stable_mir::all_local_items();
-    assert!(has_item(tcx, &items, (DefKind::Fn, "foo_bar")));
-    assert!(has_item(tcx, &items, (DefKind::Fn, "foo::bar")));
+    assert!(get_item(tcx, &items, (DefKind::Fn, "foo_bar")).is_some());
+    assert!(get_item(tcx, &items, (DefKind::Fn, "foo::bar")).is_some());
 
     // Find the `std` crate.
     assert!(stable_mir::find_crate("std").is_some());
+
+    let bar = get_item(tcx, &items, (DefKind::Fn, "bar")).unwrap();
+    let body = bar.body();
+    assert_eq!(body.blocks.len(), 1);
+    let block = &body.blocks[0];
+    assert_eq!(block.statements.len(), 1);
+    match &block.statements[0] {
+        stable_mir::mir::Statement::Assign(..) => {}
+        other => panic!("{other:?}"),
+    }
+    match &block.terminator {
+        stable_mir::mir::Terminator::Return => {}
+        other => panic!("{other:?}"),
+    }
 }
 
 // Use internal API to find a function in a crate.
-fn has_item(tcx: TyCtxt, items: &stable_mir::CrateItems, item: (DefKind, &str)) -> bool {
-    items.iter().any(|crate_item| {
+fn get_item<'a>(
+    tcx: TyCtxt,
+    items: &'a stable_mir::CrateItems,
+    item: (DefKind, &str),
+) -> Option<&'a stable_mir::CrateItem> {
+    items.iter().find(|crate_item| {
         let def_id = rustc_internal::item_def_id(crate_item);
         tcx.def_kind(def_id) == item.0 && tcx.def_path_str(def_id) == item.1
     })
@@ -94,6 +113,10 @@ fn generate_input(path: &str) -> std::io::Result<()> {
         }}
     }}
 
+    pub fn bar(x: i32) -> i32 {{
+        x
+    }}
+
     pub fn foo_bar(x: i32, y: i32) -> i64 {{
         let x_64 = foo::bar(x);
         let y_64 = foo::bar(y);