雑記
コンパイルの話4:マシン語に落ちるということ2:最適化
最終更新:
匿名ユーザー
-
view
コンパイラには「最適化」という機能がある。
最近のコンパイラはこの最適化機能が優れているので、下手にアセンブラでプログラミングするよりもC言語あたりで書いたプログラムをコンパイルしたものの方が良かったりする。
石の方の命令系統も、最近のはC言語でコンパイルされることを前提に作られていたりするし。
いまどき、アセンブラが必要な場面ってどうしてもC言語などで表現できない(あるいはしにくい)局面でしかほとんど使用されていないのではないだろうか。
じゃあコンパイラの最適化って、どんなことをしてくれるのか?
大まかに言って、
①静的な演算
②無駄な処理の省略
と言う感じ。他にもあるけど。
①静的な演算
②無駄な処理の省略
と言う感じ。他にもあるけど。
具体的にどんなのっていうのは、
①の場合、例えば
①の場合、例えば
unsigned int iHoge; iHoge = 100*100;
なんてあった場合にいちいち実行時に計算するのは馬鹿馬鹿しいのでコンパイル時点で「10000」という値に置き換えてくれる。
上の例のように即値で見たら自分でやってもいいように見えるけど、定数を#defineしてるときとかもあるのでやっぱりありがたい。
他にもsizeof()演算子なども、①に含まれる。これは、前にも書いたけど。
②の場合は、ループ処理など。
int i, j, n; ・・・・ for(i = 0; i < 10; i++) { j = i * 100 * m; }
のようなソースがあった場合、「100 * k」はループ内で変更されることはない。それなのにkが変数であるために、①のように単純には置き換えができない。
こんなときは
int i, j, n, m; ・・・・ m = 100 * n; for(i = 0; i < 10; i++) { j = i * m; }
のようなコードに置き換えられる。
また、同一の関数内で
if(i == TRUE) { return; } ・・・・ if(i == TRUE) { ・・・・ }
なんて処理があった場合に、変数iに何も代入した形跡がなければ二つ目のif()は意味がないため、コンパイラはその部分を処理しない。
同様に
int i = 0; i = 100;
と言う場合でも最初の0での初期化は無意味なため、省略される(初期化と代入の間に変数iを評価する処理があったら別だけど)。
他にも、代入されても一度も評価されない変数などは、その処理が省略されたりもする。
ただし、この最適化の処理はコンパイラの実装に依存する。
全てのコンパイラで同じような最適化処理が行われているわけではないことに注意。
全てのコンパイラで同じような最適化処理が行われているわけではないことに注意。
さらに、コンパイラでは最適化できない(あるいはやりにくい)処理もある。
例えば、以下の多重ループ処理。
ここでは単純に、配列の中身を表示したいだけとする。
ここでは単純に、配列の中身を表示したいだけとする。
int i, j; int array[10][100]; for(i = 0; i < 100; i++) { for(j = 0; j < 10; j++) { printf("%d\n", array[j][i]); } }
このソースで注意して欲しいのは、「array[j][i]」としていること。
上記の書き方では、メモリのアクセス効率が非常に良くない。
上記の書き方では、メモリのアクセス効率が非常に良くない。
array[][]は二次元配列のように見えるけど、実際にメモリ上に確保されるのはひとつなぎの領域だ。上の例だと100byteが10個、の1000byteの領域と言うことになる(10byteが100個ではないのは、判るよね??)。
なので、上のようなループを組んでしまうと、メモリに飛び飛びにアクセスするため、とても効率が悪い。しかしながら、やむを得ずそうする必要があったのかそれともプログラマが間抜けなのかはコンパイラにはわからない。最適化したいけど、できないのだ。
素直に
int i, j; int array[10][100]; for(i = 0; i < 100; i++) { for(j = 0; j < 10; j++) { printf("%d\n", array[i][j]); } }
となっていたら、array[][]は連続した領域なので、②によって最適化されるとループはひとつ、
for(i = 0; i < 10 * 100; i++)
で済む。さらに①を適用して、
for(i = 0; i < 1000; i++)
となる。
ぜんぜん違うでしょ??
このほかにもコンパイラはさまざまな最適化のノウハウを持っている。
だけど、それを適用してもらうにはプログラマの意図をコンパイラに判ってもらう必要もある。
だけど、それを適用してもらうにはプログラマの意図をコンパイラに判ってもらう必要もある。
プログラムを書くときに、最適化のことも多少考慮に入れて、最適化しやすい(コンパイラに優しい)ソースを書くようにしましょう。