LLVM Pass 简介(1)

LLVM Pass框架是LLVM系统的重要组成部分,因为LLVM Pass负责LLVM编译器绝大部分的工作。 构成编译器的Pass执行各种转换和优化,在转换中使用的前边Pass的分析结果。所有的类实现都必须继承至Pass基类,一般来说可供使用的Pass类型一般包括 ModulePass , CallGraphSCCPassFunctionPass , or LoopPass, or RegionPass 这几个类。Function/Module/Loop/Region这几个Pass都不难理解,主要是 CallGraphSCCPass这个,CallGraph顾名思义,SCC(Strongly-Connected-Component)是强联通分量,这个从llvm/ADT/SCCIterator.h中定义的scc_iterator定义中可以得到,是一个DFS遍历顺序。

下边介绍了一段对CallGraphSCC中的runOnFunction进行遍历的代码:

 1  std::stack<scc_iterator<Function*> > sccs;
 2     for(scc_iterator<Function*> SCCI=scc_begin(F),SCCE=scc_end(F);SCCI!=SCCE;++SCCI)
 3         sccs.push(SCCI);
 4 
 5     //按照顺序遍历强连通分量(SCC)
 6     unsigned sccNum=0;
 7     while(!sccs.empty()){
 8         scc_iterator<Function*> SCCI=sccs.top();
 9         sccs.pop();
10         std::vector<BasicBlock*> & nextSCC=*SCCI;
11         errs()<<"
 SCC#"<<++sccNum<<":";
12          //遍历SCC中的块(DFS顺序 )
13         std::vector<BasicBlock*>::const_iterator I=nextSCC.begin(),E=nextSCC.end();
14         for(--E,--I;E!=I;--E){
15             errs()<<(*E)->getName()<<",";
16         }
17      }
View Code

下边介绍如何添加一个最简单的Pass。该Hello pass位于lib/Transform/Hello文件夹下。

添加在lib/Transforms/CMakeLists.txt:

add_subdirectory(Hello)

在Hello文件夹下新建CMakeLists.txt,内容如下:

add_llvm_library( LLVMHello MODULE
  Hello.cpp

  PLUGIN_TOOL
  opt
  )

 新建Hello.cpp,内容

//===- Hello.cpp - Example code from "Writing an LLVM Pass" ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements two versions of the LLVM "Hello World" pass described
// in docs/WritingAnLLVMPass.html
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <string>
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
using namespace llvm;

#define DEBUG_TYPE "hello"

STATISTIC(HelloCounter, "Counts number of functions greeted");
namespace {
  // Hello - The first implementation, without getAnalysisUsage.
  struct Hello : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    Hello() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {
      ++HelloCounter;
      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '
';
      return false;
    }
  };
}

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

这里说点不一样的,这是旧版本的LLVM中的Pass添加方式,现在只有部分Machine部分采用这种Pass管理方式,新的PassManager使用方式https://llvm.org/docs/NewPassManager.html

在正常编译后,build/bin/目录下出现了clang/llvm-dis等各种binary文件,而build/lib目录下可以找到LLVMHello.so,是刚才生成的。

采用的测试代码hello.c

 1 int foo(int a, int b, int *c) {
 2     int ret = 0;
 3     if (a > b) {
 4         ret = a;
 5     } else {
 6         ret = b;
 7     }
 8     for (int temp = 0; temp < 100; ++temp) {
 9         *c = (*c + temp);
10     }
11     return ret;
12 }
13 
14 
15 int main() {
16     int a = 1, b = 2;
17     int c = 0;
18     int d = foo(a, b, &c);
19     return 0;
20 }

使用./bin/clang -c -emit-llvm hello.c -o hello.bc 生成bc文件

 opt -load lib/LLVMHello.so -hello < hello.bc > /dev/null 进行测试

测试结果如图:

本教程来自于:https://llvm.org/docs/WritingAnLLVMPass.html

http://stackoverflow.com/questions/18650999/topological-sorting-of-basic-blocks-in-llvm

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