PowerPC アセンブラ 64bit版

ysd@KLab > PowerPC > 64bit拡張

PowerPCは32bitモードと64bitモードを持つアーキテクチャなので、同時に32bitアプリケーションと64bitアプリケーションを扱えます。

32bitモードの説明はスタックフレームのページでやったので、ここにあるのは64bitモードの拡張の説明です。

64bitレジスタ

G5は64bit CPUなので、一部の32bitレジスタは64bitに変わっている。64bitになったレジスタは以下の通り。

スタックフレーム

汎用レジスタなどが64bitになったため、一部スタックフレームのサイズも変更される。

連結エリア

連結エリアの構成(64bitモード)
呼び出し側引数エリア
呼び出し側連結エリア TOCレジスタ内容保存先(スタックポインタ+40のアドレス)※Mac OSXでは未使用
予約領域
呼び出された側のリンクレジスタ保存先(スタックポインタ+16のアドレス)
呼び出された側の状態レジスタ保存先(スタックポインタ+8のアドレス)
呼び出し側のスタックポインタ
呼び出された側のスタックフレーム
以上の通り、連結エリアのサイズが48byteになった。

退避エリア

汎用レジスタのサイズが大きくなったため、汎用レジスタを退避する場合、8byteが必要になった。

引数エリア

汎用レジスタのサイズが大きくなったため、最低サイズも32byteから64byteへ変更。

拡張された命令

64bitモードと32bitモードとの違いを吸収するため、通常のPowerPC命令の一部への拡張や、命令の追加が加えられている。

32bitモードで整数演算+比較命令を行った場合、32bit整数の時の比較結果となり、64bitモードで整数演算+比較命令を行った場合、64bit整数の時の比較結果となるので注意。

算術演算命令

64bitモードの場合、これらの命令に付加する処理(キャリービットの格納や条件テスト)は、64bitとしての計算結果が反映されるようになった。基本的には、算術命令で32bit整数を扱おうが64bit整数を扱おうが、処理は同じなのだが、乗除算命令はそうはいかないので、新たな命令が追加されたり、振る舞いが変更されたりしている。

divd(o)(.) rD, rA, rB
rAとrBとの64bit符号付き除算結果をrDに格納する。
divw(o)(.) rD, rA, rB
32bitモードにもある命令。
rAとrBとの32bit符号付き除算結果をrDに格納する。上32bitの内容は未定義になる。
divdu(o)(.) rD, rA, rB
rAとrBとの64bit符号なし除算結果をrDに格納する。
divwu(o)(.) rD, rA, rB
32bitモードにもある命令。
rAとrBとの32bit符号なし除算結果をrDに格納する。上32bitの内容は未定義になる。
mulhd(.) rD, rA, rB
rAとrBとの64bit符号付き乗算結果の上64bitをrDに格納する。
mulhdu(.) rD, rA, rB
rAとrBとの64bit符号なし乗算結果の上64bitをrDに格納する。
mulhw(.) rD, rA, rB
32bitモードにもある命令。
rAとrBとの、32bitでの符号付き乗算結果の上32bitを、rDの下32bitに格納するという命令となっている。
mulhwu(.) rD, rA, rB
32bitモードにもある命令。
rAとrBとの、32bitでの符号なし乗算結果の上32bitを、rDの下32bitに格納するという命令となっている。
mulli rD, rA, SIMM
32bitモードにもある命令。
rAと16bit符号付き整数との、64bitでの乗算結果の下64bitをrDに格納する、となっている。
mulld(o)(.) rD, rA, rB
rAとrBとの64bit乗算結果の下64bitをrDに格納する。
mullw rD, rA, rB
32bitモードにもある命令。
rAとrBとの、32bitでの乗算結果をrDに格納する、となっている。

論理演算命令

64bitモードの場合、これらの命令に付加する処理(キャリービットの格納や条件テスト)は、64bitとしての計算結果が反映されるようになった。既存の命令のほとんどは、命令実行サイズが64bitになった以外変わりはないが、シフトとマスクを実行する命令は大量に追加された。

なお、32bit用の論理演算命令(slw, srw, rlwinm, rlwnm, rlwimiといった命令)は、64bit演算において、上32bitを0クリアする。

clrldi(.) rA, rS, n
rSの下からnバイト目までを取り出してrAに格納する。rldicl rA, rS, 0, nで実現。
clrrdi(.) rA, rS, n
rSの下からnバイト目までを0にしてrAに格納する。rldicr rA, rS, 0, 63 - nで実現。
cntlzd(.) rA, rS
rSの一番上のbitから下に、0の続く数をrAに格納する。値の範囲は0 ~ 64
cntlzw(.) rA, rS
32bitモードにもある命令。
rSの下から31bit目から下に、0の続く数をrAに格納する。ゆえに、値の範囲は0 ~ 32
extsw(.) rA, rS
rSの下32bitを符号拡張した値をrAに格納する。
rldcl(.) rA, rS, rB, MB
MBは6bitの値(0 ~ 63)。
rSの値をrBの下位6bitの値ぶんだけ左回転シフト後、上からMB bit目までの値を0クリア(MB bit目はクリアしない)し、rAに格納する。
rldcr(.) rA, rS, rB, ME
MEは6bitの値(0 ~ 63)。rldclとは逆で、左回転シフト後、下bitから63 - ME bit目までの値を0クリア(ME bit目はクリアしない)し、rAに格納する。
rldic(.) rA, rS, SH, MB
SH、MBは6bitの値(0 ~ 63)。
SHの値分だけ左回転シフト後、上からMB bit目から、上から63 - SH目までを残し、他を0クリアして、rAに格納する。63 - SH > MBの場合、マスク範囲はループする。
rldicl(.) rA, rS, SH, MB
rldclのrBの代わりに即値を利用する命令。簡略ニーモニックsrdi clrldi
rldicr(.) rA, rS, SH, MB
rldcrのrBの代わりに即値を利用する命令。簡略ニーモニックsldi clrrdi
rldimi(.) rA, rS, SH, MB
rSの値をSHの値ぶんだけ左回転シフト後、上bitからMB bit目から、上bitから63 - SH bit目までをrAに挿入する。63 - SH > MBの場合、マスク範囲はループする。
sld(.) rA, rS, rB
rSの値をrBの値ぶんだけ64bit左シフトしてrAに格納する。
slwは32bit整数用だが、この命令は64bit整数用である。
sldi(.) rA, rS, u6
rSの値を即値u6の値ぶんだけ64bit左シフトしてrAに格納する。rldicl rA, rS, n, 63 - nで実現。
srad(.) rA, rS, rB
rSの値をrBの値ぶんだけ64bit右算術シフトしてrAに格納する。
srawは32bit整数用だが、この命令は64bit整数用である。
srd(.) rA, rS, rB
rSの値をrBの値ぶんだけ64bit右論理シフトしてrAに格納する。
srwは32bit整数用だが、この命令は64bit整数用である。
srdi(.) rA, rS, u6
rSの値を即値u6の値ぶんだけ64bit右論理シフトしてrAに格納する。rldicl rA, rS, 64 - n, nで実現。

浮動小数演算命令

通常PowerPC命令は変わらず、整数と浮動小数との変換命令が増えたのみである。

fcfid(.) fD, fB
fBの値を64bit符号付き整数値として64bit倍精度浮動小数に変換し、fDに格納する。
fctid(.) fD, fB
fBの値を64bit符号付き整数に変換してfDに格納する。小数の丸め方は、FPSCR[RN]で指定された方法。
fctidz(.) fD, fB
fBの値を64bit符号付き整数値に変換し、fDに格納する。小数は切り捨て。

データ転送命令

汎用レジスタが64bitに拡張されたため、32bitデータの符号付きロードと、64bitデータのロード/ストア命令が追加された。今までの4byteロード命令は、符号なしロード命令となる。

また、32bitモードでは、汎用レジスタの上32bitは無視され、下32bitだけでメモリにアクセスされる。

64bitモードでは、lmwやstmwは下32bitしか格納しないので、使うと危険。なぜかlwau(符号あり4byteロード+更新)は存在しないようだ…

lwa rD, d(rA)
rAの値(r0の場合は0)と16bit符号付き整数との和をメモリアドレス位置として、rDに4byte符号付き整数をロードする。4の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
lwaux rD, rA, rB
rAの値とrBとの和をメモリアドレス位置として、rDに4byte符号付き整数をロードする。さらに、rAにはこの命令で読み込んだメモリアドレスが格納される。4の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
lwax rD, rA, rB
rAの値(r0の場合は0)とrBとの和をメモリアドレス位置として、rDに4byte符号付き整数をロードする。4の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
ld rD, d(rA)
rAの値(r0の場合は0)と16bit符号付き整数×8との和をメモリアドレス位置として、rDに8byte整数をロードする。8の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
ldu rD, d(rA)
rAの値と16bit符号付き整数×8との和をメモリアドレス位置として、rDに8byte整数をロードする。さらに、rAにはこの命令で読み込んだメモリアドレスが格納される。8の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
ldux rD, rA, rB
rAの値とrBとの和をメモリアドレス位置として、rDに8byte整数をロードする。さらに、rAにはこの命令で読み込んだメモリアドレスが格納される。8の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
ldx rD, rA, rB
rAの値(r0の場合は0)とrBとの和をメモリアドレス位置として、rDに8byte符号付き整数をロードする。8の倍数のアドレスから読み込む方がメモリアクセス効率がいい。
std rS, d(rA)
rSの8byteを、rA(r0の時は0)と16bit符号付き即値d×8との和のアドレスのメモリに格納する。メモリアドレスが8の倍数であるほうが効率がいい。
stdu rS, d(rA)
rSの8byteを、rAと16bit符号付き即値d×8との和のアドレスのメモリに格納する。さらに、rAにはこの命令で書き出したメモリアドレスが格納される。メモリアドレスが8の倍数であるほうが効率がいい。
stdux rS, rA, rB
rSの8byteを、rAとrBとの和のアドレスのメモリに格納する。さらに、rAにはこの命令で書き出したメモリアドレスが格納される。メモリアドレスが8の倍数であるほうが効率がいい。
stdx rS, rA, rB
rSの8byte全てを、rA(r0の時は0)とrBとの和のアドレスのメモリに格納する。メモリアドレスが8の倍数であるほうが効率がいい。

条件比較命令

PowerPCの汎用レジスタ比較命令には、全て'L'というフラグが存在する。通常のPowerPCでは、これらには必ず0を入れなければならなかった。G5では、Lに1を入れた場合、比較命令を64bit整数同士の比較とみなしLに0を入れた場合、比較命令を32bit整数同士の比較とみなす

つまり、普通のPowerPCの比較命令の簡略ニーモニック(cmpw, cmpwi, cmplw, cmplwi)を使った場合、上32bitを無視し、下32bitのみで、32bit整数として比較を行う。これにともない、新しく簡略ニーモニックが追加された。

cmpd (crD,) rS, rB
rSとrBとの64bitでの算術比較結果をcrD(なければcr0)に格納する。
この命令は、cmp crD, 1, rS, rBで実現されている。
cmpdi (crD,) rS, SIMM
rSと16bit符号付き整数との64bitでの算術比較結果をcrD(なければcr0)に格納する。
この命令は、cmpi crD, 1, rS, SIMMで実現されている。
cmpld (crD,) rS, rB
rSとrBとの64bitでの論理比較結果をcrD(なければcr0)に格納する。
この命令は、cmpl crD, 1, rS, rBで実現されている。
cmpldi (crD,) rS, UIMM
rSと16bit符号なし整数との64bitでの論理比較結果をcrD(なければcr0)に格納する。
この命令は、cmpli crD, 1, rS, UIMMで実現されている。

分岐命令

基本的に、分岐命令には変更はなく普通に使えるが、G5においては分岐ヒントが、『分岐を期待』(++)『分岐なしを期待』(--)『弱く分岐を期待』(+)『弱く分岐なしを期待』(-)に増えている。

トラップ命令

そもそもPowerPCのトラップ命令の説明を確認してないので、変更点があまりわからないが、64bitトラップ命令が追加されたようだ。