This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[patch] avr-gcc -mtiny-stack and other changes


Hi,

This is my first larger batch of avr-gcc improvements (hopefully!).
Tested for a while, but please review for "brown paper bag" bugs.
Suggestions are also welcome, of course.

I apologize in advance for making several logical changes in one patch -
I have even more pending patches, and it would take very long to submit
everything synchronously (by analogy to synchronous filesystem writes:
send one patch, wait for it to be approved and applied, then send
another one... must be slow if there are 10 or so patches).

Some of the other patches (multilib support etc.) will need to be
applied to both gcc and binutils at the same time, so I'm saving
them for later (to not distract Denis from the avr-gdb work too much
right now).  They are available at:

	http://www.itnet.pl/amelektr/avr/experimental/

This patch does the following:
 - fix for libgcc2 (instead of __muldi3, there was __mulhi3 etc.).
 - new option -mtiny-stack (generate smaller code by assuming that
   the entire stack fits within one 256-byte page, so there is no
   need to ever change the high byte), should be especially useful
   for small devices (<256 bytes of RAM).
 - some cleanups (move common pieces of code to functions, make
   HARD_REGNO_MODE_OK call a function, so it can be hacked further
   without recompiling everything after each avr.h change).
 - write SPH before SPL - this is consistent with the recommendation
   for other 16-bit I/O registers, written via TEMP register.  This
   doesn't change much now, but will if Atmel ever adds one feature
   I suggested to them: when SPH is written, disable interrupts for the
   next instruction so it can write SPL without an interrupt in between.
   (The idea is that you either change both SPH and SPL, or only SPL.
   The latter is atomic and doesn't require disabling interrupts.
   So interrupts should be disabled after writing SPH, and not SPL.)

Thanks,
Marek

gcc/ChangeLog:

2000-06-24  Marek Michalkiewicz  <marekm@linux.org.pl>

	* config/avr/avr-protos.h (avr_hard_regno_mode_ok): New prototype.
	* config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr):
	New functions, common code moved from function_{prologue,epilogue}
	and extended to support the -mtiny-stack option.
	(function_prologue, function_epilogue): Use them.
	Use lo8/hi8 consistently for asm output readability.
	(avr_hard_regno_mode_ok): New function.
	* config/avr/avr.h (TARGET_SWITCHES): Fix typo.  Add -mtiny-stack.
	(UNITS_PER_WORD): Define as 4 (not 1) when compiling libgcc2.c.
	(HARD_REGNO_MODE_OK): Call the avr_hard_regno_mode_ok function.
	* config/avr/avr.md (*mov_sp_r): Add support for -mtiny-stack.
	Write SPH before SPL.
	(*movqi): No need to disable interrupts for just one "out"
	in alternative 5.  Change length attribute from 4 to 1.
	* config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
	Write SPH before SPL.


diff -Nrc3p orig/egcs/gcc/config/avr/avr-protos.h egcs/gcc/config/avr/avr-protos.h
*** orig/egcs/gcc/config/avr/avr-protos.h	Fri May 12 17:35:57 2000
--- egcs/gcc/config/avr/avr-protos.h	Sat Jun 24 10:54:41 2000
*************** extern int    byte_immediate_operand PAR
*** 138,143 ****
--- 138,145 ----
  extern int    test_hard_reg_class    PARAMS ((enum reg_class class, rtx x));
  extern int    jump_over_one_insn_p   PARAMS ((rtx insn, rtx dest));
  
+ extern int    avr_hard_regno_mode_ok PARAMS ((int regno,
+ 					     enum machine_mode mode));
  #endif /* RTX_CODE */
  
  #ifdef HAVE_MACHINE_MODES
diff -Nrc3p orig/egcs/gcc/config/avr/avr.c egcs/gcc/config/avr/avr.c
*** orig/egcs/gcc/config/avr/avr.c	Sat Jun 10 11:26:20 2000
--- egcs/gcc/config/avr/avr.c	Sat Jun 24 15:46:30 2000
*************** static int    signal_function_p    PARAM
*** 49,54 ****
--- 49,56 ----
  static int    sequent_regs_live    PARAMS ((void));
  static char * ptrreg_to_str        PARAMS ((int));
  static char * cond_string          PARAMS ((enum rtx_code));
+ static int    out_adj_frame_ptr    PARAMS ((FILE *, int));
+ static int    out_set_stack_ptr    PARAMS ((FILE *, int, int));
  
  
  /* Allocate registers from r25 to r8 for parameters for function calls */
*************** sequent_regs_live ()
*** 332,337 ****
--- 334,457 ----
  }
  
  
+ /* 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, adj)
+      FILE *file;
+      int adj;
+ {
+   int size = 0;
+ 
+   if (adj)
+     {
+       /* For -mtiny-stack, the high byte (r29) does not change -
+ 	 prefer "subi" (1 cycle) over "sbiw" (2 cycles).  */
+ 
+       if (adj < -63 || adj > 63 || TARGET_TINY_STACK)
+ 	{
+ 	  fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB), adj);
+ 	  size++;
+ 
+ 	  if (TARGET_TINY_STACK)
+ 	    {
+ 	      /* In addition to any local data, each level of function calls
+ 		 needs at least 4 more bytes of stack space for the saved
+ 		 frame pointer and return address.  So, (255 - 16) leaves
+ 		 room for 4 levels of function calls.  */
+ 
+ 	      if (adj < -(255 - 16) || adj > (255 - 16))
+ 		fatal ("Frame pointer change (%d) too big for -mtiny-stack",
+ 		       adj);
+ 	    }
+ 	  else
+ 	    {
+ 	      fprintf (file, (AS2 (sbci, r29, hi8(%d)) CR_TAB), adj);
+ 	      size++;
+ 	    }
+ 	}
+       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;
+ }
+ 
+ 
+ /* 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, before, after)
+      FILE *file;
+      int before;
+      int after;
+ {
+   int do_sph, do_cli, do_save, size;
+ 
+   if (TARGET_NO_INTERRUPTS)
+     {
+       before = 0;
+       after = 0;
+     }
+ 
+   do_sph = !TARGET_TINY_STACK;
+   do_cli = (before != 0 && (after == 0 || do_sph));
+   do_save = (before == -1 && after == -1 && do_cli);
+   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, much like x86 does when changing SS (a suggestion has been
+      sent to avr@atmel.com for consideration in future devices).  */
+   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 starts.  This was not clearly documented.
+      XXX - verify this on the new devices with enhanced AVR core.  */
+   if (do_save)
+     {
+       fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
+       size++;
+     }
+   else if (after == 1 && (before != 1 || do_cli))
+     {
+       fprintf (file, "sei" CR_TAB);
+       size++;
+     }
+ 
+   fprintf (file, AS2 (out, __SP_L__, r28) "\n");
+ 
+   return size;
+ }
+ 
+ 
  /* Output function prologue */
  
  void
*************** function_prologue (FILE *file, int size)
*** 392,399 ****
    else if (minimize && (frame_pointer_needed || live_seq > 6)) 
      {
        fprintf (file, ("\t"
! 		      AS2 (ldi, r26, %d) CR_TAB
! 		      AS2 (ldi, r27, %d) CR_TAB), size & 0xff, size / 0x100);
  
        fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
  		      AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
--- 512,519 ----
    else if (minimize && (frame_pointer_needed || live_seq > 6)) 
      {
        fprintf (file, ("\t"
! 		      AS2 (ldi, r26, lo8(%d)) CR_TAB
! 		      AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size);
  
        fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
  		      AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
*************** function_prologue (FILE *file, int size)
*** 444,487 ****
  	    prologue_size += 4;
  	    if (size)
  	      {
! 		if (size > 63)
! 		  {
! 		    fprintf (file, ("\t"
! 				    AS2 (subi,r28,%d) CR_TAB
! 				    AS2 (sbci,r29,%d) CR_TAB)
! 			     , size & 0xff, size / 0x100);
! 		    prologue_size += 2;
! 		  }
! 		else
! 		  {
! 		    fprintf (file, "\t" AS2 (sbiw,r28,%d) CR_TAB, size);
! 		    ++prologue_size;
! 		  }
  		if (interrupt_func_p)
  		  {
! 		    fprintf (file,
! 			     "cli" CR_TAB
! 			     AS2 (out,__SP_L__,r28) CR_TAB
! 			     "sei" CR_TAB
! 			     AS2 (out,__SP_H__,r29) "\n");
! 		    prologue_size += 4;
  		  }
! 		else if (signal_func_p || TARGET_NO_INTERRUPTS)
  		  {
! 		    fprintf (file,
! 			     AS2 (out,__SP_L__,r28) CR_TAB
! 			     AS2 (out,__SP_H__,r29) "\n");
! 		    prologue_size += 2;
  		  }
  		else
  		  {
! 		    fprintf (file,
! 			     AS2 (in,__tmp_reg__,__SREG__) CR_TAB
! 			     "cli" CR_TAB
! 			     AS2 (out,__SP_L__,r28) CR_TAB
! 			     AS2 (out,__SREG__,__tmp_reg__) CR_TAB
! 			     AS2 (out,__SP_H__,r29) "\n");
! 		    prologue_size += 5;
  		  }
  	      }
  	  }
--- 564,583 ----
  	    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);
  		  }
  	      }
  	  }
*************** function_epilogue (FILE *file, int size)
*** 533,552 ****
        ++epilogue_size;
        if (frame_pointer_needed)
  	{
! 	  if (size)
! 	    {
! 	      if (size > 63)
! 		{
! 		  fprintf (file, AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
! 		  fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
! 		  epilogue_size += 2;
! 		}
! 	      else
! 		{
! 		  fprintf (file, AS2 (adiw,r28,%d) CR_TAB, size);
! 		  ++epilogue_size;
! 		}
! 	    }
  	}
        else
  	{
--- 629,635 ----
        ++epilogue_size;
        if (frame_pointer_needed)
  	{
! 	  epilogue_size += out_adj_frame_ptr (file, -size);
  	}
        else
  	{
*************** function_epilogue (FILE *file, int size)
*** 574,614 ****
  	{
  	  if (size)
  	    {
! 	      if (size > 63)
! 		{
! 		  fprintf (file, "\t" AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
! 		  fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
! 		  epilogue_size += 2;
! 		}
! 	      else
! 		{
! 		  fprintf (file, "\t" AS2 (adiw,r28,%d) CR_TAB, size);
! 		  ++epilogue_size;
! 		}
  	      if (interrupt_func_p | signal_func_p)
  		{
! 		  fprintf (file,
! 			   "cli" CR_TAB
! 			   AS2 (out,__SP_L__,r28) CR_TAB
! 			   AS2 (out,__SP_H__,r29) "\n");
! 		  epilogue_size += 3;
! 		}
! 	      else if (TARGET_NO_INTERRUPTS)
! 		{
! 		  fprintf (file,
! 			   AS2 (out,__SP_L__,r28) CR_TAB
! 			   AS2 (out,__SP_H__,r29) "\n");
! 		  epilogue_size += 2;
  		}
  	      else
  		{
! 		  fprintf (file,
! 			   AS2 (in,__tmp_reg__,__SREG__) CR_TAB
! 			   "cli" CR_TAB
! 			   AS2 (out,__SP_L__,r28) CR_TAB
! 			   AS2 (out,__SREG__,__tmp_reg__) CR_TAB
! 			   AS2 (out,__SP_H__,r29) "\n");
! 		  epilogue_size += 5;
  		}
  	    }
  	  fprintf (file, "\t"
--- 657,672 ----
  	{
  	  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"
*************** jump_over_one_insn_p (insn, dest)
*** 3885,3888 ****
--- 3943,3963 ----
    int jump_addr = insn_addresses[INSN_UID (insn)];
    int dest_addr = insn_addresses[uid];
    return dest_addr - jump_addr == 2;
+ }
+ 
+ /* Returns 1 if a value of mode MODE can be stored starting with hard
+    register number REGNO.  On the enhanced core, it should be a win to
+    align modes larger than QI on even register numbers (even if < 24).
+    so that the "movw" instruction can be used on them.  */
+ 
+ int
+ avr_hard_regno_mode_ok (regno, mode)
+      int regno;
+      enum machine_mode mode;
+ {
+   if (mode == QImode)
+     return 1;
+   if (regno < 24 /* && !TARGET_ENHANCED */ )
+     return 1;
+   return !(regno & 1);
  }
diff -Nrc3p orig/egcs/gcc/config/avr/avr.h egcs/gcc/config/avr/avr.h
*** orig/egcs/gcc/config/avr/avr.h	Wed Jun 14 17:40:26 2000
--- egcs/gcc/config/avr/avr.h	Sat Jun 24 10:52:34 2000
*************** extern int target_flags;
*** 52,57 ****
--- 52,58 ----
  #define TARGET_NO_INTERRUPTS	(target_flags & 0x20000)
  #define TARGET_INSN_SIZE_DUMP	(target_flags &  0x2000)
  #define TARGET_CALL_PROLOGUES	(target_flags & 0x40000)
+ #define TARGET_TINY_STACK	(target_flags & 0x80000)
  
  /* Dump each assembler insn's rtl into the output file.
     This is for debugging the compiler itself.  */
*************** extern int target_flags;
*** 87,93 ****
    {"int8",0x10000,"Assume int to be 8 bit integer"},			\
    {"no-interrupts",0x20000,"Don't output interrupt compatible code"},	\
    {"call-prologues",0x40000,						\
!    "Use subroutines for functions prologeu/epilogue"},			\
    {"rtl",0x10, NULL},							\
    {"size",0x2000,"Output instruction size's to the asm file"},		\
    {"deb",0xfe0, NULL},							\
--- 88,95 ----
    {"int8",0x10000,"Assume int to be 8 bit integer"},			\
    {"no-interrupts",0x20000,"Don't output interrupt compatible code"},	\
    {"call-prologues",0x40000,						\
!    "Use subroutines for functions prologue/epilogue"},			\
!   {"tiny-stack", 0x80000, "Change only low 8 bits of stack pointer"},	\
    {"rtl",0x10, NULL},							\
    {"size",0x2000,"Output instruction size's to the asm file"},		\
    {"deb",0xfe0, NULL},							\
*************** extern struct mcu_type_s *avr_mcu_type;
*** 194,201 ****
--- 196,208 ----
     Note that this is not necessarily the width of data type `int';  */
  #define BITS_PER_WORD 8
  
+ #ifdef IN_LIBGCC2
+ /* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits).  */
+ #define UNITS_PER_WORD 4
+ #else
  /* Width of a word, in units (bytes). */
  #define UNITS_PER_WORD 1
+ #endif
  
  /* Width in bits of a pointer.
     See also the macro `Pmode' defined below.  */
*************** extern struct mcu_type_s *avr_mcu_type;
*** 452,460 ****
     ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
     / UNITS_PER_WORD))  */
  
! #define HARD_REGNO_MODE_OK(REGNO, MODE) (((REGNO) >= 24 && (MODE) != QImode) \
! 					 ? ! ((REGNO) & 1)		     \
! 					 : 1)
  /* A C expression that is nonzero if it is permissible to store a
     value of mode MODE in hard register number REGNO (or in several
     registers starting with that one).  For a machine where all
--- 459,465 ----
     ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
     / UNITS_PER_WORD))  */
  
! #define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE)
  /* A C expression that is nonzero if it is permissible to store a
     value of mode MODE in hard register number REGNO (or in several
     registers starting with that one).  For a machine where all
diff -Nrc3p orig/egcs/gcc/config/avr/avr.md egcs/gcc/config/avr/avr.md
*** orig/egcs/gcc/config/avr/avr.md	Sat May 13 10:03:33 2000
--- egcs/gcc/config/avr/avr.md	Sat Jun 24 11:53:10 2000
***************
*** 147,168 ****
  (define_insn "*mov_sp_r"
    [(set (reg:HI 32)
          (match_operand:HI 0 "register_operand" "r"))]
!   "!TARGET_NO_INTERRUPTS"
    "in __tmp_reg__,__SREG__
  	cli
! 	out __SP_L__,%A0
  	out __SREG__,__tmp_reg__
! 	out __SP_H__,%B0"
    [(set_attr "length" "5")])
  
  (define_insn "*mov_sp_r_no_interrupts"
    [(set (reg:HI 32)
          (match_operand:HI 0 "register_operand" "r"))]
!   "TARGET_NO_INTERRUPTS"
!   "out __SP_L__,%A0
! 	out __SP_H__,%B0"
    [(set_attr "length" "2")])
  
  ;;========================================================================
  ;; move byte
  (define_expand "movqi"
--- 147,175 ----
  (define_insn "*mov_sp_r"
    [(set (reg:HI 32)
          (match_operand:HI 0 "register_operand" "r"))]
!   "(!TARGET_TINY_STACK && !TARGET_NO_INTERRUPTS)"
    "in __tmp_reg__,__SREG__
  	cli
! 	out __SP_H__,%B0
  	out __SREG__,__tmp_reg__
! 	out __SP_L__,%A0"
    [(set_attr "length" "5")])
  
  (define_insn "*mov_sp_r_no_interrupts"
    [(set (reg:HI 32)
          (match_operand:HI 0 "register_operand" "r"))]
!   "(!TARGET_TINY_STACK && TARGET_NO_INTERRUPTS)"
!   "out __SP_H__,%B0
! 	out __SP_L__,%A0"
    [(set_attr "length" "2")])
  
+ (define_insn "*mov_sp_r_tiny"
+   [(set (reg:HI 32)
+         (match_operand:HI 0 "register_operand" "r"))]
+   "TARGET_TINY_STACK"
+   "out __SP_L__,%A0"
+   [(set_attr "length" "1")])
+ 
  ;;========================================================================
  ;; move byte
  (define_expand "movqi"
***************
*** 209,221 ****
        case 4:
          return out_movqi_r_mr (insn,operands,NULL);
        case 5:
!         return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB
! 	        \"cli\"                       CR_TAB
! 	        AS2 (out,__SREG__,__tmp_reg__)CR_TAB
! 	        AS2 (out,%0,%1));
        }
  }"
!   [(set_attr "length" "1,1,1,5,5,4")
     (set_attr "cc" "none,clobber,none,clobber,clobber,none")])
  
  ;;============================================================================
--- 216,225 ----
        case 4:
          return out_movqi_r_mr (insn,operands,NULL);
        case 5:
!         return (AS2 (out,%0,%1));
        }
  }"
!   [(set_attr "length" "1,1,1,5,5,1")
     (set_attr "cc" "none,clobber,none,clobber,clobber,none")])
  
  ;;============================================================================
diff -Nrc3p orig/egcs/gcc/config/avr/libgcc.S egcs/gcc/config/avr/libgcc.S
*** orig/egcs/gcc/config/avr/libgcc.S	Thu Jun  8 19:00:50 2000
--- egcs/gcc/config/avr/libgcc.S	Sat Jun 24 13:57:44 2000
*************** __prologue_saves__:
*** 583,591 ****
  	sbc	r29,r27
  	in	__tmp_reg__,__SREG__
  	cli
- 	out	__SP_L__,r28
- 	out	__SREG__,__tmp_reg__
  	out	__SP_H__,r29
  _prologue_end:
  	ijmp
  .endfunc
--- 583,591 ----
  	sbc	r29,r27
  	in	__tmp_reg__,__SREG__
  	cli
  	out	__SP_H__,r29
+ 	out	__SREG__,__tmp_reg__
+ 	out	__SP_L__,r28
  _prologue_end:
  	ijmp
  .endfunc
*************** __epilogue_restores__:
*** 621,629 ****
  	adc	r29,__zero_reg__
  	in	__tmp_reg__,__SREG__
  	cli
- 	out	__SP_L__,r28
- 	out	__SREG__,__tmp_reg__
  	out	__SP_H__,r29
  	mov	r28,r26
  	mov	r29,r27
  	ret
--- 621,629 ----
  	adc	r29,__zero_reg__
  	in	__tmp_reg__,__SREG__
  	cli
  	out	__SP_H__,r29
+ 	out	__SREG__,__tmp_reg__
+ 	out	__SP_L__,r28
  	mov	r28,r26
  	mov	r29,r27
  	ret


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]