オペコード (IA-32)
読み:オペコード
外語:opcode

 IA-32プロセッサーに対する命令を表わす番号。
目次

概要
 元々は16ビットマイクロプロセッサーとして設計された8086で採用されたものが初出。
 32ビット化されたことから若干の仕様変更が施されているが、基本的な設計方針は維持されている。

特徴

基本構成
 IA-32オペコードの基本的な特徴は次の通りである。

ModR/M
 ModR/M(Mode Register Memory)バイトは、二つのソースの種類を表わすために使われる。
 片方はレジスターに固定、もう片方はレジスターまたはメモリーが選択可能で、またレジスターを使う場合はオフセットを追加することができる。
76543210
modregr/m
 modは、次のようにr/mの用途を切り替える。

オペコード拡張
 8086/80186の後継として80286を作る際、追加する命令を符号化するだけのオペコードの空きがなかった。
 そこで、Z80がED XXという2バイトで拡張命令を表現するように、80286も0F XXという2バイトで拡張命令を表現するようになった。
 なお、0Fは、元々は8086/8088でpop csのオペコードに使われていた。しかし、このような命令はまず使用しないことから機能廃止、80286以降では命令のプリフィックスとして使われるようになった。

実数演算命令
 8086の初期の設計では、実数演算は数値演算プロセッサーとしてCPUとは別のプロセッサー(コプロセッサー)として提供されていた。
 このためオペコードも数字演算プロセッサー用の領域が専用に確保され、CPUの処理と分離されていた。
 具体的には、D8HからDFHの範囲で、元々の8086のニーモニックは「ESC」とされていた。
 現在の製品では機能が融合されておりシームレスに扱えるようになっており、MMXSSEなどの拡張も行なわれた。結果、オペコードの表現で不足する分は通常の命令と同様の書式による拡張方法で表現するようになっている。

SIMD命令
 SSEの命令は0F XX XXという3バイトのものが多いが、これはSIMD命令用というわけではなく、IA-32における拡張方法の一つである。
 これに更に66/F3/F2のプリフィックスを加えることにより、最大4種類に切り替わる。お互い全く無関係の命令になるというわけではなく、互いに相関性がある。従って、利用されるプリフィックスも66のみもあればF3/F2のみもあり、またプリフィックスの無いオペコードが未定義の命令もある。
 具体的には、例えばaddpsは0F 58だが、バリエーションであるスカラーaddssはプリフィックスとしてF3が追加され、SSE2の倍精度命令はさらに66とF2が加わる。

プリフィックス拡張
 こうして、IA-32では0F XXという2バイトエスケープ形式で命令は増やされたが、領域は枯渇寸前である。
 SIMD命令で全てを埋めてしまうわけにはいかないので、SSSE3/SSE 4.1頃から0F 38 XX、SSE 4.1/SSE 4.2からイミディエイト付き命令用の0F 3A XXという3バイトエスケープ形式がそれぞれ導入された。
 更に、新たに導入されるVEXプリフィックスはこの問題の改善技術で、C5 XXまたはC4 XX XX形式で、REXプリフィックスの機能を取り込みながら、SSE/MMX命令をシンプルに記述できる。
 AMDのSSE5も同様に0F 24/0F 25に続く3バイトオペコード方式を採用する予定だったが、AMDもIntel AVXを採用するために破棄された。

AVX
 Intel AVXでオペコードのエンコーディング方法が変更された。
 SSEで、従来の128ビットXMMレジスター×8が、256ビットYMMレジスター×16に増強されている。
 SSEの従来命令は殆どが2オペランド命令、たまに3オペランド命令だったが、AVXのエンコーディングを使うとオペランドが一つ増える。例えば、
 addps xmm1, xmm2/m128
 addps命令に対して、AVXの命令は次のようになる。
 vaddps xmm1, xmm2, xmm3/m128
 ニーモニックの頭にvを付けて区別する。オペランドが一つ増えるだけでなく、m256も可能になっている。この命令では、xmm2とxmm3またはm128(m256)の値を加算し、結果をxmm1に戻す。従って元の値は破壊されない。

一覧

凡例
 これら以外については、各々で説明する。

1バイトオペコード
 szと書かれた命令は、66プリフィックスによってサイズが変わるもの。

0x
 80286以降の拡張命令は、0Fから始まるオペコードで符号化される。

1x

2x

3x

4x
 4XはIA-64ではREXプリフィックスとなるため使用できない。
 2バイトになるが、incはFF /0、decはFF /1でも表現できる。

5x

6x

7x
 cbは8ビットのオフセット。$+2。
 条件には別名がいくつかある。例えばjbは、jc、jnaeでも良い。

8x
 ibは1バイト、1dは4バイトのイミディエイトを表わす。

9x

Ax

Bx

Cx

Dx

Ex

Fx

ESC命令
 ESC命令は、1バイト目がD8からDFまでの命令をいう。数値演算プロセッサー(FPU)用の命令がここに配置されている。

D8

D9

DA

DB

DC

DD

DE

DF

0F拡張
 [※AVX]が附された命令は、VEXプリフィックスを使って符号化するものであり、参考として記されたもの。記載されたオペコードでは処理できない。
 オペコードは「インテル Advanced Vector Extensions プログラミング・リファレンス 2010年4月」を基本に、いくつかの未記載の命令を加えている。
 特に明記しないが、この領域は、SSE命令が大多数を占めている。

0F 0x
 3DNow!の命令は、現在のAMDのプロセッサーでも廃止されており、prefetch/prefetchw命令以外は削除されている。

0F 1x
 *ps命令に対し、66を付けると*pd命令、F3を付けると*ss命令、F2を付けると*sd命令になる。
 nop r/m32は、3から9バイト長までのNOPである。REXプリフィックスを併用すると10バイト以上も可能と見込まれる。
 hint_nopはundocumentedな命令で非公式なニーモニック。nop r/m32と同様の動作をするものと思われる。量が多いので、単に #UD 例外を出すのをサボっているだけとも思われるが、詳細不明。

0F 2x

0F 3x
 VEX命令のr32 r/m32は、VEX.W=1にすることでr64 r/m64命令に切り替わる。

0F 4x
 条件には別名がいくつかある。例えばcmovbは、cmovc、cmovnaeでも良い。

0F 5x
 *ps命令に対し、66を付けると*pd命令、F3を付けると*ss命令、F2を付けると*sd命令になる。

0F 6x
 mm mm/m32またはmm mm/m64の命令に66をつけると、xmm xmm/m128の命令になる。

0F 7x
 mm imm8の命令に66をつけると、xmm imm8の命令になる。

0F 8x
 cdは32ビットのオフセット。$+6。
 条件には別名がいくつかある。例えばjbは、jc、jnaeでも良い。

0F 9x
 条件には別名がいくつかある。例えばsetbは、setc、setnaeでも良い。

0F Ax

0F Bx

0F Cx
 pinsrw/pextrwはMMX命令だが、66をつけるとXMM命令になる。
 0F C8〜CFは、REXプリフィックスによって対象レジスターを64ビットやR8〜R15に変更できる。

0F Dx

0F Ex
 mm mm/m64の命令に66をつけると、xmm xmm/m128の命令になる。

0F Fx

66拡張
 66hを付けることで動作が変化する命令。特に顕著な変化がないものは、有効なオペコードであっても省略する。
 pushfd/popfdは、32ビットでは9C/9Dだが、64ビットでは66のプリフィクスが必要である。
 0Fから始まるMMX命令に66を冠するとXMM命令になるものもある。
 また、r32やm32の命令に66を冠すると概ねr16やm16命令になる。

66 0F拡張

66 0F 1x

66 0F 2x

66 0F 38
 66 0F 38は、イミディエイト付きのSSE命令拡張。

66 0F 38 0x

66 0F 38 1x
 xmm m32の命令は、VEX.L=1にすることでymm m32命令に切り替わる。両者でニーモニックに差はない。
 xmm m64の命令は、VEX.L=1にすることでymm m128命令に切り替わる。両者でニーモニックに差はない。

66 0F 38 2x
 次の命令は、VEX.L=1にすることでymmとm256命令に切り替わる。両者でニーモニックに差はない。

66 0F 38 3x

66 0F 38 4x
 *vd命令はVEX.L=1にすることで*vq命令に切り替わる。

66 0F 38 5x

66 0F 38 7x

66 0F 38 8x
 vpmaskmovd命令は、VEX.W=1でvpmaskmovq命令に変更可能。

66 0F 38 9x
 AVXのxmm xmm xmm/m128の命令は、VEX.L=1にすることでymm ymm ymm/m256命令に切り替わる。VEX.L=0/1で、それぞれps/pdになる。
 AVXのxmm xmm xmm/m32の命令は、VEX.W=1にすることでxmm xmm xmm/m64命令に切り替わる。VEX.W=0/1で、それぞれss/sdになる。

66 0F 38 Ax

66 0F 38 Bx

66 0F 38 Dx

66 0F 38 Fx

66 0F 3A
 66 0F 3Aは、イミディエイト付きのSSE命令拡張。

66 0F 3A 0x
 xmm/m64 xmmの命令は、VEX.L=1にすることでxmmm128 ymm命令に切り替わる。両者でニーモニックに差はない。
 xmm xmm/m128の命令は、VEX.L=1にすることでymm ymm/m256命令に切り替わる。両者でニーモニックに差はない。

66 0F 3A 1x
 vcvtps2phは、VEX.L=1でymm/m128 ymmに変更できる。

66 0F 3A 2x

66 0F 3A 3x

66 0F 3A 4x
 AVX命令のうちvpblendvb以外は、VMM.L=1にすることでymmとm256に切り替わる。

66 0F 3A 5x
 Intel AVXではキャンセルされ、AMDが搭載することになった4オペランドFMA命令。VEXで符号化しないと利用できない。
 VEX.L=1で、ymmおよびm256命令になる。
 /is4の上位4ビットでソースレジスターを指定。下位4ビットは予約で、常に0とする。

66 0F 3A 6x

66 0F 3A 7x

66 0F 3A Dx

66 0F 5x

66 0F 6x

66 0F 7x

66 0F Cx

66 0F Dx

66 0F Ex

66 0F Fx

F2 0F拡張
 AVX命令は、VEX.W=1でr64 r/m64に切り替えられる。

F3 0F拡張

F3 0F 1x

F3 0F 2x

F3 0F 38

F3 0F 5x

F3 0F 6x

F3 0F 7x

F3 0F Ax

F3 0F Bx

F3 0F Cx

F3 0F Dx

F3 0F Ex

REX.W
 REX.Wを付けることで動作が変化する命令。特に顕著な変化がないものは、有効なオペコードであっても省略する。
 なお、REX以前の従来のプリフィックス(66H、67H、F2H、F3H)は、REX.Wより前に置く。

再検索