究竟PHI指令本身以及如何使用它LLVM

问题描述 投票:73回答:2

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

看起来像披节点产生可以使用的结果。而我是在印象中披节点仅仅定义了从路径值到来。

有人能解释一下什么是披节点,以及如何实现||呢?

llvm
2个回答
69
投票

阿披节点是用于选择依赖于当前块的前任一个值的指令(查找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.endlor.rhs

lor.end我们终于拥有的价值||运营商。如果我们从入口块到来 - 那么它只是真实的。否则,它等于%tobool2的价值 - 这正是我们从以下IR线获得:

%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]

28
投票

你并不需要在所有使用披。只要创建一堆临时变量。 LLVM优化过程,将采取优化临时变量远的照顾,并会自动使用披节点为。

例如,如果你想这样做:

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

您可以使用披节点为(伪代码):

  1. 分配4 X1
  2. 如果(!东西)分支4
  3. 通过加入2计算从X1 X2
  4. 从X1和X2分配X3披
  5. 打电话与X3打印

但是你可以不用(在伪代码)披节点:

  1. 上堆称为X分配的局部变量
  2. 加载到临时X1值4
  3. 店内X1为x
  4. 如果(!东西)分公司8
  5. 负载x到临时X2
  6. 与4添加到X2 X3的温度
  7. 店内X3为x
  8. 负载x到临时X4
  9. 打电话与X4打印

通过运行优化与LLVM通过本次代码将得到优化,以第一个代码。

© www.soinside.com 2019 - 2024. All rights reserved.