如何确保执行没有副作用的函数并且不会在稳定的 Rust 中得到优化?
是否有我可以使用的属性组合,或者我必须调用另一个具有副作用的函数?在需要函数调用的情况下,Rust 标准库是否提供了保证不会被优化掉的廉价函数?
如何确保执行没有副作用的函数并且不会在稳定的 Rust 中得到优化?
是否有我可以使用的属性组合,或者我必须调用另一个具有副作用的函数?在需要函数调用的情况下,Rust 标准库是否提供了保证不会被优化掉的廉价函数?
#[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]
,因为没有人实施它。
有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。我当然不会在生产库中发布这种代码,但它对于测试目的肯定很有用!
只要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)
}
}