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
  • R: REX.rの1の補数
    • 1: REX.r=0
    • 0: REX.r=1 (64ビットモードのみ)
  • X: REX.xの1の補数
    • 1: REX.x=0
    • 0: REX.x=1 (64ビットモードのみ)
  • B: REX.bの1の補数
    • 1: REX.b=0
    • 0: REX.b=1 (64ビットモードのみ)
  • W: REX.w
  • m-mmmm:
    • 00000: 拡張用の予約 (無効オペコード例外#UD)
    • 00001: 0Fがオペコードに前置されるとみなす
    • 00010: 0F 38がオペコードに前置されるとみなす
    • 00011: 0F 3Aがオペコードに前置されるとみなす
    • それ以外: 拡張用の予約 (無効オペコード例外#UD)
  • vvvv: レジスター指定の1の補数 (1111で未使用)
  • L: ベクトル長
    • 0: 128ビットベクトルまたは32/64ビットスカラー
    • 1: 256ビットベクトル
  • pp: SIMDプリフィクスの同等の機能を提供するオペコード拡張
    • 00: なし
    • 01: 66
    • 10: F3
    • 11: F2

32ビット

32ビットモードでは、VEXプリフィックスは、C4はLES命令、C5がLDS命令である。しかし、ビットの使い方を工夫することで、LES命令やLDS命令は元のまま利用可能にしながら、VEXプリフィックスを拡張した。

8086の命令は、オペコードの直後にModR/M(Mode Register Memory)バイトと呼ばれるものがあり、LES/LDS命令も同様である。

76543210
modregr/m

modは、次のようにr/mの用途を切り替える。

  • mod=00: [レジスター+レジスター]
  • mod=01: [レジスター+disp8]
  • mod=10: [レジスター+disp16/32]
  • mod=11: レジスター

但し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フィールドの種類を表わす。

  • VEX.NDS: VEX.vvvvは、ソースレジスターが保存される命令の場合に、最初のソースレジスターを符号化する
  • VEX.NDD: VEX.vvvvは、ModR/M:regフィールドで符号化できなかったデスティネーションレジスターを符号化する
  • VEX.DDS: VEX.vvvvは、最初のソースレジスターが結果で上書きされる命令を3オペランド命令にする場合に、2番目のソースレジスターを符号化する

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などは、それぞれイミディエイトが続くことを表わす。

  • /ibはバイト、/idはダブルワード、となる。
  • /is4は、8ビットのイミディエイトがあり、うち、imm[7:4]でソースレジスター、imm[3:0]で4ビットの即値を表わす。

由来

全機能を表現するには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で表現できる情報は、次のものである。

  • VEX.R : REX.R相当で、ModR/Mのregフィールドのビット4として機能。xmm8〜xmm15の選択
  • VEX.vvvv : 追加のレジスター
  • VEX.L : 128ビット/256ビットの切り替え
  • VEX.pp : SIMDプリフィクス(なし/66/F3/F2)

2バイトVEXで表現できない情報は、次のものである。

  • VEX.X : REX.X相当で、SIBバイトのindexフィールドのビット4として機能
  • VEX.B : REX.B相当で、ModR/Mのr/mフィールドや、SIBのbaseフィールドのビット4として機能
  • VEX.W : REX.W相当で、オペランドサイズを64ビット化
  • VEX.mmmmm : 0F/0F38/0F3Aなどの命令セットの切り替え

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

3オペランド

Intel AVXでは3オペランド命令があり従来よりオペランドが一つ増えているが、ソース/デスティネーションの解釈は、次の通りとなっている。

  • destination: VEX.R+ModRM:reg
  • source 1: VEX.vvvv
  • source 2: VEX.B+ModRM:r/m

追加された情報で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ステートの凌ぎを削るプログラミング」は決して過去のものではなく、今もなお現実なのである。

コメントなどを投稿するフォームは、日本語対応時のみ表示されます


KisoDic通信用語の基礎知識検索システム WDIC Explorer Version 7.04a (27-May-2022)
Search System : Copyright © Mirai corporation
Dictionary : Copyright © WDIC Creators club