This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
AVR mul/divmod optimizations
- To: denisc at overta dot ru
- Subject: AVR mul/divmod optimizations
- From: Marek Michalkiewicz <marekm at linux dot org dot pl>
- Date: Sat, 20 Jan 2001 18:40:59 +0100 (CET)
- CC: gcc-patches at gcc dot gnu dot org, marekm at linux dot org dot pl
I have finally applied this, hope that's OK. Too late before the branch,
I know - but I have tested it for some time now. (And, on weekends I have
"only" 20% packet loss to gcc.gnu.org - normally it's about 50%...)
2001-01-20 Marek Michalkiewicz <marekm@linux.org.pl>
* config/avr/avr.h (INIT_TARGET_OPTABS): Remove most of it, was
the same as the default library function names.
* config/avr/avr.md: Document special characters after '%'.
(mulqi3, mulhi3, mulsi3): Call libgcc.S functions ourselves,
knowing which of the call-used registers are really clobbered.
(divmodqi4, udivmodqi4, divmodhi4, udivmodhi4, divmodsi4, udivmodsi4):
New. Both quotient and remainder from one libgcc.S call.
* config/avr/libgcc.S: Optimize mul/divmod for the new insns above,
clobber as few registers as possible.
* config/avr/t-avr (LIB1ASMFUNCS): Adjust for the above changes.
Index: config/avr/avr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/avr/avr.h,v
retrieving revision 1.17
diff -c -3 -p -r1.17 avr.h
*** avr.h 2001/01/01 20:35:27 1.17
--- avr.h 2001/01/20 16:42:55
*************** valid_machine_decl_attribute (DECL, ATTR
*** 3228,3277 ****
#define INIT_TARGET_OPTABS \
{ \
- smul_optab->handlers[(int) QImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__mulqi3"); \
- \
- sdiv_optab->handlers[(int) QImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__divqi3"); \
- \
- smod_optab->handlers[(int) QImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__modqi3"); \
- \
- udiv_optab->handlers[(int) QImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__udivqi3"); \
- \
- umod_optab->handlers[(int) QImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__umodqi3"); \
- \
- smul_optab->handlers[(int) HImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__mulhi3"); \
- \
- sdiv_optab->handlers[(int) HImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__divhi3"); \
- \
- smod_optab->handlers[(int) HImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__modhi3"); \
- \
- udiv_optab->handlers[(int) HImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__udivhi3"); \
- \
- umod_optab->handlers[(int) HImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__umodhi3"); \
- \
- smul_optab->handlers[(int) SImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__mulsi3"); \
- \
- sdiv_optab->handlers[(int) SImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__divsi3"); \
- \
- smod_optab->handlers[(int) SImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__modsi3"); \
- \
- udiv_optab->handlers[(int) SImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__udivsi3"); \
- \
- umod_optab->handlers[(int) SImode].libfunc \
- = gen_rtx (SYMBOL_REF, Pmode, "__umodsi3"); \
avr_init_once (); \
}
--- 3228,3233 ----
Index: config/avr/avr.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/avr/avr.md,v
retrieving revision 1.24
diff -c -3 -p -r1.24 avr.md
*** avr.md 2001/01/13 21:42:07 1.24
--- avr.md 2001/01/20 16:43:10
***************
*** 21,26 ****
--- 21,36 ----
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
+ ;; Special characters after '%':
+ ;; A No effect (add 0).
+ ;; B Add 1 to REG number, MEM address or CONST_INT.
+ ;; C Add 2.
+ ;; D Add 3.
+ ;; j Branch condition.
+ ;; k Reverse branch condition.
+ ;; o Displacement for (mem (plus (reg) (const_int))) operands.
+ ;; ~ Output 'r' if not AVR_MEGA.
+
;; UNSPEC usage:
;; 0 Length of a string, see "strlenhi".
;; 1 Read from a word address in program memory, see "casesi".
***************
*** 633,640 ****
;******************************************************************************
; mul
! (define_insn "mulqi3"
[(set (match_operand:QI 0 "register_operand" "=r")
(mult:QI (match_operand:QI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r")))]
--- 643,663 ----
;******************************************************************************
; mul
+
+ (define_expand "mulqi3"
+ [(set (match_operand:QI 0 "register_operand" "")
+ (mult:QI (match_operand:QI 1 "register_operand" "")
+ (match_operand:QI 2 "register_operand" "")))]
+ ""
+ "{
+ if (!AVR_ENHANCED)
+ {
+ emit_insn (gen_mulqi3_call (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ }")
! (define_insn "*mulqi3_enh"
[(set (match_operand:QI 0 "register_operand" "=r")
(mult:QI (match_operand:QI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r")))]
***************
*** 645,650 ****
--- 668,692 ----
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
+ (define_expand "mulqi3_call"
+ [(set (reg:QI 24) (match_operand:QI 1 "register_operand" ""))
+ (set (reg:QI 22) (match_operand:QI 2 "register_operand" ""))
+ (parallel [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 22))])
+ (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))]
+ ""
+ "")
+
+ (define_insn "*mulqi3_call"
+ [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 22))]
+ "!AVR_ENHANCED"
+ "%~call __mulqi3"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
(define_insn "mulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d"))
***************
*** 667,673 ****
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
! (define_insn "mulhi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (match_operand:HI 1 "register_operand" "r")
(match_operand:HI 2 "register_operand" "r")))]
--- 709,729 ----
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
! (define_expand "mulhi3"
! [(set (match_operand:HI 0 "register_operand" "")
! (mult:HI (match_operand:HI 1 "register_operand" "")
! (match_operand:HI 2 "register_operand" "")))]
! ""
! "
! {
! if (!AVR_ENHANCED)
! {
! emit_insn (gen_mulhi3_call (operands[0], operands[1], operands[2]));
! DONE;
! }
! }")
!
! (define_insn "*mulhi3_enh"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (match_operand:HI 1 "register_operand" "r")
(match_operand:HI 2 "register_operand" "r")))]
***************
*** 682,687 ****
--- 738,937 ----
[(set_attr "length" "7")
(set_attr "cc" "clobber")])
+ (define_expand "mulhi3_call"
+ [(set (reg:HI 24) (match_operand:HI 1 "register_operand" ""))
+ (set (reg:HI 22) (match_operand:HI 2 "register_operand" ""))
+ (parallel [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 22))
+ (clobber (reg:QI 21))])
+ (set (match_operand:HI 0 "register_operand" "") (reg:HI 24))]
+ ""
+ "")
+
+ (define_insn "*mulhi3_call"
+ [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 22))
+ (clobber (reg:QI 21))]
+ "!AVR_ENHANCED"
+ "%~call __mulhi3"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ ;; Operand 2 (reg:SI 18) not clobbered on the enhanced core.
+ ;; All call-used registers clobbered otherwise - normal library call.
+ (define_expand "mulsi3"
+ [(set (reg:SI 22) (match_operand:SI 1 "register_operand" ""))
+ (set (reg:SI 18) (match_operand:SI 2 "register_operand" ""))
+ (parallel [(set (reg:SI 22) (mult:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))])
+ (set (match_operand:SI 0 "register_operand" "") (reg:SI 22))]
+ "AVR_ENHANCED"
+ "")
+
+ (define_insn "*mulsi3_call"
+ [(set (reg:SI 22) (mult:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))]
+ "AVR_ENHANCED"
+ "%~call __mulsi3"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ ; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / %
+ ; divmod
+
+ ;; Generate libgcc.S calls ourselves, because:
+ ;; - we know exactly which registers are clobbered (for QI and HI
+ ;; modes, some of the call-used registers are preserved)
+ ;; - we get both the quotient and the remainder at no extra cost
+
+ (define_expand "divmodqi4"
+ [(set (reg:QI 24) (match_operand:QI 1 "register_operand" ""))
+ (set (reg:QI 22) (match_operand:QI 2 "register_operand" ""))
+ (parallel [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22)))
+ (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 22))
+ (clobber (reg:QI 23))])
+ (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))
+ (set (match_operand:QI 3 "register_operand" "") (reg:QI 25))]
+ ""
+ "")
+
+ (define_insn "*divmodqi4_call"
+ [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22)))
+ (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 22))
+ (clobber (reg:QI 23))]
+ ""
+ "%~call __divmodqi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ (define_expand "udivmodqi4"
+ [(set (reg:QI 24) (match_operand:QI 1 "register_operand" ""))
+ (set (reg:QI 22) (match_operand:QI 2 "register_operand" ""))
+ (parallel [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22)))
+ (set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 23))])
+ (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))
+ (set (match_operand:QI 3 "register_operand" "") (reg:QI 25))]
+ ""
+ "")
+
+ (define_insn "*udivmodqi4_call"
+ [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22)))
+ (set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22)))
+ (clobber (reg:QI 23))]
+ ""
+ "%~call __udivmodqi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ (define_expand "divmodhi4"
+ [(set (reg:HI 24) (match_operand:HI 1 "register_operand" ""))
+ (set (reg:HI 22) (match_operand:HI 2 "register_operand" ""))
+ (parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
+ (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 26))
+ (clobber (reg:QI 21))])
+ (set (match_operand:HI 0 "register_operand" "") (reg:HI 22))
+ (set (match_operand:HI 3 "register_operand" "") (reg:HI 24))]
+ ""
+ "")
+
+ (define_insn "*divmodhi4_call"
+ [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
+ (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 26))
+ (clobber (reg:QI 21))]
+ ""
+ "%~call __divmodhi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ (define_expand "udivmodhi4"
+ [(set (reg:HI 24) (match_operand:HI 1 "register_operand" ""))
+ (set (reg:HI 22) (match_operand:HI 2 "register_operand" ""))
+ (parallel [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
+ (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 26))
+ (clobber (reg:QI 21))])
+ (set (match_operand:HI 0 "register_operand" "") (reg:HI 22))
+ (set (match_operand:HI 3 "register_operand" "") (reg:HI 24))]
+ ""
+ "")
+
+ (define_insn "*udivmodhi4_call"
+ [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
+ (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
+ (clobber (reg:HI 26))
+ (clobber (reg:QI 21))]
+ ""
+ "%~call __udivmodhi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ (define_expand "divmodsi4"
+ [(set (reg:SI 22) (match_operand:SI 1 "register_operand" ""))
+ (set (reg:SI 18) (match_operand:SI 2 "register_operand" ""))
+ (parallel [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18)))
+ (set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))])
+ (set (match_operand:SI 0 "register_operand" "") (reg:SI 18))
+ (set (match_operand:SI 3 "register_operand" "") (reg:SI 22))]
+ ""
+ "")
+
+ (define_insn "*divmodsi4_call"
+ [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18)))
+ (set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))]
+ ""
+ "%~call __divmodsi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
+ (define_expand "udivmodsi4"
+ [(set (reg:SI 22) (match_operand:SI 1 "register_operand" ""))
+ (set (reg:SI 18) (match_operand:SI 2 "register_operand" ""))
+ (parallel [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18)))
+ (set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))])
+ (set (match_operand:SI 0 "register_operand" "") (reg:SI 18))
+ (set (match_operand:SI 3 "register_operand" "") (reg:SI 22))]
+ ""
+ "")
+
+ (define_insn "*udivmodsi4_call"
+ [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18)))
+ (set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))]
+ ""
+ "%~call __udivmodsi4"
+ [(set (attr "length") (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "clobber")])
+
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; and
***************
*** 1794,1802 ****
AS2 (mov, r31, %B0) CR_TAB
\"icall\");
}
! else if (!AVR_MEGA)
! return AS1(rcall,%c0);
! return AS1(call,%c0);
}"
[(set_attr "cc" "clobber,clobber,clobber")
(set_attr_alternative "length"
--- 2044,2050 ----
AS2 (mov, r31, %B0) CR_TAB
\"icall\");
}
! return AS1(%~call,%c0);
}"
[(set_attr "cc" "clobber,clobber,clobber")
(set_attr_alternative "length"
***************
*** 1829,1837 ****
AS2 (mov, r31, %B1) CR_TAB
\"icall\");
}
! else if (!AVR_MEGA)
! return AS1(rcall,%c1);
! return AS1(call,%c1);
}"
[(set_attr "cc" "clobber,clobber,clobber")
(set_attr_alternative "length"
--- 2077,2083 ----
AS2 (mov, r31, %B1) CR_TAB
\"icall\");
}
! return AS1(%~call,%c1);
}"
[(set_attr "cc" "clobber,clobber,clobber")
(set_attr_alternative "length"
Index: config/avr/libgcc.S
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/avr/libgcc.S,v
retrieving revision 1.9
diff -c -3 -p -r1.9 libgcc.S
*** libgcc.S 2000/11/14 19:05:41 1.9
--- libgcc.S 2001/01/20 16:43:11
*************** Boston, MA 02111-1307, USA. */
*** 32,39 ****
--- 32,60 ----
#define __SP_H__ 0x3e
#define __SP_L__ 0x3d
+ /* Most of the functions here are called directly from avr.md
+ patterns, instead of using the standard libcall mechanisms.
+ This can make better code because GCC knows exactly which
+ of the call-used registers (not all of them) are clobbered. */
+
.section .text.libgcc, "ax", @progbits
+ .macro mov_l r_dest, r_src
+ #if defined (__AVR_ENHANCED__)
+ movw \r_dest, \r_src
+ #else
+ mov \r_dest, \r_src
+ #endif
+ .endm
+
+ .macro mov_h r_dest, r_src
+ #if defined (__AVR_ENHANCED__)
+ ; empty
+ #else
+ mov \r_dest, \r_src
+ #endif
+ .endm
+
/* Note: mulqi3, mulhi3 are open-coded on the enhanced core. */
#if !defined (__AVR_ENHANCED__)
/*******************************************************
*************** __mulqi3_exit:
*** 67,72 ****
--- 88,116 ----
.endfunc
#endif /* defined (L_mulqi3) */
+ #if defined (L_mulqihi3)
+ .global __mulqihi3
+ .func __mulqihi3
+ __mulqihi3:
+ clr r25
+ sbrc r24, 7
+ dec r25
+ clr r23
+ sbrc r22, 7
+ dec r22
+ rjmp __mulhi3
+ .endfunc
+ #endif /* defined (L_mulqihi3) */
+
+ #if defined (L_umulqihi3)
+ .global __umulqihi3
+ .func __umulqihi3
+ __umulqihi3:
+ clr r25
+ clr r23
+ rjmp __mulhi3
+ .endfunc
+ #endif /* defined (L_umulqihi3) */
/*******************************************************
Multiplication 16 x 16
*************** __mulqi3_exit:
*** 76,82 ****
#define r_arg1H r25 /* multiplier High */
#define r_arg2L r22 /* multiplicand Low */
#define r_arg2H r23 /* multiplicand High */
! #define r_resL r20 /* result Low */
#define r_resH r21 /* result High */
.global __mulhi3
--- 120,126 ----
#define r_arg1H r25 /* multiplier High */
#define r_arg2L r22 /* multiplicand Low */
#define r_arg2H r23 /* multiplicand High */
! #define r_resL __tmp_reg__ /* result Low */
#define r_resH r21 /* result High */
.global __mulhi3
*************** __mulhi3_exit:
*** 116,121 ****
--- 160,197 ----
#endif /* defined (L_mulhi3) */
#endif /* !defined (__AVR_ENHANCED__) */
+ #if defined (L_mulhisi3)
+ .global __mulhisi3
+ .func __mulhisi3
+ __mulhisi3:
+ mov_l r18, r24
+ mov_h r19, r25
+ clr r24
+ sbrc r23, 7
+ dec r24
+ mov r25, r24
+ clr r20
+ sbrc r19, 7
+ dec r20
+ mov r21, r20
+ rjmp __mulsi3
+ .endfunc
+ #endif /* defined (L_mulhisi3) */
+
+ #if defined (L_umulhisi3)
+ .global __umulhisi3
+ .func __umulhisi3
+ __umulhisi3:
+ mov_l r18, r24
+ mov_h r19, r25
+ clr r24
+ clr r25
+ clr r20
+ clr r21
+ rjmp __mulsi3
+ .endfunc
+ #endif /* defined (L_umulhisi3) */
+
#if defined (L_mulsi3)
/*******************************************************
Multiplication 32 x 32
*************** __mulsi3_exit:
*** 227,307 ****
/*******************************************************
Division 8 / 8 => (result + remainder)
*******************************************************/
! #define r_rem r26 /* remainder */
! #define r_arg1 r24 /* dividend */
#define r_arg2 r22 /* divisor */
! #define r_cnt r27 /* loop count */
!
! #if defined (L_umodqi3)
!
! .global __umodqi3
! .func __umodqi3
! __umodqi3:
! clt
! rcall __udivqi3
! mov r24,r_rem
! ret
! .endfunc
! #endif /* defined (L_umodqi3) */
!
! #if defined (L_udivqi3)
!
! .global __udivqi3
! .func __udivqi3
! __udivqi3:
! clr __tmp_reg__
! rjmp __divqi_raw
! .endfunc
! #endif /* defined (L_udivqi3) */
! #if defined (L_modqi3)
!
! .global __modqi3
! .func __modqi3
! __modqi3:
! rcall __divqi3
! mov r24,r_rem
ret
! .endfunc
! #endif /* defined (L_modqi3) */
! #if defined (L_divqi3)
!
! .global __divqi3
! .func __divqi3
! __divqi3:
! bst r_arg1,7 ; store sign of divident
mov __tmp_reg__,r_arg1
eor __tmp_reg__,r_arg2; r0.7 is sign of result
sbrc r_arg1,7
! neg r_arg1 ; divident negative : negate
sbrc r_arg2,7
! neg r_arg2 ; divisor negative : negate
! .global __divqi_raw
! __divqi_raw:
! sub r_rem,r_rem ; clear remainder and carry
! ldi r_cnt,9 ; init loop counter
! rjmp __divqi3_ep ; jump to entry point
! __divqi3_loop:
! rol r_rem ; shift dividend into remainder
! cp r_rem,r_arg2 ; compare remainder & divisor
! brcs __divqi3_ep ; remainder <= divisor
! sub r_rem,r_arg2 ; restore remainder
! __divqi3_ep:
! rol r_arg1 ; shift dividend (with CARRY)
! dec r_cnt ; decrement loop counter
! brne __divqi3_loop ; loop
! com r_arg1 ; complement result
! ; because C flag was complemented in loop
! brtc __divqi3_1
neg r_rem ; correct remainder sign
! __divqi3_1:
sbrc __tmp_reg__,7
neg r_arg1 ; correct result sign
! __divqi3_exit:
! ret ; result already in r24 (r_arg1)
! .endfunc
! #endif /* defined (L_divqi3) */
#undef r_rem
#undef r_arg1
--- 303,356 ----
/*******************************************************
Division 8 / 8 => (result + remainder)
*******************************************************/
! #define r_rem r25 /* remainder */
! #define r_arg1 r24 /* dividend, quotient */
#define r_arg2 r22 /* divisor */
! #define r_cnt r23 /* loop count */
! #if defined (L_udivmodqi4)
! .global __udivmodqi4
! .func __udivmodqi4
! __udivmodqi4:
! sub r_rem,r_rem ; clear remainder and carry
! ldi r_cnt,9 ; init loop counter
! rjmp __udivmodqi4_ep ; jump to entry point
! __udivmodqi4_loop:
! rol r_rem ; shift dividend into remainder
! cp r_rem,r_arg2 ; compare remainder & divisor
! brcs __udivmodqi4_ep ; remainder <= divisor
! sub r_rem,r_arg2 ; restore remainder
! __udivmodqi4_ep:
! rol r_arg1 ; shift dividend (with CARRY)
! dec r_cnt ; decrement loop counter
! brne __udivmodqi4_loop
! com r_arg1 ; complement result
! ; because C flag was complemented in loop
ret
! .endfunc
! #endif /* defined (L_udivmodqi4) */
! #if defined (L_divmodqi4)
! .global __divmodqi4
! .func __divmodqi4
! __divmodqi4:
! bst r_arg1,7 ; store sign of dividend
mov __tmp_reg__,r_arg1
eor __tmp_reg__,r_arg2; r0.7 is sign of result
sbrc r_arg1,7
! neg r_arg1 ; dividend negative : negate
sbrc r_arg2,7
! neg r_arg2 ; divisor negative : negate
! rcall __udivmodqi4 ; do the unsigned div/mod
! brtc __divmodqi4_1
neg r_rem ; correct remainder sign
! __divmodqi4_1:
sbrc __tmp_reg__,7
neg r_arg1 ; correct result sign
! __divmodqi4_exit:
! ret
! .endfunc
! #endif /* defined (L_divmodqi4) */
#undef r_rem
#undef r_arg1
*************** __divqi3_exit:
*** 314,426 ****
*******************************************************/
#define r_remL r26 /* remainder Low */
#define r_remH r27 /* remainder High */
!
#define r_arg1L r24 /* dividend Low */
#define r_arg1H r25 /* dividend High */
!
#define r_arg2L r22 /* divisor Low */
#define r_arg2H r23 /* divisor High */
#define r_cnt r21 /* loop count */
- #if defined (L_umodhi3)
- .global __umodhi3
- .func __umodhi3
- __umodhi3:
- clt
- rcall __udivhi3
- .global __umodhi3_ret
- __umodhi3_ret:
- #if defined (__AVR_ENHANCED__)
- movw r24, r_remL
- #else
- mov r24,r_remL
- mov r25,r_remH
- #endif
- ret
- .endfunc
- #endif /* defined (L_umodhi3) */
-
- #if defined (L_udivhi3)
-
- .global __udivhi3
- .func __udivhi3
- __udivhi3:
- clr __tmp_reg__
- rjmp __divhi_raw
- .endfunc
- #endif /* defined (L_udivhi3) */
! #if defined (L_modhi3)
! .global __modhi3
! .func __modhi3
! __modhi3:
! .global _div
! _div:
! rcall __divhi3
! #if defined (__AVR_ENHANCED__)
! movw r22, r24
! #else
! mov r22,r24 ; needed for div () function
! mov r23,r25
! #endif
! rjmp __umodhi3_ret
! .endfunc
! #endif /* defined (L_modhi3) */
!
!
! #if defined (L_divhi3)
! .global __divhi3
! .func __divhi3
! __divhi3:
! bst r_arg1H,7 ; store sign of divident
! mov __tmp_reg__,r_arg1H
! eor __tmp_reg__,r_arg2H ; r0.7 is sign of result
! brtc __divhi3_skip1
! com r_arg1H
! neg r_arg1L ; divident negative : negate
! sbci r_arg1H,0xff
! __divhi3_skip1:
! tst r_arg2H
! brpl __divhi3_skip2
! com r_arg2H
! neg r_arg2L ; divisor negative : negate
! sbci r_arg2H,0xff
! __divhi3_skip2:
! .global __divhi_raw
! __divhi_raw:
sub r_remL,r_remL
! sub r_remH,r_remH ; clear remainder and carry
ldi r_cnt,17 ; init loop counter
! rjmp __divhi3_ep ; jump to entry point
! __divhi3_loop:
rol r_remL ; shift dividend into remainder
rol r_remH
cp r_remL,r_arg2L ; compare remainder & divisor
cpc r_remH,r_arg2H
! brcs __divhi3_ep ; remainder < divisor
sub r_remL,r_arg2L ; restore remainder
sbc r_remH,r_arg2H
! __divhi3_ep:
rol r_arg1L ; shift dividend (with CARRY)
rol r_arg1H
dec r_cnt ; decrement loop counter
! brne __divhi3_loop ; loop
! brtc __divhi3_1
! com r_remH
! neg r_remL ; correct remainder sign
! sbci r_remH,0xff
! __divhi3_1:
tst __tmp_reg__
! brpl __divhi3_exit
! adiw r_arg1L,1 ; correct result sign
ret
! __divhi3_exit:
! com r_arg1L
com r_arg1H
ret
! .endfunc
! #endif /* defined (L_divhi3) */
!
#undef r_remH
#undef r_remL
--- 363,442 ----
*******************************************************/
#define r_remL r26 /* remainder Low */
#define r_remH r27 /* remainder High */
!
! /* return: remainder */
#define r_arg1L r24 /* dividend Low */
#define r_arg1H r25 /* dividend High */
!
! /* return: quotient */
#define r_arg2L r22 /* divisor Low */
#define r_arg2H r23 /* divisor High */
#define r_cnt r21 /* loop count */
! #if defined (L_udivmodhi4)
! .global __udivmodhi4
! .func __udivmodhi4
! __udivmodhi4:
sub r_remL,r_remL
! sub r_remH,r_remH ; clear remainder and carry
ldi r_cnt,17 ; init loop counter
! rjmp __udivmodhi4_ep ; jump to entry point
! __udivmodhi4_loop:
rol r_remL ; shift dividend into remainder
rol r_remH
cp r_remL,r_arg2L ; compare remainder & divisor
cpc r_remH,r_arg2H
! brcs __udivmodhi4_ep ; remainder < divisor
sub r_remL,r_arg2L ; restore remainder
sbc r_remH,r_arg2H
! __udivmodhi4_ep:
rol r_arg1L ; shift dividend (with CARRY)
rol r_arg1H
dec r_cnt ; decrement loop counter
! brne __udivmodhi4_loop
! com r_arg1L
! com r_arg1H
! ; div/mod results to return registers, as for the div() function
! mov_l r_arg2L, r_arg1L ; quotient
! mov_h r_arg2H, r_arg1H
! mov_l r_arg1L, r_remL ; remainder
! mov_h r_arg1H, r_remH
! ret
! .endfunc
! #endif /* defined (L_udivmodhi4) */
!
! #if defined (L_divmodhi4)
! .global __divmodhi4
! .func __divmodhi4
! __divmodhi4:
! .global _div
! _div:
! bst r_arg1H,7 ; store sign of dividend
! mov __tmp_reg__,r_arg1H
! eor __tmp_reg__,r_arg2H ; r0.7 is sign of result
! rcall __divmodhi4_neg1 ; dividend negative : negate
! sbrc r_arg2H,7
! rcall __divmodhi4_neg2 ; divisor negative : negate
! rcall __udivmodhi4 ; do the unsigned div/mod
! rcall __divmodhi4_neg1 ; correct remainder sign
tst __tmp_reg__
! brpl __divmodhi4_exit
! __divmodhi4_neg2:
! com r_arg2H
! neg r_arg2L ; correct divisor/result sign
! sbci r_arg2H,0xff
! __divmodhi4_exit:
ret
! __divmodhi4_neg1:
! brtc __divmodhi4_exit
com r_arg1H
+ neg r_arg1L ; correct dividend/remainder sign
+ sbci r_arg1H,0xff
ret
! .endfunc
! #endif /* defined (L_divmodhi4) */
!
#undef r_remH
#undef r_remL
*************** __divhi3_exit:
*** 439,551 ****
#define r_remHL r30
#define r_remH r27
#define r_remL r26 /* remainder Low */
!
#define r_arg1HH r25 /* dividend High */
#define r_arg1HL r24
#define r_arg1H r23
#define r_arg1L r22 /* dividend Low */
!
#define r_arg2HH r21 /* divisor High */
#define r_arg2HL r20
#define r_arg2H r19
#define r_arg2L r18 /* divisor Low */
#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
-
- #if defined (L_umodsi3)
! .global __umodsi3
! .func __umodsi3
! __umodsi3:
! clt
! rcall __udivsi3
! .global __umodsi3_ret
! __umodsi3_ret:
! #if defined (__AVR_ENHANCED__)
! movw r24, r_remHL
! movw r22, r_remL
! #else
! mov r25,r_remHH
! mov r24,r_remHL
! mov r23,r_remH
! mov r22,r_remL
! #endif
! ret
! .endfunc
! #endif /* defined (L_umodsi3) */
!
! #if defined (L_udivsi3)
!
! .global __udivsi3
! .func __udivsi3
! __udivsi3:
! clr __tmp_reg__
! rjmp __divsi_raw
! .endfunc
! #endif /* defined (L_udivsi3) */
!
! #if defined (L_modsi3)
!
! .global __modsi3
! .func __modsi3
! __modsi3:
! .global _ldiv
! _ldiv:
! rcall __divsi3
! #if defined (__AVR_ENHANCED__)
! movw r18, r22
! movw r20, r24
! #else
! mov r18,r22 /* Needed for ldiv */
! mov r19,r23
! mov r20,r24
! mov r21,r25
! #endif
! rjmp __umodsi3_ret
! .endfunc
! #endif /* defined (L_modsi3) */
!
! #if defined (L_divsi3)
!
! .global __divsi3
! .func __divsi3
! __divsi3:
! bst r_arg1HH,7 ; store sign of divident
! mov __tmp_reg__,r_arg1HH
! eor __tmp_reg__,r_arg2HH ; r0.7 is sign of result
! brtc __divsi3_skip1
! com r_arg1HH
! com r_arg1HL
! com r_arg1H
! neg r_arg1L ; divident negative : negate
! sbci r_arg1H, 0xff
! sbci r_arg1HL,0xff
! sbci r_arg1HH,0xff
! __divsi3_skip1:
! tst r_arg2HH
! brpl __divsi3_skip2
! com r_arg2HH
! com r_arg2HL
! com r_arg2H
! neg r_arg2L ; divisor negative : negate
! sbci r_arg2H, 0xff
! sbci r_arg2HL,0xff
! sbci r_arg2HH,0xff
! __divsi3_skip2:
! .global __divsi_raw
! __divsi_raw:
ldi r_remL, 33 ; init loop counter
mov r_cnt, r_remL
sub r_remL,r_remL
! sub r_remH,r_remH
! #if defined (__AVR_ENHANCED__)
! movw r_remHL, r_remL
! #else
! sub r_remHL,r_remHL
! sub r_remHH,r_remHH ; clear remainder and carry
! #endif
! rjmp __divsi3_ep ; jump to entry point
! __divsi3_loop:
rol r_remL ; shift dividend into remainder
rol r_remH
rol r_remHL
--- 455,487 ----
#define r_remHL r30
#define r_remH r27
#define r_remL r26 /* remainder Low */
!
! /* return: remainder */
#define r_arg1HH r25 /* dividend High */
#define r_arg1HL r24
#define r_arg1H r23
#define r_arg1L r22 /* dividend Low */
!
! /* return: quotient */
#define r_arg2HH r21 /* divisor High */
#define r_arg2HL r20
#define r_arg2H r19
#define r_arg2L r18 /* divisor Low */
#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
! #if defined (L_udivmodsi4)
! .global __udivmodsi4
! .func __udivmodsi4
! __udivmodsi4:
ldi r_remL, 33 ; init loop counter
mov r_cnt, r_remL
sub r_remL,r_remL
! sub r_remH,r_remH ; clear remainder and carry
! mov_l r_remHL, r_remL
! mov_h r_remHH, r_remH
! rjmp __udivmodsi4_ep ; jump to entry point
! __udivmodsi4_loop:
rol r_remL ; shift dividend into remainder
rol r_remH
rol r_remHL
*************** __divsi3_loop:
*** 554,596 ****
cpc r_remH,r_arg2H
cpc r_remHL,r_arg2HL
cpc r_remHH,r_arg2HH
! brcs __divsi3_ep ; remainder <= divisor
sub r_remL,r_arg2L ; restore remainder
sbc r_remH,r_arg2H
sbc r_remHL,r_arg2HL
sbc r_remHH,r_arg2HH
! __divsi3_ep:
rol r_arg1L ; shift dividend (with CARRY)
rol r_arg1H
rol r_arg1HL
rol r_arg1HH
dec r_cnt ; decrement loop counter
! brne __divsi3_loop ; loop
; __zero_reg__ now restored (r_cnt == 0)
- brtc __divsi3_1
- com r_remHH
- com r_remHL
- com r_remH
- neg r_remL ; correct remainder sign
- sbci r_remH, 0xff
- sbci r_remHL,0xff
- sbci r_remHH,0xff
- __divsi3_1:
- rol __tmp_reg__
- brcc __divsi3_exit
- adc r_arg1L,__zero_reg__; correct result sign
- adc r_arg1H,__zero_reg__
- adc r_arg1HL,__zero_reg__
- adc r_arg1HH,__zero_reg__
- ret
- __divsi3_exit:
com r_arg1L
com r_arg1H
com r_arg1HL
com r_arg1HH
ret
! .endfunc
! #endif /* defined (L_divsi3) */
/**********************************
* This is a prologue subroutine
--- 490,561 ----
cpc r_remH,r_arg2H
cpc r_remHL,r_arg2HL
cpc r_remHH,r_arg2HH
! brcs __udivmodsi4_ep ; remainder <= divisor
sub r_remL,r_arg2L ; restore remainder
sbc r_remH,r_arg2H
sbc r_remHL,r_arg2HL
sbc r_remHH,r_arg2HH
! __udivmodsi4_ep:
rol r_arg1L ; shift dividend (with CARRY)
rol r_arg1H
rol r_arg1HL
rol r_arg1HH
dec r_cnt ; decrement loop counter
! brne __udivmodsi4_loop
; __zero_reg__ now restored (r_cnt == 0)
com r_arg1L
com r_arg1H
com r_arg1HL
com r_arg1HH
+ ; div/mod results to return registers, as for the ldiv() function
+ mov_l r_arg2L, r_arg1L ; quotient
+ mov_h r_arg2H, r_arg1H
+ mov_l r_arg2HL, r_arg1HL
+ mov_h r_arg2HH, r_arg1HH
+ mov_l r_arg1L, r_remL ; remainder
+ mov_h r_arg1H, r_remH
+ mov_l r_arg1HL, r_remHL
+ mov_h r_arg1HH, r_remHH
+ ret
+ .endfunc
+ #endif /* defined (L_udivmodsi4) */
+
+ #if defined (L_divmodsi4)
+ .global __divmodsi4
+ .func __divmodsi4
+ __divmodsi4:
+ bst r_arg1HH,7 ; store sign of dividend
+ mov __tmp_reg__,r_arg1HH
+ eor __tmp_reg__,r_arg2HH ; r0.7 is sign of result
+ rcall __divmodsi4_neg1 ; dividend negative : negate
+ sbrc r_arg2HH,7
+ rcall __divmodsi4_neg2 ; divisor negative : negate
+ rcall __udivmodsi4 ; do the unsigned div/mod
+ rcall __divmodsi4_neg1 ; correct remainder sign
+ rol __tmp_reg__
+ brcc __divmodsi4_exit
+ __divmodsi4_neg2:
+ com r_arg2HH
+ com r_arg2HL
+ com r_arg2H
+ neg r_arg2L ; correct divisor/quotient sign
+ sbci r_arg2H,0xff
+ sbci r_arg2HL,0xff
+ sbci r_arg2HH,0xff
+ __divmodsi4_exit:
+ ret
+ __divmodsi4_neg1:
+ brtc __divmodsi4_exit
+ com r_arg1HH
+ com r_arg1HL
+ com r_arg1H
+ neg r_arg1L ; correct dividend/remainder sign
+ sbci r_arg1H, 0xff
+ sbci r_arg1HL,0xff
+ sbci r_arg1HH,0xff
ret
! .endfunc
! #endif /* defined (L_divmodsi4) */
/**********************************
* This is a prologue subroutine
*************** __epilogue_restores__:
*** 664,675 ****
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
! #if defined (__AVR_ENHANCED__)
! movw r28, r26
! #else
! mov r28,r26
! mov r29,r27
! #endif
ret
.endfunc
#endif /* defined (L_epilogue) */
--- 629,636 ----
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
! mov_l r28, r26
! mov_h r29, r27
ret
.endfunc
#endif /* defined (L_epilogue) */
*************** __tablejump2__:
*** 708,714 ****
lpm
push r0
ret
- .endfunc
#endif
#endif /* defined (L_tablejump) */
--- 669,675 ----
lpm
push r0
ret
#endif
+ .endfunc
#endif /* defined (L_tablejump) */
Index: config/avr/t-avr
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/avr/t-avr,v
retrieving revision 1.4
diff -c -3 -p -r1.4 t-avr
*** t-avr 2000/08/29 19:37:45 1.4
--- t-avr 2001/01/20 16:43:12
*************** LIB1ASMFUNCS = \
*** 8,25 ****
_mulqi3 \
_mulhi3 \
_mulsi3 \
! _umodqi3 \
! _udivqi3 \
! _modqi3 \
! _divqi3 \
! _umodhi3 \
! _udivhi3 \
! _modhi3 \
! _divhi3 \
! _umodsi3 \
! _udivsi3 \
! _modsi3 \
! _divsi3 \
_prologue \
_epilogue \
_exit \
--- 8,19 ----
_mulqi3 \
_mulhi3 \
_mulsi3 \
! _udivmodqi4 \
! _divmodqi4 \
! _udivmodhi4 \
! _divmodhi4 \
! _udivmodsi4 \
! _divmodsi4 \
_prologue \
_epilogue \
_exit \