Sunday, 8 October 2006

Intel Mac のコンパイラ



しばらくアセンブラ出力を眺めて、やっぱり書くことを決意したのはいいんだけど...

Relocatable つまり、コードの位置をリンク時に決めない方式なので、サブルーチンの先頭に、自分のコードの位置を知るために、

0x19d9c <__i686.get_pc_thunk.bx>: mov (%esp),%ebx
0x19d9f <__i686.get_pc_thunk.bx+3>: ret

とかいうのを呼んでいる。もちろん、メモリ上の固定数値も呼ばず、大域変数にもアクセスしなければ、呼ぶ必要はないわけだけど。しかも、この位置を記憶するEBXレジスタは、ずーっと、潰れることになる。

で、大域変数は、
  leal L_uc1$non_lazy_ptr-"L00000000006$pb"(%ebx), %eax
  movl (%eax), %eax
  movb $-56, (%eax)
でアクセスすることになる。だから、一旦ポインタに入れないと大域変数にアクセスできない。
  movl L_uc1$non_lazy_ptr-"L00000000006$pb"(%ebx), %eax
  movb $-56, (%eax)
これでもいいのか。

ってことは、大域変数にアクセスする時は、6個しかないia32の汎用レジスタのうち2つは、必ず、潰れているってことだね。ま、いいんだけど。ia32 には、わり算するときにはEDXがつぶれるという楽しい技もあるんだよな。 32個レジスタあるってならともかく。

なんか、昔の MC6800 を使ったアセンブラプログラミングみたい。MC6800はポインタ一つ、アキュームレータ一つだったから。これで、そこそこ速く動くCPUだってのが奇跡だ... 仮想レジスタの威力なのかなぁ。get_pc_thunk.bx みたいなので、実メモリにアクセスしていたんじゃだめだめそうなものなんだが。

もちろん、大域最適化をすれば、このあたりはだいぶましにはなるんだけど。あぁ、たくさん文字列定数を使うときには、先にまとめて、取得して局所変数に入れておくみたいなことするのかぁ。
  leal LC143-"L00000000027$pb"(%ebx), %edi
  movl %edi, -660(%ebp)
  leal LC144-"L00000000027$pb"(%ebx), %eax
  movl %eax, -664(%ebp)
  leal LC145-"L00000000027$pb"(%ebx), %edi
  movl %edi, -668(%ebp)
  leal LC146-"L00000000027$pb"(%ebx), %eax
  movl %eax, -672(%ebp)
  leal LC147-"L00000000027$pb"(%ebx), %edi
  movl %edi, -676(%ebp)
  leal LC148-"L00000000027$pb"(%ebx), %eax
  movl %eax, -680(%ebp)
なにやってるのかと思ったよ... その方がEBXが空くから有利ってことなんだろうな。大域最適化の結果がこれかよ。

なんで、こんなCPUが流行ってしまったのか。

Intel Mac のコンパイラのfixが、予想外に早く終ることを期待します。

No comments: