Dai*_*Dai 7 compiler-construction compiler-optimization rust
在Rust中,Option
定义为:
pub enum Option<T> {
None,
Some(T),
}
Run Code Online (Sandbox Code Playgroud)
像这样使用:
fn may_return_none() -> Option<i32> {
if is_full_moon {
None
} else {
Some(1)
}
}
fn main() {
let optional = may_return_none();
match optional {
None => println!("None"),
Some(v) => println!("Some"),
}
}
Run Code Online (Sandbox Code Playgroud)
我不熟悉Rust内部,但最初我认为它可能与Nullable
.NET 类似,所以我上面的Rust代码的编译逻辑就像这样:
// occupies `sizeof(T) + 1` memory space, possibly more depending on `Bool`'s alignment, so `Nullable<Int32>` consumes 5 bytes.
struct Nullable<T> {
Bool hasValue;
T value;
}
Nullable<Int32> MayReturnNone() {
if( isFullMoon )
// as a `struct`, the Nullable<Int32> instance is returned via the stack
return Nullable<Int32>() { HasValue = false }
else
return Nullable<Int32>() { HasValue = true, Value = 1 }
}
void Test() {
Nullable<Int32> optional = may_return_none();
if( !optional.HasValue ) println("None");
else println("Some");
}
Run Code Online (Sandbox Code Playgroud)
然而,由于Bool hasValue
标志所需的空间,这不是零成本抽象- 而Rust提供了零成本抽象的观点.
我意识到Option
可以通过编译器的直接返回跳转来实现,尽管它需要在堆栈上作为参数提供精确的跳转值 - 就像你可以推送多个返回地址一样:
(伪码)
mayReturnNone(returnToIfNone, returnToIfHasValue) {
if( isFullMoon ) {
cleanup-current-stackframe
jump-to returnToIfNone
else {
cleanup-current-stackframe
push-stack 1
jump-to returnToIfHasValue
}
test() {
mayReturnNone( instructionAddressOf( ifHasValue ), instructionAddressOf( ifNoValue ) )
ifHasValue:
println("Some")
ifNoValue:
println("None")
}
Run Code Online (Sandbox Code Playgroud)
这是如何实现的?这种方法也适用enum
于Rust中的其他类型 - 但是我已经演示的这个特定应用程序非常脆弱,如果你想在调用mayReturnNone
和match
语句之间执行代码,例如(因为它mayReturnNone
会直接跳转到match
,跳过)中间指示).
这完全取决于优化.考虑这个实现(playground):
#![feature(asm)]
extern crate rand;
use rand::Rng;
#[inline(never)]
fn is_full_moon() -> bool {
rand::thread_rng().gen()
}
fn may_return_none() -> Option<i32> {
if is_full_moon() { None } else { Some(1) }
}
#[inline(never)]
fn usage() {
let optional = may_return_none();
match optional {
None => unsafe { asm!("nop") },
Some(v) => unsafe { asm!("nop; nop") },
}
}
fn main() {
usage();
}
Run Code Online (Sandbox Code Playgroud)
在这里,我使用内联汇编而不是打印,因为它不会使得到的输出混乱.这是usage
在发布模式下编译时的程序集:
.section .text._ZN10playground5usage17hc2760d0a512fe6f1E,"ax",@progbits
.p2align 4, 0x90
.type _ZN10playground5usage17hc2760d0a512fe6f1E,@function
_ZN10playground5usage17hc2760d0a512fe6f1E:
.cfi_startproc
pushq %rax
.Ltmp6:
.cfi_def_cfa_offset 16
callq _ZN10playground12is_full_moon17h78e56c4ffd6b7730E
testb %al, %al
je .LBB1_2
#APP
nop
#NO_APP
popq %rax
retq
.LBB1_2:
#APP
nop
nop
#NO_APP
popq %rax
retq
.Lfunc_end1:
.size _ZN10playground5usage17hc2760d0a512fe6f1E, .Lfunc_end1-_ZN10playground5usage17hc2760d0a512fe6f1E
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
快速简介是:
is_full_moon
函数(callq _ZN10playground12is_full_moon17h78e56c4ffd6b7730E
).testb %al, %al
)nop
,另一个进入nop; nop
其他一切都已经过优化.该功能may_return_none
基本上不存在; 没有Option
创造过,价值1
永远不会实现.
我确信不同的人有不同的意见,但我认为我不能写得更优化了.
同样,如果我们使用Some
(我更改为42更容易找到)中的值:
Some(v) => unsafe { asm!("nop; nop" : : "r"(v)) },
Run Code Online (Sandbox Code Playgroud)
然后在使用它的分支中内联该值:
.section .text._ZN10playground5usage17hc2760d0a512fe6f1E,"ax",@progbits
.p2align 4, 0x90
.type _ZN10playground5usage17hc2760d0a512fe6f1E,@function
_ZN10playground5usage17hc2760d0a512fe6f1E:
.cfi_startproc
pushq %rax
.Ltmp6:
.cfi_def_cfa_offset 16
callq _ZN10playground12is_full_moon17h78e56c4ffd6b7730E
testb %al, %al
je .LBB1_2
#APP
nop
#NO_APP
popq %rax
retq
.LBB1_2:
movl $42, %eax ;; Here it is
#APP
nop
nop
#NO_APP
popq %rax
retq
.Lfunc_end1:
.size _ZN10playground5usage17hc2760d0a512fe6f1E, .Lfunc_end1-_ZN10playground5usage17hc2760d0a512fe6f1E
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
但是,没有任何东西可以围绕合同义务"优化"; 如果一个函数必须返回一个Option
,它必须返回一个Option
:
#[inline(never)]
pub fn may_return_none() -> Option<i32> {
if is_full_moon() { None } else { Some(42) }
}
Run Code Online (Sandbox Code Playgroud)
这使得一些Deep Magic组装:
.section .text._ZN10playground15may_return_none17ha1178226d153ece2E,"ax",@progbits
.p2align 4, 0x90
.type _ZN10playground15may_return_none17ha1178226d153ece2E,@function
_ZN10playground15may_return_none17ha1178226d153ece2E:
.cfi_startproc
pushq %rax
.Ltmp6:
.cfi_def_cfa_offset 16
callq _ZN10playground12is_full_moon17h78e56c4ffd6b7730E
movabsq $180388626432, %rdx
leaq 1(%rdx), %rcx
testb %al, %al
cmovneq %rdx, %rcx
movq %rcx, %rax
popq %rcx
retq
.Lfunc_end1:
.size _ZN10playground15may_return_none17ha1178226d153ece2E, .Lfunc_end1-_ZN10playground15may_return_none17ha1178226d153ece2E
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
让我们希望我做对了......
Option
正在建造的; 这是None
变种.Some
变种.这里的要点是,无论优化如何,一个表明它将以特定格式返回数据的函数必须这样做.只有当它与其他代码内联时,删除该抽象才有效.
归档时间: |
|
查看次数: |
464 次 |
最近记录: |