从__builtin_ia32_lzcnt_u16到lzcntw指令

内联函数的原始定义

gcc\config\i386\i386-builtin.def

/* LZCNT */
BDESC (OPTION_MASK_ISA_LZCNT, CODE_FOR_lzcnt_hi, "__builtin_ia32_lzcnt_u16", IX86_BUILTIN_LZCNT16, UNKNOWN, (int) UINT16_FTYPE_UINT16)
/* Same as above, for backward compatibility.  */
BDESC (OPTION_MASK_ISA_LZCNT, CODE_FOR_lzcnt_hi, "__builtin_clzs", IX86_BUILTIN_CLZS, UNKNOWN, (int) UINT16_FTYPE_UINT16)

builtin函数code的声明

可以看到,通过宏将第四列定义为C语言中的枚举类型,这个是builtin函数的标识符(codeid),这个codeid和字符串形式的函数名一一对应。

/* Codes for all the SSE/MMX builtins.  Builtins not mentioned in any
   bdesc_* arrays below should come first, then builtins for each bdesc_*
   array in ascending order, so that we can use direct array accesses.  */
enum ix86_builtins
{
//……
  /* All the remaining builtins are tracked in bdesc_* arrays in
     i386-builtin.def.  Don't add any IX86_BUILTIN_* enumerators after
     this point.  */
#define BDESC(mask, icode, name, code, comparison, flag) \
  code,
#define BDESC_FIRST(kind, kindu, mask, icode, name, code, comparison, flag) \
  code,									    \
  IX86_BUILTIN__BDESC_##kindu##_FIRST = code,
#define BDESC_END(kind, next_kind)

#include "i386-builtin.def"

builtin函数可能直接对应的机器指令

该工具会扫描机器描述文件gcc\config\i386\i386.md,为其中定义的每一条指令定义一个对应的CODE_FOR_XXXX的枚举值,并且它的值指向该机器指令集的下标。
gcc\gencodes.c

static void
gen_insn (md_rtx_info *info)
{
  const char *name = XSTR (info->def, 0);
  int truth = maybe_eval_c_test (XSTR (info->def, 2));

  /* Don't mention instructions whose names are the null string
     or begin with '*'.  They are in the machine description just
     to be recognized.  */
  if (name[0] != 0 && name[0] != '*')
    {
      if (truth == 0)
	printf (",\n   CODE_FOR_%s = CODE_FOR_nothing", name);
      else
	printf (",\n  CODE_FOR_%s = %d", name, info->index);
    }
}

例如,i386.md中的"<lt_zcnt>_hi"将会生成一个CODE_FOR_lzcnt_hi的枚举变量,并且它的值是该指令对应指令集数组struct insn_data_d insn_data[]的下标。

(define_insn "<lt_zcnt>_hi"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(unspec:HI
	  [(match_operand:HI 1 "nonimmediate_operand" "rm")] LT_ZCNT))
   (clobber (reg:CC FLAGS_REG))]
  ""
  "<lt_zcnt>{w}\t{%1, %0|%0, %1}"
  [(set_attr "type" "<lt_zcnt_type>")
   (set_attr "prefix_0f" "1")
   (set_attr "prefix_rep" "1")
   (set_attr "mode" "HI")])

从builtin函数到rtx表达式

根据字符串形式函数,找到对应builtin_description对象,从中找到对应的机器指令,调用机器指令的insn_gen_fn函数,为该指令生成对应的rtx表达式。注意,不是直接生成会汇编代码,因为编译器需要根据语义进行优化和上下文分析。

static rtx
ix86_expand_args_builtin (const struct builtin_description *d,
			  tree exp, rtx target)
{
//……
  enum insn_code icode = d->icode;
//……
      pat = GEN_FCN (icode) (real_target, args[0].op);
//……
}

insn-emit.c
1882 /* ../.././gcc/config/i386/i386.md:12950 */
1883 rtx
1884 gen_lzcnt_hi (rtx operand0 ATTRIBUTE_UNUSED,
1885 rtx operand1 ATTRIBUTE_UNUSED)
1886 {
1887 return gen_rtx_PARALLEL (VOIDmode,
1888 gen_rtvec (2,
1889 gen_rtx_SET (operand0,
1890 gen_rtx_UNSPEC (HImode,
1891 gen_rtvec (1,
1892 operand1),
1893 85)),
1894 gen_hard_reg_clobber (CCmode, 17)));
1895 }

从rtx到汇编

如果gen_lzcnt_hi返回的rtx没有被修改(通常也不会),那么最后从rtx到机器指令的时候还会再次匹配到这个机器指令,然后调用它的insn_output_fn即可生成字符串形式的汇编指令。

posted on 2022-07-28 20:19  tsecer  阅读(128)  评论(0编辑  收藏  举报

导航