avr-libc-dev
[Top][All Lists]
Advanced

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

Re: [avr-libc-dev] [AVR] RTL prologue/epilogue


From: Anatoly Sokolov
Subject: Re: [avr-libc-dev] [AVR] RTL prologue/epilogue
Date: Tue, 18 Jul 2006 20:13:33 +0400

----- Original Message ----- 
From: "Denis Chertykov" <address@hidden>
To: "Anatoly Sokolov" <address@hidden>
Cc: <address@hidden>; <address@hidden>; "Denis Chertykov" <address@hidden>; 
<address@hidden>
Sent: Monday, June 26, 2006 6:51 PM
Subject: Re: [avr-libc-dev] [AVR] RTL prologue/epilogue


>> > 
>> > Attached is modifed Andy Hutchinson patch that changes AVR GCC to use RTL 
>> > prologue/epilogue generation. 
>> > Original patch: http://gcc.gnu.org/ml/gcc/2005-03/msg00923.html
>> > 
>> > New pach is for GCC 4.2.
> 

It is necessary to do:

> This patch seems wrong for me:
> 2. insn "incstackhi" (Now - "subhi3_sp_1", "subhi3_sp_2", ..., "subhi3_sp_6") 
> must be part of addhi
>   (even more I would to have addhi sp,
>    -1 push
>    -2 rcall
>    -3 push + rcall
>    -4 rcall + rcall
>    -5 rcall + rcall + push
>    -6 rcall + rcall + rcall);

> 5. ... "jump_exit" - ...., better to generate real jump insn and label 'exit'.

Anatoly.

Index: gcc/config/avr/avr-protos.h
===================================================================
--- gcc/config/avr/avr-protos.h (revision 115554)
+++ gcc/config/avr/avr-protos.h (working copy)
@@ -88,6 +88,10 @@
 extern const char *lshrhi3_out (rtx insn, rtx operands[], int *len);
 extern const char *lshrsi3_out (rtx insn, rtx operands[], int *len);
 
+extern void expand_prologue (void);
+extern void expand_epilogue (void);
+extern int avr_epilogue_uses (int regno);
+
 extern void avr_output_bld (rtx operands[], int bit_nr);
 extern void avr_output_addr_vec_elt (FILE *stream, int value);
 extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md (revision 115554)
+++ gcc/config/avr/avr.md (working copy)
@@ -43,11 +43,24 @@
    (REG_Y 28)
    (REG_Z 30)
    (REG_W 24)
+   (REG_SP 32)
    (TMP_REGNO 0) ; temporary register r0
    (ZERO_REGNO 1) ; zero register r1
+   
+   (SREG_ADDR   0x5F)
+   
    (UNSPEC_STRLEN 0)
-   (UNSPEC_INDEX_JMP 1)])
+   (UNSPEC_INDEX_JMP 1)
+   (UNSPEC_SEI  2)
+   (UNSPEC_CLI  3)
+   (UNSPEC_CLR_ZERO_REG 4)
+   (UNSPECV_RETI  5)
+   (UNSPECV_PROLOGUE_SAVES 6)
+   (UNSPECV_EPILOGUE_RESTORES 7)
+   
 
+   (UNSPECV_JMP_EXIT 101)])
+
 (include "constraints.md")
   
 ;; Condition code settings.
@@ -142,6 +155,48 @@
  pop __tmp_reg__"
   [(set_attr "length" "5")])
 
+(define_insn "*subhi3_sp_1"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 1)))]
+  ""
+  "push __tmp_reg__"
+  [(set_attr "length" "1")])
+
+(define_insn "*subhi3_sp_2"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 2)))]
+  "AVR_2_BYTE_PC"
+  "rcall ."
+  [(set_attr "length" "1")])
+
+(define_insn "*subhi3_sp_3"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 3)))]
+  "AVR_2_BYTE_PC"
+  "rcall .
+  push __tmp_reg__"
+  [(set_attr "length" "2")])
+
+(define_insn "*subhi3_sp_4"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 4)))]
+  "AVR_2_BYTE_PC"
+  "rcall .
+ rcall ."
+  [(set_attr "length" "2")])
+
+(define_insn "*subhi3_sp_5"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 5)))]
+  "AVR_2_BYTE_PC"
+  "rcall .
+ rcall .
+ push __tmp_reg__"
+  [(set_attr "length" "3")])
+
+(define_insn "*subhi3_sp_6"
+  [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 6)))]
+  "AVR_2_BYTE_PC"
+  "rcall .
+ rcall .
+ rcall ."
+  [(set_attr "length" "3")])
+
 (define_insn "*pushqi"
   [(set (mem:QI (post_dec (reg:HI 32)))
         (match_operand:QI 0 "nonmemory_operand" "r,L"))]
@@ -179,7 +234,23 @@
  push %B0
  push %A0"
   [(set_attr "length" "4")])
-
+  
+(define_insn "popqi"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (mem:QI (post_inc (reg:HI REG_SP))))]
+  ""
+  "pop %0"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+   
+(define_insn "pophi"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (mem:HI (post_inc (reg:HI REG_SP))))]
+  ""
+  "pop %A0\;pop %B0"
+  [(set_attr "cc" "none")
+   (set_attr "length" "2")])   
+   
 ;;========================================================================
 ;; move byte
 ;; The last alternative (any immediate constant to any register) is
@@ -2536,3 +2607,136 @@
         (pc)))]
   "jump_over_one_insn_p (insn, operands[2])"
   "cpse %0,%1")
+
+;;pppppppppppppppppppppppppppppppppppppppppppppppppppp
+;;prologue/epilogue support instructions
+
+;; Enable Interrupts
+(define_insn "enable_interrupt"
+  [(unspec [(const_int 0)] UNSPEC_SEI)]
+  ""
+  "sei"
+  [(set_attr "length" "1")
+  (set_attr "cc" "none")
+  ])
+
+;; Disable Interrupts
+(define_insn "disable_interrupt"
+  [(unspec [(const_int 0)] UNSPEC_CLI)]
+  ""
+  "cli"
+  [(set_attr "length" "1")
+  (set_attr "cc" "none")
+  ])
+
+;;  Unspec to clr r1 or gcc will attempt to delete it.
+(define_insn "clr_zero_reg"
+  [(unspec [(const_int 0)] UNSPEC_CLR_ZERO_REG)
+   (set (reg:QI 1) (const_int 0))]
+  ""
+  "clr __zero_reg__"
+  [(set_attr "length" "1")
+  (set_attr "cc" "clobber")
+  ])
+
+;  Library prologue saves
+(define_insn "call_prologue_saves"
+  [(unspec_volatile:HI [(const_int 0)] UNSPECV_PROLOGUE_SAVES)
+   (set (reg:HI 32 ) (minus:HI 
+                           (reg:HI 32)
+                           (match_operand:HI 0 "immediate_operand" "")))
+   (set (reg:HI 32 ) (minus:HI 
+                           (reg:HI 32)
+                           (match_operand:HI 1 "immediate_operand" "")))
+   (set (reg:HI 26) (match_dup 0))
+   (clobber (reg:HI 30))]
+  ""
+  "*
+  {
+    return (AS2 (ldi,r26,lo8(%0)) CR_TAB
+            AS2 (ldi,r27,hi8(%0)) CR_TAB
+            AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
+            AS2 (ldi,r31,pm_hi8(1f)) CR_TAB
+            AS1 (%~jmp,__prologue_saves__+(%1)) \"\\n\"
+            \"1:\");
+  }"
+  [(set_attr_alternative "length"
+    [(if_then_else (eq_attr "mcu_mega" "yes")
+     (const_int 6)
+     (const_int 5))])
+  (set_attr "cc" "clobber")
+  ])
+
+;  epilogue  restores using library
+(define_insn "epilogue_restores"
+  [(unspec_volatile:QI [(const_int 0)] UNSPECV_EPILOGUE_RESTORES)
+   (set (reg:HI 28 ) (plus:HI 
+                        (reg:HI 28)
+                        (match_operand:HI 0 "immediate_operand" ""))) 
+   (set (reg:HI 32) (reg:HI 28))
+   (clobber  (reg:QI 30))]
+  ""
+  "*
+  {
+    rtx ops[4];  
+    ops[0]=operands[0];
+    ops[1]=gen_int_mode((18 - INTVAL(operands[0])) * 2,HImode);
+    
+    output_asm_insn(AS2 (ldi,r30,lo8(%0)),ops);
+    output_asm_insn(AS1 (%~jmp,__epilogue_restores__+(%1)),ops);
+    
+    return \"\";
+  }"
+  [(set_attr_alternative "length"
+    [(if_then_else (eq_attr "mcu_mega" "yes")
+     (const_int 3)
+     (const_int 2))])
+  (set_attr "cc" "clobber")
+  ])
+  
+;  Main epilogue  jump to exit
+(define_insn "jump_exit"
+  [(unspec_volatile:HI [(const_int 0)] UNSPECV_JMP_EXIT)]
+  ""
+  "%~jmp exit"
+  [(set_attr_alternative "length"
+    [(if_then_else (eq_attr "mcu_mega" "yes")
+     (const_int 2)
+     (const_int 1))])
+  (set_attr "cc" "clobber")
+  ])
+
+(define_insn "ret"
+  [(return)]
+  "reload_completed"
+  "ret"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+(define_insn "reti"
+  [(unspec_volatile:QI [(const_int 0)] UNSPECV_RETI)
+   (return)]
+  "reload_completed"
+  "reti"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "
+  {
+    expand_prologue (); 
+    DONE;
+  }")
+
+(define_expand "epilogue"
+  [(const_int 0)]
+  ""
+  "
+  {
+    expand_epilogue (); 
+    DONE;
+  }")
+  
\ No newline at end of file
Index: gcc/config/avr/avr.c
===================================================================
--- gcc/config/avr/avr.c (revision 115554)
+++ gcc/config/avr/avr.c (working copy)
@@ -56,8 +56,7 @@
 static const char *ptrreg_to_str (int);
 static const char *cond_string (enum rtx_code);
 static int avr_num_arg_regs (enum machine_mode, tree);
-static int out_adj_frame_ptr (FILE *, int);
-static int out_set_stack_ptr (FILE *, int, int);
+
 static RTX_CODE compare_condition (rtx insn);
 static int compare_sign_p (rtx insn);
 static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *);
@@ -66,8 +65,8 @@
 static bool avr_assemble_integer (rtx, unsigned int, int);
 static void avr_file_start (void);
 static void avr_file_end (void);
-static void avr_output_function_prologue (FILE *, HOST_WIDE_INT);
-static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static void avr_asm_function_end_prologue (FILE *);
+static void avr_asm_function_begin_epilogue (FILE *);
 static void avr_insert_attributes (tree, tree *);
 static void avr_asm_init_sections (void);
 static unsigned int avr_section_type_flags (tree, const char *, int);
@@ -79,7 +78,15 @@
 static bool avr_rtx_costs (rtx, int, int, int *);
 static int avr_address_cost (rtx);
 static bool avr_return_in_memory (tree, tree);
+static bool is_prologue_epilogue_insn(rtx insn);
 
+/* A C structure for machine-specific, per-function data.
+   This is added to the cfun structure.  */
+struct machine_function GTY(())
+{
+  int interrupt_handler;
+};
+
 /* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
 
@@ -107,9 +114,12 @@
 /* Prologue/Epilogue size in words */
 static int prologue_size;
 static int epilogue_size;
+/*  Flag is true if we are building prologue/epilogue */
+static bool building_prologue_epilogue;
 
 /* Size of all jump tables in the current function, in words.  */
 static int jump_tables_size;
+static int function_size;
 
 /* Preprocessor macros to define depending on MCU type.  */
 const char *avr_base_arch_macro;
@@ -276,10 +286,10 @@
 #undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END avr_file_end
 
-#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
-#undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE avr_asm_function_end_prologue
+#undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE
+#define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE avr_asm_function_begin_epilogue
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE avr_attribute_table
 #undef TARGET_ASM_FUNCTION_RODATA_SECTION
@@ -303,6 +313,14 @@
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
+
+static struct machine_function *
+avr_init_machine_status (void)
+{
+  return ((struct machine_function *) 
+          ggc_alloc_cleared (sizeof (struct machine_function)));
+}
+
 void
 avr_override_options (void)
 {
@@ -334,6 +352,8 @@
 
   tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
   zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
+
+  init_machine_status = avr_init_machine_status;
 }
 
 /*  return register class from register number.  */
@@ -526,254 +546,285 @@
 }
 
 
-/* Output to FILE the asm instructions to adjust the frame pointer by
-   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
-   (epilogue).  Returns the number of instructions generated.  */
-
-static int
-out_adj_frame_ptr (FILE *file, int adj)
+static int size_of_insn(rtx insn)
 {
-  int size = 0;
-
-  if (adj)
-    {
-      if (TARGET_TINY_STACK)
- {
-   if (adj < -63 || adj > 63)
-     warning (0, "large frame pointer change (%d) with -mtiny-stack", adj);
-
-   /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
-      over "sbiw" (2 cycles, same size).  */
-
-   fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
-   size++;
- }
-      else if (adj < -63 || adj > 63)
- {
-   fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
-     AS2 (sbci, r29, hi8(%d)) CR_TAB),
-     adj, adj);
-   size += 2;
- }
-      else if (adj < 0)
- {
-   fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
-   size++;
- }
-      else
- {
-   fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
-   size++;
- }
-    }
-  return size;
+  int l=get_attr_length (insn);
+  l= adjust_insn_length (insn,l);
+  return l;
 }
 
-
-/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
-   handling various cases of interrupt enable flag state BEFORE and AFTER
-   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
-   Returns the number of instructions generated.  */
-
-static int
-out_set_stack_ptr (FILE *file, int before, int after)
+/*  Return true if insn is part of prologue or epilogue.*/
+static bool is_prologue_epilogue_insn(rtx insn)
 {
-  int do_sph, do_cli, do_save, do_sei, lock_sph, size;
-
-  /* The logic here is so that -mno-interrupts actually means
-     "it is safe to write SPH in one instruction, then SPL in the
-     next instruction, without disabling interrupts first".
-     The after != -1 case (interrupt/signal) is not affected.  */
-
-  do_sph = !TARGET_TINY_STACK;
-  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
-  do_cli = (before != 0 && (after == 0 || lock_sph));
-  do_save = (do_cli && before == -1 && after == -1);
-  do_sei = ((do_cli || before != 1) && after == 1);
-  size = 1;
-
-  if (do_save)
-    {
-      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
-      size++;
-    }
-
-  if (do_cli)
-    {
-      fprintf (file, "cli" CR_TAB);
-      size++;
-    }
-
-  /* Do SPH first - maybe this will disable interrupts for one instruction
-     someday (a suggestion has been sent to address@hidden for consideration
-     in future devices - that would make -mno-interrupts always safe).  */
-  if (do_sph)
-    {
-      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
-      size++;
-    }
-
-  /* Set/restore the I flag now - interrupts will be really enabled only
-     after the next instruction.  This is not clearly documented, but
-     believed to be true for all AVR devices.  */
-  if (do_save)
-    {
-      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
-      size++;
-    }
-  else if (do_sei)
-    {
-      fprintf (file, "sei" CR_TAB);
-      size++;
-    }
-
-  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
-
-  return size;
+    return (building_prologue_epilogue || prologue_epilogue_contains(insn));
 }
-
-
-/* Output function prologue.  */
-
-static void
-avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
+/*  Placeholders for prologue saving of tmp/zero regs in ISR. */
+/*  Unused - potential future enhancement to avoid save/restores. */
+static int uses_zero_reg =true;
+static int uses_tmp_reg = true;
+static int uses_status_reg = true;
+/*  Output function prologue.  */
+void
+expand_prologue (void)
 {
-  int reg;
   int interrupt_func_p;
   int signal_func_p;
   int main_p;
   int live_seq;
   int minimize;
-
+  HOST_WIDE_INT size =get_frame_size();
+  building_prologue_epilogue=true;
   last_insn_address = 0;
   jump_tables_size = 0;
   prologue_size = 0;
-  fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
-    size);
-
+  /*  Define templates for push instructions. */
+  rtx pushbyte = gen_rtx_MEM (QImode,
+                  gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
+  rtx pushword = gen_rtx_MEM (HImode,
+                  gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
+  rtx insn;
+  
   if (avr_naked_function_p (current_function_decl))
     {
-      fputs ("/* prologue: naked */\n", file);
+      /* prologue: naked */
       goto out;
     }
-
   interrupt_func_p = interrupt_function_p (current_function_decl);
   signal_func_p = signal_function_p (current_function_decl);
   main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
   live_seq = sequent_regs_live ();
   minimize = (TARGET_CALL_PROLOGUES
        && !interrupt_func_p && !signal_func_p && live_seq);
+  cfun->machine->interrupt_handler = (interrupt_func_p || signal_func_p);
 
-  if (interrupt_func_p)
-    {
-      fprintf (file,"\tsei\n");
-      ++prologue_size;
-    }
   if (interrupt_func_p || signal_func_p)
     {
-      fprintf (file, "\t"
-               AS1 (push,__zero_reg__)   CR_TAB
-               AS1 (push,__tmp_reg__)    CR_TAB
-        AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-        AS1 (push,__tmp_reg__)    CR_TAB
-        AS1 (clr,__zero_reg__)    "\n");
-      prologue_size += 5;
+      if (interrupt_func_p)
+        {
+          /* enable interrupts */
+          insn = emit_insn (gen_enable_interrupt ());
+          RTX_FRAME_RELATED_P (insn) = 1;
+          prologue_size +=size_of_insn (insn);
+        }
+      /*  Push tmp, zero regs and SREG status. */
+      if (uses_tmp_reg)
+        {
+          insn = emit_move_insn (pushbyte,tmp_reg_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+          prologue_size += size_of_insn (insn);
+        }
+      if (uses_status_reg)
+      {
+         /* push SREG */
+        insn = emit_move_insn (tmp_reg_rtx, 
+                               gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)));
+        RTX_FRAME_RELATED_P (insn) = 1;
+        prologue_size += size_of_insn (insn);
+        insn=emit_move_insn (pushbyte, tmp_reg_rtx);
+        RTX_FRAME_RELATED_P (insn) = 1;
+        prologue_size += size_of_insn (insn);
+      }             
+      if (uses_zero_reg)
+        {
+          insn = emit_move_insn (pushbyte,zero_reg_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+          prologue_size += size_of_insn (insn);
+
+          /*  Clear zero reg, Use unspec so gcc wont try to remove it. */
+   //insn = emit_move_insn (zero_reg_rtx, const0_rtx);
+          //REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, 
NULL);
+          insn = emit_insn (gen_clr_zero_reg ());
+   RTX_FRAME_RELATED_P (insn) = 1;
+          prologue_size += size_of_insn (insn);
+        }
     }
   if (main_p)
     {
-      fprintf (file, ("\t" 
-        AS1 (ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
-        AS1 (ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
-        AS2 (out,__SP_H__,r29)     CR_TAB
-        AS2 (out,__SP_L__,r28) "\n"),
-        avr_init_stack, size, avr_init_stack, size);
-      
-      prologue_size += 4;
+      char buffer[40];
+      sprintf (buffer,"%s - %d", avr_init_stack,(int) size);
+      rtx sym = gen_rtx_SYMBOL_REF (HImode, ggc_strdup (buffer));
+      /*  Initialise stack pointer using frame pointer */
+      insn = emit_move_insn (frame_pointer_rtx, sym);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      prologue_size += size_of_insn (insn);
+      insn=emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      prologue_size += size_of_insn (insn);
     }
   else if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
-      fprintf (file, ("\t"
-        AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
-        AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, 
size);
-
-      fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
-       AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
-      
-      prologue_size += 4;
-      
-      if (AVR_MEGA)
- {
-   fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
-     (18 - live_seq) * 2);
-   prologue_size += 2;
- }
-      else
- {
-   fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
-     (18 - live_seq) * 2);
-   ++prologue_size;
- }
-      fputs ("1:\n", file);
+      insn = emit_insn (gen_call_prologue_saves(
+                        gen_int_mode (size, HImode),
+                        gen_int_mode ((18 - live_seq) * 2, HImode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      prologue_size += size_of_insn (insn);
+      /* Label for body  */
+      rtx label = gen_label_rtx ();
+      emit_label (label);
     }
   else
     {
       HARD_REG_SET set;
-
-      prologue_size += avr_regs_to_save (&set);
+      avr_regs_to_save (&set);
+      int reg;
       for (reg = 0; reg < 32; ++reg)
- {
-   if (TEST_HARD_REG_BIT (set, reg))
-     {
-       fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
-     }
- }
+        {
+          if (TEST_HARD_REG_BIT (set, reg))
+            {
+              /*  Emit push of register to save. */
+              insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              prologue_size +=size_of_insn (insn);      
+            }
+        }
       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);
-       prologue_size += out_adj_frame_ptr (file, size);
+        {
+          /*  Push frame pointer. */
+          insn = emit_move_insn (pushword, frame_pointer_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+          prologue_size += size_of_insn (insn);
+          if (!size)
+            {
+              insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+              prologue_size += size_of_insn (insn);
+            }
+          else
+            {
+              /*  Creating a frame can be done by direct manipulation of the
+                  stack or via the frame pointer. These two methods are:
+                    fp=sp
+                    fp-=size
+                    sp=fp
+                OR
+                    sp-=size
+                    fp=sp
+              the optimum method depends on function type, stack and frame 
size.
+              To avoid a complex logic, both methods are tested and shortest
+              is selected */
+              rtx myfp;
+              /*  First method. */
+              if (TARGET_TINY_STACK)
+                {
+                  if (size < -63 || size > 63)
+                    warning ("large frame pointer change (%d) with 
-mtiny-stack", size);
+                    
+                  /* The high byte (r29) doesn't change - prefer 'subi' (1 
cycle)
+                     over 'sbiw' (2 cycles, same size).  */
+                  myfp = gen_rtx_REG (QImode,REGNO (frame_pointer_rtx));
+                }
+              else 
+                {
+                  /*  Normal sized addition. */
+                  myfp=frame_pointer_rtx;
+                }
+              /* calculate length */ 
+              int method1_length;
+              method1_length = size_of_insn (gen_move_insn (
+                                   frame_pointer_rtx, stack_pointer_rtx));     
  
+              method1_length += size_of_insn (gen_move_insn (myfp,
+                                    gen_rtx_PLUS (GET_MODE(myfp), myfp, 
+                                    gen_int_mode (-size,GET_MODE(myfp))))); 
+              /*  output_movhi()  takes care of variants*/
+              method1_length += size_of_insn(gen_move_insn (
+                                    stack_pointer_rtx, frame_pointer_rtx));
+              
+       /* Method 2-Adjust Stack pointer. */
+              int sp_plus_length = 0;
+              if (size <= 6)
+                {
+                  sp_plus_length = size_of_insn (gen_move_insn (
+                                     stack_pointer_rtx,
+                                     gen_rtx_MINUS (HImode, stack_pointer_rtx, 
+                                     gen_int_mode (size, HImode))));
+    sp_plus_length += size_of_insn (gen_move_insn (
+                                     frame_pointer_rtx, stack_pointer_rtx));
+                }
+              /* Use shortest method. */
+              if (size <= 6 && (sp_plus_length<method1_length))
+                {
+                  insn = emit_move_insn (stack_pointer_rtx,
+                                  gen_rtx_MINUS (HImode, stack_pointer_rtx, 
+                                  gen_int_mode (size, HImode)));
+                  RTX_FRAME_RELATED_P (insn) = 1;
+    insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+                  RTX_FRAME_RELATED_P (insn) = 1;
+                  prologue_size += sp_plus_length;
+                }
+              else
+                {  
+                  insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+                  RTX_FRAME_RELATED_P (insn) = 1;
+                  insn = emit_move_insn (myfp,
+                              gen_rtx_PLUS (GET_MODE(myfp), frame_pointer_rtx, 
+                              gen_int_mode (-size,GET_MODE(myfp))));  
+                  RTX_FRAME_RELATED_P (insn) = 1;
+                  insn = emit_move_insn ( stack_pointer_rtx,frame_pointer_rtx);
+                  RTX_FRAME_RELATED_P (insn) = 1;
+                  prologue_size += method1_length;
+                }
+            }
+        }
+    }
+ out:
+  building_prologue_epilogue=false;
+}
 
-       if (interrupt_func_p)
-  {
-    prologue_size += out_set_stack_ptr (file, 1, 1);
-  }
-       else if (signal_func_p)
-  {
-    prologue_size += out_set_stack_ptr (file, 0, 0);
-  }
-       else
-  {
-    prologue_size += out_set_stack_ptr (file, -1, -1);
-  }
-     }
- }
+/* Output summary at end of function prologue.  */
+static void
+avr_asm_function_end_prologue (FILE *file)
+{
+  if (avr_naked_function_p (current_function_decl))
+    {
+      fputs ("/* prologue: naked */\n", file);
     }
+  else
+    {
+      if (interrupt_function_p (current_function_decl))
+        {
+          fputs ("/* prologue: Interrupt */\n", file);
+        }
+      else if (signal_function_p (current_function_decl))
+        {
+          fputs ("/* prologue: Signal */\n", file);
+        }
+      else if  (MAIN_NAME_P (DECL_NAME (current_function_decl)))
+        {
+          fputs ("/* prologue: main */\n", file);
+        }
+      else
+        fputs ("/* prologue: function */\n", file);
+    }
+  fprintf (file, "/* frame size=" HOST_WIDE_INT_PRINT_DEC 
+                " prologue size %d  */\n",
+                get_frame_size(), prologue_size);
+}
 
- out:
-  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
+
+/* Implement EPILOGUE_USES.  */
+int
+avr_epilogue_uses (int regno)
+{
+  if (cfun->machine && cfun->machine->interrupt_handler && reload_completed)
+    return 1;
+  return 0;
 }
 
-/* Output function epilogue.  */
+/*  Output RTL epilogue. */
 
-static void
-avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
+void
+expand_epilogue (void)
 {
   int reg;
   int interrupt_func_p;
   int signal_func_p;
   int main_p;
-  int function_size;
   int live_seq;
   int minimize;
   rtx last = get_last_nonnote_insn ();
-
+  HOST_WIDE_INT size = get_frame_size();
+  building_prologue_epilogue=true;
+  rtx insn;
   function_size = jump_tables_size;
   if (last)
     {
@@ -782,19 +833,18 @@
    INSN_ADDRESSES (INSN_UID (first)));
       function_size += get_attr_length (last);
     }
-
-  fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", 
size);
+    
   epilogue_size = 0;
 
   if (avr_naked_function_p (current_function_decl))
     {
-      fputs ("/* epilogue: naked */\n", file);
+      /* epilogue: naked */
       goto out;
     }
 
   if (last && GET_CODE (last) == BARRIER)
     {
-      fputs ("/* epilogue: noreturn */\n", file);
+      /* epilogue: noreturn */
       goto out;
     }
 
@@ -808,106 +858,159 @@
   if (main_p)
     {
       /* Return value from main() is already in the correct registers
-  (r25:r24) as the exit() argument.  */
-      if (AVR_MEGA)
- {
-   fputs ("\t" AS1 (jmp,exit) "\n", file);
-   epilogue_size += 2;
- }
-      else
- {
-   fputs ("\t" AS1 (rjmp,exit) "\n", file);
-   ++epilogue_size;
- }
+         (r25:r24) as the exit() argument.  */
+      insn = emit_insn (gen_jump_exit ());
+      RTX_FRAME_RELATED_P (insn) = 1;
+      epilogue_size += size_of_insn (insn);
     }
   else if (minimize && (frame_pointer_needed || live_seq > 4))
     {
-      fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
-      ++epilogue_size;
       if (frame_pointer_needed)
  {
-   epilogue_size += out_adj_frame_ptr (file, -size);
+          /*  Get rid of frame. */
+          insn = emit_move_insn(frame_pointer_rtx,
+                                gen_rtx_PLUS (HImode, frame_pointer_rtx, 
+                                gen_int_mode (size, HImode)));
+          RTX_FRAME_RELATED_P (insn) = 1;
+          epilogue_size += size_of_insn (insn);  
  }
       else
  {
-   fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
-     AS2 (in , r29, __SP_H__) CR_TAB));
-   epilogue_size += 2;
+          insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+          epilogue_size += size_of_insn (insn);      
  }
-      
-      if (AVR_MEGA)
- {
-   fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
-     (18 - live_seq) * 2);
-   epilogue_size += 2;
- }
-      else
- {
-   fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
-     (18 - live_seq) * 2);
-   ++epilogue_size;
- }
+      insn = emit_insn (gen_epilogue_restores(
+                        gen_int_mode (live_seq, HImode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      epilogue_size+=size_of_insn (insn);
     }
   else
     {
-      HARD_REG_SET set;
-
       if (frame_pointer_needed)
  {
    if (size)
      {
-       fputs ("\t", file);
-       epilogue_size += out_adj_frame_ptr (file, -size);
-
-       if (interrupt_func_p || signal_func_p)
-  {
-    epilogue_size += out_set_stack_ptr (file, -1, 0);
-  }
-       else
-  {
-    epilogue_size += out_set_stack_ptr (file, -1, -1);
-  }
-     }
-   fprintf (file, "\t"
-     AS1 (pop,r29) CR_TAB
-     AS1 (pop,r28) "\n");
-   epilogue_size += 2;
+              /*  Try two methods to adjust stack and select shortest. */
+              int fp_plus_length;
+              /*  Method 1-Adjust frame pointer. */
+              fp_plus_length =size_of_insn (gen_move_insn (
+                                            frame_pointer_rtx,
+                                            gen_rtx_PLUS (HImode, 
frame_pointer_rtx,
+                                            gen_int_mode (size, HImode))));    
       
+              /*  Copy to stack pointer */
+              fp_plus_length += size_of_insn (gen_move_insn (
+                                              stack_pointer_rtx, 
frame_pointer_rtx));    
+          
+              /* Method 2-Adjust Stack pointer. */
+              int sp_plus_length = 0;
+              if (size <= 5)
+                {
+                  sp_plus_length = size_of_insn (gen_move_insn (
+                                                 stack_pointer_rtx,
+                                                 gen_rtx_PLUS (HImode, 
stack_pointer_rtx, 
+                                                 gen_int_mode (size, 
HImode))));      
+                }
+              /* Use shortest method. */
+              if (size <= 5 && (sp_plus_length<fp_plus_length))
+                {
+                  insn = emit_move_insn (stack_pointer_rtx,
+                                  gen_rtx_PLUS (HImode, stack_pointer_rtx, 
+                                  gen_int_mode (size, HImode)));
+                  RTX_FRAME_RELATED_P (insn) = 1;
+                  epilogue_size += sp_plus_length;
+                }
+              else
+                {
+                  insn = emit_move_insn (frame_pointer_rtx,
+                                         gen_rtx_PLUS (HImode, 
frame_pointer_rtx,
+                                         gen_int_mode (size, HImode)));
+           RTX_FRAME_RELATED_P (insn) = 1;    
+                  /*  Copy to stack pointer */
+                  insn = emit_move_insn (stack_pointer_rtx, 
frame_pointer_rtx); 
+           RTX_FRAME_RELATED_P (insn) = 1;
+                  epilogue_size += fp_plus_length;
+                }
+            }
+        
+          /* Restore previous frame_pointer. */
+          insn = emit_insn (gen_pophi (frame_pointer_rtx));
+          RTX_FRAME_RELATED_P (insn) = 1;
+          epilogue_size += size_of_insn (insn);
  }
-
-      epilogue_size += avr_regs_to_save (&set);
+      /*  Restore used registers. */
+      HARD_REG_SET set;      
+      avr_regs_to_save (&set);
       for (reg = 31; reg >= 0; --reg)
- {
-   if (TEST_HARD_REG_BIT (set, reg))
-     {
-       fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
-     }
- }
-
+        {
+          if (TEST_HARD_REG_BIT (set, reg))
+            {
+              insn = emit_insn (gen_popqi (gen_rtx_REG (QImode, reg)));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              epilogue_size += size_of_insn (insn);      
+            }
+        }
       if (interrupt_func_p || signal_func_p)
- {
-   fprintf (file, "\t"
-     AS1 (pop,__tmp_reg__)      CR_TAB
-     AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-     AS1 (pop,__tmp_reg__)      CR_TAB
-     AS1 (pop,__zero_reg__)     "\n");
-   epilogue_size += 4;
-   fprintf (file, "\treti\n");
- }
+        {
+          if (uses_zero_reg)
+            {
+              insn = emit_insn (gen_popqi (zero_reg_rtx));
+       RTX_FRAME_RELATED_P (insn) = 1;
+              epilogue_size += size_of_insn (insn); 
+            }
+          if (uses_status_reg)
+            {
+              /*  Restore SREG using tmp reg as scratch. */
+              insn = emit_insn (gen_popqi (tmp_reg_rtx));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              epilogue_size += size_of_insn (insn);
+      
+              insn = emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
+                              tmp_reg_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+              epilogue_size += size_of_insn (insn);
+            }
+          if (uses_tmp_reg)
+            {
+              insn = emit_insn (gen_popqi (tmp_reg_rtx));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              epilogue_size += size_of_insn (insn);
+            }
+          insn = emit_insn (gen_reti ());
+   RTX_FRAME_RELATED_P (insn) = 1;
+          epilogue_size += size_of_insn (insn);
+        }
       else
- fprintf (file, "\tret\n");
-      ++epilogue_size;
+        {
+          insn = emit_insn (gen_ret ());
+   RTX_FRAME_RELATED_P (insn) = 1;
+          epilogue_size += size_of_insn (insn);
+        }
     }
 
  out:
-  fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
-  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (),
-    prologue_size + function_size + epilogue_size, function_size);
   commands_in_file += prologue_size + function_size + epilogue_size;
   commands_in_prologues += prologue_size;
   commands_in_epilogues += epilogue_size;
+  building_prologue_epilogue=false;
 }
 
+/* Output summary messages at beginning of function epilogue.  */
+static void
+avr_asm_function_begin_epilogue (FILE *file)
+{
+  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (),
+    prologue_size + function_size + epilogue_size, function_size);
+  fprintf (file, "/* epilogue start (size=%d) */\n", epilogue_size);
+  rtx last = get_last_nonnote_insn ();
+  if (last && GET_CODE (last) == BARRIER)
+    {
+      fputs ("/* epilogue: noreturn */\n", file);
+    }
 
+}
+
+
 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
    machine for a memory operand of mode MODE.  */
 
@@ -1642,13 +1745,32 @@
     *l = 1;
     return AS2 (out,__SP_L__,%A1);
   }
-       else if (TARGET_NO_INTERRUPTS)
-  {
-    *l = 2;
-    return (AS2 (out,__SP_H__,%B1) CR_TAB
-     AS2 (out,__SP_L__,%A1));
-  }
-
+        /*  Use simple load of stack pointer if no interrupts are used
+            or inside main or signal function prologue where they disabled*/
+       else if (TARGET_NO_INTERRUPTS 
+                || (reload_completed 
+                    && MAIN_NAME_P (DECL_NAME (current_function_decl)) 
+                    && is_prologue_epilogue_insn (insn))
+                || (reload_completed 
+                    && signal_function_p (current_function_decl) 
+                    && is_prologue_epilogue_insn (insn))
+                )
+            {
+            *l = 2;
+            return (AS2 (out,__SP_H__,%B1) CR_TAB
+                AS2 (out,__SP_L__,%A1));
+            }
+            /*  In interrupt prolog we know interrupts are enabled. */
+          else if (reload_completed 
+                    && interrupt_function_p (current_function_decl) 
+                    && is_prologue_epilogue_insn (insn))
+            {
+            *l = 4;
+         return ("cli"                   CR_TAB
+                AS2 (out,__SP_H__,%B1)      CR_TAB
+                    "sei"                    CR_TAB
+                AS2 (out,__SP_L__,%A1));
+            }
        *l = 5;
        return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
         "cli"                          CR_TAB
@@ -1796,6 +1918,11 @@
   
   if (CONSTANT_ADDRESS_P (x))
     {
+      if (GET_CODE (x) == CONST_INT && INTVAL (x) == SREG_ADDR)
+ {
+   *l = 1;
+   return AS2 (in,%0,__SREG__);
+ }
       if (avr_io_address_p (x, 1))
  {
    *l = 1;
@@ -2479,6 +2606,11 @@
   
   if (CONSTANT_ADDRESS_P (x))
     {
+      if (GET_CODE (x) == CONST_INT && INTVAL (x) == SREG_ADDR)
+ {
+   *l = 1;
+   return AS2 (out,__SREG__,%1);
+ }
       if (avr_io_address_p (x, 1))
  {
    *l = 1;
Index: gcc/config/avr/avr.h
===================================================================
--- gcc/config/avr/avr.h (revision 115554)
+++ gcc/config/avr/avr.h (working copy)
@@ -21,6 +21,9 @@
 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
+/* Offset from the frame pointer register value to the top of the stack.  */
+#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0
+
 /* Names to predefine in the preprocessor for this target machine.  */
 
 #define TARGET_CPU_CPP_BUILTINS()  \
@@ -60,6 +63,8 @@
 #define AVR_ENHANCED (avr_enhanced_p)
 #define AVR_HAVE_MOVW (avr_have_movw_lpmx_p)
 
+#define AVR_2_BYTE_PC 1
+
 #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
 
 #define OVERRIDE_OPTIONS avr_override_options ()
@@ -332,7 +337,8 @@
 
 #define DEFAULT_PCC_STRUCT_RETURN 0
 
-#define EPILOGUE_USES(REGNO) 0
+#define EPILOGUE_USES(REGNO) avr_epilogue_uses(REGNO)
+//&& reload_completed)
 
 #define HAVE_POST_INCREMENT 1
 #define HAVE_PRE_DECREMENT 1

reply via email to

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