Skip to content

Commit 82bfda8

Browse files
committed
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`
2 parents 1033857 + 480e042 commit 82bfda8

File tree

6 files changed

+239
-11
lines changed

6 files changed

+239
-11
lines changed

Diff for: compiler/rustc_smir/src/rustc_internal/mod.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,28 @@
33
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
44
//! until stable MIR is complete.
55
6+
use std::sync::RwLock;
7+
68
use crate::stable_mir;
79
pub use rustc_span::def_id::{CrateNum, DefId};
810

11+
static DEF_ID_MAP: RwLock<Vec<DefId>> = RwLock::new(Vec::new());
12+
913
pub fn item_def_id(item: &stable_mir::CrateItem) -> DefId {
10-
item.0
14+
DEF_ID_MAP.read().unwrap()[item.0]
15+
}
16+
17+
pub fn crate_item(did: DefId) -> stable_mir::CrateItem {
18+
// FIXME: this becomes inefficient when we have too many ids
19+
let mut map = DEF_ID_MAP.write().unwrap();
20+
for (i, &d) in map.iter().enumerate() {
21+
if d == did {
22+
return stable_mir::CrateItem(i);
23+
}
24+
}
25+
let id = map.len();
26+
map.push(did);
27+
stable_mir::CrateItem(id)
1128
}
1229

1330
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {

Diff for: compiler/rustc_smir/src/rustc_smir/mod.rs

+114-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
//!
88
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
99
10-
use crate::stable_mir::{self};
10+
use crate::{
11+
rustc_internal::{crate_item, item_def_id},
12+
stable_mir::{self},
13+
};
1114
use rustc_middle::ty::{tls::with, TyCtxt};
1215
use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
1316
use tracing::debug;
@@ -34,9 +37,7 @@ pub fn find_crate(name: &str) -> Option<stable_mir::Crate> {
3437

3538
/// Retrieve all items of the local crate that have a MIR associated with them.
3639
pub fn all_local_items() -> stable_mir::CrateItems {
37-
with(|tcx| {
38-
tcx.mir_keys(()).iter().map(|item| stable_mir::CrateItem(item.to_def_id())).collect()
39-
})
40+
with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
4041
}
4142

4243
/// 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 {
4647
debug!(?crate_name, ?crate_num, "smir_crate");
4748
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
4849
}
50+
51+
pub fn mir_body(item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
52+
with(|tcx| {
53+
let def_id = item_def_id(item);
54+
let mir = tcx.optimized_mir(def_id);
55+
stable_mir::mir::Body {
56+
blocks: mir
57+
.basic_blocks
58+
.iter()
59+
.map(|block| stable_mir::mir::BasicBlock {
60+
terminator: rustc_terminator_to_terminator(block.terminator()),
61+
statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
62+
})
63+
.collect(),
64+
}
65+
})
66+
}
67+
68+
fn rustc_statement_to_statement(
69+
s: &rustc_middle::mir::Statement<'_>,
70+
) -> stable_mir::mir::Statement {
71+
use rustc_middle::mir::StatementKind::*;
72+
match &s.kind {
73+
Assign(assign) => stable_mir::mir::Statement::Assign(
74+
rustc_place_to_place(&assign.0),
75+
rustc_rvalue_to_rvalue(&assign.1),
76+
),
77+
FakeRead(_) => todo!(),
78+
SetDiscriminant { .. } => todo!(),
79+
Deinit(_) => todo!(),
80+
StorageLive(_) => todo!(),
81+
StorageDead(_) => todo!(),
82+
Retag(_, _) => todo!(),
83+
PlaceMention(_) => todo!(),
84+
AscribeUserType(_, _) => todo!(),
85+
Coverage(_) => todo!(),
86+
Intrinsic(_) => todo!(),
87+
ConstEvalCounter => todo!(),
88+
Nop => stable_mir::mir::Statement::Nop,
89+
}
90+
}
91+
92+
fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Operand {
93+
use rustc_middle::mir::Rvalue::*;
94+
match rvalue {
95+
Use(op) => rustc_op_to_op(op),
96+
Repeat(_, _) => todo!(),
97+
Ref(_, _, _) => todo!(),
98+
ThreadLocalRef(_) => todo!(),
99+
AddressOf(_, _) => todo!(),
100+
Len(_) => todo!(),
101+
Cast(_, _, _) => todo!(),
102+
BinaryOp(_, _) => todo!(),
103+
CheckedBinaryOp(_, _) => todo!(),
104+
NullaryOp(_, _) => todo!(),
105+
UnaryOp(_, _) => todo!(),
106+
Discriminant(_) => todo!(),
107+
Aggregate(_, _) => todo!(),
108+
ShallowInitBox(_, _) => todo!(),
109+
CopyForDeref(_) => todo!(),
110+
}
111+
}
112+
113+
fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Operand {
114+
use rustc_middle::mir::Operand::*;
115+
match op {
116+
Copy(place) => stable_mir::mir::Operand::Copy(rustc_place_to_place(place)),
117+
Move(place) => stable_mir::mir::Operand::Move(rustc_place_to_place(place)),
118+
Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()),
119+
}
120+
}
121+
122+
fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
123+
assert_eq!(&place.projection[..], &[]);
124+
stable_mir::mir::Place { local: place.local.as_usize() }
125+
}
126+
127+
fn rustc_terminator_to_terminator(
128+
terminator: &rustc_middle::mir::Terminator<'_>,
129+
) -> stable_mir::mir::Terminator {
130+
use rustc_middle::mir::TerminatorKind::*;
131+
use stable_mir::mir::Terminator;
132+
match &terminator.kind {
133+
Goto { target } => Terminator::Goto { target: target.as_usize() },
134+
SwitchInt { discr, targets } => Terminator::SwitchInt {
135+
discr: rustc_op_to_op(discr),
136+
targets: targets
137+
.iter()
138+
.map(|(value, target)| stable_mir::mir::SwitchTarget {
139+
value,
140+
target: target.as_usize(),
141+
})
142+
.collect(),
143+
otherwise: targets.otherwise().as_usize(),
144+
},
145+
Resume => Terminator::Resume,
146+
Abort => Terminator::Abort,
147+
Return => Terminator::Return,
148+
Unreachable => Terminator::Unreachable,
149+
Drop { .. } => todo!(),
150+
Call { .. } => todo!(),
151+
Assert { .. } => todo!(),
152+
Yield { .. } => todo!(),
153+
GeneratorDrop => todo!(),
154+
FalseEdge { .. } => todo!(),
155+
FalseUnwind { .. } => todo!(),
156+
InlineAsm { .. } => todo!(),
157+
}
158+
}

Diff for: compiler/rustc_smir/src/stable_mir/mir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod body;
2+
3+
pub use body::*;

Diff for: compiler/rustc_smir/src/stable_mir/mir/body.rs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#[derive(Clone, Debug)]
2+
pub struct Body {
3+
pub blocks: Vec<BasicBlock>,
4+
}
5+
6+
#[derive(Clone, Debug)]
7+
pub struct BasicBlock {
8+
pub statements: Vec<Statement>,
9+
pub terminator: Terminator,
10+
}
11+
12+
#[derive(Clone, Debug)]
13+
pub enum Terminator {
14+
Goto {
15+
target: usize,
16+
},
17+
SwitchInt {
18+
discr: Operand,
19+
targets: Vec<SwitchTarget>,
20+
otherwise: usize,
21+
},
22+
Resume,
23+
Abort,
24+
Return,
25+
Unreachable,
26+
Drop {
27+
place: Place,
28+
target: usize,
29+
unwind: Option<usize>,
30+
},
31+
Call {
32+
func: Operand,
33+
args: Vec<Operand>,
34+
destination: Place,
35+
target: Option<usize>,
36+
cleanup: Option<usize>,
37+
},
38+
Assert {
39+
cond: Operand,
40+
expected: bool,
41+
msg: String,
42+
target: usize,
43+
cleanup: Option<usize>,
44+
},
45+
}
46+
47+
#[derive(Clone, Debug)]
48+
pub enum Statement {
49+
Assign(Place, Operand),
50+
Nop,
51+
}
52+
53+
#[derive(Clone, Debug)]
54+
pub enum Operand {
55+
Copy(Place),
56+
Move(Place),
57+
Constant(String),
58+
}
59+
60+
#[derive(Clone, Debug)]
61+
pub struct Place {
62+
pub local: usize,
63+
}
64+
65+
#[derive(Clone, Debug)]
66+
pub struct SwitchTarget {
67+
pub value: u128,
68+
pub target: usize,
69+
}

Diff for: compiler/rustc_smir/src/stable_mir/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! There shouldn't be any direct references to internal compiler constructs in this module.
1212
//! If you need an internal construct, consider using `rustc_internal` or `rustc_smir`.
1313
14-
use crate::rustc_internal;
14+
pub mod mir;
1515

1616
/// Use String for now but we should replace it.
1717
pub type Symbol = String;
@@ -37,7 +37,13 @@ pub struct Crate {
3737
/// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to
3838
/// use this item.
3939
#[derive(Clone, PartialEq, Eq, Debug)]
40-
pub struct CrateItem(pub(crate) rustc_internal::DefId);
40+
pub struct CrateItem(pub(crate) DefId);
41+
42+
impl CrateItem {
43+
pub fn body(&self) -> mir::Body {
44+
crate::rustc_smir::mir_body(self)
45+
}
46+
}
4147

4248
/// Access to the local crate.
4349
pub fn local_crate() -> Crate {

Diff for: tests/ui-fulldeps/stable-mir/crate-info.rs

+27-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// ignore-stage-1
55
// ignore-cross-compile
66
// ignore-remote
7+
// edition: 2021
78

89
#![feature(rustc_private)]
910

@@ -30,16 +31,34 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
3031

3132
// Find items in the local crate.
3233
let items = stable_mir::all_local_items();
33-
assert!(has_item(tcx, &items, (DefKind::Fn, "foo_bar")));
34-
assert!(has_item(tcx, &items, (DefKind::Fn, "foo::bar")));
34+
assert!(get_item(tcx, &items, (DefKind::Fn, "foo_bar")).is_some());
35+
assert!(get_item(tcx, &items, (DefKind::Fn, "foo::bar")).is_some());
3536

3637
// Find the `std` crate.
3738
assert!(stable_mir::find_crate("std").is_some());
39+
40+
let bar = get_item(tcx, &items, (DefKind::Fn, "bar")).unwrap();
41+
let body = bar.body();
42+
assert_eq!(body.blocks.len(), 1);
43+
let block = &body.blocks[0];
44+
assert_eq!(block.statements.len(), 1);
45+
match &block.statements[0] {
46+
stable_mir::mir::Statement::Assign(..) => {}
47+
other => panic!("{other:?}"),
48+
}
49+
match &block.terminator {
50+
stable_mir::mir::Terminator::Return => {}
51+
other => panic!("{other:?}"),
52+
}
3853
}
3954

4055
// Use internal API to find a function in a crate.
41-
fn has_item(tcx: TyCtxt, items: &stable_mir::CrateItems, item: (DefKind, &str)) -> bool {
42-
items.iter().any(|crate_item| {
56+
fn get_item<'a>(
57+
tcx: TyCtxt,
58+
items: &'a stable_mir::CrateItems,
59+
item: (DefKind, &str),
60+
) -> Option<&'a stable_mir::CrateItem> {
61+
items.iter().find(|crate_item| {
4362
let def_id = rustc_internal::item_def_id(crate_item);
4463
tcx.def_kind(def_id) == item.0 && tcx.def_path_str(def_id) == item.1
4564
})
@@ -94,6 +113,10 @@ fn generate_input(path: &str) -> std::io::Result<()> {
94113
}}
95114
}}
96115
116+
pub fn bar(x: i32) -> i32 {{
117+
x
118+
}}
119+
97120
pub fn foo_bar(x: i32, y: i32) -> i64 {{
98121
let x_64 = foo::bar(x);
99122
let y_64 = foo::bar(y);

0 commit comments

Comments
 (0)