VFP関連のメモ
とりあえずVFPを使う場合の最小のスタートアップコード。 _stack_initは適当にリンカスクリプトにでも書く事にする。とりあえずSVC modeのスタックだけ初期化しておけばいいだろう。
OSの場合は、普通VFP命令を実行して、Undefined Instructionが起こってから例外ハンドラで有効にするんだろうけど。使わないのにいちいちVFPレジスタの退避と復帰をしてたら効率悪いもんな。CPUの初期化部分を大分省いてるけど、そんなのはデバッガがやってくれるから関係ない。
.arm
.text
.globl _start
_start:
/* Initialize Stack */
mov r0, #0x13+0xc0
msr cpsr, r0
ldr sp, stack_init
bic sp, sp, #3/* Full access to VFP */
mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #(0xf << 20)
mcr p15, 0, r0, c1, c0, 2/* Enable VFP function */
mov r0, #0x40000000
fmxr fpexc, r0
b mainstack_init:
.long _stack_init
STM
GCCにSTM(Software Transactional Memory)ブランチが新しく作成された模様。
http://www.hipeac.net/node/2419
ARMv7 MP Extentions からはcmpxchg8b命令があるから結構楽に実装できそうだな。というか、これがないと完全には実装できないのか。
LTO
GCC summitを見学しにいったときに、CodeSourceryのMark Mitchellと話をする機会があった。彼はGCCのC++フロントエンドのメンテナで、リリースマネージャーでもある。リンク時最適化については、組み込みの世界でも非常に有用だし、待ち望んでる人達もいるので頑張って下さいと言ってきた。今考えてみれば、お前もコミットしろよという感じであるが、言語は日本語しかわからない俺にとってはハードルが高いのである。C言語とか何をやってんのかさっぱりわからん。でもソース見てたら何か出来そうな気がしてきた。気がするだけ。
GCCのltoが結構活発に開発が進められている。whopr(Whole Program Optimization)やgimple tuplesなんかとも連動して、最近はGoogleの人達がよくコードをコミットしている。CodeSourceryはどうしたんだ? SourceryG++のサポートCPUが増えたし、4.3ベースのリリースが待ってたりするから忙しいのかな?
それはともかく、-fwpa -fltrans とかいうオプションが増えた。基本的には前からあった-flto1発でいけるみたいだが、他のオプションは何が違うのか気になるところだ(良くわかってない)。メーリングリストでは、ユーザが混乱するからいっぱい似たようなオプション作るのはやめようぜという意見が出てきたので、最終的には-fltoと-fwpaぐらいになるのかもしれない。
Link-Time Optimizationといってはいるが、別にリンカで最適化してくれるわけではなく(GCCのブランチなんだから当たり前だけど...)、コンパイル過程で作られるコールグラフの情報をオブジェクト単位で残しておき、リンカが呼ばれる直前にもう1度GCCを起動して、全てのオブジェクトを入力する。そして、ローカルなコールグラフを全部ロードしてグローバルなコールグラフを作ればIPOが出来るじゃん、という寸法である。実際、2008/10/3の時点では、各オブジェクト毎に以下のようなセクションが増えてた。
[ 4] .gnu.lto_internal PROGBITS [ 5] .gnu.lto_main PROGBITS [ 6] .gnu.lto_.static PROGBITS [ 7] .gnu.lto_.cgraph PROGBITS [ 8] .gnu.lto_.decls PROGBITS [ 9] .gnu.lto_.symtab PROGBITS
ltoのコンパイラドライバ(?)のlto.cを見たが、確かにリンカが起動する直前にGCCを起動してたし、グローバルなコールグラフを作成してから、IPAのパス(今のところインライン展開だけ)が実行されてた。ソースのコメントに書いてあったが、まだ色々問題があるようだ。
ltoプロジェクトを進めている人達は、メモリ効率とコンパイル時間を非常に気にしていて、特にコンパイル時間は倍近くなる可能性もあるため、結構悩んでいるようである。ただでさえGCCはコンパイル遅いのに、更に遅くなったら誰が使うんじゃいとか言ってた気がするが、たぶん俺なら喜んで使うと思う。
どうでもいいけど、llvmのbcにはコールグラフの情報が含まれてるんでしょうね。ARMのコンパイラはそんなのが入ってるようなセクションあったかなあ。
10/16追記: -fwpaオプションはさっくりと無くなって -fwhoprに変わった。
デバッガ
個人的には、ソフトの開発にはデバッガが必須であると考えている。しかし、プロのエンジニアの人たちに聞いてみても、デバッガを使っていない人が驚くほど多い。ちゃんとした(?)ソフトウェアの開発現場に居たことがないのでよくわからないが、みんなどうやって開発してるんだろうか。
バグをほとんど出さないような天才とか、頭の中にCPUエミュレータを搭載していてステップ実行なんかが出来てしまうような特異能力者ならまだしも、普通にコードを書いて、その後のバグ取りに時間をかけている開発者にとって、デバッガは無くてはならないものだと思う。現場でほとんど使われていないような高級言語とか、最近流行のLightWeightなものに関しては知りません。
確かにprintfを使って、任意の時点での環境をそれなりに把握することができるし、これを繰り返せば原因は特定できる。熟練したソフトウェア開発者であれば、経験からバグの原因を短い時間で特定することができるかもしれない(熟練した開発者じゃないのでわからないけど)。しかし、デバッガを使えば、それほどの熟練者でなくとも、驚くほど短い時間で問題を見つける事が可能である。正しく解決できるかどうかは別だが。
デバッグの準備
基本的にはコンパイル時にデバッグ情報を付加すれば、ソースレベルでのデバッグが可能である。ただし、最適化をはずさないと非常にデバッグしづらい。デバッガの歴史は最適化との戦いの歴史である(そうでもない)。デバッグ情報も進化する余地が十分残っているのだが、変数が削除されてしまったり、命令の順序がガラッと変わったりしてしまうと、もうどうしようもない。
というわけで、この際思い切ってGCCの場合には-O0オプションで最適化をはずす事にする。デバッグ情報を付加するオプションは -g -gstabs -gstabs+など。-g はDWARFで、-gstabs -gstabs+ はstabのデバッグ情報フォーマットである。DWARF2の場合は、同じヘッダをいっぱいインクルードすると、その数だけデバッグ情報が出てしまうのでサイズがでかくなってしまう。stabは大丈夫。DWARF3でも、この辺は改良されるみたい。
最適化について
最適化をはずさないとデバッグしづらいとは書いたが、ソースレベルデバッグできないわけではない。ただ、ソース上でステップ実行したりすると、あっちこっちに飛んでいってしまって、正確にどこを実行しているのかを把握するのは難しい。ローカル変数なんかも、無くなってしまったものは当然ながら表示されない。
gdbでは、optimized outとか表示されたような気がする。gccはvar-trackingとかで、最適化されてもローカル変数が今どこにあるのかという情報を出来るだけ吐こうとするが、完全に正確というわけではない。gccのプロジェクト内では、現在もデバッグ情報の精度向上について頑張っている人もいるが、最適化のパスを書いてる人達はあまり考えてないような気がする。最適化が進めば進むほど、ソースコードと最終的なコードの対応がつかなくなり、最適化したプログラムのソースレベルデバッグが更に困難になっていくのは避けられない。
んじゃあんまりデバッグに影響を与えないような最適化のパスだけ通せばいいんじゃねーのって事で、-Ogオプションなんかも提案されているが、動きがあるんだか無いんだかわからない。