Module core::intrinsics::mir

source ·
🔬This is a nightly-only experimental API. (custom_mir)
Expand description

Rustc 用于手写 MIR 的内部工具。

如果由于某些原因您没有编写 rustc 测试,并且发现自己正在考虑使用此特性,那么请返回。这是非常不稳定的。 除了 rustc 测试套件恰好需要的那些东西之外,根本没有尝试使任何东西工作。 如果您打错字,您可能会 ICE。 真的,这不是解决您问题的方法。 考虑改为支持 稳定的 MIR 项目组

此模块的文档描述了如何使用此特性。 如果您有兴趣破解实现,大部分文档都位于 rustc_mir_build/src/build/custom/mod.rs

典型用法如下所示:

#![feature(core_intrinsics, custom_mir)]

use core::intrinsics::mir::*;

#[custom_mir(dialect = "built")]
pub fn simple(x: i32) -> i32 {
    mir!(
        let temp2: i32;

        {
            let temp1 = x;
            Goto(my_second_block)
        }

        my_second_block = {
            temp2 = Move(temp1);
            RET = temp2;
            Return()
        }
    )
}
Run

custom_mir 属性告诉编译器将函数视为自定义 MIR。 此属性仅适用于函数 - 无法将自定义 MIR 插入另一个函数的中间。 dialectphase 参数指示您要在此处插入哪个 version of MIR。 一般来说,如果您希望您的 MIR 被完整的 MIR 管道修改,您将希望使用 #![custom_mir(dialect = "built")],如果您不希望使用 #![custom_mir(dialect = "runtime", phase = "optimized")]

mir! 宏的输入是:

  • type RET = ...; 形式的可选返回类注解。如果编译器无法推断 RET 的类型,则可能需要这样做。
  • 一个可能为空的本地声明列表。局部变量也可以通过 let 声明为内联赋值。类型推断通常有效。阴影没有。
  • 基本块列表。其中第一个是开始块,是执行开始的地方。 除了起始块之外的所有块都需要命名,以便以后可以引用它们。
    • 每个块都是一个以分号结尾的语句列表,后跟一个终止符。 各种语言句法和终止符的语法被设计为与原生 Rust 中类似概念的语法尽可能相似。 请参见下面的列表。

Examples

#![feature(core_intrinsics, custom_mir)]

use core::intrinsics::mir::*;

#[custom_mir(dialect = "built")]
pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
    mir!(
        {
            match c {
                true => t,
                _ => f,
            }
        }

        t = {
            let temp = a;
            Goto(load_and_exit)
        }

        f = {
            temp = b;
            Goto(load_and_exit)
        }

        load_and_exit = {
            RET = *temp;
            Return()
        }
    )
}

#[custom_mir(dialect = "built")]
fn unwrap_unchecked<T>(opt: Option<T>) -> T {
    mir!({
        RET = Move(Field(Variant(opt, 1), 0));
        Return()
    })
}

#[custom_mir(dialect = "runtime", phase = "optimized")]
fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
    mir!(
        let unused;
        let popped;

        {
            Call(unused, pop, Vec::push(v, value))
        }

        pop = {
            Call(popped, drop, Vec::pop(v))
        }

        drop = {
            Drop(popped, ret)
        }

        ret = {
            Return()
        }
    )
}

#[custom_mir(dialect = "runtime", phase = "optimized")]
fn annotated_return_type() -> (i32, bool) {
    mir!(
        type RET = (i32, bool);
        {
            RET.0 = 1;
            RET.1 = true;
            Return()
        }
    )
}
Run

我们还可以触发在编译器足够晚的阶段发生的编译失败:

#![feature(core_intrinsics, custom_mir)]

extern crate core;
use core::intrinsics::mir::*;

#[custom_mir(dialect = "built")]
fn borrow_error(should_init: bool) -> i32 {
    mir!(
        let temp: i32;

        {
            match should_init {
                true => init,
                _ => use_temp,
            }
        }

        init = {
            temp = 0;
            Goto(use_temp)
        }

        use_temp = {
            RET = temp;
            Return()
        }
    )
}
Run
error[E0381]: used binding is possibly-uninitialized
  --> test.rs:24:13
   |
8  | /     mir!(
9  | |         let temp: i32;
10 | |
11 | |         {
...  |
19 | |             temp = 0;
   | |             -------- binding initialized here in some conditions
...  |
24 | |             RET = temp;
   | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
25 | |             Return()
26 | |         }
27 | |     )
   | |_____- binding declared here but left uninitialized

error: aborting due to previous error

For more information about this error, try `rustc --explain E0381`.

Syntax

下面的列表详尽地描述了如何创建各种 MIR 构造。 列表中遗漏的任何内容都应假定为不受支持,欢迎 PR。

Locals
  • _0 返回本地始终可以通过 RET 访问。
  • 参数可以通过他们的常规名称访问。
  • 所有其他局部变量都需要在某处用 let 声明,然后才能通过名称访问。
Places
  • 本地人隐式转换为地点。
  • 字段访问、解引用和索引工作正常。
  • 变体中的字段可以通过 VariantField 关联函数访问,请参见它们的文档以获取详细信息。
Operands
  • 地方隐式转换为 Copy 操作数。
  • Move 操作数可以通过 Move 创建。
  • Const 块、字面量、命名常量和 const 参数都可以正常工作。
  • StaticStaticMut 可用于创建 &T*mut T 到静态。这些是 MIR 中的常量,也是访问静态的唯一方法。
Statements
Rvalues
  • 操作数隐式转换为 Use 右值。
  • &&mutaddr_of!addr_of_mut! 都用于创建其关联的右值。
  • DiscriminantLenCopyForDeref 具有关联的函数。
  • 一元和二元运算使用其正常的 Rust 语法 –a * b!c 等。
  • 二元运算 Offset 可以通过 Offset 创建。
  • 已检查的二进制操作通过将关联的 binop 包装在 Checked 中来表示。
  • 数组重复语法 ([foo; 10]) 创建关联的右值。
Terminators

自定义 MIR 当前不支持清理块或非平凡展开路径。 因此,没有恢复和中止终结符,并且,可能展开的终结符没有任何方式指示展开块。

  • GotoReturnUnreachableDrop 有关联函数。
  • match some_int_operand 变成 SwitchInt。每个 arm 应该是 literal => basic_block
    • 例外的是最后一个 arm,它必须是 _ => basic_block,并且对应于 otherwise 分支。
  • Call 也有一个关联函数。该函数的第三个参数是一个普通的函数调用表达式,例如 my_other_function(a, 5)

Macros

  • mirExperimental
    用于生成自定义 MIR。
  • placeExperimental
    Helper 宏允许您将值表达式视为位置表达式。

Structs

Functions