3

如何确保执行没有副作用的函数并且不会在稳定的 Rust 中得到优化?

是否有我可以使用的属性组合,或者我必须调用另一个具有副作用的函数?在需要函数调用的情况下,Rust 标准库是否提供了保证不会被优化掉的廉价函数?

4

3 回答 3

3

#[no_mangle]目前会这样做,但这可能会改变

#[no_mangle]
pub fn do_what_i_say_dammit(x: i64) -> i64 { x*x }

澄清(从那个帖子):

我的心理模型是符号默认归 rustc 所有(例如,如果符号是私有的,只要正确处理,rustc 可以发出不同类型的“arg-promoted”符号而不是预期的符号),并且#[no_mangle]将符号的所有权转移给程序员。

现在,因为所有权转移给了程序员,所以不能使用 rustc 的未指定符号修改方案,所以符号保持未修改。

拥有一个未损坏的 rustc 拥有的符号几乎没有任何意义(你实际上不能使用它,因为编译器拥有它) - 所以#[no_mangle] 暗示#[linker_owned]. 没有松散#[linker_owned],因为没有人实施它。

编辑:这是一个简单的例子。no_mangle 描述

于 2017-03-19T19:23:17.833 回答
2

test::black_box()(链接到旧文档)仍然不稳定(就像整个test箱子一样)。此函数采用任意类型的值并再次返回相同的值。所以它基本上是身份功能。“哦,好吧,现在这很有用不是吗?” 你可能会讽刺地问。

但是有一些特别的东西:传递的值对 LLVM 是隐藏的(现在在 Rust 中进行几乎所有优化的东西)!它确实是一个黑匣子,因为 LLVM 对一段代码一无所知。在不知道任何事情的情况下,LLVM 无法证明优化不会改变程序的行为。因此:没有优化。

它是如何做到的?让我们看一下定义:

pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}

如果我要假装我完全理解这段代码,我会撒谎,但它是这样的:我们插入空的内联程序集(不是一条指令)但告诉 Rust(告诉 LLVM)这段程序集使用变量dummy。这使得优化器无法对变量进行推理。愚蠢的编译器,好容易被骗,muhahahaha!如果你想要另一种解释,Chandler Carruth在 CppCon 2015 上解释了黑魔法。

那么你现在如何使用它呢?只需将它用于某种价值......任何经历的事情都black_box()需要计算。这样的事情怎么样?

black_box(my_function());

的返回值my_function()需要计算,因为编译器无法证明它没用!所以函数调用不会被删除。但是请注意,您必须使用不稳定的功能(您test自己编写函数的 crate 或内联 asm)或使用 FFI。我当然不会在生产库中发布这种代码,但它对于测试目的肯定很有用!

于 2017-03-19T22:28:56.073 回答
0

只要std::hint:black_box仍然不稳定,您就可以自己使用std::ptr::read_volatile. 与 一样std::hint::black_box,使用其他未使用的值调用它应该可以防止该值被优化掉:

fn black_box<T>(dummy: T) -> T {
    unsafe {
        std::ptr::read_volatile(&dummy)
    }
}
于 2021-11-14T21:58:07.110 回答