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
,在LLVM IR中变量可以为0或1,因此必须定义一次。因此,我们检查是否%tobool
为true,然后跳至lor.end
或lor.rhs
。
在lor.end
我们终于拥有的价值|| 操作员。如果我们是从入口处到达的-那是真的。否则,它等于-的值,%tobool2
而这正是我们从以下IR行获得的结果:
%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
phi
节点是编译器将IR转换为“静态单分配”形式的问题的解决方案。为了更好地理解解决方案,我建议更好地理解问题。所以我将为您“为什么是phi
节点”。