pub static FOO: AtomicUsize = AtomicUsize::new(0);
pub fn foo(buf: &[u8]) {
for val in buf {
if FOO.load(Relaxed) == 1 {
foo1(val);
} else {
foo2(val);
}
}
}
Compiler as expected will generate code which checks value behind FOO on each iteration. But what if we can guarantee that value behind FOO does not change? Can we somehow convince compiler to treat FOO as &usize so it will generate code like here (note that compiler checks value behind foo only once)? Simply casting &FOO to &usize has no effect. Using static mut FOO: usize instead of the atomic has no effect as well.
To give a practical example, in the cpufeatures crate under the hood we have atomic variables which get initialized only once per program execution (well, strictly speaking they may get initialized several times, but always to the same value) and we use ZST tokens which prove that we have indeed checked that initialization has been performed. This token allows compiler to remove branch responsible for initialization, but it also proves that value behind the underlying atomic will not change. Unfortunately, I couldn't find a way to convince compiler to trust me about this.
Note that in real life code the loop and the FOO check reside in separate crates, so I can't simply move the check outside of the loop manually.
IIRC we hit a similar thing in glib and investigated using the GCC attribute((pure)) which is almost what's desired here. I think the problem is it also declares the function won't mutate global state.
What we really want here is a slight weakening like __hoistable__ or something that just says it's OK to hoist multiple calls out of a loop.