v5.4.0)の生成するアセンブリコードを解読してきた。これまでの内容は、以下のような感じになる。ループと自動ベクトル化これまでは、私が読んでいく過程で何を思ったかをだだ漏れに垂れ流していたので、推敲も何もあったものではなく、読みやすくわかりやすい記事というには程遠かった。ここで一度小休止してここまでのちょっとしたまとめをしてみよう。それぞれの記事を読んでいる人にはこれは無意味な記録ということになる。あと、私にはアセンブリの解説ができるほどの技量はまだないので、そういう方向の期待はあまりしないでほしい。レジスタの役割や命令のまとめをしようと思ったが気力がなかったので箇条書きになった。その1Linuxでは、第一から第六までの引数がそれぞれrdi、rsi、rcx、rdx、r8、r9に乗せられて渡される。それ以上はスタックに載せる。Windowsでは、第一から第四までの引数がrcx、rdx、r8、r9に乗せられて渡される(らしい)。それ以上はスタックに載せる。呼びだされた関数は、基本的にはprologueとepilogueを行う。これは主に以下のようなことを行う。スタックベースポインタなどの値を退避し、あとで戻す関数内で使うスタックフレームをわかりやすくする必要ならスタックアロケーション最適化すると、必要ないスタックアロケーションやスタックメモリアクセスがなくなる。最適化すると、整数演算はアドレス演算で置き換えられることがある。その2testやcmpでフラグを立てた後、je/jneなどのジャンプやcmovなどの条件命令によって条件分岐が行われる。最適化レベル0でも割り算は避けられ、マジックナンバーを使った乗算と桁あふれによって割り算が計算される。その3最適化レベルが0でも、定数除算はマジックナンバーやシフト演算によって行われる。ゼロクリアは即値0のmovよりも自分自身とのxorが好まれる(何故?)。渡す値が決まっている場合、できるところまで計算が進められる。場合によっては関数が即値に置き換えられる。翻訳単位を分けると、リンクしても関数は定数伝播・定数畳み込みの恩恵を受けられない。リンク時最適化を行えば、別々にコンパイルしてリンクしても定数伝播・定数畳み込みの恩恵を受けられる。その代わり、コンパイル時間が爆発する。リンク時最適化を行うためには、リンク時でなく、コンパイル時にリンク時最適化オプションをつける必要がある。その4ループは、比較とジャンプによってなされる。-O2まではベクトル化などはなされず、比較とジャンプによる素直なコードが生成される。-O3にすると、要素の余りの他にメモリアライメントまで考慮したベクトル化が行われる(少なくともgcc5.4では)。-march=nativeにすると、使えるベクトル命令のうちで、データ量が十分多かった時に最も効率的と思われるものが使われるようになる。非常に小さい配列を渡すと、ベクトル化のためのオーバーヘッドが(その場合はそもそもの計算量が少ないので無視できる程度だが)出かねない。配列のサイズと関数の実装がコンパイラから同時に参照できる状態なら、定数伝播と関数コピー(-fipa-cp-cloneまたは-O3)によってサイズに応じた最適化が生じる可能性があるが、未検証。小休止Tweet広告を非表示にする関連記事2018-11-11脳を破壊するFortranコード今日、後輩と色々試していて面白いことに気付いた。Addという命令がある。(7)はてなブログをはじめよう!tniinaさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。