Powerこそが俺のパワーだ!

はーふ・あだーーー(半加算器)えいだです!1+1=10までは計算できます!
LL Ringというのがあったような気がしました。来年はAdaも参戦できるようにがんばろうと思います。いや、多分、その頃には飽きてると思わるがー。もはや一ヶ月続くかどうかもわからぬー。


というわけで、手元にPPCが戻ってきたので、PPC読めるようになろうと思います。あいかわらずAda関係ぬ。


と、みせかけて、この資料が大変素晴らしいので各自読んでおけばよいと思いましたー。相変わらずリンク集にしかなってない説ですー。
http://www.nk.rim.or.jp/~jun/ppcasm/ppcasm03.html


PPCニーモニックの特徴は、命令フォーマットがモロにニーモニックに表現されてる点という理解でよいでしょーかねー。
例えば、某32bitCPUとかだと、

	movl    $1, %eax
        movl    %ecx, %ebx

ここで、上のmovlと下のmovlって実際、違う命令だろーとか、ごくごくたまーにややこしくなりますよねー。あと、アセンブラ(≠アセンブリ)書いてると、内部表現のときの命令の名前を何にするかで迷いますよなー。(例えば、movを勝手にmov_long_rrとかの名前を付ける必要が出てきますよなー)


それに対して、PowerPCのほうは、そういう点で悩まなくてよい!

	addi    3,3,3	# r3 = r3 + $3
        add     3,3,3   # r3 = r3 + r3

定数加算とレジスタ加算は別の命令でするー
と思ったけど、それってRISCでは普通のような気がしてきたー。某どっかの32bit CPUがアレすぎるだけかもですが、いや、それってCISCだと普通のような気ががが。まあ、そんなもんかもしれずー。


PPC命令を見ていくと、いっこだけ気になるのが、レジスタ間接ジャンプ(っていう名前であってたかなー)が、命令一個でできないってのがあるですねー。

	mtctr	3	# 一旦r3をctrにmoveして、
	bctr		# ctrに分岐

これは一体どゆことですかねー。前々回くらいのネタだった、OSXのマッチョABIが遅い理由の10%くらいは、こいつの責任のような気がするんですがー。そもそもctrレジスタってカウンタレジスタっていう名目なんだから、それって使い方違うだろーと、思ったり思わなかたり。


そこらへんの言い訳は、
http://www-306.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF7785256996007558C6
これに若干書いてあるようですよ。


3.1.1.2 Count Register
(... 略 ... )

To transfer control to a computed address, the Count Register
may be loaded with a target address from a General-Purpose
Register using the mtctr instruction, followed by a branch to the
Count Register. When possible, independent instructions should
separate the load of the Count Register from the branch to pre-
vent pipeline stalls.

(多分訳:制御を算出したアドレスに移すにはmtctr命令を使って、Count Registerにアドレスをロードしたあと、カウントレジスタへ分岐してくらさい。可能なら、パイプラインストールを防ぐために、分岐とロードのあいだになんか独立した命令を入れてあげてくださ)

(... 略 ... )

memo: may be loaded の訳がわからぬ。


ハードウェアの実装を勝手に推測するに、mtctrした瞬間に、分岐先の命令先読みとかが行われて、そのおかげで、bctrしたときには、命令がパイプラインに乗っかってるから、間接分岐してもパイプラインストール起こらねーぜーってなってるんじゃないですかねー。多分。
パイプラインストール無くせるようなアーキテクチャにしたからコンパイラ屋さんは頑張ってmtctrとbctrの間になんか処理を入れてくれ!て感じねー。まー、コンパイラ屋さんは頑張ってくれー。
(そう考えると、マッチョABI作ったひとは、アーキテクチャ作った人の意図を汲み取ってないと言えますなー)


あと、上の、Compiler Write's GuideのCount Registerの周辺に、Condition Registerの説明もあったようです!英語わからんかったので、ぼーっと読んでたら、辿り付いてしまいました!
Count Registerについて調べてたはずが、こっちのほうがおもろかったですよ!

PPCの特徴として、もういっこ、フラグレジスタが8セットあるという点があるんで。で、そこらへんの意図が謎だったるですが、ようやくわかりました!条件分岐を減らすためなのだったっ!
フラグレジスタは、それぞれ、andしたり、orしたりできる見込みです。

int func( int a, int b, int c, int d, int e )
{
	if ( (a+e>b) && (c+e>d) ) {
		return 500;
	}
	return 30;
}

例えば、こんなプログラムを考えると、ふとぅーに考えると、条件分岐ふたつになりそうですっがっ、PPCだと、比較した結果をand(crand)できるので分岐が一個にできるんですっ!なるほどー。
さっそく、上のコードをコンパイルしてみよー

/home/ada/test/gcc$ cat and.c
int func( int a, int b, int c, int d, int e )
{
	if ( (a+e>b) && (c+e>d) ) {
		return 500;
	}
	return 30;
}
/home/ada/test/gcc$ gcc-4.1 -S -O2 and.c 
/home/ada/test/gcc$ cat and.s
	.file	"and.c"
	.section	".text"
	.align 2
	.p2align 4,,15
	.globl func
	.type	func, @function
func:
	add 3,3,7
	add 7,7,5
	li 0,500
	cmpw 7,3,4
	cmpw 6,7,6
	ble 7,.L2	# …?
	ble 6,.L2	# …?
	mr 3,0
	blr
	.p2align 4,,15
.L2:
	li 0,30
	mr 3,0
	blr
	.size	func,.-func
	.ident	"GCC: (GNU) 4.1.0 (Ubuntu 4.1.0-1ubuntu8)"
	.section	.note.GNU-stack,"",@progbits

Noooohhhhーーーー!じーーーしいーーーしぃいーーーーーーー!!!


今日のまとめ:
GCCで最適化できないアーキテクチャーを作った奴が悪いー!!(それはない)


あと、気になった点として、

extern void f() ;
void nanika( ) { f(); }

末尾最適化がされないですかね?AppleGCCはやってたような記憶があったんですが、記憶違いかもしれずー。