LLVM 使用其他pass

2019/07/02 LLVM

(一)什么是pass 官网是这么介绍的:

The LLVM Pass Framework is an important part of the LLVM system, because LLVM passes are where most of the interesting parts of the compiler exist. Passes perform the transformations and optimizations that make up the compiler, they build the analysis results that are used by these transformations, and they are, above all, a structuring technique for compiler code. 大概意思就是说:

LLVM的pass框架是LLVM系统的一个很重要的一部分,也是LLVM很有趣的一个地方,LLVM 的转换和优化是由很多个pass一起完成的,以上的这些,可以称之为一种编译代码的结构化技术。

所有的pass 都是pass 类的子类,它们通过重写pass 中的虚函数来实现功能,根据你的pass 的功能,你的pass 可以继承自ModulePassCallGraphSCCPassFunctionPass、or LoopPass or ReginPassBasicBlockPass,结合其他的pass ,将会有关你的pass 的更多信息。llvm pass框架的一个主要特性是,它根据您的pass满足的约束,以高效的方式调度pass的运行。

(二)创建一个pass 在上一篇中,已经创建了一个hello world pass,这次应该很熟练了。

首先、编写lib/transform/CMakeLists.txt 文件,

add_subdirectory(Utils)
add_subdirectory(Instrumentation)
add_subdirectory(AggressiveInstCombine)
add_subdirectory(InstCombine)
add_subdirectory(Scalar)
add_subdirectory(IPO)
add_subdirectory(Vectorize)
add_subdirectory(Hello)
add_subdirectory(ObjCARC)
add_subdirectory(Coroutines)
add_subdirectory(FirstPass)
add_subdirectory(FuncBlockCount)

然后,创建目录LLVMFuncBlockCount

然后,在LLVMFuncBlockCount创建CMakeLists.txtFuncBlockCount.cppFuncBlockCount.exports,CMakeLists.txt 文件如下:

# If we don't need RTTI or EH, there's no reason to export anything
# from the hello plugin.
if( NOT LLVM_REQUIRES_RTTI )
  if( NOT LLVM_REQUIRES_EH )
    set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/FuncBlockCount.exports)
  endif()
endif()

if(WIN32 OR CYGWIN)
  set(LLVM_LINK_COMPONENTS Core Support)
endif()

add_llvm_library( LLVMFuncBlockCount MODULE BUILDTREE_ONLY
  FuncBlockCount.cpp

  DEPENDS
  intrinsics_gen
  PLUGIN_TOOL
  opt
  )

最后,打开xcode 选择all_build 编译,编译完后,就可以看到LLVMFuncBlockCount group,然后就可以在xcode 中编辑FuncBlockCount.cpp 文件了。

#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/LoopInfo.h"
using namespace llvm;

//#define DEBUG_TYPE "hello"

//STATISTIC(HelloCounter, "Counts number of functions greeted");

namespace {
  // Hello - The first implementation, without getAnalysisUsage.
  struct FunctionBlockCount : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    FunctionBlockCount() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {

      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '\n';
      return false;
    }
      
  };
}

char FunctionBlockCount::ID = 0;
static RegisterPass<FunctionBlockCount> X("Funcbc", "Hello World Pass",false,false);

然后,xcode中选择LLVMFunctionBlockCount 编译。

最后,选择opt,设置opt 参数如下:

成功后输出:

Hello: foo
===-------------------------------------------------------------------------===
                      ... Pass execution timing report ...
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0028 seconds (0.0086 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0011 ( 65.5%)   0.0010 ( 90.8%)   0.0021 ( 75.3%)   0.0079 ( 91.8%)  Hello World Pass
   0.0003 ( 17.2%)   0.0000 (  0.1%)   0.0003 ( 10.6%)   0.0003 (  3.5%)  Module Verifier
   0.0002 ( 11.6%)   0.0001 (  8.0%)   0.0003 ( 10.2%)   0.0003 (  3.4%)  Natural Loop Information
   0.0001 (  5.6%)   0.0000 (  1.1%)   0.0001 (  3.9%)   0.0001 (  1.3%)  Dominator Tree Construction
   0.0017 (100.0%)   0.0011 (100.0%)   0.0028 (100.0%)   0.0086 (100.0%)  Total

===-------------------------------------------------------------------------===
                                LLVM IR Parsing
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0039 seconds (0.0041 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0031 (100.0%)   0.0008 (100.0%)   0.0039 (100.0%)   0.0041 (100.0%)  Parse IR
   0.0031 (100.0%)   0.0008 (100.0%)   0.0039 (100.0%)   0.0041 (100.0%)  Total

(三)使用其他 pass

计算一个IR中基本块的数量

如果需要计算基本块的数量,需要用到getAnalysis 循环函数。

LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();

在这里将会使用到LoopInfo pass 来获取循环信息。通过遍历来获取基本块的信息。

Loop::block_iterator bb;
for (bb = L->block_begin(); bb != L->block_end(); ++bb) {
     num_Blocks++;
     errs() << "Loop level " << nest << "has " <<  num_Blocks << " blocks \n";
     std::vector<Loop *> subLoops = L->getSubLoops();
     Loop::iterator j, f;
     for (j = subLoops.begin(),f = subLoops.end(); j != f; ++j) {
         countBlocksInLoop(*j, nest + 1);
      }
  }

文件最终状态:

namespace {
  // Hello - The first implementation, without getAnalysisUsage.
  struct FunctionBlockCount : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    FunctionBlockCount() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {

      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '\n';
        
        LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
        for (Loop * L : *LI) {
            countBlocksInLoop(L, 0);
        }
      return false;
    }
      // This example modifies the program, but does not modify the CFG
      void getAnalysisUsage(AnalysisUsage &AU) const override {
          AU.setPreservesCFG();
          AU.addRequired<LoopInfoWrapperPass>();
      }
      
      void countBlocksInLoop(Loop *L,unsigned nest) {
          unsigned num_Blocks = 0;
          Loop::block_iterator bb;
          for (bb = L->block_begin(); bb != L->block_end(); ++bb) {
              num_Blocks++;
              errs() << "Loop level " << nest << "has " <<  num_Blocks << " blocks \n";
              std::vector<Loop *> subLoops = L->getSubLoops();
              Loop::iterator j, f;
              for (j = subLoops.begin(),f = subLoops.end(); j != f; ++j) {
                  countBlocksInLoop(*j, nest + 1);
              }
          }
      }
  };
}

char FunctionBlockCount::ID = 0;
static RegisterPass<FunctionBlockCount> X("Funcbc", "Hello World Pass",false,false);

接下来,写case:

sample.c

#include <stdio.h>
int foo(int n,int m) {
    int sum = 0;
    int c0;
    for (c0 = n; c0 > 0; c0--) {
        int c1 = m;
        for (; c1 > c0; c1--) {
            sum += c0 > c1 ? 1:0;
        }
    }
    return sum;
}

编译:

$ clang -O0 -S -emit-llvm sample.c -o sample.ll

最后,编译运行:

WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.

Hello: foo
Loop level 0has 1 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 2 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 3 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 4 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 5 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 6 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
Loop level 0has 7 blocks 
Loop level 1has 1 blocks 
Loop level 1has 2 blocks 
Loop level 1has 3 blocks 
===-------------------------------------------------------------------------===
                      ... Pass execution timing report ...
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0028 seconds (0.0086 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0011 ( 65.5%)   0.0010 ( 90.8%)   0.0021 ( 75.3%)   0.0079 ( 91.8%)  Hello World Pass
   0.0003 ( 17.2%)   0.0000 (  0.1%)   0.0003 ( 10.6%)   0.0003 (  3.5%)  Module Verifier
   0.0002 ( 11.6%)   0.0001 (  8.0%)   0.0003 ( 10.2%)   0.0003 (  3.4%)  Natural Loop Information
   0.0001 (  5.6%)   0.0000 (  1.1%)   0.0001 (  3.9%)   0.0001 (  1.3%)  Dominator Tree Construction
   0.0017 (100.0%)   0.0011 (100.0%)   0.0028 (100.0%)   0.0086 (100.0%)  Total

===-------------------------------------------------------------------------===
                                LLVM IR Parsing
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0039 seconds (0.0041 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0031 (100.0%)   0.0008 (100.0%)   0.0039 (100.0%)   0.0041 (100.0%)  Parse IR
   0.0031 (100.0%)   0.0008 (100.0%)   0.0039 (100.0%)   0.0041 (100.0%)  Total

Program ended with exit code: 0

参考:

[1]:Writing an LLVM Pass

[2]:LLVM CookBook

Search

    Post Directory