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()
}
)
}
Runcustom_mir
属性告诉编译器将函数视为自定义 MIR。
此属性仅适用于函数 - 无法将自定义 MIR 插入另一个函数的中间。
dialect
和 phase
参数指示您要在此处插入哪个 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()
}
)
}
Runerror[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
Operands
- 地方隐式转换为
Copy
操作数。 Move
操作数可以通过Move
创建。- Const 块、字面量、命名常量和 const 参数都可以正常工作。
Static
和StaticMut
可用于创建&T
和*mut T
到静态。这些是 MIR 中的常量,也是访问静态的唯一方法。
Statements
- 通过正常的 Rust 分配分配语言句子工作。
Retag
,StorageLive
,StorageDead
,Deinit
语句有一个关联函数。
Rvalues
- 操作数隐式转换为
Use
右值。 &
、&mut
、addr_of!
和addr_of_mut!
都用于创建其关联的右值。Discriminant
、Len
、CopyForDeref
具有关联的函数。- 一元和二元运算使用其正常的 Rust 语法 –
a * b
、!c
等。 - 二元运算
Offset
可以通过Offset
创建。 - 已检查的二进制操作通过将关联的 binop 包装在
Checked
中来表示。 - 数组重复语法 (
[foo; 10]
) 创建关联的右值。
Terminators
自定义 MIR 当前不支持清理块或非平凡展开路径。 因此,没有恢复和中止终结符,并且,可能展开的终结符没有任何方式指示展开块。
Goto
、Return
、Unreachable
、Drop
有关联函数。match some_int_operand
变成SwitchInt
。每个 arm 应该是literal => basic_block
- 例外的是最后一个 arm,它必须是
_ => basic_block
,并且对应于 otherwise 分支。
- 例外的是最后一个 arm,它必须是
Call
也有一个关联函数。该函数的第三个参数是一个普通的函数调用表达式,例如my_other_function(a, 5)
。
Macros
Structs
- BasicBlockExperimental表示基本块的类型。
Functions
- CallExperimental
- CastTransmuteExperimental触发一个
CastKind::Transmute
cast。 - CheckedExperimental
- CopyForDerefExperimental
- DeinitExperimental
- DiscriminantExperimental获取一个地方的判别式。
- DropExperimental
- FieldExperimental访问具有某个地方的给定索引的字段。
- GotoExperimental
- LenExperimental
- MoveExperimental
- OffsetExperimental
- RetagExperimental
- ReturnExperimental
- SetDiscriminantExperimental
- StaticExperimental
- StaticMutExperimental
- StorageDeadExperimental
- StorageLiveExperimental
- UnreachableExperimental
- VariantExperimental将具有给定索引的变体投影添加到该位置。