* config/avr/avr-protos.h (expand_prologue, expand_epilogue,
authoraesok <aesok@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 May 2007 10:59:17 +0000 (10:59 +0000)
committeraesok <aesok@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 May 2007 10:59:17 +0000 (10:59 +0000)
avr_epilogue_uses) : Add declaration.
* config/avr/predicates.md (avr_sp_immediate_operand): New predicate.
* config/avr/constraints.md (R): New constraint.
config/avr/avr.md (SREG_ADDR,  UNSPEC_SEI, UNSPEC_CLI,
UNSPECV_PROLOGUE_SAVES, UNSPECV_EPILOGUE_RESTORES): New constants.
(*pop1, *pop2, *pop3, *pop4, *pop5): Combine into ...
(*addhi3_sp_R_pc2, *addhi3_sp_R_pc3): ... these patterns.
(*movhi_sp, popqi, pophi, enable_interrupt, disable_interrupt,
call_prologue_saves, epilogue_restores, return_from_epilogue,
return_from_main_epilogue, return_from_interrupt_epilogue,
return_from_naked_epilogue, prologue, epilogue): New patterns.
(jump): Handle symbol reference.
* config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr,
avr_output_function_prologue, avr_output_function_epilogue): Remove
functions.
(avr_init_machine_status, expand_prologue, expand_epilogue,
avr_asm_function_end_prologue, avr_epilogue_uses,
avr_asm_function_begin_epilogue): New functions.
(prologue_size, epilogue_size, jump_tables_size): Remove global
variables.
(TARGET_ASM_FUNCTION_PROLOGUE, TARGET_ASM_FUNCTION_EPILOGUE): Remove.
(TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
(TARGET_ASM_FUNCTION_BEGIN_EPILOGUE): Define.
(avr_override_options): Initialise init_machine_status.
(output_movhi): Handle all stack pointer loads.
(out_movqi_r_mr, out_movqi_mr_r): Handle SREG_ADDR address.
(avr_output_addr_vec_elt): Do not use variable jump_tables_size.
* config/avr/avr.h (AVR_2_BYTE_PC, AVR_3_BYTE_PC): New.
(EPILOGUE_USES) Redefine.
(machine_function) Declare.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@124854 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/avr/avr-protos.h
gcc/config/avr/avr.c
gcc/config/avr/avr.h
gcc/config/avr/avr.md
gcc/config/avr/constraints.md
gcc/config/avr/predicates.md

index 4d75f78..c012554 100644 (file)
@@ -1,3 +1,38 @@
+2007-05-19 Andy Hutchinson <HutchinsonAndy@netscape.net>
+           Anatoly Sokolov <aesok@dol.ru>
+
+       * config/avr/avr-protos.h (expand_prologue, expand_epilogue, 
+       avr_epilogue_uses) : Add declaration.
+       * config/avr/predicates.md (avr_sp_immediate_operand): New predicate.
+       * config/avr/constraints.md (R): New constraint.
+       config/avr/avr.md (SREG_ADDR,  UNSPEC_SEI, UNSPEC_CLI, 
+       UNSPECV_PROLOGUE_SAVES, UNSPECV_EPILOGUE_RESTORES): New constants.
+       (*pop1, *pop2, *pop3, *pop4, *pop5): Combine into ...
+       (*addhi3_sp_R_pc2, *addhi3_sp_R_pc3): ... these patterns.
+       (*movhi_sp, popqi, pophi, enable_interrupt, disable_interrupt, 
+       call_prologue_saves, epilogue_restores, return_from_epilogue,
+       return_from_main_epilogue, return_from_interrupt_epilogue, 
+       return_from_naked_epilogue, prologue, epilogue): New patterns.
+       (jump): Handle symbol reference.
+       * config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr, 
+       avr_output_function_prologue, avr_output_function_epilogue): Remove 
+       functions.
+       (avr_init_machine_status, expand_prologue, expand_epilogue, 
+       avr_asm_function_end_prologue, avr_epilogue_uses, 
+       avr_asm_function_begin_epilogue): New functions.
+       (prologue_size, epilogue_size, jump_tables_size): Remove global 
+       variables.
+       (TARGET_ASM_FUNCTION_PROLOGUE, TARGET_ASM_FUNCTION_EPILOGUE): Remove.
+       (TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
+       (TARGET_ASM_FUNCTION_BEGIN_EPILOGUE): Define.
+       (avr_override_options): Initialise init_machine_status.
+       (output_movhi): Handle all stack pointer loads.
+       (out_movqi_r_mr, out_movqi_mr_r): Handle SREG_ADDR address.
+       (avr_output_addr_vec_elt): Do not use variable jump_tables_size.
+       * config/avr/avr.h (AVR_2_BYTE_PC, AVR_3_BYTE_PC): New.
+       (EPILOGUE_USES) Redefine.
+       (machine_function) Declare.
+
 2007-05-19  Richard Sandiford  <richard@codesourcery.com>
 
        * config/mips/mips.c (mips_offset_within_alignment_p): Tweak comment.
index ef084f0..50dbd12 100644 (file)
@@ -87,6 +87,10 @@ extern const char *lshrqi3_out (rtx insn, rtx operands[], int *len);
 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 df6fe10..950777c 100644 (file)
@@ -56,8 +56,7 @@ static int sequent_regs_live (void);
 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 @@ const struct attribute_spec avr_attribute_table[];
 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,7 @@ static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
 static bool avr_rtx_costs (rtx, int, int, int *);
 static int avr_address_cost (rtx);
 static bool avr_return_in_memory (tree, tree);
-
+static struct machine_function * avr_init_machine_status (void);
 /* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
 
@@ -104,13 +103,6 @@ static int commands_in_prologues;
 /* Commands in the functions epilogues in the compiled file */
 static int commands_in_epilogues;
 
-/* Prologue/Epilogue size in words */
-static int prologue_size;
-static int epilogue_size;
-
-/* Size of all jump tables in the current function, in words.  */
-static int jump_tables_size;
-
 /* Preprocessor macros to define depending on MCU type.  */
 const char *avr_base_arch_macro;
 const char *avr_extra_arch_macro;
@@ -299,10 +291,10 @@ int avr_case_values_threshold = 30000;
 #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
@@ -359,6 +351,8 @@ avr_override_options (void)
 
   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.  */
@@ -377,6 +371,15 @@ static const int reg_class_tab[]={
   STACK_REG,STACK_REG           /* SPL,SPH */
 };
 
+/* Function to set up the backend function structure.  */
+
+static struct machine_function *
+avr_init_machine_status (void)
+{
+  return ((struct machine_function *) 
+          ggc_alloc_cleared (sizeof (struct machine_function)));
+}
+
 /* Return register class for register R.  */
 
 enum reg_class
@@ -550,388 +553,382 @@ sequent_regs_live (void)
   return (cur_seq == live_seq) ? live_seq : 0;
 }
 
+/*  Output function prologue.  */
 
-/* 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)
+void
+expand_prologue (void)
 {
-  int size = 0;
+  int live_seq;
+  int minimize;
+  HOST_WIDE_INT size = get_frame_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 (adj)
+  last_insn_address = 0;
+  
+  /* Init cfun->machine.  */
+  cfun->machine->is_main = MAIN_NAME_P (DECL_NAME (current_function_decl));
+  cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
+  cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
+  cfun->machine->is_signal = signal_function_p (current_function_decl);
+  
+  /* Prologue: naked.  */
+  if (cfun->machine->is_naked)
     {
-      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;
     }
-  return size;
-}
-
 
-/* 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)
-{
-  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;
+  live_seq = sequent_regs_live ();
+  minimize = (TARGET_CALL_PROLOGUES
+             && !(cfun->machine->is_interrupt || cfun->machine->is_signal) 
+             && live_seq);
 
-  if (do_save)
+  if (cfun->machine->is_interrupt || cfun->machine->is_signal)
     {
-      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
-      size++;
-    }
+      if (cfun->machine->is_interrupt)
+        {
+          /* Enable interrupts.  */
+          insn = emit_insn (gen_enable_interrupt ());
+          RTX_FRAME_RELATED_P (insn) = 1;
+        }
+       
+      /* Push zero reg.  */
+      insn = emit_move_insn (pushbyte, zero_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Push tmp reg.  */
+      insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Push SREG.  */
+      insn = emit_move_insn (tmp_reg_rtx, 
+                             gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      
+      /* Clear zero reg.  */
+      insn = emit_move_insn (zero_reg_rtx, const0_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
 
-  if (do_cli)
-    {
-      fprintf (file, "cli" CR_TAB);
-      size++;
+      /* Prevent any attempt to delete the setting of ZERO_REG!  */
+      emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
     }
-
-  /* Do SPH first - maybe this will disable interrupts for one instruction
-     someday (a suggestion has been sent to avr@atmel.com for consideration
-     in future devices - that would make -mno-interrupts always safe).  */
-  if (do_sph)
+  if (cfun->machine->is_main)
     {
-      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
-      size++;
+      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;
+      insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
-
-  /* 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)
+  else if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
-      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
-      size++;
+      insn = 
+        emit_insn (gen_call_prologue_saves (gen_int_mode (size, HImode),
+                                            gen_int_mode (live_seq, HImode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
-  else if (do_sei)
+  else
     {
-      fprintf (file, "sei" CR_TAB);
-      size++;
+      HARD_REG_SET set;
+      avr_regs_to_save (&set);
+      int reg;
+      for (reg = 0; reg < 32; ++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;
+            }
+        }
+      if (frame_pointer_needed)
+        {
+          /* Push frame pointer.  */
+         insn = emit_move_insn (pushword, frame_pointer_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+          if (!size)
+            {
+              insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
+          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 (0, "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 =
+               get_attr_length (gen_move_insn (frame_pointer_rtx, stack_pointer_rtx));
+              method1_length +=
+               get_attr_length (gen_move_insn (myfp, 
+                                                gen_rtx_PLUS (GET_MODE(myfp), myfp,
+                                                              gen_int_mode (-size, 
+                                                                           GET_MODE(myfp)))));
+              method1_length += 
+               get_attr_length (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 = 
+                   get_attr_length (gen_move_insn (stack_pointer_rtx,
+                                                    gen_rtx_PLUS (HImode, stack_pointer_rtx,
+                                                                  gen_int_mode (-size, 
+                                                                               HImode))));
+                 sp_plus_length += 
+                   get_attr_length (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_PLUS (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;
+                }
+              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;
+                }
+            }
+        }
     }
-
-  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
-
-  return size;
 }
 
-
-/* Output function prologue.  */
+/* Output summary at end of function prologue.  */
 
 static void
-avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
+avr_asm_function_end_prologue (FILE *file)
 {
-  int reg;
-  int interrupt_func_p;
-  int signal_func_p;
-  int main_p;
-  int live_seq;
-  int minimize;
-
-  last_insn_address = 0;
-  jump_tables_size = 0;
-  prologue_size = 0;
-  fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
-          size);
-
-  if (avr_naked_function_p (current_function_decl))
+  if (cfun->machine->is_naked)
     {
       fputs ("/* prologue: naked */\n", file);
-      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);
-
-  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 (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;
     }
-  else if (minimize && (frame_pointer_needed || live_seq > 6)) 
+  else
     {
-      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;
-       }
+      if (cfun->machine->is_interrupt)
+        {
+          fputs ("/* prologue: Interrupt */\n", file);
+        }
+      else if (cfun->machine->is_signal)
+        {
+          fputs ("/* prologue: Signal */\n", file);
+        }
+      else if (cfun->machine->is_main)
+        {
+          fputs ("/* prologue: main */\n", file);
+        }
       else
-       {
-         fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
-                  (18 - live_seq) * 2);
-         ++prologue_size;
-       }
-      fputs ("1:\n", file);
+        fputs ("/* prologue: function */\n", file);
     }
-  else
-    {
-      HARD_REG_SET set;
+  fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n",
+                 get_frame_size());
+}
 
-      prologue_size += avr_regs_to_save (&set);
-      for (reg = 0; reg < 32; ++reg)
-       {
-         if (TEST_HARD_REG_BIT (set, reg))
-           {
-             fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
-           }
-       }
-      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);
 
-             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);
-               }
-           }
-       }
-    }
+/* Implement EPILOGUE_USES.  */
 
- out:
-  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
+int
+avr_epilogue_uses (int regno ATTRIBUTE_UNUSED)
+{
+  if (reload_completed 
+      && cfun->machine
+      && (cfun->machine->is_interrupt || cfun->machine->is_signal))
+    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 ();
-
-  function_size = jump_tables_size;
-  if (last)
-    {
-      rtx first = get_first_nonnote_insn ();
-      function_size += (INSN_ADDRESSES (INSN_UID (last)) -
-                       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);
-      goto out;
-    }
-
-  if (last && GET_CODE (last) == BARRIER)
+  HOST_WIDE_INT size = get_frame_size();
+  rtx insn;
+  
+  /* epilogue: naked  */
+  if (cfun->machine->is_naked)
     {
-      fputs ("/* epilogue: noreturn */\n", file);
-      goto out;
+      insn = emit_jump_insn (gen_return ());
+      RTX_FRAME_RELATED_P (insn) = 1;
+      return;
     }
 
-  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->is_interrupt || cfun->machine->is_signal)
+             && live_seq);
   
-  if (main_p)
+  if (cfun->machine->is_main)
     {
       /* 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_jump_insn (gen_return ());
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
   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);
-       }
-      else
-       {
-         fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
-                         AS2 (in , r29, __SP_H__) CR_TAB));
-         epilogue_size += 2;
-       }
-      
-      if (AVR_MEGA)
-       {
-         fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
-                  (18 - live_seq) * 2);
-         epilogue_size += 2;
+          /*  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;
        }
       else
        {
-         fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
-                  (18 - live_seq) * 2);
-         ++epilogue_size;
+          insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
        }
+       
+      insn = 
+        emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
   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 = 
+               get_attr_length (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 += 
+               get_attr_length (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 = 
+                   get_attr_length (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;
+                }
+              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;
+                }
+            }
+        
+          /* Restore previous frame_pointer.  */
+         insn = emit_insn (gen_pophi (frame_pointer_rtx));
+          RTX_FRAME_RELATED_P (insn) = 1;
        }
-
-      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;
+            }
+        }
+      if (cfun->machine->is_interrupt || cfun->machine->is_signal)
+        {
 
-      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");
-       }
-      else
-       fprintf (file, "\tret\n");
-      ++epilogue_size;
-    }
+          /* Restore SREG using tmp reg as scratch.  */
+          insn = emit_insn (gen_popqi (tmp_reg_rtx));
+          RTX_FRAME_RELATED_P (insn) = 1;
+      
+          insn = emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
+                                tmp_reg_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+
+          /* Restore tmp REG.  */
+          insn = emit_insn (gen_popqi (tmp_reg_rtx));
+          RTX_FRAME_RELATED_P (insn) = 1;
 
- 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;
+          /* Restore zero REG.  */
+          insn = emit_insn (gen_popqi (zero_reg_rtx));
+         RTX_FRAME_RELATED_P (insn) = 1;
+        }
+
+      insn = emit_jump_insn (gen_return ());
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 }
 
+/* Output summary messages at beginning of function epilogue.  */
+
+static void
+avr_asm_function_begin_epilogue (FILE *file)
+{
+  fprintf (file, "/* epilogue start */\n");
+}
 
 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
    machine for a memory operand of mode MODE.  */
@@ -1651,13 +1648,31 @@ output_movhi (rtx insn, rtx operands[], int *l)
                  *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 
+                            && cfun->machine->is_main 
+                            && prologue_epilogue_contains (insn))
+                        || (reload_completed 
+                            && cfun->machine->is_signal 
+                            && prologue_epilogue_contains (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 
+                        && cfun->machine->is_interrupt
+                        && prologue_epilogue_contains (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
@@ -1798,6 +1813,11 @@ out_movqi_r_mr (rtx insn, rtx op[], int *l)
   
   if (CONSTANT_ADDRESS_P (x))
     {
+      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+       {
+         *l = 1;
+         return AS2 (in,%0,__SREG__);
+       }
       if (avr_io_address_p (x, 1))
        {
          *l = 1;
@@ -2481,6 +2501,11 @@ out_movqi_mr_r (rtx insn, rtx op[], int *l)
   
   if (CONSTANT_ADDRESS_P (x))
     {
+      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+       {
+         *l = 1;
+         return AS2 (out,__SREG__,%1);
+       }
       if (avr_io_address_p (x, 1))
        {
          *l = 1;
@@ -5772,8 +5797,6 @@ avr_output_addr_vec_elt (FILE *stream, int value)
     fprintf (stream, "\t.word pm(.L%d)\n", value);
   else
     fprintf (stream, "\trjmp .L%d\n", value);
-
-  jump_tables_size++;
 }
 
 /* Returns 1 if SCRATCH are safe to be allocated as a scratch
index a7216f4..9c80f53 100644 (file)
@@ -63,6 +63,9 @@ extern GTY(()) section *progmem_section;
 #define AVR_HAVE_MOVW (avr_have_movw_lpmx_p)
 #define AVR_HAVE_LPMX (avr_have_movw_lpmx_p)
 
+#define AVR_2_BYTE_PC 1
+#define AVR_3_BYTE_PC 0
+
 #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
 
 #define OVERRIDE_OPTIONS avr_override_options ()
@@ -338,7 +341,7 @@ extern int avr_reg_order[];
 
 #define DEFAULT_PCC_STRUCT_RETURN 0
 
-#define EPILOGUE_USES(REGNO) 0
+#define EPILOGUE_USES(REGNO) avr_epilogue_uses(REGNO)
 
 #define HAVE_POST_INCREMENT 1
 #define HAVE_PRE_DECREMENT 1
@@ -933,3 +936,22 @@ mmcu=*:-mmcu=%*}"
 #define DWARF2_ADDR_SIZE 4
 
 #define OBJECT_FORMAT_ELF
+
+/* A C structure for machine-specific, per-function data.
+   This is added to the cfun structure.  */
+struct machine_function GTY(())
+{
+  /* 'true' - if current function is a 'main' function.  */
+  int is_main;
+
+  /* 'true' - if current function is a naked function.  */
+  int is_naked;
+
+  /* 'true' - if current function is an interrupt function 
+     as specified by the "interrupt" attribute.  */
+  int is_interrupt;
+
+  /* 'true' - if current function is a signal function 
+     as specified by the "signal" attribute.  */
+  int is_signal;
+};
index a71e76c..34dc703 100644 (file)
    (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)
+
+   (UNSPECV_PROLOGUE_SAVES     0)
+   (UNSPECV_EPILOGUE_RESTORES  1)])
 
 (include "predicates.md")
 (include "constraints.md")
                       (const_int 2))]
         (const_int 2)))
 
-(define_insn "*pop1"
-  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))]
-  ""
-  "pop __tmp_reg__"
-  [(set_attr "length" "1")])
-
-(define_insn "*pop2"
-  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 2)))]
-  ""
-  "pop __tmp_reg__
-       pop __tmp_reg__"
-  [(set_attr "length" "2")])
-
-(define_insn "*pop3"
-  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 3)))]
-  ""
-  "pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__"
-  [(set_attr "length" "3")])
-
-(define_insn "*pop4"
-  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 4)))]
-  ""
-  "pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__"
-  [(set_attr "length" "4")])
-
-(define_insn "*pop5"
-  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 5)))]
-  ""
-  "pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__
-       pop __tmp_reg__"
-  [(set_attr "length" "5")])
-
 (define_insn "*pushqi"
   [(set (mem:QI (post_dec (reg:HI REG_SP)))
         (match_operand:QI 0 "reg_or_0_operand" "r,L"))]
     }
 }")
 
+(define_insn "*movhi_sp"
+  [(set (match_operand:HI 0 "register_operand" "=q,r")
+        (match_operand:HI 1 "register_operand"  "r,q"))]
+  "((stack_register_operand(operands[0], HImode) && register_operand (operands[1], HImode))
+    || (register_operand (operands[0], HImode) && stack_register_operand(operands[1], HImode)))"
+  "* return output_movhi (insn, operands, NULL);"
+  [(set_attr "length" "5,2")
+   (set_attr "cc" "none,none")])
 
 (define_peephole2
   [(match_scratch:QI 2 "d")
   [(set_attr "length" "3")
    (set_attr "cc" "set_n")])
 
+(define_insn "*addhi3_sp_R_pc2"
+  [(set (match_operand:HI 1 "stack_register_operand" "=q")
+        (plus:HI (match_operand:HI 2 "stack_register_operand" "q")
+                 (match_operand:HI 0 "avr_sp_immediate_operand" "R")))]
+  "AVR_2_BYTE_PC"
+  "*{
+      if (CONST_INT_P (operands[0]))
+        {
+         switch(INTVAL (operands[0]))
+           {
+           case -6: 
+             return \"rcall .\" CR_TAB 
+                    \"rcall .\" CR_TAB 
+                    \"rcall .\";
+           case -5: 
+             return \"rcall .\" CR_TAB 
+                    \"rcall .\" CR_TAB 
+                    \"push __tmp_reg__\";
+           case -4: 
+             return \"rcall .\" CR_TAB 
+                    \"rcall .\";
+           case -3: 
+             return \"rcall .\" CR_TAB 
+                    \"push __tmp_reg__\";
+           case -2: 
+             return \"rcall .\";
+           case -1: 
+             return \"push __tmp_reg__\";
+           case 0: 
+             return \"\";
+           case 1: 
+             return \"pop __tmp_reg__\";
+           case 2: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 3: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 4: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 5: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           }
+        }
+      return \"bug\";
+    }"
+  [(set (attr "length") 
+        (cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
+               (eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
+               (eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int  0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
+               (eq (const_int  1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int  2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int  3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
+               (eq (const_int  4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
+               (eq (const_int  5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
+               (const_int 0)))])
+
+(define_insn "*addhi3_sp_R_pc3"
+  [(set (match_operand:HI 1 "stack_register_operand" "=q")
+        (plus:HI (match_operand:HI 2 "stack_register_operand" "q")
+                 (match_operand:QI 0 "avr_sp_immediate_operand" "R")))]
+  "AVR_3_BYTE_PC"
+  "*{
+      if (CONST_INT_P (operands[0]))
+        {
+         switch(INTVAL (operands[0]))
+           {
+           case -6: 
+             return \"rcall .\" CR_TAB 
+                    \"rcall .\";
+           case -5: 
+             return \"rcall .\" CR_TAB 
+                    \"push __tmp_reg__\" CR_TAB 
+                    \"push __tmp_reg__\";
+           case -4: 
+             return \"rcall .\" CR_TAB 
+                    \"push __tmp_reg__\";
+           case -3: 
+             return \"rcall .\";
+           case -2: 
+             return \"push __tmp_reg__\" CR_TAB 
+                    \"push __tmp_reg__\";
+           case -1: 
+             return \"push __tmp_reg__\";
+           case 0: 
+             return \"\";
+           case 1: 
+             return \"pop __tmp_reg__\";
+           case 2: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 3: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 4: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           case 5: 
+             return \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\" CR_TAB 
+                    \"pop __tmp_reg__\";
+           }
+        }
+      return \"bug\";
+    }"
+  [(set (attr "length") 
+        (cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
+               (eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int  0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
+               (eq (const_int  1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
+               (eq (const_int  2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
+               (eq (const_int  3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
+               (eq (const_int  4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
+               (eq (const_int  5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
+               (const_int 0)))])
+
 (define_insn "*addhi3"
   [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
        (plus:HI
   return AS1 (rjmp,%0);
 }"
   [(set (attr "length")
-       (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047))
-                          (le (minus (pc) (match_dup 0)) (const_int 2047)))
-                     (const_int 1)
-                     (const_int 2)))
+       (if_then_else (match_operand 0 "symbol_ref_operand" "") 
+               (if_then_else (eq_attr "mcu_mega" "no")
+                             (const_int 1)
+                             (const_int 2))
+               (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047))
+                                  (le (minus (pc) (match_dup 0)) (const_int 2047)))
+                             (const_int 1)
+                             (const_int 2))))
    (set_attr "cc" "none")])
 
 ;; call
                                        (const_int 1))
                          (const_int 3)])])
 
-(define_insn "return"
-  [(return)]
-  "reload_completed && avr_simple_epilogue ()"
-  "ret"
-  [(set_attr "cc" "none")
-   (set_attr "length" "1")])
-
 (define_insn "nop"
   [(const_int 0)]
   ""
                      (pc)))]
   "jump_over_one_insn_p (insn, operands[2])"
   "cpse %0,%1")
+
+;;pppppppppppppppppppppppppppppppppppppppppppppppppppp
+;;prologue/epilogue support instructions
+
+(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")])
+
+;; 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")
+  ])
+
+;;  Library prologue saves
+(define_insn "call_prologue_saves"
+  [(unspec_volatile:HI [(const_int 0)] UNSPECV_PROLOGUE_SAVES)
+   (set (reg:HI REG_SP) (minus:HI 
+                           (reg:HI REG_SP)
+                           (match_operand:HI 0 "immediate_operand" "")))
+   (set (reg:HI REG_SP) (minus:HI 
+                           (reg:HI REG_SP)
+                           (match_operand:HI 1 "immediate_operand" "")))
+   (set (reg:HI REG_X) (match_dup 0))
+   (clobber (reg:HI REG_Z))]
+  ""
+  "ldi r26,lo8(%0)
+       ldi r27,hi8(%0)
+       ldi r30,pm_lo8(1f)
+       ldi r31,pm_hi8(1f)
+       %~jmp __prologue_saves__+((18 - %1) * 2)
+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 REG_Y ) (plus:HI 
+                           (reg:HI REG_Y)
+                           (match_operand:HI 0 "immediate_operand" ""))) 
+   (set (reg:HI REG_SP) (reg:HI REG_Y))
+   (clobber  (reg:QI REG_Z))]
+  ""
+  "ldi r30, lo8(%0)
+       %~jmp __epilogue_restores__ + ((18 - %0) * 2)"
+  [(set_attr_alternative "length"
+                        [(if_then_else (eq_attr "mcu_mega" "yes")
+                                       (const_int 3)
+                                       (const_int 2))])
+  (set_attr "cc" "clobber")
+  ])
+  
+; return
+(define_insn "return"
+  [(return)]
+  "reload_completed && avr_simple_epilogue ()"
+  "ret"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+(define_insn "return_from_epilogue"
+  [(return)]
+  "(reload_completed 
+    && cfun->machine 
+    && !cfun->machine->is_main
+    && !(cfun->machine->is_interrupt || cfun->machine->is_signal)
+    && !cfun->machine->is_naked)"
+  "ret"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+(define_insn "return_from_main_epilogue"
+  [(return)]
+  "(reload_completed 
+    && cfun->machine 
+    && cfun->machine->is_main
+    && !cfun->machine->is_naked)"
+  "%~jmp exit"
+  [(set_attr_alternative "length"
+                        [(if_then_else (eq_attr "mcu_mega" "yes")
+                                       (const_int 2)
+                                       (const_int 1))])
+  (set_attr "cc" "none")
+  ])
+  
+(define_insn "return_from_interrupt_epilogue"
+  [(return)]
+  "(reload_completed 
+    && cfun->machine 
+    && !cfun->machine->is_main
+    && (cfun->machine->is_interrupt || cfun->machine->is_signal)
+    && !cfun->machine->is_naked)"
+  "reti"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+(define_insn "return_from_naked_epilogue"
+  [(return)]
+  "(reload_completed 
+    && cfun->machine 
+    && cfun->machine->is_naked)"
+  ""
+  [(set_attr "cc" "none")
+   (set_attr "length" "0")])
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "
+  {
+    expand_prologue (); 
+    DONE;
+  }")
+
+(define_expand "epilogue"
+  [(const_int 0)]
+  ""
+  "
+  {
+    expand_epilogue (); 
+    DONE;
+  }")
index eca5cbe..f3ff9e9 100644 (file)
   (and (match_code "const_double")
        (match_test "op == CONST0_RTX (SFmode)")))
 
+(define_constraint "R"
+  "Integer constant in the range -6 @dots{} 5."
+  (and (match_code "const_int")
+       (match_test "ival >= -6 && ival <= 5")))
+       
 (define_memory_constraint "Q"
   "A memory address based on X or Y pointer with displacement."
   (and (match_code "mem")
index 914ad9b..acc82f6 100755 (executable)
 (define_predicate "single_zero_operand"
   (and (match_code "const_int")
        (match_test "exact_log2(~INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
-      
+
+;;
+(define_predicate "avr_sp_immediate_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) >= -6 && INTVAL (op) <= 5")))
+
 ;; True for EQ & NE
 (define_predicate "eqne_operator"
   (match_code "eq,ne"))