phi 节点是用于根据当前块的前身选择值的指令(在此处查看完整的层次结构 - 它也用作值,它是它继承的类之一)。
由于 LLVM 代码的 SSA(静态单一分配)样式的结构,Phi 节点是必需的 - 例如,以下 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
}
那么这里会发生什么?与 C++ 代码中的变量bool l
可以是 0 或 1 不同,在 LLVM IR 中它必须定义一次。所以我们检查是否%tobool
为真,然后跳转到lor.end
or lor.rhs
。
在lor.end
我们终于有了 || 的值 操作员。如果我们是从入口处到达的——那就是真的。否则,它等于 - 的值,%tobool2
这正是我们从以下 IR 行得到的:
%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]