在LLVM中编写pass的详细教程(3)

来源:互联网 发布:淘宝网闲余非要下载吗 编辑:程序博客网 时间:2024/04/28 20:26

LLVM是一个自由软件项目,它是一种编译器基础设施,以C++写成。它的发展起源于2000年伊利诺伊大学厄巴纳-香槟分校(UIUC)的维克拉姆·艾夫(Vikram Adve)与其第一博士生克里斯·拉特纳(Chris Lattner)的研究,彼时他们想要为所有静态及动态语言创造出动态的编译技术。


LLVM的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,但现在这个项目的范围早已大大超越其最初的意思。当前,LLVM已经发展成为被用于开发从编译器前端到后端的“一套模块及可重用的编译器及工具链技术的集合”("collection of modular and reusable compiler and toolchain technologies")。

2005年,苹果电脑雇用了克里斯·拉特纳及他的团队为苹果电脑开发应用程序系统,LLVM为现今Mac OS X及iOS开发工具的一部分,Xcode开发环境的内核使用的即是LLVM。因LLVM对产业的贡献,ACM于2012年将ACM软件系统奖授与Adve、Lattner及Evan Cheng。

----------------------------------------------------------------------------------------------------------------------------------------

在前面的文章中,我们已经介绍了通过编写pass对函数中的Basic Blocks进行遍历的方法,本文将介绍利用pass对程序中的操作码(Operation Code, OPCode)进行计数的方法。


跟之前一样,假设你的LLVM之安装目录为 ... .../llvm,那么你首先在路径 ... .../llvm/lib/Transforms 中创建一个子文件夹,例如名字叫做OpcodeCounter。然后在此文件夹下创建如下三个文件:CMakeLists.txt、OpcodeCounter.exports、OpcodeCounter.cpp。因为LLVM中作为pass的一个示例,提供了另外一个现成的pass,即在Transforms中的Hello文件夹,你可以从该文件夹下面把三个名为CMakeLists.txt、Hello.exports、Hello.cpp的文件拷贝到OpcodeCounter文件夹中并修改相应的文件名。


然后修改上层目录(即Transforms)中的CMakeLists.txt,在其末尾添加:add_subdirectory(OpcodeCounter)。然后修改... .../llvm/lib/Transforms/OpcodeCounter 中的CMakeLists.txt。注意这个文件是你从... .../llvm/lib/Transforms/Hello 中拷贝过来的。You must set up a build script that will compile the source code for the new pass,具体来说,你需要把其中出现了三次的Hello,都修改成OpcodeCounter,修改后该文件的内容如下:

# 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}/OpcodeCounter.exports)  endif()endif()if(WIN32 OR CYGWIN)  set(LLVM_LINK_COMPONENTS Core Support)endif()add_llvm_loadable_module( LLVMOpcodeCounter  OpcodeCounter.cpp  DEPENDS  intrinsics_gen  PLUGIN_TOOL  opt  )
然后,需要编写pass文件的具体内容。这个pass文件其实就是一个.cpp文件,就当前这个例子而言,我们要做的就是编辑OpcodeCounter.cpp的内容。该文件内容如下:
#include "llvm/IR/Function.h"#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h"using namespace llvm;namespace {    struct OpcodeCounter : public FunctionPass {    static char ID; // Pass identification, replacement for typeid    OpcodeCounter() : FunctionPass(ID) {}    bool runOnFunction(Function &F) override {        std::map<std::string, int> opcode_map;    errs() << "Function name: ";    errs() << F.getName() << '\n';    for(Function::iterator bb = F.begin(), e = F.end(); bb!=e; bb++)    {    for(BasicBlock::iterator i = bb->begin(), i2 = bb->end(); i!=i2; i++)    {    if(opcode_map.find(i->getOpcodeName()) == opcode_map.end())                    opcode_map[i->getOpcodeName()] = 1;                else                    opcode_map[i->getOpcodeName()] += 1;    }    }        std::map<std::string, int> :: iterator p_start = opcode_map.begin();        std::map<std::string, int> :: iterator p_final = opcode_map.end();        while(p_start != p_final)        {            outs()<< p_start->first << " ::: " << p_start->second <<"\n";            p_start++;        }        opcode_map.clear();    return false;    }  };}char OpcodeCounter::ID = 0;static RegisterPass<OpcodeCounter> X("OpcodeCounter", "Count the number of opcode for every type");
接下来要做的就是重新bulid LLVM。进入... .../llvm/build文件夹下面,直接使用make。整个过程大概需要几分钟的样子。然后来试用一下上面编写的Pass,为此你需要在你期望的位置(例如Desktop)上建立一个新的测试文件,例如使用上一篇文章《在LLVM中编写pass的详细教程(2)》 中的名为test.c的文件。在使用Clang命令编译生成.ll文件之后,再使用下面的命令来执行上面编写的pass:

opt -load /Users/fzuo/llvm/build/lib/LLVMOpcodeCounter.dylib -OpcodeCounter test.ll

然后,你便会得到如下输出:

WARNING: You're attempting to print out a bitcode file.This is inadvisable as it may cause display problems. Ifyou REALLY want to taste LLVM bitcode first-hand, youcan force output with the `-f' option.Function name: addadd ::: 1alloca ::: 2load ::: 2ret ::: 1store ::: 2Function name: mainalloca ::: 2br ::: 3call ::: 4icmp ::: 1load ::: 2ret ::: 1store ::: 1
分析上面的输出,对比之前文章中给出的IR文件,便可以知道我们的pass对每个函数进行了分析,然后统计了其中各个操作码出现的次数。


【本系列文章目录】

  • 在LLVM中编写Pass的详细教程(1):一个Hello World的Pass
  • 在LLVM中编写Pass的详细教程(2):遍历一个函数中的Basic Blocks
  • 在LLVM中编写Pass的详细教程(3):对程序中的OpCode进行计数
  • 在LLVM中编写Pass的详细教程(4):def use 与 use def
  • 在LLVM中编写Backend Pass的详细教程(1)
  • 在LLVM中编写Backend Pass的详细教程(2)


(本文完)
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为手机里突然有个pp助手怎么办 华为手机与电脑连接不上怎么办 买房交了首付贷不了款怎么办 手机买贵了实体店不肯退怎么办 在实体店里手机买贵了怎么办 红米手机开启不了安装系统怎么办? 捡个荣耀8双清后要账号怎么办 荣耀7x升级8.0后耗电快怎么办 手机提示当前为耳机播放模式怎么办 华为手机进水了显示耳机模式怎么办 苹果6s突然变成耳机模式怎么办 华为手机出现耳机标志没声音怎么办 苹果手机微信变成耳机模式怎么办 5s不能用4g网络怎么办 华为麦芒四手机系统乱了好卡怎么办 信翼路由器登录密码忘了怎么办 苹果手机电信4g信号变3g怎么办 苹果7手机4g变3g怎么办 朵唯v3逆客手机不支持计步怎么办 移动卡升级4g后网络不好怎么办 电信办宽带送的手机卡不用了怎么办 移动华为悦盒遥控器丢了怎么办 移动签了两年套餐不想用了怎么办 华为手机隐私空间密码忘记了怎么办 华为的隐私空间密码忘记了怎么办 格力新机没密码开不了怎么办 百度下载谷歌浏览器网页错误怎么办 华为手机进水开不了机怎么办开 华为7x金属外壳掉漆了怎么办 华为麦芒6连接蓝牙音响卡顿怎么办 华为芒麦6恢复出厂设置怎么办 华为麦芒4下拉通知栏没反应怎么办 怎么看华为麦芒6信号差怎么办 华为手机锁屏密码忘了怎么办 苹果手机进水后手机卡无服务怎么办 摩拜单车绑定的手机号注销了怎么办 摩拜单车注册的手机号注销了怎么办 摩拜单车注册手机号换了怎么办 被手机店骗话费送合约机怎么办 机蜜租赁的手机丢了怎么办 合约机返话费手机掉了怎么办