diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_smir | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_smir')
-rw-r--r-- | compiler/rustc_smir/Cargo.toml | 19 | ||||
-rw-r--r-- | compiler/rustc_smir/README.md | 37 | ||||
-rw-r--r-- | compiler/rustc_smir/rust-toolchain.toml | 2 | ||||
-rw-r--r-- | compiler/rustc_smir/src/lib.rs | 8 | ||||
-rw-r--r-- | compiler/rustc_smir/src/mir.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_smir/src/rustc_internal/mod.rs | 32 | ||||
-rw-r--r-- | compiler/rustc_smir/src/rustc_smir/mod.rs | 162 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/mir.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/mir/body.rs | 69 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/mod.rs | 73 | ||||
-rw-r--r-- | compiler/rustc_smir/src/very_unstable.rs | 27 |
11 files changed, 384 insertions, 58 deletions
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 5e0d1f369..fb97ee5be 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,25 +4,12 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_borrowck = { path = "../rustc_borrowck", optional = true } -rustc_driver = { path = "../rustc_driver", optional = true } -rustc_hir = { path = "../rustc_hir", optional = true } -rustc_interface = { path = "../rustc_interface", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } -rustc_mir_dataflow = { path = "../rustc_mir_dataflow", optional = true } -rustc_mir_transform = { path = "../rustc_mir_transform", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } -rustc_trait_selection = { path = "../rustc_trait_selection", optional = true } +rustc_span = { path = "../rustc_span", optional = true } +tracing = "0.1" [features] default = [ - "rustc_borrowck", - "rustc_driver", - "rustc_hir", - "rustc_interface", "rustc_middle", - "rustc_mir_dataflow", - "rustc_mir_transform", - "rustc_serialize", - "rustc_trait_selection", + "rustc_span", ] diff --git a/compiler/rustc_smir/README.md b/compiler/rustc_smir/README.md index ae49098dd..31dee955f 100644 --- a/compiler/rustc_smir/README.md +++ b/compiler/rustc_smir/README.md @@ -73,3 +73,40 @@ git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/proje Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks. Then open a PR against rustc just like a regular PR. + +## Stable MIR Design + +The stable-mir will follow a similar approach to proc-macro2. It’s +implementation will eventually be broken down into two main crates: + +- `stable_mir`: Public crate, to be published on crates.io, which will contain +the stable data structure as well as proxy APIs to make calls to the +compiler. +- `rustc_smir`: The compiler crate that will translate from internal MIR to +SMIR. This crate will also implement APIs that will be invoked by +stable-mir to query the compiler for more information. + +This will help tools to communicate with the rust compiler via stable APIs. Tools will depend on +`stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. I.e.: + +``` + ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ + │ External Tool ┌──────────┐ │ │ ┌──────────┐ Rust Compiler │ + │ │ │ │ │ │ │ │ + │ │stable_mir| │ │ │rustc_smir│ │ + │ │ │ ├──────────►| │ │ │ + │ │ │ │◄──────────┤ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ └──────────┘ │ │ └──────────┘ │ + └──────────────────────────────────┘ └──────────────────────────────────┘ +``` + +More details can be found here: +https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view + +For now, the code for these two crates are in separate modules of this crate. +The modules have the same name for simplicity. We also have a third module, +`rustc_internal` which will expose APIs and definitions that allow users to +gather information from internal MIR constructs that haven't been exposed in +the `stable_mir` module. diff --git a/compiler/rustc_smir/rust-toolchain.toml b/compiler/rustc_smir/rust-toolchain.toml index 7b696fc1f..157dfd620 100644 --- a/compiler/rustc_smir/rust-toolchain.toml +++ b/compiler/rustc_smir/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-01" +channel = "nightly-2023-02-28" components = [ "rustfmt", "rustc-dev" ] diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 3e93c6bba..54d474db0 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -11,9 +11,9 @@ test(attr(allow(unused_variables), deny(warnings))) )] #![cfg_attr(not(feature = "default"), feature(rustc_private))] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] -pub mod mir; +pub mod rustc_internal; +pub mod stable_mir; -pub mod very_unstable; +// Make this module private for now since external users should not call these directly. +mod rustc_smir; diff --git a/compiler/rustc_smir/src/mir.rs b/compiler/rustc_smir/src/mir.rs deleted file mode 100644 index 887e65729..000000000 --- a/compiler/rustc_smir/src/mir.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub use crate::very_unstable::hir::ImplicitSelfKind; -pub use crate::very_unstable::middle::mir::{ - visit::MutVisitor, AggregateKind, AssertKind, BasicBlock, BasicBlockData, BinOp, BindingForm, - BlockTailInfo, Body, BorrowKind, CastKind, ClearCrossCrate, Constant, ConstantKind, - CopyNonOverlapping, Coverage, FakeReadCause, Field, GeneratorInfo, InlineAsmOperand, Local, - LocalDecl, LocalInfo, LocalKind, Location, MirPhase, MirSource, NullOp, Operand, Place, - PlaceRef, ProjectionElem, ProjectionKind, Promoted, RetagKind, Rvalue, Safety, SourceInfo, - SourceScope, SourceScopeData, SourceScopeLocalData, Statement, StatementKind, UnOp, - UserTypeProjection, UserTypeProjections, VarBindingForm, VarDebugInfo, VarDebugInfoContents, -}; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs new file mode 100644 index 000000000..5998c8b65 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -0,0 +1,32 @@ +//! Module that implements the bridge between Stable MIR and internal compiler MIR. +//! +//! 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; +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 { + 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 { + item.id.into() +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs new file mode 100644 index 000000000..4dad3c6bc --- /dev/null +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -0,0 +1,162 @@ +//! Module that implements what will become the rustc side of Stable MIR. +//! +//! This module is responsible for building Stable MIR components from internal components. +//! +//! This module is not intended to be invoked directly by users. It will eventually +//! become the public API of rustc that will be invoked by the `stable_mir` crate. +//! +//! 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 tracing::debug; + +/// Get information about the local crate. +pub fn local_crate() -> stable_mir::Crate { + with(|tcx| smir_crate(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()) +} + +/// 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)) + }) + }) +} + +/// 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); + 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, + Terminate => Terminator::Abort, + Return => Terminator::Return, + Unreachable => Terminator::Unreachable, + Drop { .. } => todo!(), + Call { .. } => todo!(), + Assert { .. } => todo!(), + Yield { .. } => todo!(), + GeneratorDrop => todo!(), + FalseEdge { .. } => todo!(), + FalseUnwind { .. } => todo!(), + InlineAsm { .. } => todo!(), + } +} diff --git a/compiler/rustc_smir/src/stable_mir/mir.rs b/compiler/rustc_smir/src/stable_mir/mir.rs new file mode 100644 index 000000000..a9dbc3463 --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/mir.rs @@ -0,0 +1,3 @@ +mod body; + +pub use body::*; diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs new file mode 100644 index 000000000..c504065c9 --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -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, +} diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs new file mode 100644 index 000000000..1d2efb5ea --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -0,0 +1,73 @@ +//! Module that implements the public interface to the Stable MIR. +//! +//! This module shall contain all type definitions and APIs that we expect 3P tools to invoke to +//! interact with the compiler. +//! +//! The goal is to eventually move this module to its own crate which shall be published on +//! [crates.io](https://crates.io). +//! +//! ## Note: +//! +//! 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`. + +pub mod mir; + +/// Use String for now but we should replace it. +pub type Symbol = String; + +/// The number that identifies a crate. +pub type CrateNum = usize; + +/// A unique identification number for each item accessible for the current compilation unit. +pub type DefId = usize; + +/// A list of crate items. +pub type CrateItems = Vec<CrateItem>; + +/// Holds information about a crate. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Crate { + pub(crate) id: CrateNum, + pub name: Symbol, + pub is_local: bool, +} + +/// Holds information about an item in the crate. +/// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to +/// use this item. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CrateItem(pub(crate) DefId); + +impl CrateItem { + pub fn body(&self) -> mir::Body { + crate::rustc_smir::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() +} + +/// Access to the local crate. +pub fn local_crate() -> Crate { + crate::rustc_smir::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) +} + +/// Try to find a crate with the given name. +pub fn external_crates() -> Vec<Crate> { + crate::rustc_smir::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() +} diff --git a/compiler/rustc_smir/src/very_unstable.rs b/compiler/rustc_smir/src/very_unstable.rs deleted file mode 100644 index 12ba133db..000000000 --- a/compiler/rustc_smir/src/very_unstable.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! This module reexports various crates and modules from unstable rustc APIs. -//! Add anything you need here and it will get slowly transferred to a stable API. -//! Only use rustc_smir in your dependencies and use the reexports here instead of -//! directly referring to the unstable crates. - -macro_rules! crates { - ($($rustc_name:ident -> $name:ident,)*) => { - $( - #[cfg(not(feature = "default"))] - pub extern crate $rustc_name as $name; - #[cfg(feature = "default")] - pub use $rustc_name as $name; - )* - } -} - -crates! { - rustc_borrowck -> borrowck, - rustc_driver -> driver, - rustc_hir -> hir, - rustc_interface -> interface, - rustc_middle -> middle, - rustc_mir_dataflow -> dataflow, - rustc_mir_transform -> transform, - rustc_serialize -> serialize, - rustc_trait_selection -> trait_selection, -} |