This patch factors out negating R18:SI which is used in several
places.  It also adds

   .macro  .call_if_neg  reg, labl

for convenience.  It calls <labl> iff <reg> < 0.

libgcc/
        * config/avr/t-avr (LIB1ASMFUNCS): Add _negsi2_r18.
        * config/avr/asm-defs.h (.call_if_neg): New .macro.
        * config/avr/lib1funcs.S (__divmodsi4): Use .call_if_neg.
        (__negsi2_r18): New function.
        * config/avr/lib1funcs-fixed.S (__divsa3): Use .call_if_neg.

Johann
diff --git a/libgcc/config/avr/asm-defs.h b/libgcc/config/avr/asm-defs.h
index 62879464f9d..cf943f046e9 100644
--- a/libgcc/config/avr/asm-defs.h
+++ b/libgcc/config/avr/asm-defs.h
@@ -159,6 +159,21 @@
 .endm ; .branch_plus
 
 
+;;; [R]CALL label LABL when REG is negative (REG.7 = 1).
+;;; Otherwise, fallthrough.
+.macro  .call_if_neg  reg, labl
+#ifdef __AVR_ERRATA_SKIP_JMP_CALL__
+    ;; Some cores have a problem skipping 2-word instructions.
+    tst     \reg
+    brpl    .L.call_if_neg.\@
+#else
+    sbrc    \reg, 7
+#endif /* skip erratum */
+    XCALL   \labl
+.L.call_if_neg.\@:
+.endm ; .call_if_neg
+
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Macros for convenience.
 
diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S
index 4b77ee2dd56..0414b3a2eed 100644
--- a/libgcc/config/avr/lib1funcs-fixed.S
+++ b/libgcc/config/avr/lib1funcs-fixed.S
@@ -1118,10 +1118,7 @@ DEFUN   __udivuha3
 DEFUN   __divsa3
     mov     r0, r_arg1HH
     eor     r0, r_divHH
-    sbrs    r_divHH, 7
-    rjmp    1f
-    NEG4    r_divL
-1:
+    .call_if_neg r_divHH, __negsi2_r18
     sbrs    r_arg1HH, 7
     rjmp    2f
     NEG4    r_arg1L
diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S
index 6af40122f02..f307ea6a064 100644
--- a/libgcc/config/avr/lib1funcs.S
+++ b/libgcc/config/avr/lib1funcs.S
@@ -1509,37 +1509,16 @@ DEFUN __divmodsi4
     com     __tmp_reg__         ; r0.7 is sign of result
     XCALL   __negsi2            ; dividend negative: negate
 0:
-    sbrc    r_arg2HH,7
-    rcall   __divmodsi4_neg2    ; divisor negative: negate
+    .call_if_neg r_arg2HH, __negsi2_r18 ; divisor negative: negate
     XCALL   __udivmodsi4        ; do the unsigned div/mod
-    sbrc    __tmp_reg__, 7      ; correct quotient sign
-    rcall   __divmodsi4_neg2
+    .call_if_neg __tmp_reg__, __negsi2_r18 ; correct quotient sign
     brtc    __divmodsi4_exit    ; correct remainder sign
     XJMP    __negsi2
-__divmodsi4_neg2:
-    ;; correct divisor/quotient sign
-    com     r_arg2HH
-    com     r_arg2HL
-    com     r_arg2H
-    neg     r_arg2L
-    sbci    r_arg2H,0xff
-    sbci    r_arg2HL,0xff
-    sbci    r_arg2HH,0xff
 __divmodsi4_exit:
     ret
 ENDF __divmodsi4
 #endif /* defined (L_divmodsi4) */
 
-#if defined (L_negsi2)
-;; (set (reg:SI 22)
-;;      (neg:SI (reg:SI 22)))
-;; Sets the V flag for signed overflow tests
-DEFUN __negsi2
-    NEG4    22
-    ret
-ENDF __negsi2
-#endif /* L_negsi2 */
-
 #undef r_remHH
 #undef r_remHL
 #undef r_remH
@@ -1554,6 +1533,26 @@ DEFUN __negsi2
 #undef r_arg2L
 #undef r_cnt
 
+#if defined (L_negsi2)
+;; (set (reg:SI 22)
+;;      (neg:SI (reg:SI 22)))
+;; Sets the V flag for signed overflow tests
+DEFUN __negsi2
+    NEG4    22
+    ret
+ENDF __negsi2
+#endif /* L_negsi2 */
+
+#if defined (L_negsi2_r18)
+;; (set (reg:SI 18)
+;;      (neg:SI (reg:SI 18)))
+;; Sets the V flag for signed overflow tests
+DEFUN __negsi2_r18
+    NEG4    18
+    ret
+ENDF __negsi2_r18
+#endif /* L_negsi2_r18 */
+
 /* *di routines use registers below R19 and won't work with tiny arch
    right now. */
 
diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr
index 9b05c8575b6..2f9a2efc3cf 100644
--- a/libgcc/config/avr/t-avr
+++ b/libgcc/config/avr/t-avr
@@ -14,6 +14,7 @@ LIB1ASMFUNCS = \
 	_udivmodsi4 \
 	_divmodsi4 \
 	_negsi2 \
+	_negsi2_r18 \
 	_exit \
 	_cleanup \
 	_tablejump2 \

Reply via email to