LLVM有相当怪异的解释phi指令:
在“披”指令被用来实现在表示该函数的曲线图SSA的φ节点。
通常,它被用来实现分支。如果我理解正确的,它是需要做出的依赖性分析成为可能,并在某些情况下,它可能有助于避免不必要的负载。但是它仍然很难理解它做什么确切。
万花筒example解释它是相当漂亮的if
情况。但是它并不清楚如何实现像&&
和||
逻辑运算。如果我键入以下命令来online 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
看起来像披节点产生可以使用的结果。而我是在印象中披节点仅仅定义了从路径值到来。
有人能解释一下什么是披节点,以及如何实现||
呢?
阿披节点是用于选择依赖于当前块的前任一个值的指令(查找here看到完整的分级结构 - 它也被用作一个值,该值是它从继承的类中的一个)。
披节点是必要的,因为在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
}
那么,这里发生了什么?不同于C ++代码,其中所述可变bool l
可以是0或1,在LLVM IR它必须被定义一次。因此,我们检查,如果%tobool
是真实的,然后跳转到lor.end
或lor.rhs
。
在lor.end
我们终于拥有的价值||运营商。如果我们从入口块到来 - 那么它只是真实的。否则,它等于%tobool2
的价值 - 这正是我们从以下IR线获得:
%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
你并不需要在所有使用披。只要创建一堆临时变量。 LLVM优化过程,将采取优化临时变量远的照顾,并会自动使用披节点为。
例如,如果你想这样做:
x = 4;
if (something) x = x + 2;
print(x);
您可以使用披节点为(伪代码):
但是你可以不用(在伪代码)披节点:
通过运行优化与LLVM通过本次代码将得到优化,以第一个代码。