diff options
Diffstat (limited to 'chapter11/README.ja.md')
| -rw-r--r-- | chapter11/README.ja.md | 16 |
1 files changed, 3 insertions, 13 deletions
diff --git a/chapter11/README.ja.md b/chapter11/README.ja.md index 7de65f28..fe1c771d 100644 --- a/chapter11/README.ja.md +++ b/chapter11/README.ja.md @@ -100,21 +100,11 @@ return p;  -**Store をくくり出してから、上書きされた初期化を取り除きます。** ひとまとめの Phi と入力の集約がなくなると、Store #14 と #16 を使うのは MemPhi #20 だけになります。これらは同じポインタとエイリアスに格納し、同じ入力メモリを共有します。`PhiNode` は Store を合流の下に引き下げられます。 +**分岐の Store は別々に保ちます。** これが最終グラフです。Store の等価性はノードの同一性で判定するので、GVN も一般的な Phi の共通化も Store #14 と #16 をまとめません。それぞれが自身の分岐に残ります。両方が初期の `p.x = 0` の Store #7 を使うため、ユーザーが1つという条件を満たさず、連続する Store の除去でも #7 は消えません。オブジェクトを返すので、`p.y = 0` の Store #8 も残ります。 -```text -MemPhi_x(Store_x(mem, p, 3), Store_x(mem, p, 4)) - becomes -Store_x(mem, p, Phi(3, 4)) -``` - -一般に Phi の組み替えでは、第10章と同じく、Load や Store を押し上げたり引き下げたりして組み合わせられます。Phi の新しいメモリオペランドには、そのエイリアスの精密な MemPhi を使えます。このピープホール変換は精密なエイリアスを必要とし、BulkMem があると妨げられます。そのため、BulkMem を分割するきっかけにもなります。 - -例の続きを見ると、新しい値の Phi #28 は true 側で 3、false 側で 4 を選びます。Store #27 が両分岐の Store とそのメモリ Phi を置き換えます。初期の `p.x = 0` の Store #7 は、この1つの Store だけをユーザーに持つようになり、連続するストアの除去で迂回されます。`p.y = 0` の Store #8 は残ります。オブジェクトを返すので、その `y` フィールドは引き続き初期化が必要です。 - - +グラフには4つの Store、1つの MemPhi、1つの MemMerge があり、BulkMemPhi は消えています。このダイヤモンドだけなら2つの Store の共通化は安全に行えますが、Store GVN とともにこの書き換えも無効にしています。3経路のうち2経路だけにある同じ Store を共有すると、残る経路でも書き込んでしまうことがあるためです。第10章の Store の等価性の説明を参照してください。Load の共通化は有効なままで、ひとまとめのメモリの分割後、異なるメモリオペランドには精密な MemPhi を使います。 -したがって最終グラフには、2つの Store、通常の値の Phi が1つ、MemMerge が1つあり、MemPhi も BulkMemPhi も残りません。ワークリストの順序が違えば、たとえば元の入力 MemMerge を平坦化前に迂回し、一時的な `y` の分割を避けられる場合もあります。 +ワークリストの順序が違えば、元の入力 MemMerge を平坦化前に迂回し、一時的な `y` の分割を避けられる場合もあります。 このメモリ分割変換は大きくグラフに介入するため、再帰的に呼び出すことを禁止します。ループの周囲を分割することはよいのですが、その途中にあるループ先頭を分割しようとすると問題になります。分割で生まれた新しいノードをワークリストに入れ、現在の分割が完了してから訪問します。これによって、ループを巡るメモリを安全に完全分割できます。 |
