在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。