Alright, here's an interesting look:
[Playground - Do LLVM IR output on release]
There is something interesting to note here:
pub fn foo_test1(buf: &[u8], discriminant: &usize) {
for val in buf {
if *discriminant == 1 {
foo1(val);
} else {
foo2(val);
}
}
}
This is optimized as intended, with two loops where the check is done beforehand.
pub fn foo_test3(buf: &[u8]) {
let ptr = unsafe {
&*(&FOO as *const AtomicUsize as *const usize)
};
foo_test1(buf, ptr);
}
This does get optimized too, we observe two loops, with the check on FOO done beforehand.
However
pub fn foo_test2(buf: &[u8]) {
let ptr = unsafe {
&*(&FOO as *const AtomicUsize as *const usize)
};
for val in buf {
if *ptr == 1 {
foo1(val);
} else {
foo2(val);
}
}
}
Inlining the foo_test1 causes LLVM to still view ptr as an atomic variable, and therefore check on each iteration.