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,

Reply via email to