2015-04-21 15:52:10
©娜迦 charme版权所有
版权声明:未经许可,请勿转载
什么是pass
LLVM 的Pass框架是LLVM系统的一个很重要的部分。LLVM的优化和转换工作就是由很多个Pass来一起完成的。类似流水线操作一样,每个pass完成特定的优化工作。
在一些特殊的情况下,新插入的pass可能会与其他现有的pass有一定的关联性,所谓的关联体现之一就是:在运行此pass之前必须先运行某pass。类似这种情况,都有相应的接口可以实现。具体参考 Specifying interactions between passes。
另外一种特殊情况就是,我们需要一种更高level的抽象去控制pass,比如将特定功能的一些pass进行分组。一个pass可以被重复注册到不同的分组中。具体参考 Implementing Analysis Groups。
了解了上述两个特殊情况,你可以也就能够理解,为什么我说“类似流水线”了。
但总而言之,llvm Pass架构的可重用性和可控制性都非常好,这允许我们嵌入自己开发的pass或者关闭一些默认提供的pass。
单个pass的开发及调试也很独立,因此你不必担心破坏llvm整体的源码结构,只需要学会操作llvm ir即可实现自己的pass。这些过程都将在本文的后面及以后的系列文章中提及。
pass的分类
所有的pass大致可以分为两类:分析和转换
分析类的pass以提供信息为主,转换类的会修改中间代码。
可以实现的具体的pass类型如下:
通过继承指定的类实现相关的虚函数即可。
以上链接对每一种pass的作用范围及实现途径做了简单的介绍。
如果想更为清晰的掌握LLVM Pass,以下的一些源码文件是你需要简单的浏览一下的。 他们都是与pass相关的一些源码文件,你以后的学习过程中肯定也会有需求去翻阅它们。
Pass.h - /include/llvm/Pass.h
Pass.cpp - /lib/IR/Pass.cpp
PassSupport.h - include/llvm/PassSupport.h
PassAnalysisSupport.h -/include/llvm/PassAnalysisSupport.h
编写pass
这一篇文章中我仅仅是按部就班的完成一个pass的示例,让大家对pass有一个宏观的初步认识,至于内部实现细节以及后续的拓展,现在还不必太在意,我们后续会提到。
在官方的文档以及源码中提供了一个简单的hello pass,在此,我提供一个略微复杂一点的pass作为示例。
在llvm src/lib/Transforms/ 目录下创建Test目录
转到Test目录,创建三个文件
CMakeLists.txt
add_llvm_loadable_module( LLVMTest Test.cpp )
Makefile
LEVEL = ../../.. LIBRARYNAME = LLVMTest LOADABLE_MODULE = 1 USEDLIBS = include $(LEVEL)/Makefile.common
Test.cpp
#include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Instructions.h" using namespace llvm; #define DEBUG_TYPE "test" namespace { struct Test : public FunctionPass { static char ID; // Pass identification, replacement for typeid Test() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { Function *tmp = &F; // 遍历函数中的所有基本块 for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) { // 遍历基本块中的每条指令 for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { // 是否是add指令 if (inst->isBinaryOp()) { if (inst->getOpcode() == Instruction::Add) { ob_add(cast<BinaryOperator>(inst)); } } } } return false; } // a+b === a-(-b) bool ob_add(BinaryOperator *bo) { BinaryOperator *op = NULL; if (bo->getOpcode() == Instruction::Add) { // 生成 (-b) op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); // 生成 a-(-b) op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo); op->setHasNoSignedWrap(bo->hasNoSignedWrap()); op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); } // 替换所有出现该指令的地方 bo->replaceAllUsesWith(op); } }; } char Test::ID = 0; // 注册pass 命令行选项显示为test static RegisterPass<Test> X("test", "Test Pass”);
3. 终端下面直接 make ,生成的LLVMTest.dylib存放在最终工具链旁边的lib目录下。
运行pass
加载pass
./opt -load ../lib/LLVMTest.dylib -help
2. 作用pass到bc文件上(如何生成bc文件,查看这里)
./opt -load ../lib/LLVMTest.dylib -test < test.bc > charge_test.bc
最终效果如下:
上述的例子跟自带的示例一样简单,与自带示例不同的是它实现了一个转换性质的pass。
下一站,针对pass还需要做很多的功课,这一节仅仅是一个开始。
参考文献:
Writing an LLVM Pass - http://llvm.org/docs/WritingAnLLVMPass.html
LLVM’s Analysis and Transform Passes - http://llvm.org/docs/Passes.html