博客已迁移到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
添加这个文件,命名规则就和其他的后端保持一致好了。
这个文件建议参照着其他后端的写就行了。我添加了两条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]>;
}
需要在这个文件的末尾添加上:
include "llvm/IR/IntrinsicsCpu0.td"
这个文件里面包含了所有后端的关于intrinsic function的文件。
在class Triple里面你会发现注册了好多后端,仿照着添加上我们的cpu0。
需要在这个文件里的多个函数中注册后端,把你的后端添加在合适的位置。我们的cpu0是32位的dsp,添加在了54行、106行、217行、292行、840行、895行、926行。
在这个文件的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
};
}
其实也是仿照着其他后端写的。
这个文件也是跟Intrinsic Function相关的,我添加了如下两行代码:
BUILTIN(__builtin_cpu0_max_qb, "iii", "")
BUILTIN(__builtin_cpu0_min_qb, "iii", "")
在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;
}
}
在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。