一键重新编译Pass脚本
因为每次都要重新cmake和make,不断切换目录很繁琐,于是自己写了一个makefile文件提升效率
.PHONY=make so all
BUILD_PATH=/home/happy/Documents/llvm8_build
SOURCE_PATH=/home/happy/Documents/llvm-8.0.0.src/lib/Transforms
all:cmake so
cmake:
cd $(BUILD_PATH) && cmake -G "Unix Makefiles" --enable-optimized --enable-targets=host-only -DCMAKE_BUILD_TYPE=Release ../llvm-8.0.0.src
so:
cd $(BUILD_PATH)/lib/Transforms && make
edit:
@ gedit $(SOURCE_PATH)/mypass/Mypass.cpp
show_source:
nautilus $(SOURCE_PATH)/mypass
show:
nautilus $(BUILD_PATH)/lib
path:
-@ echo $(SOURCE_PATH)/../Mypass.so
gll:
clang -emit-llvm -S 1.c
opt:
opt -load=/home/happy/Documents/llvm8_build/lib/Mypass.so -Mypass < 1.ll >/dev/null
使用
- 重新生成cmake
make cmake
- 编译pass文件到so文件
make so
- 一键重新生成pass(包括cmake的生成)
make
- 打开生成后的so文件目录
make show
只要修改相应的目录和文件名即可使用。
vscode开发环境配置
修改相应的目录,在Windows中安装clang,并将llvm的inlcude下的文件夹(头文件)拷贝到某个目录即可
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"E:\\LLVM_Project",
"E:\\LLVM_Project\\llvm\\**",
"E:\\LLVM_Project\\llvm-c\\**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"compilerPath": "D:\\LLVM\\bin\\clang.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
pass的分类
所有的pass大致可以分为两类:分析和转换
分析类的pass以提供信息为主,转换类的会修改中间代码。
可以实现的具体的pass类型如下:
- ImmutablePass
- ModulePass
- CallGraphSCCPass
- FunctionPass
- LoopPass
- RegionPass
- BasicBlockPass
- MachineFunctionPass
通过继承指定的类实现相关的虚函数即可。
以上链接对每一种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片段
指令遍历和替换
此处遍历所有指令并将加法指令(a+b)替换为减法a-(-b)
#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 "mypass"
namespace {
struct Mypass : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
Mypass() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
Function *tmp = &F;
// 遍历函数中的所有基本块
for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) {
// 遍历基本块中的每条指令
errs() << "I am running on a block...\n";
for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) {
// 是否是add指令
errs() << "I am running in Instruction...\n";
if (inst->isBinaryOp()) {
errs() << "Find OP\n";
if (inst->getOpcode() == Instruction::Add) {
errs() << "Find ADD instruction\n";
ob_add(cast<BinaryOperator>(inst));
}
}
}
}
return false;
}
// a+b === a-(-b)
bool ob_add(BinaryOperator *bo) {
BinaryOperator *op = NULL;
errs() << "Modify~~\n";
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);
errs() << "Modify2\n";
op->setHasNoSignedWrap(bo->hasNoSignedWrap());
op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
}
errs() << "Modify3\n";
// 替换所有出现该指令的地方
bo->replaceAllUsesWith(op);
errs() << "Modify Finish\n";
return true;
}
};
}
char Mypass::ID = 0;
//注册命令行选项Mypass
static RegisterPass<Mypass> X("Mypass", "DIY pass");
执行效果
原来的加法
%5 = load i32, i32* %2, align 4
%6 = load i32, i32* %3, align 4
%7 = add nsw i32 %5, %6
store i32 %7, i32* %4, align 4
pass后
%5 = load i32, i32* %2, align 4
%6 = load i32, i32* %3, align 4
%7 = sub i32 0, %6
%8 = sub nsw i32 %5, %7
%9 = add nsw i32 %5, %6
store i32 %8, i32* %4, align 4
转载于:https://www.jianshu.com/p/b5b9310a8650