rust - 如果打印值,为什么 Rust 编译器不能优化 Option::take 和 "if let"?

标签 rust compiler-optimization

我遇到了以下观察结果:

pub fn xx(mut x: Option<usize>) -> usize {
    let y = x.take();
    //print!("{:?}", x);
    if let Some(x) = x {
        x
    } else {
        0
    }
}

此代码(print! 被注释掉)被优化为“无”:

xorl    %eax, %eax
retq

一旦我取消注释 print!,它就不能再优化 if let Some(x) = x 了。我继续扩展宏(使用 rustc +nightly --pretty=expanded -Z unstable-options main.rs)并将代码最小化为最小的可编译示例:

#![feature(print_internals)]
#![feature(fmt_internals)]

pub fn xx(mut x: Option<usize>) -> usize {
    let y = x.take();

    std::io::_print(
        ::std::fmt::Arguments::new_v1_formatted(
            &[""],
            &[::std::fmt::ArgumentV1::new(&x, ::std::fmt::Debug::fmt)],
            &[]
        )
    );

    if let Some(x) = x {
        x
    } else {
        0
    }
}

据我所知,我们只引用了一次x,而且它是一个不可变的引用,所以没有什么可以阻止优化器假设它是None (因为我们 take() 它)并且只是不断地返回 0 就像在第一个片段中一样。

Here are the snippets in the Compiler Explorer

最佳答案

优化器只允许对程序进行不改变运行时行为的改变。通过打印选项您已经更改了运行时行为,因此优化器现在受到更多限制。

通过添加 print 语句,您可以使变量的地址可见并且对代码很重要:

&[::std::fmt::ArgumentV1::new(&x, ::std::fmt::Debug::fmt)],
//                            ^^

这意味着优化器不能再跳过为值生成内存位置或操作存储在其中的值。一旦你添加了所有关于动态调度和 IO 的垃圾,一个额外的 if 不会增加明显的开销。


真正的答案是阅读 LLVM 源代码。优化非常重要,它们适用和不适用的深奥原因。

关于rust - 如果打印值,为什么 Rust 编译器不能优化 Option::take 和 "if let"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51120292/

相关文章:

api - 如何使用Rust通过访问 token 提交新的github问题

java - 编译器是否优化了同一语句中对同一方法的多次调用?

c++ - O2 优化级别中断程序工作

compiler-errors - 在移植到 ARM 期间使用指针访问数组不起作用

c# - 为什么不能在编译时将值类型上的 GetType() 替换为字符串文字?

rust - 如何在切片上实现等同于 take_while?

rust - try_into() 在 u8 上使用时中断

enums - 我最接近通过 char 区分枚举的是什么?

unit-testing - 如何在 Rust 中运行特定的单元测试?

c++ - 如何强制编译器不跳过我的函数调用?