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`
This commit is contained in:
Matthias Krüger 2023-05-10 06:12:13 +02:00 committed by GitHub
commit f1922275b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 65 deletions

View File

@ -11,6 +11,8 @@
test(attr(allow(unused_variables), deny(warnings)))
)]
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
#![feature(local_key_cell_methods)]
#![feature(ptr_metadata)]
pub mod rustc_internal;
pub mod stable_mir;

View File

@ -3,30 +3,49 @@
//! 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;
use crate::{
rustc_smir::Tables,
stable_mir::{self, with},
};
use rustc_middle::ty::TyCtxt;
pub use rustc_span::def_id::{CrateNum, DefId};
static DEF_ID_MAP: RwLock<Vec<DefId>> = RwLock::new(Vec::new());
fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
let mut ret = None;
with(|tables| tables.rustc_tables(&mut |t| ret = Some(f(t))));
ret.unwrap()
}
pub fn item_def_id(item: &stable_mir::CrateItem) -> DefId {
DEF_ID_MAP.read().unwrap()[item.0]
with_tables(|t| t.item_def_id(item))
}
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);
}
with_tables(|t| t.crate_item(did))
}
impl<'tcx> Tables<'tcx> {
pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
self.def_ids[item.0]
}
pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
// FIXME: this becomes inefficient when we have too many ids
for (i, &d) in self.def_ids.iter().enumerate() {
if d == did {
return stable_mir::CrateItem(i);
}
}
let id = self.def_ids.len();
self.def_ids.push(did);
stable_mir::CrateItem(id)
}
let id = map.len();
map.push(did);
stable_mir::CrateItem(id)
}
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
item.id.into()
}
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
}

View File

@ -7,55 +7,36 @@
//!
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
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 crate::stable_mir::{self, ty::TyKind, Context};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use tracing::debug;
/// Get information about the local crate.
pub fn local_crate() -> stable_mir::Crate {
with(|tcx| smir_crate(tcx, LOCAL_CRATE))
}
impl<'tcx> Context for Tables<'tcx> {
fn local_crate(&self) -> stable_mir::Crate {
smir_crate(self.tcx, LOCAL_CRATE)
}
/// Retrieve a list of all external crates.
pub fn external_crates() -> Vec<stable_mir::Crate> {
with(|tcx| tcx.crates(()).iter().map(|crate_num| smir_crate(tcx, *crate_num)).collect())
}
fn external_crates(&self) -> Vec<stable_mir::Crate> {
self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
}
/// Find a crate with the given name.
pub fn find_crate(name: &str) -> Option<stable_mir::Crate> {
with(|tcx| {
[LOCAL_CRATE].iter().chain(tcx.crates(()).iter()).find_map(|crate_num| {
let crate_name = tcx.crate_name(*crate_num).to_string();
(name == crate_name).then(|| smir_crate(tcx, *crate_num))
fn find_crate(&self, name: &str) -> Option<stable_mir::Crate> {
[LOCAL_CRATE].iter().chain(self.tcx.crates(()).iter()).find_map(|crate_num| {
let crate_name = self.tcx.crate_name(*crate_num).to_string();
(name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
})
})
}
}
/// 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| crate_item(item.to_def_id())).collect())
}
pub fn entry_fn() -> Option<stable_mir::CrateItem> {
with(|tcx| Some(crate_item(tcx.entry_fn(())?.0)))
}
/// Build a stable mir crate from a given crate number.
fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
let crate_name = tcx.crate_name(crate_num).to_string();
let is_local = crate_num == LOCAL_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);
fn all_local_items(&mut self) -> stable_mir::CrateItems {
self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
}
fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
Some(self.crate_item(self.tcx.entry_fn(())?.0))
}
fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
let def_id = self.item_def_id(item);
let mir = self.tcx.optimized_mir(def_id);
stable_mir::mir::Body {
blocks: mir
.basic_blocks
@ -65,8 +46,76 @@ pub fn mir_body(item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
})
.collect(),
locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(),
}
})
}
fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)) {
f(self)
}
fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind {
self.rustc_ty_to_ty(self.types[ty.0])
}
}
pub struct Tables<'tcx> {
pub tcx: TyCtxt<'tcx>,
pub def_ids: Vec<DefId>,
pub types: Vec<Ty<'tcx>>,
}
impl<'tcx> Tables<'tcx> {
fn rustc_ty_to_ty(&mut self, ty: Ty<'tcx>) -> TyKind {
match ty.kind() {
ty::Bool => TyKind::Bool,
ty::Char => todo!(),
ty::Int(_) => todo!(),
ty::Uint(_) => todo!(),
ty::Float(_) => todo!(),
ty::Adt(_, _) => todo!(),
ty::Foreign(_) => todo!(),
ty::Str => todo!(),
ty::Array(_, _) => todo!(),
ty::Slice(_) => todo!(),
ty::RawPtr(_) => todo!(),
ty::Ref(_, _, _) => todo!(),
ty::FnDef(_, _) => todo!(),
ty::FnPtr(_) => todo!(),
ty::Placeholder(..) => todo!(),
ty::Dynamic(_, _, _) => todo!(),
ty::Closure(_, _) => todo!(),
ty::Generator(_, _, _) => todo!(),
ty::GeneratorWitness(_) => todo!(),
ty::GeneratorWitnessMIR(_, _) => todo!(),
ty::Never => todo!(),
ty::Tuple(fields) => {
TyKind::Tuple(fields.iter().map(|ty| self.intern_ty(ty)).collect())
}
ty::Alias(_, _) => todo!(),
ty::Param(_) => todo!(),
ty::Bound(_, _) => todo!(),
ty::Infer(_) => todo!(),
ty::Error(_) => todo!(),
}
}
fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
if let Some(id) = self.types.iter().position(|&t| t == ty) {
return stable_mir::ty::Ty(id);
}
let id = self.types.len();
self.types.push(ty);
stable_mir::ty::Ty(id)
}
}
/// Build a stable mir crate from a given crate number.
fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
let crate_name = tcx.crate_name(crate_num).to_string();
let is_local = crate_num == LOCAL_CRATE;
debug!(?crate_name, ?crate_num, "smir_crate");
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
}
fn rustc_statement_to_statement(

View File

@ -1,6 +1,9 @@
use crate::stable_mir::ty::Ty;
#[derive(Clone, Debug)]
pub struct Body {
pub blocks: Vec<BasicBlock>,
pub locals: Vec<Ty>,
}
#[derive(Clone, Debug)]

View File

@ -11,7 +11,14 @@
//! 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 std::cell::Cell;
use crate::rustc_smir::Tables;
use self::ty::{Ty, TyKind};
pub mod mir;
pub mod ty;
/// Use String for now but we should replace it.
pub type Symbol = String;
@ -41,7 +48,7 @@ pub struct CrateItem(pub(crate) DefId);
impl CrateItem {
pub fn body(&self) -> mir::Body {
crate::rustc_smir::mir_body(self)
with(|cx| cx.mir_body(self))
}
}
@ -49,25 +56,72 @@ impl CrateItem {
/// crate defines that. This is usually `main`, but could be
/// `start` if the crate is a no-std crate.
pub fn entry_fn() -> Option<CrateItem> {
crate::rustc_smir::entry_fn()
with(|cx| cx.entry_fn())
}
/// Access to the local crate.
pub fn local_crate() -> Crate {
crate::rustc_smir::local_crate()
with(|cx| cx.local_crate())
}
/// Try to find a crate with the given name.
pub fn find_crate(name: &str) -> Option<Crate> {
crate::rustc_smir::find_crate(name)
with(|cx| cx.find_crate(name))
}
/// Try to find a crate with the given name.
pub fn external_crates() -> Vec<Crate> {
crate::rustc_smir::external_crates()
with(|cx| cx.external_crates())
}
/// Retrieve all items in the local crate that have a MIR associated with them.
pub fn all_local_items() -> CrateItems {
crate::rustc_smir::all_local_items()
with(|cx| cx.all_local_items())
}
pub trait Context {
fn entry_fn(&mut self) -> Option<CrateItem>;
/// Retrieve all items of the local crate that have a MIR associated with them.
fn all_local_items(&mut self) -> CrateItems;
fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
/// Get information about the local crate.
fn local_crate(&self) -> Crate;
/// Retrieve a list of all external crates.
fn external_crates(&self) -> Vec<Crate>;
/// Find a crate with the given name.
fn find_crate(&self, name: &str) -> Option<Crate>;
/// Obtain the representation of a type.
fn ty_kind(&mut self, ty: Ty) -> TyKind;
/// HACK: Until we have fully stable consumers, we need an escape hatch
/// to get `DefId`s out of `CrateItem`s.
fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>));
}
thread_local! {
/// A thread local variable that stores a pointer to the tables mapping between TyCtxt
/// datastructures and stable MIR datastructures.
static TLV: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) };
}
pub fn run(mut context: impl Context, f: impl FnOnce()) {
assert!(TLV.get().is_null());
fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
TLV.set(&mut context as *mut &mut _ as _);
f();
TLV.replace(std::ptr::null_mut());
}
g(&mut context, f);
}
/// Loads the current context and calls a function with it.
/// Do not nest these, as that will ICE.
pub(crate) fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
let ptr = TLV.replace(std::ptr::null_mut()) as *mut &mut dyn Context;
assert!(!ptr.is_null());
let ret = f(unsafe { *ptr });
TLV.set(ptr as _);
ret
}

View File

@ -0,0 +1,15 @@
use super::with;
#[derive(Copy, Clone, Debug)]
pub struct Ty(pub usize);
impl Ty {
pub fn kind(&self) -> TyKind {
with(|context| context.ty_kind(*self))
}
}
pub enum TyKind {
Bool,
Tuple(Vec<Ty>),
}

View File

@ -40,6 +40,7 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
let bar = get_item(tcx, &items, (DefKind::Fn, "bar")).unwrap();
let body = bar.body();
assert_eq!(body.locals.len(), 2);
assert_eq!(body.blocks.len(), 1);
let block = &body.blocks[0];
assert_eq!(block.statements.len(), 1);
@ -54,6 +55,7 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
let foo_bar = get_item(tcx, &items, (DefKind::Fn, "foo_bar")).unwrap();
let body = foo_bar.body();
assert_eq!(body.locals.len(), 7);
assert_eq!(body.blocks.len(), 4);
let block = &body.blocks[0];
match &block.terminator {
@ -123,7 +125,7 @@ impl Callbacks for SMirCalls {
queries: &'tcx Queries<'tcx>,
) -> Compilation {
queries.global_ctxt().unwrap().enter(|tcx| {
test_stable_mir(tcx);
rustc_smir::rustc_internal::run(tcx, || test_stable_mir(tcx));
});
// No need to keep going.
Compilation::Stop