LLVM学习日志12——LLVM学习给x86添加intrinsic function(pseudo instruction)

在include/llvm/IR中定义了llvm IR的函数。

其中Intrinsics.td中描述了全部的指令,但是我基本上看不懂。大概是先定义各个类型函数的class,然后def 调用class进行函数的定义。

IntrinsicsX86.td定义了X86专有函数的定义。比如,let TargetPrefix = "x86" 是规定平台,def后面的是指令,GCCBuiltin的是指令名称,Intrinsic是函数的参数,第一个参数返回值,第二个参数,第三个是参数类型。

let TargetPrefix = "x86" in {  // All intrinsics start with "llvm.x86.".
  def int_x86_ssse3_phadd_w         : GCCBuiltin<"__builtin_ia32_phaddw">,
              Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty,
                         llvm_x86mmx_ty], [IntrNoMem]>;
  def int_x86_ssse3_phadd_w_128     : GCCBuiltin<"__builtin_ia32_phaddw128">,
              Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
                         llvm_v8i16_ty], [IntrNoMem]>;

  def int_x86_ssse3_phadd_d         : GCCBuiltin<"__builtin_ia32_phaddd">,
              Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty,
                         llvm_x86mmx_ty], [IntrNoMem]>;
//还有很多,不复制了
}

我们在Intrinsic中增加两个指令:


let TargetPrefix = "x86" in {

def int_x86_max_qb: GCCBuiltin<"__builtin_x86_max_qb">,
  Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [Commutative]>;

def int_x86_min_qb: GCCBuiltin<"__builtin_x86_min_qb">,
  Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [Commutative]>;
}

然后给clang一个添加,在/tools/clang/include/clang/Basic/BuiltinsX86.def中增加我们添加的指令。这个文件就是对应x86的内置函数的。iii表示的是使用三个寄存器,并且都是整型的。

BUILTIN(__builtin_x86_max_qb, "iii", "") 
BUILTIN(__builtin_x86_min_qb, "iii", "")

再来就是增加具体的编译过程,在/tools/clang/lib/CodeGen/CGBuiltin.cpp中增加解析。

在3792行,为不同的arch选择不同的函数,我们是x86的,所以选择EmitX86BuiltinExpr。在这个函数中,大概在9076行有一个siwtch,为不同的ID选择不同的返回值,我们参照其他指令为自己的指令增加解析。因为我们在Intrinsic中使用了GCCBuiltin(GCCBuiltin相当于是建立指令的一个模板),所以就不用在这里加了。

到这里,我们就完成了在Clang中增加指令的部分。然后我们还需要做的就是在x86后端中增加这条指令具体需要做的事情。

在lib/Target/X86/中增加这个指令的定义。

首先,增加X86的SDNode,在X86ISelLowering.h中找个位置增加上max_qb,这样你就有了X86ISD::max_qb。

然后在X86InstrInfo.td中增加伪指令。

我们先找个例子来看一下(截取了一段):

let mayLoad = 1, mayStore = 1, usesCustomInserter = 1,
    SchedRW = [WriteRMW], Defs = [ESP] in {
  let Uses = [ESP] in
  def RDFLAGS32 : PseudoI<(outs GR32:$dst), (ins),
                   [(set GR32:$dst, (int_x86_flags_read_u32))]>,
                Requires<[Not64BitMode]>;
}

let  ... in 是一个句式,相当于指令运行时的条件(需要满足的状态)。mayLoad等前三个是X86的状态flag,SchedRW是指令的调度信息,Defs,Uses是需要的寄存器等。具体信息可以在include/llvm/Target/里查看

def是定义指令。例子中 RDFLAG32是指令名称。PseudoI是说指令时伪指令,还有I,RI等,都是不同类型的指令。outs ins是输入输出。写到这里发现有些这个例子中没有。重新写一下

def name :I<.(outs),(ins),"  name  这里写的是汇编代码的输出样式",[set  xxx, xxx,xxx]>,Sched<>,TB(指令类型),OpSize32(指令的size);

我们的指令可以这样写:后面一个max_qb是我们刚刚增加的X86ISD

def max_qb : PseudoI< (outs  GR32:$dst), (ins GR32:$src1,GR32:$src2),
	         "max_qb\t {$dst, $src1,$src2}", [(set GR32:$dst, (max_qb GR32:$src1, GR32:$src2))]> ;

再在X86ISelLowering.cpp中增加一个case,大概是在26600行,有很多case,我们需要增加一个我们的case

    case X86ISD::max_qb:             return "X86ISD::max_qb";

 

然后还有一个伪指令具体含义没有定义,再找个合适的位置,增加一个case,写上具体要做的事情。这样就OK了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值