99

LLVM にはphi命令があり、非常に奇妙な説明があります。

「phi」命令は、関数を表す SSA グラフに φ ノードを実装するために使用されます。

通常、分岐を実装するために使用されます。私の理解が正しければ、依存関係の分析を可能にする必要があり、場合によっては不要な読み込みを回避するのに役立つ可能性があります。しかし、それが正確に何をするのかを理解することはまだ難しいです。

万華鏡のは、ケースについてかなりうまく説明していますif。ただし、&&や などの論理演算を実装する方法はそれほど明確ではありません||オンラインllvmコンパイラに次のように入力すると:

void main1(bool r, bool y) {
    bool l = y || r;
}

最後の数行は私を完全に混乱させます:

; <label>:10                                      ; preds = %7, %0
%11 = phi i1 [ true, %0 ], [ %9, %7 ]
%12 = zext i1 %11 to i8

phiノードが使用できる結果を生成するように見えます。そして、ファイノードはどのパスから値が来るかを定義するだけだという印象を受けました。

誰かがファイノードとは何か、そしてそれを実装||する方法を説明できますか?

4

3 に答える 3

90

ファイ ノードは、現在のブロックの先行ノードに応じて値を選択するために使用される命令です (完全な階層を確認するには、ここを参照してください。継承元のクラスの 1 つである値としても使用されます)。

Phi ノードは、LLVM コードの SSA (静的単一割り当て) スタイルの構造のために必要です。たとえば、次の C++ 関数

void m(bool r, bool y){
    bool l = y || r ;
}

次の IR に変換されます: ( clang -c -emit-llvm file.c -o out.bc- で作成され、 で表示されますllvm-dis)

define void @_Z1mbb(i1 zeroext %r, i1 zeroext %y) nounwind {
entry:
  %r.addr = alloca i8, align 1
  %y.addr = alloca i8, align 1
  %l = alloca i8, align 1
  %frombool = zext i1 %r to i8
  store i8 %frombool, i8* %r.addr, align 1
  %frombool1 = zext i1 %y to i8
  store i8 %frombool1, i8* %y.addr, align 1
  %0 = load i8* %y.addr, align 1
  %tobool = trunc i8 %0 to i1
  br i1 %tobool, label %lor.end, label %lor.rhs

lor.rhs:                                          ; preds = %entry
  %1 = load i8* %r.addr, align 1
  %tobool2 = trunc i8 %1 to i1
  br label %lor.end

lor.end:                                          ; preds = %lor.rhs, %entry
  %2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
  %frombool3 = zext i1 %2 to i8
  store i8 %frombool3, i8* %l, align 1
  ret void
}

それで、ここで何が起こりますか?bool l変数が 0 または 1 のいずれかである C++ コードとは異なり、 LLVM IR では一度定義する必要があります。が trueかどうかを確認してから、 or%toboolにジャンプします。lor.endlor.rhs

lor.end最終的に || の値が得られます。オペレーター。エントリーブロックから到着した場合、それは本当です。それ以外の場合は - の値に等しく、これは%tobool2まさに次の IR 行から得られるものです。

%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
于 2012-07-14T17:41:59.570 に答える
35

ファイを使用する必要はまったくありません。一時変数の束を作成するだけです。LLVM 最適化パスは一時変数の最適化を処理し、自動的に phi ノードを使用します。

たとえば、次のようにします。

x = 4;
if (something) x = x + 2;
print(x);

そのためにphiノードを使用できます(疑似コードで):

  1. x1に4を代入
  2. if (!something) 分岐先 4
  3. 2 を足して x1 から x2 を計算する
  4. x1 と x2 から x3 ファイを割り当てる
  5. x3 でプリントを呼び出す

ただし、phi ノードがなくても実行できます (疑似コードで):

  1. xというスタックにローカル変数を割り当てます
  2. temp へのロード x1 値 4
  3. x1 を x にストアする
  4. if (!something) は 8 に分岐します
  5. x を temp x2 にロードする
  6. temp x3 に 4 で x2 を追加
  7. x3 を x にストア
  8. x を temp x4 にロードする
  9. x4 で印刷を呼び出す

llvm で最適化パスを実行すると、この 2 番目のコードが最初のコードに最適化されます。

于 2012-07-14T21:40:47.923 に答える