The recently added 64-bit signed fixed-point multiply
calculated |B| but didn't restore it, which is wrong
code when the caller reuses B after the multiplication
in the assumption that the respective callee-saved regs
are unaltered.
This patch stores the sign of B and unclobbers B by
negating it twice when it is negative, instead of only once.
Applied to trunk.
Johann
--
libgcc/
* config/avr/lib1funcs-fixed.S (__mulQ64_work):
Restore B = R10..R17 to its original value.diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S
index 142b832c2a1..1ac7b5cf986 100644
--- a/libgcc/config/avr/lib1funcs-fixed.S
+++ b/libgcc/config/avr/lib1funcs-fixed.S
@@ -1152,6 +1152,8 @@ DEFUN __multa3
DEFUN __mulQ64_work
mov __tmp_reg__, A7
eor __tmp_reg__, B7
+ bst B7, 7
+ bld __tmp_reg__, 0
push __tmp_reg__
.call_if_neg A7, __negdi2 ; A = |A|
@@ -1160,6 +1162,20 @@ DEFUN __mulQ64_work
set ; for signed
XICALL ; __muluxx3.2
+ ;; r30.7 = sign result
+ ;; r30.0 = sign B
+ pop r30
+
+ ;; If we clobbered B, unclobber it now.
+#ifdef __AVR_ERRATA_SKIP_JMP_CALL__
+ asr r30
+ brcc 0f
+#else
+ sbrc r30, 0
+#endif
+ XCALL __negdi2_r10
+0:
+
;; Adjust for signed Q formats that have one FBIT less.
lsl A0
;; Insert LSB from the unsigned mult.
@@ -1172,9 +1188,6 @@ DEFUN __mulQ64_work
rol A6
rol A7
- ;; r30.7 = result sign
- pop r30
-
;; Handle overflow.
brcs .Lsaturate
;; In the negative result case, A = 0x80.. is no overflow,