]> git.lizzy.rs Git - rust.git/blob - library/core/src/intrinsics/mir.rs
Auto merge of #105356 - JakobDegen:more-custom-mir, r=oli-obk
[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 temp2: i32;
25 //!
26 //!         {
27 //!             let temp1 = x;
28 //!             Goto(my_second_block)
29 //!         }
30 //!
31 //!         my_second_block = {
32 //!             temp2 = Move(temp1);
33 //!             RET = temp2;
34 //!             Return()
35 //!         }
36 //!     )
37 //! }
38 //! ```
39 //!
40 //! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
41 //! attribute only works on functions - there is no way to insert custom MIR into the middle of
42 //! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
43 //! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
44 //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
45 //! "runtime", phase = "optimized")] if you don't.
46 //!
47 //! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
48 //!
49 //! The input to the [`mir!`] macro is:
50 //!
51 //!  - A possibly empty list of local declarations. Locals can also be declared inline on
52 //!    assignments via `let`. Type inference generally works. Shadowing does not.
53 //!  - A list of basic blocks. The first of these is the start block and is where execution begins.
54 //!    All blocks other than the start block need to be given a name, so that they can be referred
55 //!    to later.
56 //!     - Each block is a list of semicolon terminated statements, followed by a terminator. The
57 //!       syntax for the various statements and terminators is designed to be as similar as possible
58 //!       to the syntax for analogous concepts in native Rust. See below for a list.
59 //!
60 //! # Examples
61 //!
62 //! ```rust
63 //! #![feature(core_intrinsics, custom_mir)]
64 //!
65 //! extern crate core;
66 //! use core::intrinsics::mir::*;
67 //!
68 //! #[custom_mir(dialect = "built")]
69 //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
70 //!     mir!(
71 //!         {
72 //!             match c {
73 //!                 true => t,
74 //!                 _ => f,
75 //!             }
76 //!         }
77 //!
78 //!         t = {
79 //!             let temp = a;
80 //!             Goto(load_and_exit)
81 //!         }
82 //!
83 //!         f = {
84 //!             temp = b;
85 //!             Goto(load_and_exit)
86 //!         }
87 //!
88 //!         load_and_exit = {
89 //!             RET = *temp;
90 //!             Return()
91 //!         }
92 //!     )
93 //! }
94 //!
95 //! #[custom_mir(dialect = "built")]
96 //! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
97 //!     mir!({
98 //!         RET = Move(Field(Variant(opt, 1), 0));
99 //!         Return()
100 //!     })
101 //! }
102 //! ```
103 //!
104 //! We can also set off compilation failures that happen in sufficiently late stages of the
105 //! compiler:
106 //!
107 //! ```rust,compile_fail
108 //! #![feature(core_intrinsics, custom_mir)]
109 //!
110 //! extern crate core;
111 //! use core::intrinsics::mir::*;
112 //!
113 //! #[custom_mir(dialect = "built")]
114 //! fn borrow_error(should_init: bool) -> i32 {
115 //!     mir!(
116 //!         let temp: i32;
117 //!
118 //!         {
119 //!             match should_init {
120 //!                 true => init,
121 //!                 _ => use_temp,
122 //!             }
123 //!         }
124 //!
125 //!         init = {
126 //!             temp = 0;
127 //!             Goto(use_temp)
128 //!         }
129 //!
130 //!         use_temp = {
131 //!             RET = temp;
132 //!             Return()
133 //!         }
134 //!     )
135 //! }
136 //! ```
137 //!
138 //! ```text
139 //! error[E0381]: used binding is possibly-uninitialized
140 //!   --> test.rs:24:13
141 //!    |
142 //! 8  | /     mir!(
143 //! 9  | |         let temp: i32;
144 //! 10 | |
145 //! 11 | |         {
146 //! ...  |
147 //! 19 | |             temp = 0;
148 //!    | |             -------- binding initialized here in some conditions
149 //! ...  |
150 //! 24 | |             RET = temp;
151 //!    | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
152 //! 25 | |             Return()
153 //! 26 | |         }
154 //! 27 | |     )
155 //!    | |_____- binding declared here but left uninitialized
156 //!
157 //! error: aborting due to previous error
158 //!
159 //! For more information about this error, try `rustc --explain E0381`.
160 //! ```
161 //!
162 //! # Syntax
163 //!
164 //! The lists below are an exhaustive description of how various MIR constructs can be created.
165 //! Anything missing from the list should be assumed to not be supported, PRs welcome.
166 //!
167 //! #### Locals
168 //!
169 //!  - The `_0` return local can always be accessed via `RET`.
170 //!  - Arguments can be accessed via their regular name.
171 //!  - All other locals need to be declared with `let` somewhere and then can be accessed by name.
172 //!
173 //! #### Places
174 //!  - Locals implicit convert to places.
175 //!  - Field accesses, derefs, and indexing work normally.
176 //!  - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
177 //!    see their documentation for details.
178 //!
179 //! #### Operands
180 //!  - Places implicitly convert to `Copy` operands.
181 //!  - `Move` operands can be created via [`Move`].
182 //!  - Const blocks, literals, named constants, and const params all just work.
183 //!  - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
184 //!    constants in MIR and the only way to access statics.
185 //!
186 //! #### Statements
187 //!  - Assign statements work via normal Rust assignment.
188 //!  - [`Retag`] statements have an associated function.
189 //!
190 //! #### Rvalues
191 //!
192 //!  - Operands implicitly convert to `Use` rvalues.
193 //!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
194 //!  - [`Discriminant`] has an associated function.
195 //!
196 //! #### Terminators
197 //!
198 //!  - [`Goto`] and [`Return`] have associated functions.
199 //!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
200 //!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
201 //!       otherwise branch.
202 //!
203
204 #![unstable(
205     feature = "custom_mir",
206     reason = "MIR is an implementation detail and extremely unstable",
207     issue = "none"
208 )]
209 #![allow(unused_variables, non_snake_case, missing_debug_implementations)]
210
211 /// Type representing basic blocks.
212 ///
213 /// All terminators will have this type as a return type. It helps achieve some type safety.
214 pub struct BasicBlock;
215
216 macro_rules! define {
217     ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
218         #[rustc_diagnostic_item = $name]
219         $( #[ $meta ] )*
220         pub fn $($sig)* { panic!() }
221     }
222 }
223
224 define!("mir_return", fn Return() -> BasicBlock);
225 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
226 define!("mir_retag", fn Retag<T>(place: T));
227 define!("mir_retag_raw", fn RetagRaw<T>(place: T));
228 define!("mir_move", fn Move<T>(place: T) -> T);
229 define!("mir_static", fn Static<T>(s: T) -> &'static T);
230 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
231 define!(
232     "mir_discriminant",
233     /// Gets the discriminant of a place.
234     fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
235 );
236 define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
237 define!(
238     "mir_field",
239     /// Access the field with the given index of some place.
240     ///
241     /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
242     /// access the field of does not have variants, you can use normal field projection syntax.
243     ///
244     /// There is no proper way to do a place projection to a variant in Rust, and so these two
245     /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
246     /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
247     /// caveats:
248     ///
249     ///  - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
250     ///    still be generated.
251     ///  - In some situations, the return type of `Field` cannot be inferred. You may need to
252     ///    annotate it on the function in these cases.
253     ///  - Since `Field` is a function call which is not a place expression, using this on the left
254     ///    hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
255     ///    work around that issue. Wrap the left hand side of an assignment in the macro to convince
256     ///    the compiler that it's ok.
257     ///
258     /// # Examples
259     ///
260     /// ```rust
261     /// #![feature(custom_mir, core_intrinsics)]
262     ///
263     /// extern crate core;
264     /// use core::intrinsics::mir::*;
265     ///
266     /// #[custom_mir(dialect = "built")]
267     /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
268     ///     mir!({
269     ///         RET = *Field::<&i32>(Variant(opt, 1), 0);
270     ///         Return()
271     ///     })
272     /// }
273     ///
274     /// #[custom_mir(dialect = "built")]
275     /// fn set(opt: &mut Option<i32>) {
276     ///     mir!({
277     ///         place!(Field(Variant(*opt, 1), 0)) = 5;
278     ///         Return()
279     ///     })
280     /// }
281     /// ```
282     fn Field<F>(place: (), field: u32) -> F
283 );
284 define!(
285     "mir_variant",
286     /// Adds a variant projection with the given index to the place.
287     ///
288     /// See [`Field`] for documentation.
289     fn Variant<T>(place: T, index: u32) -> ()
290 );
291 define!(
292     "mir_make_place",
293     #[doc(hidden)]
294     fn __internal_make_place<T>(place: T) -> *mut T
295 );
296
297 /// Macro for generating custom MIR.
298 ///
299 /// See the module documentation for syntax details. This macro is not magic - it only transforms
300 /// your MIR into something that is easier to parse in the compiler.
301 #[rustc_macro_transparency = "transparent"]
302 pub macro mir {
303     (
304         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
305
306         {
307             $($entry:tt)*
308         }
309
310         $(
311             $block_name:ident = {
312                 $($block:tt)*
313             }
314         )*
315     ) => {{
316         // First, we declare all basic blocks.
317         $(
318             let $block_name: ::core::intrinsics::mir::BasicBlock;
319         )*
320
321         {
322             // Now all locals
323             #[allow(non_snake_case)]
324             let RET;
325             $(
326                 let $local_decl $(: $local_decl_ty)? ;
327             )*
328
329             ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
330             $(
331                 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
332             )*
333
334             {
335                 // Finally, the contents of the basic blocks
336                 ::core::intrinsics::mir::__internal_remove_let!({
337                     {}
338                     { $($entry)* }
339                 });
340                 $(
341                     ::core::intrinsics::mir::__internal_remove_let!({
342                         {}
343                         { $($block)* }
344                     });
345                 )*
346
347                 RET
348             }
349         }
350     }}
351 }
352
353 /// Helper macro that allows you to treat a value expression like a place expression.
354 ///
355 /// See the documentation on [`Variant`] for why this is necessary and how to use it.
356 pub macro place($e:expr) {
357     (*::core::intrinsics::mir::__internal_make_place($e))
358 }
359
360 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
361 ///
362 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
363 /// statement out of the input, does the appropriate thing with it, and then recursively calls the
364 /// same macro on the remainder of the input.
365 #[doc(hidden)]
366 pub macro __internal_extract_let {
367     // If it's a `let` like statement, keep the `let`
368     (
369         let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
370     ) => {
371         let $var $(: $ty)?;
372         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
373     },
374     // Due to #86730, we have to handle const blocks separately
375     (
376         let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
377     ) => {
378         let $var $(: $ty)?;
379         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
380     },
381     // Otherwise, output nothing
382     (
383         $stmt:stmt; $($rest:tt)*
384     ) => {
385         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
386     },
387     (
388         $expr:expr
389     ) => {}
390 }
391
392 /// Helper macro that removes the `let` declarations from a bunch of statements.
393 ///
394 /// Because expression position macros cannot expand to statements + expressions, we need to be
395 /// slightly creative here. The general strategy is also statement munching as above, but the output
396 /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
397 /// ```text
398 /// invoke!(
399 ///     {
400 ///         {
401 ///             x = 5;
402 ///         }
403 ///         {
404 ///             let d = e;
405 ///             Call()
406 ///         }
407 ///     }
408 /// )
409 /// ```
410 /// becomes
411 /// ```text
412 /// invoke!(
413 ///     {
414 ///         {
415 ///             x = 5;
416 ///             d = e;
417 ///         }
418 ///         {
419 ///             Call()
420 ///         }
421 ///     }
422 /// )
423 /// ```
424 #[doc(hidden)]
425 pub macro __internal_remove_let {
426     // If it's a `let` like statement, remove the `let`
427     (
428         {
429             {
430                 $($already_parsed:tt)*
431             }
432             {
433                 let $var:ident $(: $ty:ty)? = $expr:expr;
434                 $($rest:tt)*
435             }
436         }
437     ) => { ::core::intrinsics::mir::__internal_remove_let!(
438         {
439             {
440                 $($already_parsed)*
441                 $var = $expr;
442             }
443             {
444                 $($rest)*
445             }
446         }
447     )},
448     // Due to #86730 , we have to handle const blocks separately
449     (
450         {
451             {
452                 $($already_parsed:tt)*
453             }
454             {
455                 let $var:ident $(: $ty:ty)? = const $block:block;
456                 $($rest:tt)*
457             }
458         }
459     ) => { ::core::intrinsics::mir::__internal_remove_let!(
460         {
461             {
462                 $($already_parsed)*
463                 $var = const $block;
464             }
465             {
466                 $($rest)*
467             }
468         }
469     )},
470     // Otherwise, keep going
471     (
472         {
473             {
474                 $($already_parsed:tt)*
475             }
476             {
477                 $stmt:stmt;
478                 $($rest:tt)*
479             }
480         }
481     ) => { ::core::intrinsics::mir::__internal_remove_let!(
482         {
483             {
484                 $($already_parsed)*
485                 $stmt;
486             }
487             {
488                 $($rest)*
489             }
490         }
491     )},
492     (
493         {
494             {
495                 $($already_parsed:tt)*
496             }
497             {
498                 $expr:expr
499             }
500         }
501     ) => {
502         {
503             $($already_parsed)*
504             $expr
505         }
506     },
507 }