From f451d14dcc3720d959a95efa6eb1f79ae6edd0ae Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Mon, 4 Jul 2011 12:20:35 +0000 Subject: [PATCH] extend.texi (AVR Built-in Functions): Update documentation of __builtin_avr_fmul*. * doc/extend.texi (AVR Built-in Functions): Update documentation of __builtin_avr_fmul*. * config/avr/avr.c (avr_init_builtins): Don't depend on AVR_HAVE_MUL. * config/avr/avr-c.c (avr_cpu_cpp_builtins): Ditto. * config/avr/avr.md (fmul): Rename to fmul_insn. (fmuls): Rename to fmuls_insn. (fmulsu): Rename to fmulsu_insn. (fmul,fmuls,fmulsu): New expander. (*fmul.call,*fmuls.call,*fmulsu.call): New Insn. * config/avr/t-avr (LIB1ASMFUNCS): Add _fmul, _fmuls, _fmulsu. * config/avr/libgcc.S (__fmul): New function. (__fmuls): New function. (__fmulsu,__fmulsu_exit): New function. From-SVN: r175807 --- gcc/ChangeLog | 17 ++++++++ gcc/config/avr/avr-c.c | 9 ++-- gcc/config/avr/avr.c | 19 +++----- gcc/config/avr/avr.md | 96 +++++++++++++++++++++++++++++++++++++++-- gcc/config/avr/libgcc.S | 88 +++++++++++++++++++++++++++++++++++++ gcc/config/avr/t-avr | 3 +- gcc/doc/extend.texi | 4 +- 7 files changed, 211 insertions(+), 25 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2ef91ce3047..bd353f4d2b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2011-07-04 Georg-Johann Lay + + * doc/extend.texi (AVR Built-in Functions): Update documentation + of __builtin_avr_fmul*. + * config/avr/avr.c (avr_init_builtins): Don't depend on + AVR_HAVE_MUL. + * config/avr/avr-c.c (avr_cpu_cpp_builtins): Ditto. + * config/avr/avr.md (fmul): Rename to fmul_insn. + (fmuls): Rename to fmuls_insn. + (fmulsu): Rename to fmulsu_insn. + (fmul,fmuls,fmulsu): New expander. + (*fmul.call,*fmuls.call,*fmulsu.call): New Insn. + * config/avr/t-avr (LIB1ASMFUNCS): Add _fmul, _fmuls, _fmulsu. + * config/avr/libgcc.S (__fmul): New function. + (__fmuls): New function. + (__fmulsu,__fmulsu_exit): New function. + 2011-07-04 Richard Guenther PR tree-optimization/49615 diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c index ec314d2a139..aa1a51e538b 100644 --- a/gcc/config/avr/avr-c.c +++ b/gcc/config/avr/avr-c.c @@ -94,10 +94,7 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile) cpp_define (pfile, "__BUILTIN_AVR_SWAP"); cpp_define (pfile, "__BUILTIN_AVR_DELAY_CYCLES"); - if (AVR_HAVE_MUL) - { - cpp_define (pfile, "__BUILTIN_AVR_FMUL"); - cpp_define (pfile, "__BUILTIN_AVR_FMULS"); - cpp_define (pfile, "__BUILTIN_AVR_FMULSU"); - } + cpp_define (pfile, "__BUILTIN_AVR_FMUL"); + cpp_define (pfile, "__BUILTIN_AVR_FMULS"); + cpp_define (pfile, "__BUILTIN_AVR_FMULSU"); } diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 407a40f8c5e..fa690fb683d 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -6536,19 +6536,12 @@ avr_init_builtins (void) DEF_BUILTIN ("__builtin_avr_delay_cycles", void_ftype_ulong, AVR_BUILTIN_DELAY_CYCLES); - if (AVR_HAVE_MUL) - { - /* FIXME: If !AVR_HAVE_MUL, make respective functions available - in libgcc. For fmul and fmuls this is straight forward with - upcoming fixed point support. */ - - DEF_BUILTIN ("__builtin_avr_fmul", uint_ftype_uchar_uchar, - AVR_BUILTIN_FMUL); - DEF_BUILTIN ("__builtin_avr_fmuls", int_ftype_char_char, - AVR_BUILTIN_FMULS); - DEF_BUILTIN ("__builtin_avr_fmulsu", int_ftype_char_uchar, - AVR_BUILTIN_FMULSU); - } + DEF_BUILTIN ("__builtin_avr_fmul", uint_ftype_uchar_uchar, + AVR_BUILTIN_FMUL); + DEF_BUILTIN ("__builtin_avr_fmuls", int_ftype_char_char, + AVR_BUILTIN_FMULS); + DEF_BUILTIN ("__builtin_avr_fmulsu", int_ftype_char_uchar, + AVR_BUILTIN_FMULSU); } #undef DEF_BUILTIN diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index a07992389cb..dc186c82bb0 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -3394,7 +3394,27 @@ (set_attr "cc" "none")]) ;; FMUL -(define_insn "fmul" +(define_expand "fmul" + [(set (reg:QI 24) + (match_operand:QI 1 "register_operand" "")) + (set (reg:QI 25) + (match_operand:QI 2 "register_operand" "")) + (parallel [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMUL)) + (clobber (reg:HI 24))]) + (set (match_operand:HI 0 "register_operand" "") + (reg:HI 22))] + "" + { + if (AVR_HAVE_MUL) + { + emit_insn (gen_fmul_insn (operand0, operand1, operand2)); + DONE; + } + }) + +(define_insn "fmul_insn" [(set (match_operand:HI 0 "register_operand" "=r") (unspec:HI [(match_operand:QI 1 "register_operand" "a") (match_operand:QI 2 "register_operand" "a")] @@ -3406,8 +3426,38 @@ [(set_attr "length" "3") (set_attr "cc" "clobber")]) +(define_insn "*fmul.call" + [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMUL)) + (clobber (reg:HI 24))] + "!AVR_HAVE_MUL" + "%~call __fmul" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + ;; FMULS -(define_insn "fmuls" +(define_expand "fmuls" + [(set (reg:QI 24) + (match_operand:QI 1 "register_operand" "")) + (set (reg:QI 25) + (match_operand:QI 2 "register_operand" "")) + (parallel [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMULS)) + (clobber (reg:HI 24))]) + (set (match_operand:HI 0 "register_operand" "") + (reg:HI 22))] + "" + { + if (AVR_HAVE_MUL) + { + emit_insn (gen_fmuls_insn (operand0, operand1, operand2)); + DONE; + } + }) + +(define_insn "fmuls_insn" [(set (match_operand:HI 0 "register_operand" "=r") (unspec:HI [(match_operand:QI 1 "register_operand" "a") (match_operand:QI 2 "register_operand" "a")] @@ -3419,8 +3469,38 @@ [(set_attr "length" "3") (set_attr "cc" "clobber")]) +(define_insn "*fmuls.call" + [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMULS)) + (clobber (reg:HI 24))] + "!AVR_HAVE_MUL" + "%~call __fmuls" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + ;; FMULSU -(define_insn "fmulsu" +(define_expand "fmulsu" + [(set (reg:QI 24) + (match_operand:QI 1 "register_operand" "")) + (set (reg:QI 25) + (match_operand:QI 2 "register_operand" "")) + (parallel [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMULSU)) + (clobber (reg:HI 24))]) + (set (match_operand:HI 0 "register_operand" "") + (reg:HI 22))] + "" + { + if (AVR_HAVE_MUL) + { + emit_insn (gen_fmulsu_insn (operand0, operand1, operand2)); + DONE; + } + }) + +(define_insn "fmulsu_insn" [(set (match_operand:HI 0 "register_operand" "=r") (unspec:HI [(match_operand:QI 1 "register_operand" "a") (match_operand:QI 2 "register_operand" "a")] @@ -3432,6 +3512,16 @@ [(set_attr "length" "3") (set_attr "cc" "clobber")]) +(define_insn "*fmulsu.call" + [(set (reg:HI 22) + (unspec:HI [(reg:QI 24) + (reg:QI 25)] UNSPEC_FMULSU)) + (clobber (reg:HI 24))] + "!AVR_HAVE_MUL" + "%~call __fmulsu" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + ;; Some combiner patterns dealing with bits. ;; See PR42210 diff --git a/gcc/config/avr/libgcc.S b/gcc/config/avr/libgcc.S index 9d13d9611b4..c2459d00e6b 100644 --- a/gcc/config/avr/libgcc.S +++ b/gcc/config/avr/libgcc.S @@ -1417,3 +1417,91 @@ DEFUN __ashldi3 ret ENDF __ashldi3 #endif /* defined (L_ashldi3) */ + + +/***********************************************************/ +;;; Softmul versions of FMUL, FMULS and FMULSU to implement +;;; __builtin_avr_fmul* if !AVR_HAVE_MUL +/***********************************************************/ + +#define A1 24 +#define B1 25 +#define C0 22 +#define C1 23 +#define A0 __tmp_reg__ + +#ifdef L_fmuls +;;; r23:r22 = fmuls (r24, r25) like in FMULS instruction +;;; Clobbers: r24, r25, __tmp_reg__ +DEFUN __fmuls + ;; A0.7 = negate result? + mov A0, A1 + eor A0, B1 + ;; B1 = |B1| + sbrc B1, 7 + neg B1 + XJMP __fmulsu_exit +ENDF __fmuls +#endif /* L_fmuls */ + +#ifdef L_fmulsu +;;; r23:r22 = fmulsu (r24, r25) like in FMULSU instruction +;;; Clobbers: r24, r25, __tmp_reg__ +DEFUN __fmulsu + ;; A0.7 = negate result? + mov A0, A1 +;; FALLTHRU +ENDF __fmulsu + +;; Helper for __fmuls and __fmulsu +DEFUN __fmulsu_exit + ;; A1 = |A1| + sbrc A1, 7 + neg A1 +#ifdef __AVR_HAVE_JMP_CALL__ + ;; Some cores have problem skipping 2-word instruction + tst A0 + brmi 1f +#else + sbrs A0, 7 +#endif /* __AVR_HAVE_JMP_CALL__ */ + XJMP __fmul +1: XCALL __fmul + ;; C = -C iff A0.7 = 1 + com C1 + neg C0 + sbci C1, -1 + ret +ENDF __fmulsu_exit +#endif /* L_fmulsu */ + + +#ifdef L_fmul +;;; r22:r23 = fmul (r24, r25) like in FMUL instruction +;;; Clobbers: r24, r25, __tmp_reg__ +DEFUN __fmul + ; clear result + clr C0 + clr C1 + clr A0 +1: tst B1 + ;; 1.0 = 0x80, so test for bit 7 of B to see if A must to be added to C. +2: brpl 3f + ;; C += A + add C0, A0 + adc C1, A1 +3: ;; A >>= 1 + lsr A1 + ror A0 + ;; B <<= 1 + lsl B1 + brne 2b + ret +ENDF __fmul +#endif /* L_fmul */ + +#undef A0 +#undef A1 +#undef B1 +#undef C0 +#undef C1 diff --git a/gcc/config/avr/t-avr b/gcc/config/avr/t-avr index 026ee10b10e..a5357f0ecf6 100644 --- a/gcc/config/avr/t-avr +++ b/gcc/config/avr/t-avr @@ -78,7 +78,8 @@ LIB1ASMFUNCS = \ _bswapdi2 \ _ashldi3 \ _ashrdi3 \ - _lshrdi3 + _lshrdi3 \ + _fmul _fmuls _fmulsu LIB2FUNCS_EXCLUDE = \ _clz diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 0e80590534c..5b80616c969 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8226,8 +8226,8 @@ or if not a specific built-in is implemented or not. For example, if The following built-in functions map to the respective machine instruction, i.e. @code{nop}, @code{sei}, @code{cli}, @code{sleep}, @code{wdr}, @code{swap}, @code{fmul}, @code{fmuls} -resp. @code{fmulsu}. The latter three are only available if the AVR -device actually supports multiplication. +resp. @code{fmulsu}. The three @code{fmul*} built-ins are implemented +as library call if no hardware multiplier is available. @smallexample void __builtin_avr_nop (void) -- 2.30.2