最適化の範囲: p0 ~ p1
for (p = p0; p < p1; p = 次の命令) {
if (pの命令がAEs_OpCmpEq~AEs_OpCmpRnz) { r = p; (この命令の場所を覚えておく) }
if (pの命令がAEs_OpSetCc && 次の命令がAEs_OpCmpEqかAEs_OpCmpNeで定数0との比較 && OpSetCcの結果をその先で一切使わない) {
if (次の命令がAEs_OpCmpEq) { rに書いてある命令の比較条件を反転させる }
pのSetCc命令をNopにしてしまう
pの次のAEs_OpCmpEq/AEs_OpCmpNe命令もNopにしてしまう
}
}if ((a > 1) != 0) goto label; // HLX-001が内部的に生成してしまう共通中間コードをC言語風に書いたもの 1: OpCmpGt(a, 1); // (最適前)上記を共通中間コードにしたもの 2: OpSetCc(tmp); // この2行目と3行目は最適化によって消される 3: OpCmpNe(tmp, 0); 4: Op0Jcc(label); 1: OpCmpGt(a, 1); // (最適化後)このようにうまくいく 2: Op0Jcc(label);
最適化の範囲: p0 ~ p1
変数の値を記憶するテーブルを初期化
for (p = p0; p < p1; p = 次の命令) {
定数代入命令があったら、テーブルに変数の値を登録
その他、結果が定数になるような演算があれば、それも結果をテーブルに登録
もし定数のみの演算ではなく結果が定数じゃないかもしれないと思われるときは、テーブルから変数に関する行を削除
命令の中で変数が使われていたら、その変数がテーブルに登録されていないかを確認し、登録されていれば定数値に置換する。
ラベル宣言文に当たったら、テーブルをいったん全クリアする(もうどの変数に定数値がはいっているか分からないので)
}最適化の範囲: p0 ~ p1
for (p = p0; p < p1; p = 次の命令) {
if (pの命令がOp0JmpかOp0Jcc) {
分岐先の命令を見る(NOPなどは読み飛ばす)
もしOp0Jmpだったら、分岐先を修正
}
}最適化範囲: p0 ~ p1 範囲内のプログラムの、Op0JmpやOp0Jcc命令を探してラベルの参照回数をカウントする そして参照回数が0回のラベル宣言文は削除してしまう
最適化範囲: p0 ~ p1 関数の先頭から見て行って、Op0Jccを見つけたら、スタックにそのラベルを登録。Op0RetやOp0Jmpを見つけたら、そこで終わり。 終わったら、スタックを見に行って、もしラベルが登録されていればそこからまた見て行ってOp0Jccが来たらスタックに登録。・・・これを繰り返す。 同じラベルを二度見に行かないようにフラグで管理。 こうすることで、どうやっても到達しないラベルにはフラグが付いていないことになるので、フラグのないラベルは消す。 その上で、Op0Jmpの後でラベル宣言命令までの間は、どうやっても到達しないコードになるので、これを削る。
最適化範囲: p0 ~ p1
for (p = p0; p < p1; p = 次の命令) {
if (pの命令がOp0JmpかOp0Jcc) {
if (pの次の命令がラベル宣言 && そのラベルはpの分岐先と同じ) {
pの分岐命令を消す
}
}
}最適化範囲: p0 ~ p1
for (p = p0; p < p1; p = 次の命令) {
命令の開始位置を配列t[i]に記憶させる(以下で、命令を逆順にたどりたいので)
}
for (i--; i >= 0; i--) {
p = t[i];
if (pの演算結果が次のOpCpyでしか使われていない) {
OpCpyの代入先へ直接代入するようにする
そしてOpCpyは消す
[註] ここは以下のようなコードを最適化する
tmp = a + b; c = tmp; → c = a + b;
}
if (pの演算結果がその先で使われていない) {
pの命令を消す
}
}