Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Encode types in SMIR #110747

Merged
merged 2 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_smir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
45 changes: 32 additions & 13 deletions compiler/rustc_smir/src/rustc_internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
135 changes: 92 additions & 43 deletions compiler/rustc_smir/src/rustc_smir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,107 @@
//!
//! 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))
})
})
}

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
.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(),
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])
}
}

/// 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 struct Tables<'tcx> {
pub tcx: TyCtxt<'tcx>,
pub def_ids: Vec<DefId>,
pub types: Vec<Ty<'tcx>>,
}

pub fn entry_fn() -> Option<stable_mir::CrateItem> {
with(|tcx| Some(crate_item(tcx.entry_fn(())?.0)))
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.
Expand All @@ -52,23 +118,6 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::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 {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_smir/src/stable_mir/mir/body.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
66 changes: 60 additions & 6 deletions compiler/rustc_smir/src/stable_mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -41,33 +48,80 @@ 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))
}
}

/// Return the function where execution starts if the current
/// 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
}
15 changes: 15 additions & 0 deletions compiler/rustc_smir/src/stable_mir/ty.rs
Original file line number Diff line number Diff line change
@@ -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>),
}
4 changes: 3 additions & 1 deletion tests/ui-fulldeps/stable-mir/crate-info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down