For devices with 8-bit SP reading the high byte SP_H of SP will get garbage.
The patch uses CLR instead of IN SP_H to "read" the high part of SP.
There are two issues with this patch:
== 1 ==
I cannot really test it because for devices that small running test suite
does not give usable results. So I just looked at the patch and the
small test case like the following compiled
$ avr-gcc-4.6.2 -Os -mmcu=attiny26 -m[no]call-prologues
long long a, b;
long long __attribute__((noinline,noclione))
bar (char volatile *c)
{
*c = 1;
return a+b;
}
long long foo()
{
char buf[16];
return bar (buf);
}
int main (void)
{
return foo();
}
The C parts look fine but...
== 2 ==
The libgcc parts will still read garbage to R29 as explained in the
FIXMEs there.
Solving the FIXMEs can only be achieved by splitting multilibs avr2 and avr25,
i.e. the mutlilibs that mix devices with/without SP.H, into avr2, avr21, avr24,
avr25, say.
I don't think it's a good idea to have real 8-bit SP/FP and that it would cause
all sorts of trouble.
Ok to commit to 4.6?
What about splitting multilibs? Is this appropriate for 4.7?
Johann
PR target/51002
* config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
Enclose parts using __SP_H__ in defined (__AVR_HAVE_8BIT_SP__).
Add FIXME comments.
* config/avr/avr.md (movhi_sp_r_irq_off, movhi_sp_r_irq_on): Set
insn condition to !AVR_HAVE_8BIT_SP.
* config/avr/avr.c (output_movhi): "clr%B0" instead of "in
%B0,__SP_H__" if AVR_HAVE_8BIT_SP.
(avr_file_start): Only print "__SP_H__ = 0x3e" if !AVR_HAVE_8BIT_SP.
Index: config/avr/libgcc.S
===================================================================
--- config/avr/libgcc.S (revision 181783)
+++ config/avr/libgcc.S (working copy)
@@ -582,6 +582,15 @@ __prologue_saves__:
push r17
push r28
push r29
+#if defined (__AVR_HAVE_8BIT_SP__)
+;; FIXME: __AVR_HAVE_8BIT_SP__ is set on device level, not on core level
+;; so this lines are dead code. To make it work, devices without
+;; SP_H must get their own multilib(s).
+ in r28,__SP_L__
+ sub r28,r26
+ clr r29
+ out __SP_L__,r28
+#else
in r28,__SP_L__
in r29,__SP_H__
sub r28,r26
@@ -591,6 +600,7 @@ __prologue_saves__:
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
+#endif
#if defined (__AVR_HAVE_EIJMP_EICALL__)
eijmp
#else
@@ -625,6 +635,15 @@ __epilogue_restores__:
ldd r16,Y+4
ldd r17,Y+3
ldd r26,Y+2
+#if defined (__AVR_HAVE_8BIT_SP__)
+;; FIXME: __AVR_HAVE_8BIT_SP__ is set on device level, not on core level
+;; so this lines are dead code. To make it work, devices without
+;; SP_H must get their own multilib(s).
+ ldd r29,Y+1
+ add r28,r30
+ out __SP_L__,r28
+ mov r28, r26
+#else
ldd r27,Y+1
add r28,r30
adc r29,__zero_reg__
@@ -635,6 +654,7 @@ __epilogue_restores__:
out __SP_L__,r28
mov_l r28, r26
mov_h r29, r27
+#endif
ret
.endfunc
#endif /* defined (L_epilogue) */
Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md (revision 181783)
+++ config/avr/avr.md (working copy)
@@ -299,7 +299,7 @@ (define_insn "movhi_sp_r_irq_off"
[(set (match_operand:HI 0 "stack_register_operand" "=q")
(unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")]
UNSPECV_WRITE_SP_IRQ_OFF))]
- ""
+ "!AVR_HAVE_8BIT_SP"
"out __SP_H__, %B1
out __SP_L__, %A1"
[(set_attr "length" "2")
@@ -309,7 +309,7 @@ (define_insn "movhi_sp_r_irq_on"
[(set (match_operand:HI 0 "stack_register_operand" "=q")
(unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")]
UNSPECV_WRITE_SP_IRQ_ON))]
- ""
+ "!AVR_HAVE_8BIT_SP"
"cli
out __SP_H__, %B1
sei
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c (revision 181783)
+++ config/avr/avr.c (working copy)
@@ -1879,9 +1879,12 @@ output_movhi (rtx insn, rtx operands[],
}
else if (test_hard_reg_class (STACK_REG, src))
{
- *l = 2;
- return (AS2 (in,%A0,__SP_L__) CR_TAB
- AS2 (in,%B0,__SP_H__));
+ *l = 2;
+ return AVR_HAVE_8BIT_SP
+ ? (AS2 (in,%A0,__SP_L__) CR_TAB
+ AS1 (clr,%B0))
+ : (AS2 (in,%A0,__SP_L__) CR_TAB
+ AS2 (in,%B0,__SP_H__));
}
if (AVR_HAVE_MOVW)
@@ -5173,10 +5176,10 @@ avr_file_start (void)
default_file_start ();
-/* fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
- fputs ("__SREG__ = 0x3f\n"
- "__SP_H__ = 0x3e\n"
- "__SP_L__ = 0x3d\n", asm_out_file);
+ fputs ("__SREG__ = 0x3f\n", asm_out_file);
+ if (!AVR_HAVE_8BIT_SP)
+ fputs ("__SP_H__ = 0x3e\n", asm_out_file);
+ fputs ("__SP_L__ = 0x3d\n", asm_out_file);
fputs ("__tmp_reg__ = 0\n"
"__zero_reg__ = 1\n", asm_out_file);