avr port path: switch/case improvements

Denis Chertykov denisc@overta.ru
Tue Nov 14 11:11:00 GMT 2000


Tue Nov 14 21:54:31 2000  Marek Michalkiewicz  <marekm@linux.org.pl> & Denis Chertykov  <denisc@overta.ru>

	* config/avr/avr.c (avr_case_values_threshold): New.
	(avr_override_options): Set it depending on options, make it large
	when not optimizing to work around "unable to generate reloads".

	* config/avr/avr.h (TARGET_SWITCHES): Add -mno-tablejump option.
	(EXTRA_SECTION_FUNCTIONS): Make the .progmem.gcc_sw_table section
	executable if not AVR_MEGA.  Make sure jump tables are word-aligned.
	(JUMP_TABLES_IN_TEXT_SECTION): Define as 0, not 1.
	(ASM_OUTPUT_ADDR_VEC_ELT): Optimize, use "rjmp" if not AVR_MEGA.
	(avr_case_values_threshold): Declare as extern int.
	(CASE_VALUES_THRESHOLD): Define as avr_case_values_threshold.

	* config/avr/avr.md (tablejump): Removed.
	(*tablejump_rjmp): New for jump tables made from "rjmp" instructions.
	(*tablejump_lib, *tablejump_enh, *tablejump): Change to expect the
	index in the table, not multiplied by 2.
	(casesi): Change to match the above insns.  Always enable.

	* config/avr/libgcc.S (__tablejump__): Rename to __tablejump2__.
	Change to expect the word address of the table, multiply it by 2
	here and not in the caller.  Change "adiw" to faster "inc".

diff -rc3p orig/egcs/gcc/config/avr/avr.c egcs/gcc/config/avr/avr.c
*** orig/egcs/gcc/config/avr/avr.c	Fri Oct 20 18:24:12 2000
--- egcs/gcc/config/avr/avr.c	Sat Nov 11 14:54:21 2000
*************** static const struct mcu_type_s avr_mcu_t
*** 160,165 ****
--- 160,167 ----
    { NULL, 0 }
  };
  
+ int avr_case_values_threshold = 30000;
+ 
  void
  avr_override_options ()
  {
*************** avr_override_options ()
*** 188,193 ****
--- 190,198 ----
        case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
        case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
      }
+ 
+   if (optimize && !TARGET_NO_TABLEJUMP)
+     avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
  }
  
  
diff -rc3p orig/egcs/gcc/config/avr/avr.h egcs/gcc/config/avr/avr.h
*** orig/egcs/gcc/config/avr/avr.h	Fri Oct 20 18:24:13 2000
--- egcs/gcc/config/avr/avr.h	Sat Nov 11 15:41:43 2000
*************** extern int target_flags;
*** 51,56 ****
--- 51,57 ----
  #define MASK_ORDER_1		0x00001000
  #define MASK_INSN_SIZE_DUMP	0x00002000
  #define MASK_ORDER_2		0x00004000
+ #define MASK_NO_TABLEJUMP	0x00008000
  #define MASK_INT8		0x00010000
  #define MASK_NO_INTERRUPTS	0x00020000
  #define MASK_CALL_PROLOGUES	0x00040000
*************** extern int target_flags;
*** 63,68 ****
--- 64,70 ----
  #define TARGET_INSN_SIZE_DUMP	(target_flags & MASK_INSN_SIZE_DUMP)
  #define TARGET_CALL_PROLOGUES	(target_flags & MASK_CALL_PROLOGUES)
  #define TARGET_TINY_STACK	(target_flags & MASK_TINY_STACK)
+ #define TARGET_NO_TABLEJUMP	(target_flags & MASK_NO_TABLEJUMP)
  
  /* Dump each assembler insn's rtl into the output file.
     This is for debugging the compiler itself.  */
*************** extern int target_flags;
*** 102,107 ****
--- 104,111 ----
      N_("Use subroutines for function prologue/epilogue") },		\
    { "tiny-stack", MASK_TINY_STACK,					\
      N_("Change only the low 8 bits of the stack pointer") },		\
+   { "no-tablejump", MASK_NO_TABLEJUMP,					\
+     N_("Do not generate tablejump insns") },				\
    { "rtl", MASK_RTL_DUMP, NULL },					\
    { "size", MASK_INSN_SIZE_DUMP,					\
      N_("Output instruction sizes to the asm file") },			\
*************** progmem_section (void)							      \
*** 2001,2007 ****
    if (in_section != in_progmem)						      \
      {									      \
        fprintf (asm_out_file,						      \
! 	       ".section .progmem.gcc_sw_table, \"a\", @progbits\n");	      \
        in_section = in_progmem;						      \
      }									      \
  }
--- 2005,2014 ----
    if (in_section != in_progmem)						      \
      {									      \
        fprintf (asm_out_file,						      \
! 	       "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",	      \
! 	       AVR_MEGA ? "a" : "ax"); 					      \
!       /* Should already be aligned, this is just to be safe if it isn't.  */  \
!       fprintf (asm_out_file, "\t.p2align 1\n");				      \
        in_section = in_progmem;						      \
      }									      \
  }
*************** progmem_section (void)							      \
*** 2042,2048 ****
     Do not define this macro if you put all constants in the read-only
     data section.  */
  
! #define JUMP_TABLES_IN_TEXT_SECTION 1
  /* Define this macro if jump tables (for `tablejump' insns) should be
     output in the text section, along with the assembler instructions.
     Otherwise, the readonly data section is used.
--- 2049,2055 ----
     Do not define this macro if you put all constants in the read-only
     data section.  */
  
! #define JUMP_TABLES_IN_TEXT_SECTION 0
  /* Define this macro if jump tables (for `tablejump' insns) should be
     output in the text section, along with the assembler instructions.
     Otherwise, the readonly data section is used.
*************** sprintf (STRING, "*.%s%d", PREFIX, NUM)
*** 2706,2712 ****
     not be optimal, since this macro is used only when profiling.  */
  
  #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)				      \
!   fprintf (STREAM, "\t.word pm(.L%d)\n", VALUE);
  /* This macro should be provided on machines where the addresses in a
     dispatch table are absolute.
  
--- 2713,2724 ----
     not be optimal, since this macro is used only when profiling.  */
  
  #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)				      \
! do { \
!   if (AVR_MEGA) \
!     fprintf (STREAM, "\t.word pm(.L%d)\n", VALUE); \
!   else \
!     fprintf (STREAM, "\trjmp .L%d\n", VALUE); \
! } while (0)
  /* This macro should be provided on machines where the addresses in a
     dispatch table are absolute.
  
*************** fprintf (STREAM, "\t.skip %d,0\n", n)
*** 2761,2767 ****
  /* An alias for a machine mode name.  This is the machine mode that
     elements of a jump-table should have.  */
  
! #define CASE_VALUES_THRESHOLD 17
  /* `CASE_VALUES_THRESHOLD'
     Define this to be the smallest number of different values for
     which it is best to use a jump-table instead of a tree of
--- 2773,2781 ----
  /* An alias for a machine mode name.  This is the machine mode that
     elements of a jump-table should have.  */
  
! extern int avr_case_values_threshold;
! 
! #define CASE_VALUES_THRESHOLD avr_case_values_threshold
  /* `CASE_VALUES_THRESHOLD'
     Define this to be the smallest number of different values for
     which it is best to use a jump-table instead of a tree of
diff -rc3p orig/egcs/gcc/config/avr/avr.md egcs/gcc/config/avr/avr.md
*** orig/egcs/gcc/config/avr/avr.md	Fri Oct 20 18:24:13 2000
--- egcs/gcc/config/avr/avr.md	Sat Nov 11 15:53:20 2000
***************
*** 1852,1892 ****
  (define_expand "tablejump"
    [(parallel [(set (pc) (match_operand:HI 0 "register_operand" ""))
  	      (use (label_ref (match_operand 1 "" "")))])]
!   "optimize"
    "")
  
  ;; Not a prologue, but similar idea - move the common piece of code to libgcc.
  (define_insn "*tablejump_lib"
     [(set (pc) (mem:HI (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			       (label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   "TARGET_CALL_PROLOGUES"
!   "*{
!   output_asm_insn (AS2 (subi,r30,lo8(-(%2))) CR_TAB
! 	           AS2 (sbci,r31,hi8(-(%2))), operands);
!   return (AVR_MEGA
!           ? AS1 (jmp,__tablejump__)
!           : AS1 (rjmp,__tablejump__));
!   }"
!   [(set_attr "cc" "clobber")
!    (set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
! 				      (const_int 3)
! 				      (const_int 4)))])
! 
  
  (define_insn "*tablejump_enh"
     [(set (pc) (mem:HI
  	       (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			(label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   "AVR_ENHANCED"
!   "subi r30,lo8(-(%2))
! 	sbci r31,hi8(-(%2))
  	lpm __tmp_reg__,Z+
  	lpm r31,Z
  	mov r30,__tmp_reg__
  	ijmp"
!   [(set_attr "length" "6")
     (set_attr "cc" "clobber")])
  
  (define_insn "*tablejump"
--- 1852,1904 ----
  (define_expand "tablejump"
    [(parallel [(set (pc) (match_operand:HI 0 "register_operand" ""))
  	      (use (label_ref (match_operand 1 "" "")))])]
!   "0 && optimize"
    "")
  
+ ;; Note: the (mem:HI (...)) memory references here are special - actually
+ ;; the data is read from a word address in program memory (r31:r30 is the
+ ;; index in the table, not multiplied by 2 - see the "casesi" pattern).
+ 
+ ;; Table made from "rjmp" instructions for <=8K devices.
+ (define_insn "*tablejump_rjmp"
+    [(set (pc) (mem:HI
+ 	       (plus:HI (match_operand:HI 0 "register_operand" "=&z")
+ 			(label_ref (match_operand 2 "" "")))))
+     (use (label_ref (match_operand 1 "" "")))]
+   "!AVR_MEGA"
+   "subi r30,pm_lo8(-(%2))
+ 	sbci r31,pm_hi8(-(%2))
+ 	ijmp"
+   [(set_attr "length" "3")
+    (set_attr "cc" "clobber")])
+ 
  ;; Not a prologue, but similar idea - move the common piece of code to libgcc.
  (define_insn "*tablejump_lib"
     [(set (pc) (mem:HI (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			       (label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   "AVR_MEGA && TARGET_CALL_PROLOGUES"
!   "subi r30,pm_lo8(-(%2))
! 	sbci r31,pm_hi8(-(%2))
! 	jmp __tablejump2__"
!   [(set_attr "length" "4")
!    (set_attr "cc" "clobber")])
  
  (define_insn "*tablejump_enh"
     [(set (pc) (mem:HI
  	       (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			(label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   "AVR_MEGA && AVR_ENHANCED"
!   "subi r30,pm_lo8(-(%2))
! 	sbci r31,pm_hi8(-(%2))
! 	lsl r30
! 	rol r31
  	lpm __tmp_reg__,Z+
  	lpm r31,Z
  	mov r30,__tmp_reg__
  	ijmp"
!   [(set_attr "length" "8")
     (set_attr "cc" "clobber")])
  
  (define_insn "*tablejump"
***************
*** 1894,1909 ****
  	       (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			(label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   ""
!   "subi r30,lo8(-(%2))
! 	sbci r31,hi8(-(%2))
  	lpm
  	push r0
- 	adiw r30,1
  	lpm
  	push r0
  	ret"
!   [(set_attr "length" "8")
     (set_attr "cc" "clobber")])
  
  (define_expand "casesi"
--- 1906,1923 ----
  	       (plus:HI (match_operand:HI 0 "register_operand" "=&z")
  			(label_ref (match_operand 2 "" "")))))
      (use (label_ref (match_operand 1 "" "")))]
!   "AVR_MEGA"
!   "subi r30,pm_lo8(-(%2))
! 	sbci r31,pm_hi8(-(%2))
! 	lsl r30
! 	rol r31
  	lpm
+ 	inc r30
  	push r0
  	lpm
  	push r0
  	ret"
!   [(set_attr "length" "10")
     (set_attr "cc" "clobber")])
  
  (define_expand "casesi"
***************
*** 1920,1928 ****
  			   (const_int 0))
  		      (label_ref (match_operand 4 "" ""))
  		      (pc)))
!    (set (match_dup 6)
! 	(plus:HI (match_dup 6)
! 		 (match_dup 6)))
  ;;   (set (match_dup 6)
  ;;	(plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
  		 
--- 1934,1942 ----
  			   (const_int 0))
  		      (label_ref (match_operand 4 "" ""))
  		      (pc)))
! ;;   (set (match_dup 6)
! ;;	(plus:HI (match_dup 6)
! ;;		 (match_dup 6)))
  ;;   (set (match_dup 6)
  ;;	(plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
  		 
***************
*** 1930,1936 ****
  			 (plus:HI (match_dup 6)
  				  (label_ref (match_operand:HI 3 "" "")))))
  	      (use (label_ref (match_dup 3)))])]
!   "!optimize"
    "
  {
    operands[6] = gen_reg_rtx (HImode);
--- 1944,1950 ----
  			 (plus:HI (match_dup 6)
  				  (label_ref (match_operand:HI 3 "" "")))))
  	      (use (label_ref (match_dup 3)))])]
!   ""
    "
  {
    operands[6] = gen_reg_rtx (HImode);
diff -rc3p orig/egcs/gcc/config/avr/libgcc.S egcs/gcc/config/avr/libgcc.S
*** orig/egcs/gcc/config/avr/libgcc.S	Sat Sep  2 12:48:46 2000
--- egcs/gcc/config/avr/libgcc.S	Sat Nov 11 12:46:28 2000
*************** _cleanup:
*** 691,699 ****
  #endif /* defined (L_cleanup) */
  
  #ifdef L_tablejump
! 	.global __tablejump__
! 	.func	__tablejump__
! __tablejump__:
  #if defined (__AVR_ENHANCED__)
  	lpm	__tmp_reg__, Z+
  	lpm	r31, Z
--- 691,701 ----
  #endif /* defined (L_cleanup) */
  
  #ifdef L_tablejump
! 	.global __tablejump2__
! 	.func	__tablejump2__
! __tablejump2__:
! 	lsl	r30
! 	rol	r31
  #if defined (__AVR_ENHANCED__)
  	lpm	__tmp_reg__, Z+
  	lpm	r31, Z
*************** __tablejump__:
*** 702,708 ****
  #else
  	lpm
  	push	r0
! 	adiw	r30, 1
  	lpm
  	push	r0
  	ret
--- 704,710 ----
  #else
  	lpm
  	push	r0
! 	inc	r30	; table is word aligned, no carry to high byte
  	lpm
  	push	r0
  	ret



More information about the Gcc-patches mailing list