VEXプリフィックス
読み:ヴィーイーエックス-プリフィックス
外語:VEX prefix

 Intel AVXで採用された、SIMD命令セット拡張に関する命令プリフィックス(接頭辞)。
目次

概要
 複雑なプリフィックスの組み合わせで実現されていたものを、シンプルな構造に変更することで処理の高速性を実現し、かつ更なる拡張性を確保することを目的として作られた。
 様々な拡張用のプリフィックスや、REXプリフィックスを、シンプルな構造で表現可能になった。
 VEXプリフィックスは、64ビットモードだけではなく32ビットモードでも利用できるように、ビットの使い方が工夫されている。

符号化

オペコード
 3バイトVEXはC4、2バイトVEXはC5から始まる。
 1バイト目 2バイト目 3バイト目
 76543210 76543210 76543210
3バイトVEX11000100 RXBm-mmmm WvvvvLpp
 76543210 76543210
2バイトVEX11000101 RvvvvLpp

32ビット
 32ビットモードでは、VEXプリフィックスは、C4はLES命令、C5がLDS命令である。しかし、ビットの使い方を工夫することで、LES命令やLDS命令は元のまま利用可能にしながら、VEXプリフィックスを拡張した。
 8086の命令は、オペコードの直後にModR/M(Mode Register Memory)バイトと呼ばれるものがあり、LES/LDS命令も同様である。
76543210
modregr/m
 modは、次のようにr/mの用途を切り替える。
 但しLES/LDS命令では、mod=11を使用できない。そこで、32ビットのVEXプリフィックスは、ここが常に11になるように工夫して拡張されている。
 mod=11になるよう、値を1の補数で反転してビットを配置している。

64ビット
 x64(AMD64 ISA/Intel 64)モードでは、LES命令とLDS命令は廃止されており使用できない。
 従って、32ビットでは使用できない、mod=11以外に対応するものも利用することができる。

表記方法
 使用するレジスターの範囲等によりオペコード自体が変化する。3バイトVEXの他、2バイトVEXで表現できることもあるため、16進形式で書かれることがない。
 命令とオペコードは、例えば次のように書かれる。
 VADDSD xmm1, xmm2, xmm3/m64
 VEX.NDS.128.F2.0F.WIG 58 /r
 凡例は次の通り。
 VEX.[NDS/NDD/DDS].[128,256,L0,L1,LIG].[66,F2,F3].0F/0F3A/0F38.[W0,W1,WIG] opcode [/r] [ib,/is4]
 VEXは、VEXプリフィックスを表わす。通常は3バイトVEXのC4であるが、命令によっては2バイトVEXのC5が使えることもある。
 NDS、NDD、DDSは、レジスターオペランドの符号化のために有効なVEX.vvvvフィールドの種類を表わす。
 NDS、NDD、DDSのいずれも無い場合、VEX.vvvvは1111b(すなわち、VEX.vvvvはオペランドを符号化しない)にしなければならない。VEX.vvvvフィールドは、2バイトVEX、3バイトVEX、どちらでも符号化することができる。
 128,256は、VEX.Lフィールドが0か1かを表わす。Lフィールドは、2バイトVEX、3バイトVEX、どちらでも符号化することができる。Lフィールドの解釈は命令によって幾通りかあり、Lが0か1か、どちらか一方しか命令が定義されていないものもある。
 66,F2,F3は、VEX.ppフィールドの内容を表わす。従来のオペコード形式で、プリフィックスとして66,F2,F3が存在する命令は、このフィールドで表わす。このいずれのプリフィックスもない命令の場合は、VEX.pp=00bとなり、この場合は記述しない。
 0F/0F3A/0F38は、従来のオペコード形式で、どのオペコードで表現されるかを表わし、VEX.mmmmmフィールドの内容となる。現状は、0F/0F3A/0F38のいずれかであるため、このいずれかを記述することになるが、将来的に命令が拡張された場合にはその命令セットの名前がここに書かれることになるだろう。
 W0,W1は、VEX.Wフィールドが0か1かを表わす。このビットは、(A)オペコードの拡張用 (B)汎用レジスターオペランドの32ビット/64ビット選択用(REX.W相当)、のいずれかに使われる。
 opcodeは、オペコードである。ニーモニックやオペランドに応じた内容となる。
 /rは、ModR/Mバイトである。3オペランド命令の場合、DEST,SRC1,SRC2の場合はDESTとSRC2を表わす。
 /ib,/is4などは、それぞれイミディエイトが続くことを表わす。

2バイトVEX

由来
 全機能を表現するには3バイトVEXが必要だが、冗長である。
 2バイトVEXは、オペコードの前置バイトが0Fとなる命令(つまり0F 38や0F 3Aの命令を除いたもの。主にSSEからSSE3までのSIMD命令)の表現に使うことができる、3バイトVEXの短縮表現である。
 たった1バイトの違いだが、重要な要素である。これはメモリーの節約というよりは、速度向上のための対策である。なぜならプロセッサー自体に命令フェッチ帯域の制約があるからである。16バイトの命令フェッチ帯域に、4バイト命令なら4命令/クロック格納可能なのに対し、5バイト命令なら約3.2命令/クロックしか格納できない。命令長は、短いに越したことはない。
 Intelが、わざわざ2バイトVEXという短縮表現を作りオペコード数を増やしたことには、相応の理由があるわけである。

仕様
 2バイトVEXで表現できる情報は、次のものである。
 2バイトVEXで表現できない情報は、次のものである。
 2バイトVEXで表現できないX/B/Wの各ビットは0、VEX.mmmmmは0F命令セットの00001と、それぞれ見做す。

3オペランド
 Intel AVXでは3オペランド命令があり従来よりオペランドが一つ増えているが、ソース/デスティネーションの解釈は、次の通りとなっている。
 追加された情報で1番目のソースを表わすようになっている。

最適化の余地
 例えば、次のような命令を考える。
 vpand xmm13, xmm2, xmm10
 vpand xmm13, xmm10, xmm2
 (v)pand命令はAND演算命令で、DEST ← SRC1 AND SRC2という演算を行なう。
 論理積演算なので上下どちらも得られる結果は同じだが、前者は3バイトVEXが必要なのに対し、後者は2バイトVEXで表現できる。これは、VEX.vvvvとVEX.Rは2バイトVEXでも利用できるからである。
 3レジスター間での演算のうち、第一オペランド(DEST)はVEX.R+ModRM.reg、次のソース(SRC1)はVEX.vvvvで表現でき、いずれも2バイトVEXの範囲内でxmm8〜xmm15が表現可能である。
 一方、最後のソース(SRC2)を拡張するVEX.Bは3バイトVEXにしかないため、ソース2でxmm8〜xmm15を使うためには3バイトVEXが必須になる。しかしSRC2がxmm0〜xmm7の範囲内なら2バイトVEXで充分なわけである。これらの理由により、前者は3バイトVEXが必要だが、後者は2バイトVEXで表現できるのである。
 二つのソースオペランドが交換可能な場合、その並べ方により命令長が変わることがあるため、それを考慮に入れる必要が存在することになる。
 現代においては、アセンブリ言語でコーディングする人は極めて少ない。したがって、この課題に対処するのは効率的なバイナリを出力する使命を持ったコンパイラーの作者ということになるが、8ビットCPUの時代より続く「1バイト1ステートの凌ぎを削るプログラミング」は決して過去のものではなく、今もなお現実なのである。

再検索