avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] noreturn, naked & nonret function attributes


From: Kang Tin LAI
Subject: [avr-gcc-list] noreturn, naked & nonret function attributes
Date: Sun, 17 Feb 2002 16:43:11 +0800

Dear all,

A) With or without "noreturn" function attribute, no change of prologue
and epilogue, nothing help to the code size. Attempted to add a codes to
test the "noreturn" attribute from avr.c, but always return failed, GCC
traps all the test of "noreturn" inside the share portion codes, so
nothing can be done in machine specific codes with "noreturn" attribute.

B) With "naked" function attribute, it saves quite lot of codes, but
there is a problem, if you have local variables and you access the
address of them, example:

   __attribute__ ((naked)) void func(void)
  {
     int i;
     while (1) {
       fxn(&i);
     }
  }

then you will get a problem. To access address of i, you need the frame
pointer, prologue codes setup the frame pointer for you. But with
"naked" attribute, no prologue at all.

For certain scenario, such as some rtos, task is a endless loop function
actually, never return. As in AvrX, task is a "naked" attribute
function, so no frame pointer is setup for the task. (ie., inside the
task of AvrX, you may not have any code dealing with address or playing
with frame pointer).

There is no problem using "naked" if you have only FEW automatics (autos
will be put in the registers) with simple data type and no lvalve access
of automatics. Anyway, it should not be here with this restriction.

C) I attempted to make a change to gcc by adding a new attribute -
"nonret" (non-return). Attached is the patch for this. Patch is based on
lastest release gcc 3.0.3., however, any other version should be no
problem, patch only acts on avr.c only. (actually, file date of avr.c is
last year June in 3.0.3 release).

With the "nonret" attribute:

  1) no register will be preserved onto the stack, because we never
return,
     saving any register is meaningless and code space consuming.
  2) local var frame and frame pointer will be setup as usual.
  3) no epilogue (save code space).

Unpack gcc, cd to ./gcc-3.0.3/gcc/config/avr, patch avr.c directly with
the patch attached with the command: patch < patch-avr.c-20020217, then
recompile gcc.

Layout of function with "nonret" attribute:
    __attribute__ ((nonret)) void task1(void)
    {
       local variables;
       ....
       while (1) {
             .......
             .......
       }
    }

If you confirm that your code never touch the frame pointer, choose
"naked" because of the most code space saving, else "nonret" as needs.

Cheers!

Kang Tin LAI
*** avr.c.orig  Thu Jun 28 05:35:37 2001
--- avr.c       Sun Feb 17 14:18:57 2002
***************
*** 43,48 ****
--- 43,49 ----
  #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
  
  static int    avr_naked_function_p PARAMS ((tree));
+ static int    nonret_function_p    PARAMS ((tree));
  static int    interrupt_function_p PARAMS ((tree));
  static int    signal_function_p    PARAMS ((tree));
  static int    sequent_regs_live    PARAMS ((void));
*************** avr_naked_function_p (func)
*** 290,300 ****
  
    if (TREE_CODE (func) != FUNCTION_DECL)
      abort ();
!   
    a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
  /* Return nonzero if FUNC is an interrupt function as specified
     by the "interrupt" attribute.  */
  
--- 291,316 ----
  
    if (TREE_CODE (func) != FUNCTION_DECL)
      abort ();
! 
    a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
+ /* Return non-zero if FUNC is a noreturn function.  */
+ 
+ static int
+ nonret_function_p (func)
+      tree func;
+ {
+   tree a;
+ 
+   if (TREE_CODE (func) != FUNCTION_DECL)
+     return 0;
+ 
+   a = lookup_attribute ("nonret", DECL_MACHINE_ATTRIBUTES (func));
+   return a != NULL_TREE;
+ }
+ 
  /* Return nonzero if FUNC is an interrupt function as specified
     by the "interrupt" attribute.  */
  
*************** function_prologue (file, size)
*** 531,536 ****
--- 547,553 ----
       int size;
  {
    int reg;
+   int nonret_func_p;
    int interrupt_func_p;
    int signal_func_p;
    int leaf_func_p;
*************** function_prologue (file, size)
*** 544,549 ****
--- 561,567 ----
        return;
      }
  
+   nonret_func_p = nonret_function_p (current_function_decl);
    interrupt_func_p = interrupt_function_p (current_function_decl);
    signal_func_p = signal_function_p (current_function_decl);
    leaf_func_p = leaf_function_p ();
*************** function_prologue (file, size)
*** 555,561 ****
    last_insn_address = 0;
    jump_tables_size = 0;
    prologue_size = 0;
!   fprintf (file, "/* prologue: frame size=%d */\n", size);
    
    if (interrupt_func_p)
      {
--- 573,580 ----
    last_insn_address = 0;
    jump_tables_size = 0;
    prologue_size = 0;
!   fprintf (file, "/* prologue: %sframe size=%d */\n",
!          nonret_func_p ? "non-return, " : "", size);
    
    if (interrupt_func_p)
      {
*************** function_prologue (file, size)
*** 623,641 ****
                  && ! (frame_pointer_needed
                        && (reg == REG_Y || reg == (REG_Y+1)))))
            {
!             fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
!             ++prologue_size;
            }
        }
        if (frame_pointer_needed)
        {
          {
            fprintf (file, "\t"
-                    AS1 (push,r28) CR_TAB
-                    AS1 (push,r29) CR_TAB
                     AS2 (in,r28,__SP_L__) CR_TAB
                     AS2 (in,r29,__SP_H__) "\n");
!           prologue_size += 4;
            if (size)
              {
                fputs ("\t", file);
--- 642,668 ----
                  && ! (frame_pointer_needed
                        && (reg == REG_Y || reg == (REG_Y+1)))))
            {
!             if (!nonret_func_p)
!               {
!                 fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
!                 ++prologue_size;
!               }
            }
        }
        if (frame_pointer_needed)
        {
          {
+           if (!nonret_func_p)
+               {
+               fprintf (file, "\t"
+                        AS1 (push,r28) CR_TAB
+                        AS1 (push,r29) "\n");
+               prologue_size += 2;
+               }
            fprintf (file, "\t"
                     AS2 (in,r28,__SP_L__) CR_TAB
                     AS2 (in,r29,__SP_H__) "\n");
!           prologue_size += 2;
            if (size)
              {
                fputs ("\t", file);
*************** function_epilogue (file, size)
*** 681,686 ****
--- 708,718 ----
        fprintf (file, "/* epilogue: naked */\n");
        return;
      }
+   if (nonret_function_p (current_function_decl))
+     {
+       fprintf (file, "/* epilogue: non-return */\n");
+       return;
+     }
  
    interrupt_func_p = interrupt_function_p (current_function_decl);
    signal_func_p = signal_function_p (current_function_decl);
*************** valid_machine_type_attribute(type, attri
*** 4683,4688 ****
--- 4715,4721 ----
     prologue interrupts are disabled;
     interrupt - make a function to be hardware interrupt. After function
     prologue interrupts are enabled;
+    nonret - no register saved in prologue, no epilogue (ie., naked)
     naked     - don't generate function prologue/epilogue and `ret' command.  
*/
  
  int
*************** valid_machine_decl_attribute (decl, attr
*** 4694,4699 ****
--- 4727,4733 ----
  {
    if (is_attribute_p ("interrupt", attr)
        || is_attribute_p ("signal", attr)
+       || is_attribute_p ("nonret", attr)
        || is_attribute_p ("naked", attr))
      return TREE_CODE (decl) == FUNCTION_DECL;
  

reply via email to

[Prev in Thread] Current Thread [Next in Thread]