avr-gcc puts jump tables in section .progmem.gcc_sw_table and assumes that
.text starts at 0, i.e. LPM is on order to read table entries.
This is no more the case if .text starts ata higher address like typically used
with boot loaders.
This patch adds the few instructions to set RAMPZ and make casesi and
__tablejump2__ more generic. __tablejump__ and __tablejump_elpm__ are no more
needed. Moreover, using gs() for a jump table is odd because the linker should
never generate a stub for this; thus use pm_lo8 etc. instead of gs() for >128k
devices.
Ok for trunk?
Johann
gcc/
* config/avr/avr.md (*tablejump.3byte-pc): New insn.
(*tablejump): Restrict to !AVR_HAVE_EIJMP_EICALL. Add void clobber.
(casesi): Expand to *tablejump.3byte-pc if AVR_HAVE_EIJMP_EICALL.
libgcc/
* config/avr/libgcc.S (__tablejump2__): Rewrite to use RAMPZ, ELPM
and R24 as needed. Make work for all devices and .text locations.
(__do_global_ctors, __do_global_dtors): Use word addresses.
(__tablejump__, __tablejump_elpm__): Remove functions.
* t-avr (LIB1ASMFUNCS): Remove _tablejump, _tablejump_elpm.
Add _tablejump2.
(XICALL, XIJMP): New macros.
Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md (revision 214897)
+++ gcc/config/avr/avr.md (working copy)
@@ -4931,8 +4931,9 @@ (define_insn "*tablejump"
(unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r,z")]
UNSPEC_INDEX_JMP))
(use (label_ref (match_operand 1 "" "")))
- (clobber (match_dup 0))]
- ""
+ (clobber (match_dup 0))
+ (clobber (const_int 0))]
+ "!AVR_HAVE_EIJMP_EICALL"
"@
ijmp
push %A0\;push %B0\;ret
@@ -4941,6 +4942,19 @@ (define_insn "*tablejump"
(set_attr "isa" "rjmp,rjmp,jmp")
(set_attr "cc" "none,none,clobber")])
+(define_insn "*tablejump.3byte-pc"
+ [(set (pc)
+ (unspec:HI [(reg:HI REG_Z)]
+ UNSPEC_INDEX_JMP))
+ (use (label_ref (match_operand 0 "" "")))
+ (clobber (reg:HI REG_Z))
+ (clobber (reg:QI 24))]
+ "AVR_HAVE_EIJMP_EICALL"
+ "clr r24\;subi r30,pm_lo8(-(%0))\;sbci r31,pm_hi8(-(%0))\;sbci r24,pm_hh8(-(%0))\;jmp __tablejump2__"
+ [(set_attr "length" "6")
+ (set_attr "isa" "eijmp")
+ (set_attr "cc" "clobber")])
+
(define_expand "casesi"
[(parallel [(set (match_dup 6)
@@ -4958,15 +4972,31 @@ (define_expand "casesi"
(label_ref (match_operand 4 "" ""))
(pc)))
- (set (match_dup 6)
- (plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
+ (set (match_dup 10)
+ (match_dup 7))
- (parallel [(set (pc) (unspec:HI [(match_dup 6)] UNSPEC_INDEX_JMP))
+ (parallel [(set (pc)
+ (unspec:HI [(match_dup 10)] UNSPEC_INDEX_JMP))
(use (label_ref (match_dup 3)))
- (clobber (match_dup 6))])]
+ (clobber (match_dup 10))
+ (clobber (match_dup 8))])]
""
{
operands[6] = gen_reg_rtx (HImode);
+
+ if (AVR_HAVE_EIJMP_EICALL)
+ {
+ operands[7] = operands[6];
+ operands[8] = all_regs_rtx[24];
+ operands[10] = gen_rtx_REG (HImode, REG_Z);
+ }
+ else
+ {
+ operands[7] = gen_rtx_PLUS (HImode, operands[6],
+ gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+ operands[8] = const0_rtx;
+ operands[10] = operands[6];
+ }
})
Index: libgcc/config/avr/lib1funcs.S
===================================================================
--- libgcc/config/avr/lib1funcs.S (revision 214897)
+++ libgcc/config/avr/lib1funcs.S (working copy)
@@ -46,6 +46,10 @@ see the files COPYING3 and COPYING.RUNTI
input sections together are small enough to reach every
location with a RCALL/RJMP instruction. */
+#if defined (__AVR_HAVE_EIJMP_EICALL__) && !defined (__AVR_HAVE_ELPMX__)
+#error device not supported
+#endif
+
.macro mov_l r_dest, r_src
#if defined (__AVR_HAVE_MOVW__)
movw \r_dest, \r_src
@@ -79,6 +83,14 @@ .macro wmov r_dest, r_src
#define XJMP rjmp
#endif
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+#define XICALL eicall
+#define XIJMP eijmp
+#else
+#define XICALL icall
+#define XIJMP ijmp
+#endif
+
;; Prologue stuff
.macro do_prologue_saves n_pushed n_frame=0
@@ -2127,11 +2139,7 @@ DEFUN __prologue_saves__
out __SP_L__,r28
#endif /* #SP = 8/16 */
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
-#endif
+ XIJMP
ENDF __prologue_saves__
#endif /* defined (L_prologue) */
@@ -2213,38 +2221,54 @@ _cleanup:
.section .text.libgcc, "ax", @progbits
-#ifdef L_tablejump
+#ifdef L_tablejump2
DEFUN __tablejump2__
- lsl r30
- rol r31
- ;; FALLTHRU
-ENDF __tablejump2__
-
-DEFUN __tablejump__
-#if defined (__AVR_HAVE_LPMX__)
- lpm __tmp_reg__, Z+
- lpm r31, Z
- mov r30, __tmp_reg__
+ lsl r30
+ rol r31
#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
+ ;; Word address of gs() jumptable entry in R24:Z
+ rol r24
+ out __RAMPZ__, r24
+#elif defined (__AVR_HAVE_ELPM__)
+ ;; Word address of jumptable entry in Z
+ clr __tmp_reg__
+ rol __tmp_reg__
+ out __RAMPZ__, __tmp_reg__
#endif
-#else /* !HAVE_LPMX */
- lpm
- adiw r30, 1
- push r0
- lpm
- push r0
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- in __tmp_reg__, __EIND__
- push __tmp_reg__
+ ;; Read word address from jumptable and jump
+
+#if defined (__AVR_HAVE_ELPMX__)
+ elpm __tmp_reg__, Z+
+ elpm r31, Z
+ mov r30, __tmp_reg__
+#ifdef __AVR_HAVE_RAMPD__
+ ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
+ out __RAMPZ__, __zero_reg__
+#endif /* RAMPD */
+ XIJMP
+#elif defined (__AVR_HAVE_ELPM__)
+ elpm
+ push r0
+ adiw r30, 1
+ elpm
+ push r0
+ ret
+#elif defined (__AVR_HAVE_LPMX__)
+ lpm __tmp_reg__, Z+
+ lpm r31, Z
+ mov r30, __tmp_reg__
+ ijmp
+#else
+ lpm
+ push r0
+ adiw r30, 1
+ lpm
+ push r0
+ ret
#endif
- ret
-#endif /* !HAVE_LPMX */
-ENDF __tablejump__
-#endif /* defined (L_tablejump) */
+ENDF __tablejump2__
+#endif /* L_tablejump2 */
#ifdef L_copy_data
.section .init4,"ax",@progbits
@@ -2336,116 +2360,65 @@ ENDF __do_clear_bss
#ifdef L_ctors
.section .init6,"ax",@progbits
DEFUN __do_global_ctors
-#if defined(__AVR_HAVE_ELPM__)
- ldi r17, hi8(__ctors_start)
- ldi r28, lo8(__ctors_end)
- ldi r29, hi8(__ctors_end)
- ldi r16, hh8(__ctors_end)
- rjmp .L__do_global_ctors_start
+ ldi r17, pm_hi8(__ctors_start)
+ ldi r28, pm_lo8(__ctors_end)
+ ldi r29, pm_hi8(__ctors_end)
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r16, pm_hh8(__ctors_end)
+#endif /* HAVE_EIJMP */
+ rjmp .L__do_global_ctors_start
.L__do_global_ctors_loop:
- sbiw r28, 2
+ sbiw r28, 1
+#ifdef __AVR_HAVE_EIJMP_EICALL__
sbc r16, __zero_reg__
+ mov r24, r16
+#endif /* HAVE_EIJMP */
mov_h r31, r29
mov_l r30, r28
- out __RAMPZ__, r16
- XCALL __tablejump_elpm__
-.L__do_global_ctors_start:
- cpi r28, lo8(__ctors_start)
- cpc r29, r17
- ldi r24, hh8(__ctors_start)
- cpc r16, r24
- brne .L__do_global_ctors_loop
-#else
- ldi r17, hi8(__ctors_start)
- ldi r28, lo8(__ctors_end)
- ldi r29, hi8(__ctors_end)
- rjmp .L__do_global_ctors_start
-.L__do_global_ctors_loop:
- sbiw r28, 2
- mov_h r31, r29
- mov_l r30, r28
- XCALL __tablejump__
+ XCALL __tablejump2__
.L__do_global_ctors_start:
- cpi r28, lo8(__ctors_start)
- cpc r29, r17
+ cpi r28, pm_lo8(__ctors_start)
+ cpc r29, r17
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r24, pm_hh8(__ctors_start)
+ cpc r16, r24
+#endif /* HAVE_EIJMP */
brne .L__do_global_ctors_loop
-#endif /* defined(__AVR_HAVE_ELPM__) */
ENDF __do_global_ctors
#endif /* L_ctors */
#ifdef L_dtors
.section .fini6,"ax",@progbits
DEFUN __do_global_dtors
-#if defined(__AVR_HAVE_ELPM__)
- ldi r17, hi8(__dtors_end)
- ldi r28, lo8(__dtors_start)
- ldi r29, hi8(__dtors_start)
- ldi r16, hh8(__dtors_start)
- rjmp .L__do_global_dtors_start
+ ldi r17, pm_hi8(__dtors_end)
+ ldi r28, pm_lo8(__dtors_start)
+ ldi r29, pm_hi8(__dtors_start)
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r16, pm_hh8(__dtors_start)
+#endif /* HAVE_EIJMP */
+ rjmp .L__do_global_dtors_start
.L__do_global_dtors_loop:
- sbiw r28, 2
- sbc r16, __zero_reg__
- mov_h r31, r29
- mov_l r30, r28
- out __RAMPZ__, r16
- XCALL __tablejump_elpm__
+ sbiw r28, 1
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ sbc r16, __zero_reg__
+ mov r24, r16
+#endif /* HAVE_EIJMP */
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump2__
.L__do_global_dtors_start:
- cpi r28, lo8(__dtors_end)
- cpc r29, r17
- ldi r24, hh8(__dtors_end)
- cpc r16, r24
- brne .L__do_global_dtors_loop
-#else
- ldi r17, hi8(__dtors_end)
- ldi r28, lo8(__dtors_start)
- ldi r29, hi8(__dtors_start)
- rjmp .L__do_global_dtors_start
-.L__do_global_dtors_loop:
- mov_h r31, r29
- mov_l r30, r28
- XCALL __tablejump__
- adiw r28, 2
-.L__do_global_dtors_start:
- cpi r28, lo8(__dtors_end)
- cpc r29, r17
- brne .L__do_global_dtors_loop
-#endif /* defined(__AVR_HAVE_ELPM__) */
+ cpi r28, pm_lo8(__dtors_end)
+ cpc r29, r17
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r24, pm_hh8(__dtors_end)
+ cpc r16, r24
+#endif /* HAVE_EIJMP */
+ brne .L__do_global_dtors_loop
ENDF __do_global_dtors
#endif /* L_dtors */
.section .text.libgcc, "ax", @progbits
-#ifdef L_tablejump_elpm
-DEFUN __tablejump_elpm__
-#if defined (__AVR_HAVE_ELPMX__)
- elpm __tmp_reg__, Z+
- elpm r31, Z
- mov r30, __tmp_reg__
-#if defined (__AVR_HAVE_RAMPD__)
- ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
- out __RAMPZ__, __zero_reg__
-#endif /* RAMPD */
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
-#endif
-
-#elif defined (__AVR_HAVE_ELPM__)
- elpm
- adiw r30, 1
- push r0
- elpm
- push r0
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- in __tmp_reg__, __EIND__
- push __tmp_reg__
-#endif
- ret
-#endif
-ENDF __tablejump_elpm__
-#endif /* defined (L_tablejump_elpm) */
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Loading n bytes from Flash; n = 3,4
;; R22... = Flash[Z]
Index: libgcc/config/avr/t-avr
===================================================================
--- libgcc/config/avr/t-avr (revision 214897)
+++ libgcc/config/avr/t-avr (working copy)
@@ -26,8 +26,7 @@ LIB1ASMFUNCS = \
_epilogue \
_exit \
_cleanup \
- _tablejump \
- _tablejump_elpm \
+ _tablejump2 \
_load_3 _load_4 \
_xload_1 _xload_2 _xload_3 _xload_4 \
_movmemx \