万華鏡のシンボルテーブルは、NamedValuesマップによってコード生成時に使われている。Value*を追跡し続ける。変数の変更をサポートするために、変数のメモリの位置をNamedValuesで保持するよう、少し変更する必要がある。この変更はリファクタリングであることに注意。コードの構造は変わるが、コンパイラの振る舞いは変わらない。これ以降加えていく変更は、全て万華鏡のコード生成器のなかで分離されている。この時点では、万華鏡は2種類の変数のみをサポートしている。関数の引数と、forループのための帰納変数である。一貫性のため、ユーザ定義変数に加えて、それらの変数の変更も可能にしていく。それら両方とも、メモリの位置が必要であるということである。万華鏡の改良を始めるにあたって、NamedValuesマップを、Value*じゃなくてAllocaInst*を指すよう変更する。しておけば、あとはC++のコンパイラがコードの変更すべき箇所を教えてくれる。コンパイルエラーの内容を見れば変更すべき箇所が分かる。NamedValues;そしたら、alloca命令を生成するようにする必要がある。確実にallocaが関数のentryブロックに生成されるようにするためのヘルパ関数を使う。alloca命令を関数のentryブロックに生成する。これは変更可能な変数などのために使われる。VarName.c_str());}この少々変わったコードは、entryブロックの最初の命令(.begin())を指すIRBuilderオブジェクトを生成する。したら、指定された名前でallocaを生成し、それを返す。万華鏡における値は全てdoubleなので、変数の型を渡す必要はない。これを踏まえ、我々が最初に加えたい機能上の変更点は、変数の参照である。我々の計画では、変数はスタック上に保持されているので、変数の参照についてのコード生成として、実際にスタックスロットからロードする命令の生成が必要となる。関数の中でこの変数を探す。Name.c_str());}見ての通り、実に簡単なコードである。したら次は、allocaを使うよう、変数を定義する部分を変更する必要がある。それについてはまず、ForExprAST::Codegenから始める。(”全コード”の節で、省略されてないコードを見るべし。変数のためのallocaをentryブロックに生成する。スコープ中の変数無しで、まずStartのコードを生成する。allocaの中に値を格納する。allocaを再読み込みし、インクリメントし、セットする。これは、ループの本文が変数を変化させる場合を処理する。Alloca);...このコードは、変更可能な変数を可能にする以前のコードと同一といってもいいくらい似ている。大きな違いは、もうphiノードを構築する必要がなく、そして変数へのアクセスに必要に応じてload/storeを使うという点だけである。引数の変更をサポートするために、それらに関してもallocaを生成する必要がある。そのためのコードもまた、実にシンプルである。各引数のためのallocaを生成し、そしてそれをシンボルテーブルに登録する。これによって、引数への参照が可能となる。この変数のためのallocaを生成する。allocaの中に初期値を保存する。引数をシンボルテーブルに追加する。}}各引数について、allocaを作成し、関数へ入力された値をallocaの中に保存し、引数のメモリの位置としてallocaを登録する。FunctionAST::Codegenが関数のentryブロックを準備した直後、このメソッドはFunctionAST::Codegenによって起動される。あと残ったのは、mem2regパスの追加である。これによって、効率的なコードの生成機能を今一度得ることが出来る。phiノードを使わず、alloca/load/storeで変数を操作するようにすると効率が悪くなる。”今一度得る”というのは、mem2regパスでその効率を取り戻すという意味。オプティマイザのパイプラインを準備する。ターゲットがデータ構造をどうやって配置するかについての情報をまず登録する。allocaをレジスタ化する。簡単なピープホール最適化(覗き穴最適化)とビット操作最適化を行わせる。OurFPM.add(createReassociatePass());mem2reg最適化の実行前と後で、コードがどのようになるかを見るのは面白い。以下は、再帰的なfib関数のビフォー・アフターの例である。%iftmp}ここでは変数はひとつだけである(引数x)が、我々が非常に単純なコード生成戦略を使っていることが分かる。entryブロックで、allocaは生成され、そこに初期値が保存される。変数への参照では、毎回スタックから再読み込みされている。if/then/else式を修正してないので、依然としてphiノードが挿入されている点にも注意が必要である。ここでもallocaを使うようにする事もできるが、phiノードを生成するほうが簡単なのでそのままにしてある。これがmem2regパスによる最適化後である。%iftmp}これは変数の再定義を含まないので、mem2regにとって取るに足らないなケースである。非効率な命令の挿入をしても大丈夫だ、という事を示すためにこのコードを示している。残りの最適化を実行すると以下のようになる。1.000000e+00}simplifycfgパスによって、ret命令がelseブロックの最後にも追加されている。これによって、いくらかの枝分かれやphiノードが削減可能となる。以上で、シンボルテーブルの全ての参照は、スタック変数を使うようになった。operator)を追加しよう。コメントをキャンセルメールアドレスが公開されることはありません。コメントデータの処理方法の詳細はこちらをご覧ください。...774Fedexアカウント取得後にオンラインで手続きすれ...NETこういうのずっと見てしまう気持ちがよくわかります(...BINGEブログを拝見させていただきました・・・。花粉症対策についてはこれまで次の記事を書いてきました。花粉症対策についてはこれまで次の記事を書いてきました。花粉症対策についてはこれまで次の記事を書いてきました。花粉症対策についてはこれまで次の記事を書いてきました。花粉症対策についてはこれまで次の記事を書いてきました。