NOP

前のセクションで、プログラムをリリースモードでコンパイルし、逆アセンブルした結果を実際に見ると、 delay関数が最適化されてmainから呼び出されないことに気づくでしょう。

LLVMは、delay関数が何も価値のあることをやっていないと判断し、関数を削除しました。

LLVMがforループでの遅延を最適化しないようにする方法があります。volatileアセンブリ命令を追加します。 どのような命令を追加しても良いのですが、今回の場合は、NOP (No OPeration)が特に良い選択です。NOPは副作用がないためです。

forループでの遅延は、次のようになるでしょう。

#![allow(unused)]
fn main() {
#[inline(never)]
fn delay(_tim6: &tim6::RegisterBlock, ms: u16) {
    const K: u16 = 3; // この値は微調整が必要です
    for _ in 0..(K * ms) {
        aux9::nop()
    }
}
}

今回は、プログラムをリリースモードでコンパイルしても、delayはLLVMによって削除されません。

$ cargo objdump --bin clocks-and-timers --release -- -d --no-show-raw-insn
clocks-and-timers:      file format ELF32-arm-little

Disassembly of section .text:
clocks_and_timers::delay::h711ce9bd68a6328f:
 8000188:       push    {r4, r5, r7, lr}
 800018a:       movs    r4, #0
 800018c:       adds    r4, #1
 800018e:       uxth    r5, r4
 8000190:       bl      #4666
 8000194:       cmp     r5, #150
 8000196:       blo     #-14 <clocks_and_timers::delay::h711ce9bd68a6328f+0x4>
 8000198:       pop     {r4, r5, r7, pc}

では、次のことを試して下さい。プログラムをデバッグモードでコンパイルし、実行します。その後、リリースモードでプログラムをコンパイルし、実行します。 2つの間で何が違いますか?この違いは何が原因と考えますか? 2つを同じものにするか、もしくは、少なくとも似たような振る舞いにする方法を思いつきますか?