在AVR-GCC中寻找_delay_ms调用的__builtin_avr_delay_cycles的源代码

arm*_*inb 3 gcc delay avr-gcc

我正在研究的delay_ms功能avr-gcc。在delay.h我发现它的定义:

void _delay_ms(double __ms)
{
    double __tmp ;
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
    !defined(__DELAY_BACKWARD_COMPATIBLE__) &&       \
    __STDC_HOSTED__

    uint32_t __ticks_dc;
    extern void __builtin_avr_delay_cycles(unsigned long);
    __tmp = ((F_CPU) / 1e3) * __ms;

    #if defined(__DELAY_ROUND_DOWN__)
        __ticks_dc = (uint32_t)fabs(__tmp);

    #elif defined(__DELAY_ROUND_CLOSEST__)
        __ticks_dc = (uint32_t)(fabs(__tmp)+0.5);

    #else
          //round up by default
          __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
    #endif

    __builtin_avr_delay_cycles(__ticks_dc);

#else
    ...
}
Run Code Online (Sandbox Code Playgroud)

我对__builtin_avr_delay_cycles函数的内部外观和定义位置感兴趣吗?在哪里可以找到来源?

Mar*_*ler 6

正如我在对电子学这个问题的评论中所说:

总是可以找到编译器内置函数,因为它们不仅是C函数,而且是在解析/编译代码时插入的东西(从代码本身的文本表示形式到抽象层次的不同层次,都是编译器理论的东西)。您要查找的是GCC源代码树中的avr_expand_builtin函数。那里有一个案例AVR_BUILTIN_DELAY_CYCLES。寻找那里发生了什么。

这是:

/* Implement `TARGET_EXPAND_BUILTIN'.  */
/* Expand an expression EXP that calls a built-in function,
   with result going to TARGET if that's convenient
   (and in mode MODE if that's convenient).
   SUBTARGET may be used as the target for computing one of EXP's operands.
   IGNORE is nonzero if the value is to be ignored.  */

static rtx
avr_expand_builtin (tree exp, rtx target,
                    rtx subtarget ATTRIBUTE_UNUSED,
                    machine_mode mode ATTRIBUTE_UNUSED,
                    int ignore)
{
  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
  const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
  unsigned int id = DECL_FUNCTION_CODE (fndecl);
  const struct avr_builtin_description *d = &avr_bdesc[id];
  tree arg0;
  rtx op0;

  gcc_assert (id < AVR_BUILTIN_COUNT);

  switch (id)
    {
    case AVR_BUILTIN_NOP:
      emit_insn (gen_nopv (GEN_INT (1)));
      return 0;

    case AVR_BUILTIN_DELAY_CYCLES:
      {
        arg0 = CALL_EXPR_ARG (exp, 0);
        op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);

        if (!CONST_INT_P (op0))
          error ("%s expects a compile time integer constant", bname);
        else
          avr_expand_delay_cycles (op0);

        return NULL_RTX;
      }
…
Run Code Online (Sandbox Code Playgroud)

因此,您要查找的功能avr_expand_delay_cycles在同一文件中:

static void
avr_expand_delay_cycles (rtx operands0)
{
  unsigned HOST_WIDE_INT cycles = UINTVAL (operands0) & GET_MODE_MASK (SImode);
  unsigned HOST_WIDE_INT cycles_used;
  unsigned HOST_WIDE_INT loop_count;

  if (IN_RANGE (cycles, 83886082, 0xFFFFFFFF))
    {
      loop_count = ((cycles - 9) / 6) + 1;
      cycles_used = ((loop_count - 1) * 6) + 9;
      emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode),
                                     avr_mem_clobber()));
      cycles -= cycles_used;
    }

  if (IN_RANGE (cycles, 262145, 83886081))
    {
      loop_count = ((cycles - 7) / 5) + 1;
      if (loop_count > 0xFFFFFF)
        loop_count = 0xFFFFFF;
      cycles_used = ((loop_count - 1) * 5) + 7;
      emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode),
                                     avr_mem_clobber()));
      cycles -= cycles_used;
    }

  if (IN_RANGE (cycles, 768, 262144))
    {
      loop_count = ((cycles - 5) / 4) + 1;
      if (loop_count > 0xFFFF)
        loop_count = 0xFFFF;
      cycles_used = ((loop_count - 1) * 4) + 5;
      emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode),
                                     avr_mem_clobber()));
      cycles -= cycles_used;
    }

  if (IN_RANGE (cycles, 6, 767))
    {
      loop_count = cycles / 3;
      if (loop_count > 255)
        loop_count = 255;
      cycles_used = loop_count * 3;
      emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode),
                                     avr_mem_clobber()));
      cycles -= cycles_used;
    }

  while (cycles >= 2)
    {
      emit_insn (gen_nopv (GEN_INT (2)));
      cycles -= 2;
    }

  if (cycles == 1)
    {
      emit_insn (gen_nopv (GEN_INT (1)));
      cycles--;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里最令人感兴趣的是,它修改了抽象语法树中的一个节点,并在那里发出指令。