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`
This commit is contained in:
commit
82bfda848e
6 changed files with 239 additions and 11 deletions
|
@ -3,11 +3,28 @@
|
||||||
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
|
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
|
||||||
//! until stable MIR is complete.
|
//! until stable MIR is complete.
|
||||||
|
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use crate::stable_mir;
|
use crate::stable_mir;
|
||||||
pub use rustc_span::def_id::{CrateNum, DefId};
|
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 {
|
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 {
|
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
//!
|
//!
|
||||||
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
//! 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_middle::ty::{tls::with, TyCtxt};
|
||||||
use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use tracing::debug;
|
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.
|
/// Retrieve all items of the local crate that have a MIR associated with them.
|
||||||
pub fn all_local_items() -> stable_mir::CrateItems {
|
pub fn all_local_items() -> stable_mir::CrateItems {
|
||||||
with(|tcx| {
|
with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
|
||||||
tcx.mir_keys(()).iter().map(|item| stable_mir::CrateItem(item.to_def_id())).collect()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a stable mir crate from a given crate number.
|
/// 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");
|
debug!(?crate_name, ?crate_num, "smir_crate");
|
||||||
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
3
compiler/rustc_smir/src/stable_mir/mir.rs
Normal file
3
compiler/rustc_smir/src/stable_mir/mir.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod body;
|
||||||
|
|
||||||
|
pub use body::*;
|
69
compiler/rustc_smir/src/stable_mir/mir/body.rs
Normal file
69
compiler/rustc_smir/src/stable_mir/mir/body.rs
Normal file
|
@ -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,
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
//! There shouldn't be any direct references to internal compiler constructs in this module.
|
//! 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`.
|
//! 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.
|
/// Use String for now but we should replace it.
|
||||||
pub type Symbol = String;
|
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
|
/// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to
|
||||||
/// use this item.
|
/// use this item.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[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.
|
/// Access to the local crate.
|
||||||
pub fn local_crate() -> Crate {
|
pub fn local_crate() -> Crate {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
// ignore-stage-1
|
// ignore-stage-1
|
||||||
// ignore-cross-compile
|
// ignore-cross-compile
|
||||||
// ignore-remote
|
// ignore-remote
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
|
||||||
|
@ -30,16 +31,34 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
|
||||||
|
|
||||||
// Find items in the local crate.
|
// Find items in the local crate.
|
||||||
let items = stable_mir::all_local_items();
|
let items = stable_mir::all_local_items();
|
||||||
assert!(has_item(tcx, &items, (DefKind::Fn, "foo_bar")));
|
assert!(get_item(tcx, &items, (DefKind::Fn, "foo_bar")).is_some());
|
||||||
assert!(has_item(tcx, &items, (DefKind::Fn, "foo::bar")));
|
assert!(get_item(tcx, &items, (DefKind::Fn, "foo::bar")).is_some());
|
||||||
|
|
||||||
// Find the `std` crate.
|
// Find the `std` crate.
|
||||||
assert!(stable_mir::find_crate("std").is_some());
|
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.
|
// Use internal API to find a function in a crate.
|
||||||
fn has_item(tcx: TyCtxt, items: &stable_mir::CrateItems, item: (DefKind, &str)) -> bool {
|
fn get_item<'a>(
|
||||||
items.iter().any(|crate_item| {
|
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);
|
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
|
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 {{
|
pub fn foo_bar(x: i32, y: i32) -> i64 {{
|
||||||
let x_64 = foo::bar(x);
|
let x_64 = foo::bar(x);
|
||||||
let y_64 = foo::bar(y);
|
let y_64 = foo::bar(y);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue