This patch does better re-usage of __tablejump2__ from libgcc so that switch/case statements with jump tables become smaller because the sequence needs 6 to 9 words compared to 2 when JMPing to __tablejump2__.
Moreover, __tablejump2__ does no more rely in the content of EIND (by using EIJMP) and uses RET instead. The insn conditions of tablejump insns now are the same as in avr_output_addr_vec_elt. Ok for trunk? Johann * config/avr/avr.md (*tablejump_rjmp): Change insn condition to !AVR_HAVE_JMP_CALL. (*tablejump_lib): Change insn condition to AVR_HAVE_JMP_CALL. (*tablejump_enh, *tablejump): Remove insns. * config/avr/libgcc.S (__tablejump__): Use RET instead of EIND + EIJM for indirect jump. Use LPM Z+ where available.
Index: config/avr/libgcc.S =================================================================== --- config/avr/libgcc.S (revision 179744) +++ config/avr/libgcc.S (working copy) @@ -821,13 +821,17 @@ ENDF __tablejump2__ DEFUN __tablejump__ #if defined (__AVR_HAVE_LPMX__) +#if defined (__AVR_HAVE_EIJMP_EICALL__) + lpm __tmp_reg__, Z+ + push __tmp_reg__ + lpm __tmp_reg__, Z + push __tmp_reg__ + push __zero_reg__ + ret +#else lpm __tmp_reg__, Z+ lpm r31, Z mov r30, __tmp_reg__ - -#if defined (__AVR_HAVE_EIJMP_EICALL__) - eijmp -#else ijmp #endif Index: config/avr/avr.md =================================================================== --- config/avr/avr.md (revision 179744) +++ config/avr/avr.md (working copy) @@ -3719,62 +3719,36 @@ (define_insn "*indirect_jump_avr6" (set_attr "cc" "none")]) ;; table jump +;; For entries in jump table see avr_output_addr_vec_elt. -;; Table made from "rjmp" instructions for <=8K devices. +;; Table made from "rjmp .L<n>" instructions for <= 8K devices. (define_insn "*tablejump_rjmp" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")] - UNSPEC_INDEX_JMP)) + [(set (pc) + (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")] + UNSPEC_INDEX_JMP)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] - "(!AVR_HAVE_JMP_CALL) && (!AVR_HAVE_EIJMP_EICALL)" + "!AVR_HAVE_JMP_CALL" "@ ijmp push %A0\;push %B0\;ret" [(set_attr "length" "1,3") (set_attr "cc" "none,none")]) -;; Not a prologue, but similar idea - move the common piece of code to libgcc. +;; Move the common piece of code to libgcc. +;; Table made from ".word gs(.L<n>)" addresses for > 8K devices. +;; Read jump address from table and perform indirect jump. (define_insn "*tablejump_lib" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] - UNSPEC_INDEX_JMP)) + [(set (pc) + (unspec:HI [(match_operand:HI 0 "register_operand" "z")] + UNSPEC_INDEX_JMP)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] - "AVR_HAVE_JMP_CALL && TARGET_CALL_PROLOGUES" - "%~jmp __tablejump2__" + "AVR_HAVE_JMP_CALL" + "jmp __tablejump2__" [(set_attr "length" "2") (set_attr "cc" "clobber")]) -(define_insn "*tablejump_enh" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] - UNSPEC_INDEX_JMP)) - (use (label_ref (match_operand 1 "" ""))) - (clobber (match_dup 0))] - "AVR_HAVE_JMP_CALL && AVR_HAVE_LPMX" - "lsl r30 - rol r31 - lpm __tmp_reg__,Z+ - lpm r31,Z - mov r30,__tmp_reg__ - %!ijmp" - [(set_attr "length" "6") - (set_attr "cc" "clobber")]) - -(define_insn "*tablejump" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] - UNSPEC_INDEX_JMP)) - (use (label_ref (match_operand 1 "" ""))) - (clobber (match_dup 0))] - "AVR_HAVE_JMP_CALL && !AVR_HAVE_EIJMP_EICALL" - "lsl r30 - rol r31 - lpm - inc r30 - push r0 - lpm - push r0 - ret" - [(set_attr "length" "8") - (set_attr "cc" "clobber")]) (define_expand "casesi" [(set (match_dup 6)