]> git.lizzy.rs Git - rust.git/blob - library/core/src/intrinsics/mir.rs
drive-by: Fix path spans
[rust.git] / library / core / src / intrinsics / mir.rs
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 define!("mir_static", fn Static<T>(s: T) -> &'static T);
84 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
85
86 /// Convenience macro for generating custom MIR.
87 ///
88 /// See the module documentation for syntax details. This macro is not magic - it only transforms
89 /// your MIR into something that is easier to parse in the compiler.
90 #[rustc_macro_transparency = "transparent"]
91 pub macro mir {
92     (
93         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
94
95         {
96             $($entry:tt)*
97         }
98
99         $(
100             $block_name:ident = {
101                 $($block:tt)*
102             }
103         )*
104     ) => {{
105         // First, we declare all basic blocks.
106         $(
107             let $block_name: ::core::intrinsics::mir::BasicBlock;
108         )*
109
110         {
111             // Now all locals
112             #[allow(non_snake_case)]
113             let RET;
114             $(
115                 let $local_decl $(: $local_decl_ty)? ;
116             )*
117
118             ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
119             $(
120                 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
121             )*
122
123             {
124                 // Finally, the contents of the basic blocks
125                 ::core::intrinsics::mir::__internal_remove_let!({
126                     {}
127                     { $($entry)* }
128                 });
129                 $(
130                     ::core::intrinsics::mir::__internal_remove_let!({
131                         {}
132                         { $($block)* }
133                     });
134                 )*
135
136                 RET
137             }
138         }
139     }}
140 }
141
142 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
143 ///
144 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
145 /// statement out of the input, does the appropriate thing with it, and then recursively calls the
146 /// same macro on the remainder of the input.
147 #[doc(hidden)]
148 pub macro __internal_extract_let {
149     // If it's a `let` like statement, keep the `let`
150     (
151         let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
152     ) => {
153         let $var $(: $ty)?;
154         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
155     },
156     // Due to #86730, we have to handle const blocks separately
157     (
158         let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
159     ) => {
160         let $var $(: $ty)?;
161         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
162     },
163     // Otherwise, output nothing
164     (
165         $stmt:stmt; $($rest:tt)*
166     ) => {
167         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
168     },
169     (
170         $expr:expr
171     ) => {}
172 }
173
174 /// Helper macro that removes the `let` declarations from a bunch of statements.
175 ///
176 /// Because expression position macros cannot expand to statements + expressions, we need to be
177 /// slightly creative here. The general strategy is also statement munching as above, but the output
178 /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
179 /// ```text
180 /// invoke!(
181 ///     {
182 ///         {
183 ///             x = 5;
184 ///         }
185 ///         {
186 ///             let d = e;
187 ///             Call()
188 ///         }
189 ///     }
190 /// )
191 /// ```
192 /// becomes
193 /// ```text
194 /// invoke!(
195 ///     {
196 ///         {
197 ///             x = 5;
198 ///             d = e;
199 ///         }
200 ///         {
201 ///             Call()
202 ///         }
203 ///     }
204 /// )
205 /// ```
206 #[doc(hidden)]
207 pub macro __internal_remove_let {
208     // If it's a `let` like statement, remove the `let`
209     (
210         {
211             {
212                 $($already_parsed:tt)*
213             }
214             {
215                 let $var:ident $(: $ty:ty)? = $expr:expr;
216                 $($rest:tt)*
217             }
218         }
219     ) => { ::core::intrinsics::mir::__internal_remove_let!(
220         {
221             {
222                 $($already_parsed)*
223                 $var = $expr;
224             }
225             {
226                 $($rest)*
227             }
228         }
229     )},
230     // Due to #86730 , we have to handle const blocks separately
231     (
232         {
233             {
234                 $($already_parsed:tt)*
235             }
236             {
237                 let $var:ident $(: $ty:ty)? = const $block:block;
238                 $($rest:tt)*
239             }
240         }
241     ) => { ::core::intrinsics::mir::__internal_remove_let!(
242         {
243             {
244                 $($already_parsed)*
245                 $var = const $block;
246             }
247             {
248                 $($rest)*
249             }
250         }
251     )},
252     // Otherwise, keep going
253     (
254         {
255             {
256                 $($already_parsed:tt)*
257             }
258             {
259                 $stmt:stmt;
260                 $($rest:tt)*
261             }
262         }
263     ) => { ::core::intrinsics::mir::__internal_remove_let!(
264         {
265             {
266                 $($already_parsed)*
267                 $stmt;
268             }
269             {
270                 $($rest)*
271             }
272         }
273     )},
274     (
275         {
276             {
277                 $($already_parsed:tt)*
278             }
279             {
280                 $expr:expr
281             }
282         }
283     ) => {
284         {
285             $($already_parsed)*
286             $expr
287         }
288     },
289 }