Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for source code of __builtin_avr_delay_cycles called by _delay_ms in avr-gcc

Tags:

delay

gcc

avr-gcc

I was investigating the delay_ms function of avr-gcc. In delay.h I found its definition:

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
    ...
}

I am interested in how the __builtin_avr_delay_cycles function looks like internally and where it is defined? Where can I find the source?

like image 513
arminb Avatar asked Mar 10 '23 01:03

arminb


1 Answers

As said in my comment to this very question on electronics.SE:

Compiler builtins are kinda funky to find, always, because they are not just C functions, but things that get inserted while parsing/compiling the code (at various levels of abstraction from the textual representation of the code itself. compiler theory stuff). What you're looking for is the function avr_expand_builtin in the GCC source tree. There's a case AVR_BUILTIN_DELAY_CYCLES in there. Look for what happens there.

Which is:

/* 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;
      }
…

thus, the function you're looking for is avr_expand_delay_cycles in the same file:

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--;
    }
}

Of biggest interest here is that this modifies a node in the Abstract Syntax Tree, and emits instructions there.

like image 105
Marcus Müller Avatar answered Apr 30 '23 15:04

Marcus Müller