LLVM Pass 简介(5)

本节将介绍一种特殊的IR指令——PHINode。

关于PHI,首先需要介绍SSA静态单赋值https://en.wikipedia.org/wiki/Static_single_assignment_form

为了实现SSA,需要将类似的branch语句:

int max(int a, int b)
{
   if(a>b)
      return a;
   else
      return b;
}

 转换为(不是真的这样在语言层面进行转换,是IR,为了说明方便):

int max(int a, int b) {
  int ret0, ret1;
  if(a>b)
      ret0= a;
  else
      ret1 = b;
  int ret = phi(ret0, ret1);
  return ret;
}

这里的phi函数根据条件进行选择是使用ret0还是ret1的值,或者换一种说法的话,phi是一种类似于C语言三地址码?的作用。不过phi的源是BasicBlock。

下边介绍如何使用PHI节点

 1 #include "llvm/ADT/Statistic.h"
 2 #include "llvm/IR/Function.h"
 3 #include "llvm/Pass.h"
 4 #include "llvm/Support/raw_ostream.h"
 5 #include <map>
 6 #include <string>
 7 #include "llvm/IR/Instructions.h"
 8 #include "llvm/IR/InstVisitor.h"
 9 #include "llvm/ADT/DepthFirstIterator.h"
10 #include "llvm/ADT/SmallPtrSet.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/IR/InstIterator.h"
13 #include "llvm/IR/Instructions.h"
14 #include "llvm/IR/IntrinsicInst.h"
15 using namespace llvm;
16 
17 #define DEBUG_TYPE "hello"
18 
19 STATISTIC(HelloCounter, "Counts number of functions greeted");
20 namespace {
21   struct PNINodeVisitor : public InstVisitor<PNINodeVisitor> {
22   public:
23     PNINodeVisitor(BasicBlock &bb){
24       visit(bb);
25     }
26 
27     void visitPHINode(PHINode &PN){
28       errs() <<"PN.getNumIncomingValues() " <<PN.getNumIncomingValues() <<"
";
29       for (PHINode::block_iterator i = PN.block_begin(), e = PN.block_end(); i != e;
30        ++i) {
31         (*i)->dump();
32       }
33     }
34 
35   };
36   // Hello5 - The second implementation with getAnalysisUsage implemented.
37   struct Hello5 : public FunctionPass {
38     static char ID; // Pass identification, replacement for typeid
39     Hello5() : FunctionPass(ID) {}
40     using BasicBlockListType = SymbolTableList<BasicBlock>;
41 
42     bool runOnFunction(Function &F) override {
43       errs() << "now process funcName: ";
44       errs().write_escaped(F.getName()) << '
';
45       BasicBlockListType::iterator bbEnd = F.end();
46       for(BasicBlockListType::iterator bbIter=F.begin(); bbIter!=bbEnd; ++bbIter){
47         errs() <<"bb Tr
";
48         BasicBlock &bbs = *bbIter;
49         PNINodeVisitor piv(bbs);
50       }
51       return false;
52     }
53 
54     // We don't modify the program, so we preserve all analyses.
55     void getAnalysisUsage(AnalysisUsage &AU) const override {
56       AU.setPreservesAll();
57     }
58     std::map<std::string, uint> opCodeMap;
59   };
60 }
61 
62 char Hello5::ID = 0;
63 static RegisterPass<Hello5>
64 XZ("hello5", "show how to solve PHINode");

为了能真的处理到PHINode,我们这里使用的测试源码是:

int max(int a, int b){
  if(a>b)
      return a;
  else
      return b;
}

int new_max(int a, int b) {
  int ret = 0;
  if(a>b)
      ret = a;
  ret = b;
  return ret;

}

void omi(int r, int y) {
        int l = y || r;
}

使用./bin/clang -c -emit-llvm max.c编译成max.bc后,测试结果如下:

下边附生成的max.ll

; ModuleID = 'max.c'
source_filename = "max.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @max(i32 %a, i32 %b) #0 {
entry:
  %retval = alloca i32, align 4
  %a.addr = alloca i32, align 4
  %b.addr = alloca i32, align 4
  store i32 %a, i32* %a.addr, align 4
  store i32 %b, i32* %b.addr, align 4
  %0 = load i32, i32* %a.addr, align 4
  %1 = load i32, i32* %b.addr, align 4
  %cmp = icmp sgt i32 %0, %1
  br i1 %cmp, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  %2 = load i32, i32* %a.addr, align 4
  store i32 %2, i32* %retval, align 4
  br label %return

if.else:                                          ; preds = %entry
  %3 = load i32, i32* %b.addr, align 4
  store i32 %3, i32* %retval, align 4
  br label %return

return:                                           ; preds = %if.else, %if.then
  %4 = load i32, i32* %retval, align 4
  ret i32 %4
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @new_max(i32 %a, i32 %b) #0 {
entry:
  %a.addr = alloca i32, align 4
  %b.addr = alloca i32, align 4
  %ret = alloca i32, align 4
  store i32 %a, i32* %a.addr, align 4
  store i32 %b, i32* %b.addr, align 4
  store i32 0, i32* %ret, align 4
  %0 = load i32, i32* %a.addr, align 4
  %1 = load i32, i32* %b.addr, align 4
  %cmp = icmp sgt i32 %0, %1
  br i1 %cmp, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %2 = load i32, i32* %a.addr, align 4
  store i32 %2, i32* %ret, align 4
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  %3 = load i32, i32* %b.addr, align 4
  store i32 %3, i32* %ret, align 4
  %4 = load i32, i32* %ret, align 4
  ret i32 %4
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @omi(i32 %r, i32 %y) #0 {
entry:
  %r.addr = alloca i32, align 4
  %y.addr = alloca i32, align 4
  %l = alloca i32, align 4
  store i32 %r, i32* %r.addr, align 4
  store i32 %y, i32* %y.addr, align 4
  %0 = load i32, i32* %y.addr, align 4
  %tobool = icmp ne i32 %0, 0
  br i1 %tobool, label %lor.end, label %lor.rhs

lor.rhs:                                          ; preds = %entry
  %1 = load i32, i32* %r.addr, align 4
  %tobool1 = icmp ne i32 %1, 0
  br label %lor.end

lor.end:                                          ; preds = %lor.rhs, %entry
  %2 = phi i1 [ true, %entry ], [ %tobool1, %lor.rhs ]
  %lor.ext = zext i1 %2 to i32
  store i32 %lor.ext, i32* %l, align 4
  ret void
}

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 7.0.0 (tags/RELEASE_700/final)"}
View Code

 Reference:

https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/control-structures/ssa-phi.html

https://wiki.aalto.fi/display/t1065450/LLVM+SSA

https://stackoverflow.com/questions/11485531/what-exactly-phi-instruction-does-and-how-to-use-it-in-llvm

原文地址:https://www.cnblogs.com/jourluohua/p/14556306.html