天天看點

LLVM學習日志2——PASS嘗試

我主要是學習修改,而不是學習LLVM IR

是以我先學習的是LLVM的pass

pass分analysis pass, transform pass和Utility Passes。

pass有很多種類,用法也不同,詳細的可以看官方說明http://llvm.org/docs/Passes.html#introduction

先嘗試自己編寫一個transform  pass,具體也可以看官方教材http://llvm.org/docs/WritingAnLLVMPass.html

在/llvm/lib/Transforms/下面有很多檔案夾,這些是LLVM自帶的pass,比如官方例子Hello。

先複制整個Hello檔案夾,修改名稱為Readd

接着修改CMakeLists.txt,增加一行,作用是編譯時候編譯Readd檔案夾

add_subdirectory(Readd)
           

進入Readd檔案夾,可以看到三個檔案。

先修改CMakeList.txt,将裡面的hello改成Readd

if( NOT LLVM_REQUIRES_RTTI )
  if( NOT LLVM_REQUIRES_EH )
    set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Readd.exports)
  endif()
endif()

if(WIN32 OR CYGWIN)
  set(LLVM_LINK_COMPONENTS Core Support)
endif()

add_llvm_loadable_module( LLVMReadd
  Readd.cpp

  DEPENDS
  intrinsics_gen
  PLUGIN_TOOL
  opt
  )
           

主要的是修改hello.cpp,先修改檔案名為Readd.cpp。這裡面是pass的功能,是将加法改成減去被加數的負數。

#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 "readd"
 
namespace {
    struct readd : public FunctionPass {
        static char ID; // Pass identification, replacement for typeid
         
        readd() : 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 readd::ID = 0;

static RegisterPass<readd> X("readd", "Readd Pass");
           

第三個檔案是Hello.exports,修改名稱為Readd.exports就行,這個我還不是很明白,這個空檔案夾有什麼作用。

修改完畢,需要重新編譯,在llvm/build中重新make(這裡我不知道要不要make install,因為我安裝了兩個llvm,一個make install了,一個沒有,修改的是那沒有的。)

然後在llvm/build/lib/中出現了LLVMReadd.so,這個名稱在之前那個cmakelist中修改。

下面來測試一下,先建個.c檔案裡面是整數加法

#include <stdio.h>
int main() {
 
int a=1,b=2;
int c;
c=a+b;
  return 0;
}
           

先編譯成.bc檔案,注意,優化不要太高

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

下面這句是使用哪個pass -readd是根據之前的那個Readd.cpp裡這句中(static RegisterPass<readd> X("readd", "Readd Pass");)X括号裡的确定的,是說用pass裡那個功能,因為一個pass可以有多個功能,而這個隻有一個。

opt -load ../build/lib/LLVMReadd.so -readd <test.bc> chtest.bc    

轉化成可視的.ll

llvm-dis chtest.bc

可以從LLVM IR看到變化。

如果編寫的是全局的pass,而不是opt調用的,那就需要增加幾個步驟。

首先是初始化,llvm/InitializePasses.h的頭檔案中增加自己的pass

void initializeMYADCEPass(PassRegistry&);

然後在include/llvm-c/scalar.h/Transform/scalar.h檔案下添加Pass的條目

void LLVMAddMYAggressiveDCEPass(LLVMPassManagerRef PM);

在include/llvm/Transform/scalar.h檔案中,在llvm命名空間添加Pass的條目:

FunctionPass *createMYAggressiveDCEPass();

在lib/Transforms/Scalar/scalar.cpp檔案的兩個地方添加Pass的條目,并在void llvm::initializeScalarOpts(PassRegistry &Registry)函數中添加如下代碼:

initializeMergedLoadStoreMotionPass(Registry); //已存在于檔案

initializeMYADCEPass(Registry); //增加此行

initializeNaryReassociatePass(Registry); //已存在于檔案

...

...

void LLVMAddMemCpyOptPass(LLVMPassManagerRef PM) {

unwrap(PM)->add(createMemCpyOptPass());

}

// 增加以下代碼

void LLVMAddMYAggressiveDCEPass(LLVMPassManagerRef PM) {

unwrap(PM)->add(createMYAggressiveDCEPass());

}

void LLVMAddPartiallyInlineLibCallsPass(LLVMPassManagerRef PM) {

unwrap(PM)->add(createPartiallyInlineLibCallsPass());

}

繼續閱讀