NOP
前のセクションでプログラムをリリースモードでコンパイルし、実際に逆アセンブル結果を見たのであれば、
delay 関数が最適化によって取り除かれ、main の内部からは一度も呼び出されていないことに
気づいたはずです。
LLVM は、その関数は何も価値のあることをしていないと判断し、単に削除しました。
LLVM が for ループによる遅延を最適化しないようにする方法があります。volatile なアセンブリ命令を
追加することです。どんな命令でも構いませんが、この場合は副作用がないため、NOP(No OPeration)は
特に適した選択です。
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}
では、これを試してみましょう。プログラムをデバッグモードでコンパイルして実行し、その後で プログラムをリリースモードでコンパイルして実行してください。両者の違いは何でしょうか。 その違いの主な原因は何だと思いますか。両者を同等に、あるいは少なくとも再びもっと似たものにする 方法を思いつきますか。