NOP

If in the previous section you compiled the program in release mode and actually looked at thedisassembly, you probably noticed that the delay function is optimized away and never gets calledfrom within main.

LLVM decided that the function wasn’t doing anything worthwhile and just removed it.

There is a way to prevent LLVM from optimizing the for loop delay: add a volatile assemblyinstruction. Any instruction will do but NOP (No OPeration) is a particular good choice in this casebecause it has no side effect.

Your for loop delay would become:

  1. #[inline(never)]
  2. fn delay(_tim6: &tim6::RegisterBlock, ms: u16) {
  3. const K: u16 = 3; // this value needs to be tweaked
  4. for _ in 0..(K * ms) {
  5. aux9::nop()
  6. }
  7. }

And this time delay won’t be compiled away by LLVM when you compile your program in release mode:

  1. $ cargo objdump --bin clocks-and-timers --release -- -d -no-show-raw-insn
  2. clocks-and-timers: file format ELF32-arm-little
  3. Disassembly of section .text:
  4. clocks_and_timers::delay::h711ce9bd68a6328f:
  5. 8000188: push {r4, r5, r7, lr}
  6. 800018a: movs r4, #0
  7. 800018c: adds r4, #1
  8. 800018e: uxth r5, r4
  9. 8000190: bl #4666
  10. 8000194: cmp r5, #150
  11. 8000196: blo #-14 <clocks_and_timers::delay::h711ce9bd68a6328f+0x4>
  12. 8000198: pop {r4, r5, r7, pc}

Now, test this: Compile the program in debug mode and run it, then compile the program in releasemode and run it. What’s the difference between them? What do you think is the main cause of thedifference? Can you think of a way to make them equivalent or at least more similar again?