LLVM Pass 简介(1)
LLVM Pass框架是LLVM系统的重要组成部分,因为LLVM Pass负责LLVM编译器绝大部分的工作。 构成编译器的Pass执行各种转换和优化,在转换中使用的前边Pass的分析结果。所有的类实现都必须继承至Pass基类,一般来说可供使用的Pass类型一般包括 ModulePass , CallGraphSCCPass, FunctionPass , or LoopPass, or RegionPass 这几个类。Function/Module/Loop/Region这几个Pass都不难理解,主要是 CallGraphSCCPass这个,CallGraph顾名思义,SCC(Strongly-Connected-Component)是强联通分量,这个从llvm/ADT/SCCIterator.h中定义的scc_iterator定义中可以得到,是一个DFS遍历顺序。
下边介绍了一段对CallGraphSCC中的runOnFunction进行遍历的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()<<"\n 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 }
下边介绍如何添加一个最简单的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()) << '\n'; 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