The LLVM Intermediate Representation

  官方的IR是由Instruction类产生的。IR有三种存在形式:

  1. 内存中的表示:Instruction 类
  2. 硬盘上的节省空间的表示:bitcode文件
  3. 硬盘上的可读文档:LLVM汇编文件

  生成bitcode文件:

$ clang test.c -emit-llvm -c -o test.bc

  生成汇编表示:

$ clang test.c -emit-llvm -S -c -o test.ll

  二者之间可以相互转化:

$ llvm-as test.ll -o test.bc
$ llvm-dis test.bc -o test.ll

  从bitcode文件中提取某个函数:

$ llvm-extract -func=main test.bc -o test-main.bc

IR的内存中表示

  内存中表示的相关头文件在include/llvm/IR目录下,下面是几个最为重要的类:

  1. Module类包含了整个翻译单元中用到的所有数据
  2. Function类包含与函数声明和定义相关的所有对象
  3. BasicBlock类封装了一系列的LLVM指令
  4. Instruction类代表了LLVM IR中的一些基本函数

  可以用IRBuilder<> 来构建IR指令,然后调用SetInsertPoint方法设置要放置的位置。

  可以通过bitcode来生成IR生成器:

$ llc -march=platform test.bc -o test.cpp

IR的优化

  优化bitcode文件:

$ opt -O3 test.bc -o test-O3.bc

  标准的编译时优化:

$ opt -std-compile-opts test.bc -o test-stdc.bc

  标准的链接时优化:

$ llvm-link test1.bc test2.bc test3.bc -o=test.bc
$ opt -std-link-opts test.bc -o test-stdl.bc

  查看pass的占比:

$ clang -Xclang -print-stats -emit-llvm -O1 test.c -c -o test-O1.bc

  查看pass的依赖关系:

$ opt test-O0.ll -debug-pass=Structure -mem2reg -S -o sum-O1.ll

自定义pass

  FnArgCnt输出每个函数的参数个数和函数名:

$ cd <llvm_source_tree>
$ mkdir lib/Transforms/FnArgCnt
$ cd lib/Transforms/FnArgCnt

  FnArgCnt.cpp代码如下:

#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Supprot/raw_ostream.h"

using namspace llvm;

namespace {
    class FnArgCnt : public FunctionPass {
    public:
        static char ID;
        FnArgCnt() : FunctionPass(ID) {}
        
        virtual bool runOnFunction(Function &F) {
            errs() << "FnArgCnt --- ";
            errs() << F.getName() << ": ";
            errs() << F.getArgumentList().size() << '\n';
            return false;
        }
    };
}

char FnArgCnt::ID = 0;
static RegisterPass<FnArgCnt> X("fnargcnt", "Function Argument Count Pass", false, false);

  在相同的目录下创建Makefile:

# Makefile for FnArgCnt pass
# Path to top level of LLVM hierarchy
LEVEL = ../../..

# Name of the library to build 
LIBRARYNAME = LLVMFnArgCnt

# Make the shared library become a loadable module so the tools can
# dlopen/dlsym on the resulting library.
LOADABLE_MODULE = 1

# Include the Makefile implementation stuff
include $(LEVEL)/Makefile.common

  在lib/Transforms/Makefile中添加FnArgCnt到PARALLEL_DIRS变量中:

PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO
    Vectorize Hello ObjCARC FnArgCnt

  在运行./configure 后执行make,生成的共享库会放在Debug+Asserts/lib目录中。通过下列命令执行自定义pass:

$ opt -load /lib/LLVMFnArgCnt.dylib -fnargcnt < test.bc > /dev/null

  

posted @ 2017-09-05 17:22  glob  阅读(372)  评论(0编辑  收藏  举报