1. 程式人生 > >在llvm的clang中新增新的後端和Intrinsic function

在llvm的clang中新增新的後端和Intrinsic function

部落格已遷移到http://www.zhaochaoxing.cn/blog/?p=51
本文記錄一下如何在llvm的clang原始碼中新增一種新的後端(暫時命名為cpu0),並在其中新增Intrinsic function。

一、 涉及到的檔案列表:

./src/include/llvm/IR/IntrinsicsCpu0.td
./src/include/llvm/IR/Intrinsics.td
./src/include/llvm/ADT/Triple.h
./src/lib/Support/Triple.cpp
./src/tools/clang/include/clang/Basic/TargetBuiltins.h
./src/tools/clang/include/clang/Basic/BuiltinsCpu0.def
./src/tools/clang/lib/CodeGen/CGBuiltin.cpp
./src/tools/clang/lib/Basic/Targets.cpp

1、./src/include/llvm/IR/IntrinsicsCpu0.td

新增這個檔案,命名規則就和其他的後端保持一致好了。
這個檔案建議參照著其他後端的寫就行了。我添加了兩條Intrinsic Function。

def cpu0_32_ty : LLVMType<i32>;

let TargetPrefix = "cpu0" in {

def int_cpu0_max_qb: GCCBuiltin<"__builtin_cpu0_max_qb">,
  Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [Commutative]>;

def
int_cpu0_min_qb:
GCCBuiltin<"__builtin_cpu0_min_qb">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [Commutative]>; }

2、 ./src/include/llvm/IR/Intrinsics.td

需要在這個檔案的末尾新增上:

include "llvm/IR/IntrinsicsCpu0.td"

這個檔案裡面包含了所有後端的關於intrinsic function的檔案。

3、 ./src/include/llvm/ADT/Triple.h

在class Triple裡面你會發現註冊了好多後端,仿照著新增上我們的cpu0。

4、 ./src/lib/Support/Triple.cpp

需要在這個檔案裡的多個函式中註冊後端,把你的後端新增在合適的位置。我們的cpu0是32位的dsp,新增在了54行、106行、217行、292行、840行、895行、926行。

5、 ./src/tools/clang/include/clang/Basic/TargetBuiltins.h

在這個檔案的85行添加了如下程式碼:

  /// \brief cpu0 builtins
  namespace Cpu0 {
    enum {
        LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsCpu0.def"
        LastTSBuiltin
    };  
  }

其實也是仿照著其他後端寫的。

6、 ./src/tools/clang/include/clang/Basic/BuiltinsCpu0.def

這個檔案也是跟Intrinsic Function相關的,我添加了如下兩行程式碼:

BUILTIN(__builtin_cpu0_max_qb, "iii", "") 
BUILTIN(__builtin_cpu0_min_qb, "iii", "")

7、 ./src/tools/clang/lib/CodeGen/CGBuiltin.cpp

在1705行添加了兩行程式碼如下:

case llvm::Triple::cpu0:
     return EmitCpu0BuiltinExpr(BuiltinID,E);

在5666行左右找個合適的地方添加了如下程式碼:

Value *CodeGenFunction::EmitCpu0BuiltinExpr(unsigned BuiltinID,
                                           const CallExpr *E) {

    switch (BuiltinID)
    {    
    case Cpu0::BI__builtin_cpu0_max_qb:{
                            Value *F =CGM.getIntrinsic(Intrinsic::cpu0_max_qb);
                            return Builder.CreateCall(F);
    }    

    case Cpu0::BI__builtin_cpu0_min_qb:{
                            Value *F =CGM.getIntrinsic(Intrinsic::cpu0_min_qb);
                            return Builder.CreateCall(F);
    }    
    default: return nullptr;
    }    
}

8、 ./src/tools/clang/lib/Basic/Targets.cpp

在6337行添加了兩行程式碼:

case llvm::Triple::cpu0:
           return new Cpu0TargetInfo(Triple);

二、 測試

關於intrinsic function的測試程式碼:

//test.c
void test_main()
{
    int a = 5;
    int b = 10; 
    int c,d;
    c = __builtin_cpu0_max_qb(a, b); 
    c = __builtin_cpu0_min_qb(a, b); 

}

make clang之前先clean一下,然後編譯出clang之後,用clang來編譯測試檔案test.c。會在.bc檔案中產生中間程式碼。

%3 = call i32 @llvm.cpu0.max.qb(i32 %1, i32 %2)
%6 = call i32 @llvm.cpu0.min.qb(i32 %4, i32 %5)

三、 總結

至此,完成了在llvm的clang中新增一個新的後端,並在後端中添加了兩條intrinsic function。