从__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即可生成字符串形式的汇编指令。