本节将介绍一种特殊的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() <<"\n";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 typeid39     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()) << '\n';45       BasicBlockListType::iterator bbEnd = F.end();46       for(BasicBlockListType::iterator bbIter=F.begin(); bbIter!=bbEnd; ++bbIter){47         errs() <<"bb Tr\n";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后,测试结果如下:

LLVM Pass 简介(5)_LLVM Pass

 

下边附生成的max.ll

LLVM Pass 简介(5)_LLVM Pass_02LLVM Pass 简介(5)_LLVM Pass_03

; 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.elseif.then:                                          ; preds = %entry  %2 = load i32, i32* %a.addr, align 4
  store i32 %2, i32* %retval, align 4
  br label %returnif.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.endif.then:                                          ; preds = %entry  %2 = load i32, i32* %a.addr, align 4
  store i32 %2, i32* %ret, align 4
  br label %if.endif.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