Skip to content

Commit f192227

Browse files
authored
Rollup merge of #110747 - oli-obk:smirty, r=spastorino
Encode types in SMIR The first commit makes sure we can actually store a Ty<'tcx> (with the lifetime) in the thread local and get it back out. The second commit then introduces types. r? `@spastorino`
2 parents c14d912 + 5c6e234 commit f192227

File tree

7 files changed

+207
-63
lines changed

7 files changed

+207
-63
lines changed

compiler/rustc_smir/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
test(attr(allow(unused_variables), deny(warnings)))
1212
)]
1313
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
14+
#![feature(local_key_cell_methods)]
15+
#![feature(ptr_metadata)]
1416

1517
pub mod rustc_internal;
1618
pub mod stable_mir;

compiler/rustc_smir/src/rustc_internal/mod.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,49 @@
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-
8-
use crate::stable_mir;
6+
use crate::{
7+
rustc_smir::Tables,
8+
stable_mir::{self, with},
9+
};
10+
use rustc_middle::ty::TyCtxt;
911
pub use rustc_span::def_id::{CrateNum, DefId};
1012

11-
static DEF_ID_MAP: RwLock<Vec<DefId>> = RwLock::new(Vec::new());
13+
fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
14+
let mut ret = None;
15+
with(|tables| tables.rustc_tables(&mut |t| ret = Some(f(t))));
16+
ret.unwrap()
17+
}
1218

1319
pub fn item_def_id(item: &stable_mir::CrateItem) -> DefId {
14-
DEF_ID_MAP.read().unwrap()[item.0]
20+
with_tables(|t| t.item_def_id(item))
1521
}
1622

1723
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);
24+
with_tables(|t| t.crate_item(did))
25+
}
26+
27+
impl<'tcx> Tables<'tcx> {
28+
pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
29+
self.def_ids[item.0]
30+
}
31+
32+
pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
33+
// FIXME: this becomes inefficient when we have too many ids
34+
for (i, &d) in self.def_ids.iter().enumerate() {
35+
if d == did {
36+
return stable_mir::CrateItem(i);
37+
}
2338
}
39+
let id = self.def_ids.len();
40+
self.def_ids.push(did);
41+
stable_mir::CrateItem(id)
2442
}
25-
let id = map.len();
26-
map.push(did);
27-
stable_mir::CrateItem(id)
2843
}
2944

3045
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
3146
item.id.into()
3247
}
48+
49+
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
50+
crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
51+
}

compiler/rustc_smir/src/rustc_smir/mod.rs

+92-43
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,107 @@
77
//!
88
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
99
10-
use crate::{
11-
rustc_internal::{crate_item, item_def_id},
12-
stable_mir::{self},
13-
};
14-
use rustc_middle::ty::{tls::with, TyCtxt};
15-
use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
10+
use crate::stable_mir::{self, ty::TyKind, Context};
11+
use rustc_middle::ty::{self, Ty, TyCtxt};
12+
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
1613
use tracing::debug;
1714

18-
/// Get information about the local crate.
19-
pub fn local_crate() -> stable_mir::Crate {
20-
with(|tcx| smir_crate(tcx, LOCAL_CRATE))
21-
}
15+
impl<'tcx> Context for Tables<'tcx> {
16+
fn local_crate(&self) -> stable_mir::Crate {
17+
smir_crate(self.tcx, LOCAL_CRATE)
18+
}
2219

23-
/// Retrieve a list of all external crates.
24-
pub fn external_crates() -> Vec<stable_mir::Crate> {
25-
with(|tcx| tcx.crates(()).iter().map(|crate_num| smir_crate(tcx, *crate_num)).collect())
26-
}
20+
fn external_crates(&self) -> Vec<stable_mir::Crate> {
21+
self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
22+
}
2723

28-
/// Find a crate with the given name.
29-
pub fn find_crate(name: &str) -> Option<stable_mir::Crate> {
30-
with(|tcx| {
31-
[LOCAL_CRATE].iter().chain(tcx.crates(()).iter()).find_map(|crate_num| {
32-
let crate_name = tcx.crate_name(*crate_num).to_string();
33-
(name == crate_name).then(|| smir_crate(tcx, *crate_num))
24+
fn find_crate(&self, name: &str) -> Option<stable_mir::Crate> {
25+
[LOCAL_CRATE].iter().chain(self.tcx.crates(()).iter()).find_map(|crate_num| {
26+
let crate_name = self.tcx.crate_name(*crate_num).to_string();
27+
(name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
3428
})
35-
})
29+
}
30+
31+
fn all_local_items(&mut self) -> stable_mir::CrateItems {
32+
self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
33+
}
34+
fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
35+
Some(self.crate_item(self.tcx.entry_fn(())?.0))
36+
}
37+
fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
38+
let def_id = self.item_def_id(item);
39+
let mir = self.tcx.optimized_mir(def_id);
40+
stable_mir::mir::Body {
41+
blocks: mir
42+
.basic_blocks
43+
.iter()
44+
.map(|block| stable_mir::mir::BasicBlock {
45+
terminator: rustc_terminator_to_terminator(block.terminator()),
46+
statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
47+
})
48+
.collect(),
49+
locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(),
50+
}
51+
}
52+
53+
fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)) {
54+
f(self)
55+
}
56+
57+
fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind {
58+
self.rustc_ty_to_ty(self.types[ty.0])
59+
}
3660
}
3761

38-
/// Retrieve all items of the local crate that have a MIR associated with them.
39-
pub fn all_local_items() -> stable_mir::CrateItems {
40-
with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
62+
pub struct Tables<'tcx> {
63+
pub tcx: TyCtxt<'tcx>,
64+
pub def_ids: Vec<DefId>,
65+
pub types: Vec<Ty<'tcx>>,
4166
}
4267

43-
pub fn entry_fn() -> Option<stable_mir::CrateItem> {
44-
with(|tcx| Some(crate_item(tcx.entry_fn(())?.0)))
68+
impl<'tcx> Tables<'tcx> {
69+
fn rustc_ty_to_ty(&mut self, ty: Ty<'tcx>) -> TyKind {
70+
match ty.kind() {
71+
ty::Bool => TyKind::Bool,
72+
ty::Char => todo!(),
73+
ty::Int(_) => todo!(),
74+
ty::Uint(_) => todo!(),
75+
ty::Float(_) => todo!(),
76+
ty::Adt(_, _) => todo!(),
77+
ty::Foreign(_) => todo!(),
78+
ty::Str => todo!(),
79+
ty::Array(_, _) => todo!(),
80+
ty::Slice(_) => todo!(),
81+
ty::RawPtr(_) => todo!(),
82+
ty::Ref(_, _, _) => todo!(),
83+
ty::FnDef(_, _) => todo!(),
84+
ty::FnPtr(_) => todo!(),
85+
ty::Placeholder(..) => todo!(),
86+
ty::Dynamic(_, _, _) => todo!(),
87+
ty::Closure(_, _) => todo!(),
88+
ty::Generator(_, _, _) => todo!(),
89+
ty::GeneratorWitness(_) => todo!(),
90+
ty::GeneratorWitnessMIR(_, _) => todo!(),
91+
ty::Never => todo!(),
92+
ty::Tuple(fields) => {
93+
TyKind::Tuple(fields.iter().map(|ty| self.intern_ty(ty)).collect())
94+
}
95+
ty::Alias(_, _) => todo!(),
96+
ty::Param(_) => todo!(),
97+
ty::Bound(_, _) => todo!(),
98+
ty::Infer(_) => todo!(),
99+
ty::Error(_) => todo!(),
100+
}
101+
}
102+
103+
fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
104+
if let Some(id) = self.types.iter().position(|&t| t == ty) {
105+
return stable_mir::ty::Ty(id);
106+
}
107+
let id = self.types.len();
108+
self.types.push(ty);
109+
stable_mir::ty::Ty(id)
110+
}
45111
}
46112

47113
/// Build a stable mir crate from a given crate number.
@@ -52,23 +118,6 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
52118
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
53119
}
54120

55-
pub fn mir_body(item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
56-
with(|tcx| {
57-
let def_id = item_def_id(item);
58-
let mir = tcx.optimized_mir(def_id);
59-
stable_mir::mir::Body {
60-
blocks: mir
61-
.basic_blocks
62-
.iter()
63-
.map(|block| stable_mir::mir::BasicBlock {
64-
terminator: rustc_terminator_to_terminator(block.terminator()),
65-
statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
66-
})
67-
.collect(),
68-
}
69-
})
70-
}
71-
72121
fn rustc_statement_to_statement(
73122
s: &rustc_middle::mir::Statement<'_>,
74123
) -> stable_mir::mir::Statement {

compiler/rustc_smir/src/stable_mir/mir/body.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
use crate::stable_mir::ty::Ty;
2+
13
#[derive(Clone, Debug)]
24
pub struct Body {
35
pub blocks: Vec<BasicBlock>,
6+
pub locals: Vec<Ty>,
47
}
58

69
#[derive(Clone, Debug)]

compiler/rustc_smir/src/stable_mir/mod.rs

+60-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
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 std::cell::Cell;
15+
16+
use crate::rustc_smir::Tables;
17+
18+
use self::ty::{Ty, TyKind};
19+
1420
pub mod mir;
21+
pub mod ty;
1522

1623
/// Use String for now but we should replace it.
1724
pub type Symbol = String;
@@ -41,33 +48,80 @@ pub struct CrateItem(pub(crate) DefId);
4148

4249
impl CrateItem {
4350
pub fn body(&self) -> mir::Body {
44-
crate::rustc_smir::mir_body(self)
51+
with(|cx| cx.mir_body(self))
4552
}
4653
}
4754

4855
/// Return the function where execution starts if the current
4956
/// crate defines that. This is usually `main`, but could be
5057
/// `start` if the crate is a no-std crate.
5158
pub fn entry_fn() -> Option<CrateItem> {
52-
crate::rustc_smir::entry_fn()
59+
with(|cx| cx.entry_fn())
5360
}
5461

5562
/// Access to the local crate.
5663
pub fn local_crate() -> Crate {
57-
crate::rustc_smir::local_crate()
64+
with(|cx| cx.local_crate())
5865
}
5966

6067
/// Try to find a crate with the given name.
6168
pub fn find_crate(name: &str) -> Option<Crate> {
62-
crate::rustc_smir::find_crate(name)
69+
with(|cx| cx.find_crate(name))
6370
}
6471

6572
/// Try to find a crate with the given name.
6673
pub fn external_crates() -> Vec<Crate> {
67-
crate::rustc_smir::external_crates()
74+
with(|cx| cx.external_crates())
6875
}
6976

7077
/// Retrieve all items in the local crate that have a MIR associated with them.
7178
pub fn all_local_items() -> CrateItems {
72-
crate::rustc_smir::all_local_items()
79+
with(|cx| cx.all_local_items())
80+
}
81+
82+
pub trait Context {
83+
fn entry_fn(&mut self) -> Option<CrateItem>;
84+
/// Retrieve all items of the local crate that have a MIR associated with them.
85+
fn all_local_items(&mut self) -> CrateItems;
86+
fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
87+
/// Get information about the local crate.
88+
fn local_crate(&self) -> Crate;
89+
/// Retrieve a list of all external crates.
90+
fn external_crates(&self) -> Vec<Crate>;
91+
92+
/// Find a crate with the given name.
93+
fn find_crate(&self, name: &str) -> Option<Crate>;
94+
95+
/// Obtain the representation of a type.
96+
fn ty_kind(&mut self, ty: Ty) -> TyKind;
97+
98+
/// HACK: Until we have fully stable consumers, we need an escape hatch
99+
/// to get `DefId`s out of `CrateItem`s.
100+
fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>));
101+
}
102+
103+
thread_local! {
104+
/// A thread local variable that stores a pointer to the tables mapping between TyCtxt
105+
/// datastructures and stable MIR datastructures.
106+
static TLV: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) };
107+
}
108+
109+
pub fn run(mut context: impl Context, f: impl FnOnce()) {
110+
assert!(TLV.get().is_null());
111+
fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
112+
TLV.set(&mut context as *mut &mut _ as _);
113+
f();
114+
TLV.replace(std::ptr::null_mut());
115+
}
116+
g(&mut context, f);
117+
}
118+
119+
/// Loads the current context and calls a function with it.
120+
/// Do not nest these, as that will ICE.
121+
pub(crate) fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
122+
let ptr = TLV.replace(std::ptr::null_mut()) as *mut &mut dyn Context;
123+
assert!(!ptr.is_null());
124+
let ret = f(unsafe { *ptr });
125+
TLV.set(ptr as _);
126+
ret
73127
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use super::with;
2+
3+
#[derive(Copy, Clone, Debug)]
4+
pub struct Ty(pub usize);
5+
6+
impl Ty {
7+
pub fn kind(&self) -> TyKind {
8+
with(|context| context.ty_kind(*self))
9+
}
10+
}
11+
12+
pub enum TyKind {
13+
Bool,
14+
Tuple(Vec<Ty>),
15+
}

tests/ui-fulldeps/stable-mir/crate-info.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
4040

4141
let bar = get_item(tcx, &items, (DefKind::Fn, "bar")).unwrap();
4242
let body = bar.body();
43+
assert_eq!(body.locals.len(), 2);
4344
assert_eq!(body.blocks.len(), 1);
4445
let block = &body.blocks[0];
4546
assert_eq!(block.statements.len(), 1);
@@ -54,6 +55,7 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
5455

5556
let foo_bar = get_item(tcx, &items, (DefKind::Fn, "foo_bar")).unwrap();
5657
let body = foo_bar.body();
58+
assert_eq!(body.locals.len(), 7);
5759
assert_eq!(body.blocks.len(), 4);
5860
let block = &body.blocks[0];
5961
match &block.terminator {
@@ -123,7 +125,7 @@ impl Callbacks for SMirCalls {
123125
queries: &'tcx Queries<'tcx>,
124126
) -> Compilation {
125127
queries.global_ctxt().unwrap().enter(|tcx| {
126-
test_stable_mir(tcx);
128+
rustc_smir::rustc_internal::run(tcx, || test_stable_mir(tcx));
127129
});
128130
// No need to keep going.
129131
Compilation::Stop

0 commit comments

Comments
 (0)