• 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

  • 相关阅读:
    hdoj:2033
    hdoj:2032
    hdoj:2031
    hdoj:2029
    hdoj:2028
    hdoj:2027
    hdoj:2024
    hdoj:2023
    hdoj:2022
    hdoj:题目分类
  • 原文地址:https://www.cnblogs.com/jourluohua/p/14556306.html
Copyright © 2020-2023  润新知