Skip to content

Commit 739e593

Browse files
authored
Rollup merge of #103464 - JakobDegen:mir-parsing, r=oli-obk
Add support for custom mir This implements rust-lang/compiler-team#564 . Details about the design, motivation, etc. can be found in there. r? ```@oli-obk```
2 parents 723e4c8 + eb4d889 commit 739e593

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

core/src/intrinsics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ use crate::marker::DiscriminantKind;
5959
use crate::marker::Tuple;
6060
use crate::mem;
6161

62+
#[cfg(not(bootstrap))]
63+
pub mod mir;
64+
6265
// These imports are used for simplifying intra-doc links
6366
#[allow(unused_imports)]
6467
#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))]

core/src/intrinsics/mir.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//! Rustc internal tooling for hand-writing MIR.
2+
//!
3+
//! If for some reasons you are not writing rustc tests and have found yourself considering using
4+
//! this feature, turn back. This is *exceptionally* unstable. There is no attempt at all to make
5+
//! anything work besides those things which the rustc test suite happened to need. If you make a
6+
//! typo you'll probably ICE. Really, this is not the solution to your problems. Consider instead
7+
//! supporting the [stable MIR project group](https://github.com/rust-lang/project-stable-mir).
8+
//!
9+
//! The documentation for this module describes how to use this feature. If you are interested in
10+
//! hacking on the implementation, most of that documentation lives at
11+
//! `rustc_mir_building/src/build/custom/mod.rs`.
12+
//!
13+
//! Typical usage will look like this:
14+
//!
15+
//! ```rust
16+
//! #![feature(core_intrinsics, custom_mir)]
17+
//!
18+
//! extern crate core;
19+
//! use core::intrinsics::mir::*;
20+
//!
21+
//! #[custom_mir(dialect = "built")]
22+
//! pub fn simple(x: i32) -> i32 {
23+
//! mir!(
24+
//! let temp1: i32;
25+
//! let temp2: _;
26+
//!
27+
//! {
28+
//! temp1 = x;
29+
//! Goto(exit)
30+
//! }
31+
//!
32+
//! exit = {
33+
//! temp2 = Move(temp1);
34+
//! RET = temp2;
35+
//! Return()
36+
//! }
37+
//! )
38+
//! }
39+
//! ```
40+
//!
41+
//! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
42+
//!
43+
//! - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
44+
//! attribute only works on functions - there is no way to insert custom MIR into the middle of
45+
//! another function.
46+
//! - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
47+
//! This will normally be the phase that corresponds to the thing you are trying to test. The
48+
//! phase can be omitted for dialects that have just one.
49+
//! - You should define your function signature like you normally would. Externally, this function
50+
//! can be called like any other function.
51+
//! - Type inference works - you don't have to spell out the type of all of your locals.
52+
//!
53+
//! For now, all statements and terminators are parsed from nested invocations of the special
54+
//! functions provided in this module. We additionally want to (but do not yet) support more
55+
//! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
56+
//! supported yet.
57+
//!
58+
59+
#![unstable(
60+
feature = "custom_mir",
61+
reason = "MIR is an implementation detail and extremely unstable",
62+
issue = "none"
63+
)]
64+
#![allow(unused_variables, non_snake_case, missing_debug_implementations)]
65+
66+
/// Type representing basic blocks.
67+
///
68+
/// All terminators will have this type as a return type. It helps achieve some type safety.
69+
pub struct BasicBlock;
70+
71+
macro_rules! define {
72+
($name:literal, $($sig:tt)*) => {
73+
#[rustc_diagnostic_item = $name]
74+
pub $($sig)* { panic!() }
75+
}
76+
}
77+
78+
define!("mir_return", fn Return() -> BasicBlock);
79+
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
80+
define!("mir_retag", fn Retag<T>(place: T));
81+
define!("mir_retag_raw", fn RetagRaw<T>(place: T));
82+
define!("mir_move", fn Move<T>(place: T) -> T);
83+
84+
/// Convenience macro for generating custom MIR.
85+
///
86+
/// See the module documentation for syntax details. This macro is not magic - it only transforms
87+
/// your MIR into something that is easier to parse in the compiler.
88+
#[rustc_macro_transparency = "transparent"]
89+
pub macro mir {
90+
(
91+
$(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
92+
93+
$entry_block:block
94+
95+
$(
96+
$block_name:ident = $block:block
97+
)*
98+
) => {{
99+
// First, we declare all basic blocks.
100+
$(
101+
let $block_name: ::core::intrinsics::mir::BasicBlock;
102+
)*
103+
104+
{
105+
// Now all locals
106+
#[allow(non_snake_case)]
107+
let RET;
108+
$(
109+
let $local_decl $(: $local_decl_ty)? ;
110+
)*
111+
112+
{
113+
// Finally, the contents of the basic blocks
114+
$entry_block;
115+
$(
116+
$block;
117+
)*
118+
119+
RET
120+
}
121+
}
122+
}}
123+
}

0 commit comments

Comments
 (0)