reinterpret命令


はじめに

  • いつも挿入している命令をグルーピングした図ですが、今回は特段芸術的な仕上がりになりました。12
  • 例えば、vreinterpretq_f32_s32int32x4_tを引数として、float32x4_t型を返す
  • 前述の図をよーく見ると、芸術的な網目の中に、水平に引かれている線は一本も無いことが分かる
    • 同じ型を同じ位置に並べており、同じ型への変換命令は存在しないため、水平線が存在しない

reinterpret命令

  • 大前提として、この命令はアセンブラ上には現れない命令である。
  • CPUはレジスタにデータを読み書きする訳ですが、C/C++は「float」「int」みたいに気をつけてはいるもの、レジスタ上には「int用のレジスタ」「short用のレジスタ」と区別はしていません
  • そのため、CPUがデータを読み出す際に「この命令はfloatとして扱う」というふうに、レジスタのデータをちゃんと解釈(interpret)する必要があります3
  • C/C++のcastが近いですが、castは値の変換を含みます。
float f = 1.0f;
int a = (int)f;
  • 前述のコードで、変数fには、16進数表記で0x3F800000が含まれているが、変数aには0x1が代入される。
    • これは、浮動小数点数の$1.0$を整数型の1に変換している
  • 一方で、本日紹介しているreinterpret命令は以下の処理を行っている4
float f = 1.0f;
int a = *(int*)&f;
  • ベクトル型は、前述のような変換を伴うcastは認めて無く、明示的にreinterpret命令で再解釈してやる必要がある
  • また、ベクトルの型の暗黙の型変換も認めておらず、明示的にエラーが上がります。5
 note: use -flax-vector-conversions to permit conversions between vectors with differing element types or numbers of subparts
  • 以上はGCC 7.5.0でのwarningメッセージ
    • warningメッセージだが、エラーも出る
  • オプションに-flax-vector-conversionsがあれば、コンパイラが暗黙の型変換を認めてくれるが、手間を考えると、逐一reinterpret命令を挟んだほうがいいと思う。
  • 実際にアセンブラには現れず、その代わり、レジスタを読む次の命令が、レジスタを整数なり浮動小数点数なり、再解釈した値で読んでくれる。

「変換」ではない

  • reinterpret命令のポイントは「変換」ではないということです。
  • 何でこんなのが必要になるかと言うと、明日のpopcount命令への布石です。

おわりに

  • 今日はreinterpret命令を紹介しました
  • 明日も手島の予定でpopcount命令を紹介します。

  1. 実はこの図は厳密には正しくありません。図を愚直にたどると、vreinterpret_xxx_p128という命令が存在しうる形になっていますが、qが付かないreinterpret命令は64bit幅のレジスタを扱います。しかし、p128が末尾に付くということは引数としてpoly128_t型を取るということなので、レジスタbit幅の辻褄が合いません。しかし、そこを省いて描くと、ただのカオスな樹形図になってしまうので、そこは敢えて目をつぶって今回の図を描きました。 

  2. っていうか、poly128_t型なんてあるんですね。筆者もこの記事を書いてて初めて知りました。まあ、SI M D型ではないので、省いてもよかったかも? 

  3. 予防線を張っておくと、FPU専用レジスタが用意されてる場合は「floatを保存する専用のレジスタ」が存在するわけですけれど、本記事の主題とは外れるのでそこは割愛します 

  4. 最近、C++ではこれがお行儀の宜しくない書き方だと知ったが、それはそれ 

  5. GCCで確認。でも多分MSVCやClangでも同じだと思う。