64bit ISA 比較表

命令セット比較表を見たかったけど、見当たらなかったので、作りました。 元ネタはRISC プロセッサの命令セットの特徴というページです。201x年版が欲しいなぁ、と思って作りました。

実環境無しで仕様書を見ながら作ったので間違っているところも多いかもしれません。ご承知おき下さい。

情報源はこのあたりです:

x86_64 ARM A64 MIPS64 Relase6 Power ISA Version 3.0 B RISC-V Version2.2
寸評 PCの覇者。AMD産の命令セット。政治的な理由からか名前は二転三転。正式名称は何なのか。1978年発売の8086から色々なものを引きずりつつ拡張に拡張を重ね大変なことになっている。64ビット化するときにある程度整理されたものの、それでも他のISAに比べてごちゃっとした感じがある。 モバイルの覇者。昨今はサーバー分野にも進出しようとしている。A32の特徴だった条件コードはなくなった。いわゆるRISCと比べて1命令でたくさんのことができる印象。ゼロレジスタとスタックポインタが一緒になっているのが印象的。 元祖RISCの直系ISA。RISCといえばMIPS、MISPといえばRISC。最初期のRISCであるからか負の遺産が多い。近ごろ商業的には振るわない印象がはあるが、実は結構使われているという話も聞く。 据え置きゲーム機の覇者だった PowerPCの後継。覇者だったのはWii, PlayStation3, XBox360の頃。Power ISA v3.0B は2017年の発表で、まだ終わらんよという気概を感じさせる。元々 power の ER 部分は Enhanced RISC の略だったが、その名の通りかなりenhanceされている。 期待の新人。カリフォルニア大学バークレイ校が立ち上げ、様々な会社や大学が参加している。商業的にどうなるかは未知数。妙なトリックのないきれいな命令セット。命令フォーマットは命令デコーダへの配慮があふれている。RISC-V命令セットはいくつかのサブ命令セットに分割されていて、CPUの実装はどれを採用するか選べるようになっている(たとえば浮動小数点命令の有無など)。
命令フォーマット概要 1命令1byte~15byteの可変長。15byteを超える命令は考えられるが、仕様書によればそのような命令は許されていない。 IA-32e命令とAVX命令の2系統のフォーマットがある(これらは混在できる)。IA-32e命令の1命令は[LegacyPrefix 0,1,2,3,4byte][REX Prefix 0, 1byte][Opcode 1,2,3byte][ModR/M 0,1byte][SIB 0,1byte][Displacement 0,1,2,4byte][Immediate 0,1,2,4byte] の形をしている。また、movabs命令のように8byteの即値を取れる命令もある。ModR/MとSIBはそれぞれ更に3つの領域に分解されるが、流石に略。 AVX命令の1命令は[Prefix 0byte][VEX-Prefix 2,3byte][OPCODE 1byte][ModR/M 1byte][SIB 0,1byte][Displacement 0,1,2,4byte][Immediate 0,1byte]の形式を持つ。Prefixは4種類あるが、どれを用いても#UD例外が発生する(恐らく将来の拡張の予約)。 1命令32bit固定長(命令フォーマットの解説資料が見当たらない…) 1命令32bit固定長。 3レジスタ指定のR-Type、2レジスタと16bitの即値を指定するI-Type、26bitの即値を指定するJ-Typeの3種がある。 1命令32bit固定長。 多数のフォーマットがある。列挙するとA-FORM, B-FORM, D-FORM, DQ-FORM, DS-FORM, DX-FORM, I-FORM, M-FORM, MD-FORM, MDS-FORM, SC-FORM, VA-FORM, VC-FORM, VX-FORM, X-FORM, XFL-FORM, XFX-FORM, XL-FORM, XO-FORM, XS-FORM, XX2-FORM, XX3-FORM, XX4-FORM, Z22-FORM, Z23-FORM。多くは最初の6bitでどのフォーマットか判別できるが、一部のフォーマットは末尾付近も見ないと判別できない。各フォーマットの詳細はさすがに省略させてください。 Generalと呼ばれる命令セットでは1命令32bit固定長。 R-type, I-Type, S-type, U-type の4種に大別される。R-typeは3レジスタ指定形式、I-typeは1ソースレジスタ+1デスティネーションレジスタ+即値形式、S-typeは2ソースレジスタ+即値形式、U-typeは1ソースレジスタ+即値形式。どのフォーマットでもデスティネーションレジスタは同じビットで指定し、第一ソースレジスタは同じビットで指定し、第二ソースレジスタは同じビットで指定する。命令デコーダにやさしいが人には少し読みにくいフォーマットになっている。 S-typeは更にS-typeとB-typeの2種に分別される。これらは即値の取り扱い方が異なる。 U-typeも更にU-typeとJ-typeの2種に分別され、これらも即値の取り扱い方が異なる。 B-typeとJ-typeを含めるなら全6種のフォーマットということになる。 仕様書ではGeneral以外の命令セットも拡張として規定されていて、その中には1命令16bitのものもある(この辺は略)
汎用レジスタ 64bitレジスタが16本ある。 名前はRAX,RCX,RDX,RBX,RSI,RDI,RBP,RSP,R8~R15。これらのレジスタは32bit,16bit,8bitのレジスタとしてもアクセスできる。32bitレジスタとして扱うときの名前はEAX, ECX, EDX, EBX, ESI, EDI, EBP, ESP, R8D~R15D。32bitレジスタとして値を代入されると、上位32bitは基本的にクリアされる。16bitレジスタとして扱うときの名前は AX, CX, DX, BX, SI, DI, BP, SP, R8W~R15W。8bitレジスタは20本あり、名前は、AL, AH, BL, BH, CL, CH, DL, DH, SIL, DIL, R8L~R15L。ただしAH, BH, CH, DHには色々制限がある。8bit/16bitレジスタとして値を代入しても、上位ビットはクリアされない。 RSPはスタックポインタでRBPはフレームポインタ。RSP・RBP・R13はアドレッシング方法が他のレジスタと異なる。R13に妙な影響があるのは多分命令エンコーディングのせい(R13のレジスタ番号の下位3bitとRBPのレジスタ番号の下位3bitが一致している) 64bitレジスタが31本ある。 名前はX0~X30。これらの下位32bitにW0~W30の名前でアクセスできる。 命令エンコーディング上X31に相当するレジスタは文脈によりスタックポインタとして振る舞ったりゼロレジスタとして振る舞ったりする。 A32/T32の汎用レジスタとのめんどくさい対応関係は略。 64bitレジスタが32本ある。仕様書中の名前はGPR[0]~GPR[31]。私の使ったアセンブラではレジスタ使用規約に基づいた別名が使われていた。GPR[0]はゼロレジスタで、GPR[0]から値を読むと常に0が読まれ、書き込みは無視される。GPR[31]はサブルーチン呼び出し命令のリターンアドレスを格納するために使われる。アセンブラ用に、各レジスタに別名がある。 64bitレジスタが32本がある。 仕様書中の名前はGPR0~GPR31。私が使ったアセンブラではr0~r31という名前が使われていた。 一部の命令の特定のオペランドでGPR0から読もうとすると、0が読まれる。 64bitレジスタが32本。名前はx0~x31。x0はゼロレジスタ。 アセンブラ用に、各レジスタに別名がある。例えばx0はzero、x10はa0、x11はa1等。
メモリアクセス 多くの命令はオペランドにメモリを指定できる。x86_64はいわゆる2オペランド形式の命令セットなのだが、オペランドがメモリになれるのは片方のオペランドのみ。ADD命令はアセンブリ言語レベルではソースもしくはデスティネーションにメモリを指定できるように見えるが、機械語レベルでは ADD reg, mem 形式の命令と ADD mem, reg 形式の命令との二種類がある。レジスタ同士の加算をするときは ADD reg/mem形式を使ってもADD mem/reg形式を使っても良い。 いわゆるload/store architecture。非常に豊富なload/store命令を持つ。2word同時にロード/ストアする命令や、load/store後にレジスタ値をインクリメント/デクリメントする命令、load/store前にレジスタ値をインクリメント/デクリメントする命令などもある。 いわゆるload/store architecture。オフセット付きの2レジスタ指定のload/store命令がある。(オフセット0のときはアセンブラが専用命令があるように見せかけている)。 いわゆるload/store architecture。オフセット付きの2レジスタ指定のload/store命令と、ソースレジスタの値を足して実行アドレスを得る3レジスタ指定のload/store命令があり、さらにそれぞれ符号拡張版と0拡張版がある。 いわゆるload/store architecture。オフセット付きのload命令とstore命令がある。load/storeするデータの大きさはfunct3フィールドで指定する。
スタック RSPがスタックポインタで、RBPがフレームポインタ。スタックはメモリアドレスの大きい方から小さい方に伸びる(PUSH/POP/CALL/RET命令あたりの影響でメモリアドレスの伸びる方向を固定せざるを得ない)。 命令エンコーディング上X31にあたるレジスタが、命令によってはスタックポインタとして振る舞ったりゼロレジスタとして振る舞ったりする。スタックは規約によりアドレスの大きい方から小さい方に伸びる(A32/T32ではアセンブラレベルでPUSH命令が用意されており、やはりアドレスの大きい方から小さい方に伸びる) 仕様書に stack という言葉は出てこない。 仕様書に stack という言葉は出てこない。 規約上、x2がstack pointerで、スタックはメモリアドレスの大きい方から小さい方に伸びる。(ただし、compressed instruction set にx2をスタックポインタとして特別扱いする命令もあるため、単に規約上とは言い切れないかもしれない。)
フラグと条件分岐 算術命令や比較命令がEFLAGSレジスタを変更し、条件分岐命令はEFLAGSを参照して分岐する。(EFLAGSの一部のビットだけを書き換える命令があり、命令間に意図せぬ依存性が発生したりして、最適化がめんどくさい。) CPSR(Current Program Status Register)というフラグレジスタがある。多くの算術演算や論理演算はフラグをセットする版としない版がある(たとえばADDはフラグを更新しない加算、ADDSはフラグを更新する加算)。条件分岐命令はCPSR内のフラグを参照して分岐の有無を決める。 比較と分岐を一度に行う命令がある。いわゆるフラグレジスタはない。 CRがフラグレジスタ。多くの算術命令はCRを書き換えるか書き換えないかを選べる。フラグを書き換えるだけの比較命令もある。条件分岐命令にはCRを参照して分岐する命令と、CTR(CounTer Register)を参照して分岐する命令とがある。CTRは分岐判定する毎にデクリメントされるSPRで、これを使うとループを高速にできる(?)。 比較と分岐を一度に行う命令がある。いわゆるフラグレジスタはない。
遅延スロット なし なし あり。delay slotの代わりに分岐が行われた場合後続命令が実行されないforbidden slot を持つ分岐命令もある。 なし なし
サブルーチン呼び出し CALL/RET命令。リターンアドレスはスタック上にPUSHされる。RET命令に即値の引数を指定すると、return後にスタックから値をPOPすることができる。また、スタックフレーム構築用のENTER/LEAVE命令というのもあるが、今時のプロセッサでは遅いので使われない。 BL/BLR命令でX30に次の命令のアドレスを格納してジャンプする。RET命令で任意の汎用レジスタの指す場所にジャンプする。RET命令はただの無条件分岐命令ではなく、サブルーチン呼び出しから戻るための命令であるというヒントをCPUに与える。アセンブラはRET命令のオペランドが省略されるとX30が指定されたものとして振る舞う。 GPR31に次の次の命令のアドレスを格納してジャンプするJAL命令と、指定したレジスタに次の次の命令のアドレスを格納してジャンプするJALR命令の二種類がある。JAL命令の飛び先は即値で、この命令の属する256MB内の領域にジャンプできる。JALR命令の飛び先はレジスタでの指定。 次の命令のアドレスをLR(Link Register)に格納してからジャンプする命令がある。LRはSPR。また、条件付きサブルーチン呼び出し命令もある。 規約によりx1がリターンアドレスを格納するレジスタだが、ISA上の特別扱いはない。
整数乗算 MUL命令で符号なし乗算ができる。ソースオペランドの片方はAL, AX, EAX, RAXに固定されており、乗算結果を格納するレジスタはAX, EAX, EDX:EAX, RDX:RAX に固定されている。 乗算してから加算する命令や、乗算してから減算する命令・乗算してから符号反転する命令などがある。単に乗算したいときは、乗算してから加算する命令でゼロレジスタを使う。乗算後の上位32bitを取る命令もある。 結果をHI/LOレジスタに格納する乗算命令と、乗算結果の下位64bitをGPRに格納する乗算と、乗算結果の上位64bitをGPRに格納する乗算がある。 乗算結果の下位ワードを求める命令と、乗算結果の上位ワードを求める命令がある。また、乗算結果の下位ワードを求める命令では即値が使える。 乗算結果の下位ワードを求める命令と、乗算結果の上位ワードを求める命令がある。
整数除算 被除数はAX, DX:AX, EDX:EAX, RDX:RAX に固定されており、除数はレジスタかメモリアドレスを指定できる。商はAL, AX, EAX, RAXに格納され、剰余はAH, DX, EDX, RDXに格納される。除数が0のときや結果がオーバーフローしたときは#DE(0除算エラー)が投げられる。 3オペランド形式の符号あり除算と符号なし除算がある。0で除算したときの商は0である。符号付除算で INT_MIN / -1 を計算した結果は INT_MIN である。 商をLO、剰余をHIに格納する命令と、商をGPRに格納する命令と、剰余をGPRに格納する命令がある。0除算の結果はunpredictableである。 3オペランド形式の符号あり除算・符号なし除算・符号あり剰余・符号なし剰余命令がある。0除算と INT_MIN/-1 の結果は、商・剰余共に undefined である。 3オペランド形式の符号あり除算・符号なし除算・符号あり剰余・符号なし剰余命令がある。符号なしx/0=264-1,符号なしx%0=x,符号ありx/0=-1,符号ありx%0=x,符号ありINT_MIN/-1=INT_MIN,符号ありINT_MIN%-1=0である。
浮動小数点命令概要 x87命令とSSE命令とAVX命令がある。x87命令は1982年(?)に導入されスタックマシン的な命令体系で、レジスタ8本がスタックになっている。SSE命令は1999年に導入された。いわゆる2オペランド形式の命令体系。AVX命令はSSE命令の拡張的な位置づけだが、いわゆる3オペランド形式になっている。2011年に導入された。いまだ全てサポートされている。x87命令用80bit浮動小数点レジスタが8本ある。名前はST0~ST7。SSE命令用には128bitレジスタが16本あり、名前はXMM0~XMM15。AVX命令/AVX2命令ではXMMレジスタが拡張され、YMMという名前でアクセスできる。YMMレジスタの幅は256bit。AVX-512命令で更に拡張され幅512bitのZMMレジスタになった。 32本の128bit浮動小数点レジスタがある。倍精度浮動小数点レジスタとしてアクセスするときの名前はD0~D31、単精度浮動小数点レジスタとしてアクセスするときの名前はS0~S31。 コプロセッサによる拡張とされている?事実上の標準はありそうだがよくわからない。命令フォーマットだけは定義されている。 64bit浮動小数点レジスタが32本ある。名前はFPR0~FPR31。レジスタ中の値は常に64bit浮動小数点数だが、32bit浮動小数点数の精度で演算する命令・32bit浮動小数点数に変換してストアする命令・32bit浮動小数点数から64bitに変換してロードする命令などがある。 浮動小数点命令は拡張とされている。サポートされる場合、32本の浮動小数点レジスタがある。名前はf0~f31。RISC-Vの実装は、浮動小数点サポートなし・単精度だけの実装・倍精度までの実装・四倍精度までの実装を選べる。また、64bitと128bitの十進浮動小数点数拡張もある。レジスタ幅はどの実装を選ぶかによって変わる。
SIMD概要 大きく分けて MMX, SSE, AVX の3種がある。MMXは整数演算用、SSEは浮動小数点演算用、AVXは整数演算・浮動小数点演算の両方が使える(ただしAVXの整数演算はAVX2から)。MMX命令では64bitレジスタが8本あり、名前はMM0~MM7。これらはx87命令用レジスタと共用されており、使用する際はソフトウェア側でのステートの切り替えが必要。SSE命令、AVX命令のレジスタは「浮動小数点命令概要」のとおり。 浮動小数点命令と共用のSIMDレジスタが32本ある。名前は128bitレジスタとしてアクセスするときはV0~V31、64bitレジスタとしてアクセスするときはD0-D31、32bitレジスタとしてアクセスするときはS0~S31、16bitレジスタとしてアクセスするときはH0~H31、8bitレジスタとしてアクセスするときはB0~B31。5番目の128bitレジスタの3番目のバイトはV5.B[3]などのような形でアクセスできる。 MSA(MIPS SIMD Architecture)という名前でサポートされる。拡張扱い。32本の128bitレジスタがあり、仕様書中での名前はWR0~WR31。これらのレジスタの下位64bitは浮動小数点命令と共有される(MSAをサポートする場合、CPUはIEEE754の64bit演算をサポートしなければならない)。整数演算/浮動小数点演算共にサポートされている。 Vector Facilitiesという名前でサポートされる。32本の128bitレジスタがあり、名前はVR0~VR31。整数演算/浮動小数点演算共にサポートされている。 SIMDは拡張命令とされている。サポートされる場合、SIMDレジスタは浮動小数点命令用レジスタと共用される。レジスタ幅は32bitから1024bitまでの値が実装ごとに選択される。

謝辞

ありがとうございます。