If you declare your function as #[inline(never)]
you will get a function call instruction to prevent further optimizations.
The main limitation is that your function must not be empty after optimizations, so it must have some side effect (thanks to @hellow that suggests using compiler_fence
instead of println!
).
For example, this code (godbolt):
pub fn test_loop(num: i32) {
for _i in 0..num {
dummy();
}
}
#[inline(never)]
pub extern fn dummy() {
use std::sync::atomic::*;
compiler_fence(Ordering::Release);
}
Will produce the following assembly (with -O
), that I think you need:
example::test_loop:
push r14
push rbx
push rax
test edi, edi
jle .LBB0_3
mov ebx, edi
mov r14, qword ptr [rip + example::dummy@GOTPCREL]
.LBB0_2:
call r14
add ebx, -1
jne .LBB0_2
.LBB0_3:
add rsp, 8
pop rbx
pop r14
ret
plus the code for dummy()
that is actually empty:
example::dummy:
ret