extend.texi (AVR Built-in Functions): Update documentation of __builtin_avr_fmul*.
authorGeorg-Johann Lay <avr@gjlay.de>
Mon, 4 Jul 2011 12:20:35 +0000 (12:20 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Mon, 4 Jul 2011 12:20:35 +0000 (12:20 +0000)
* 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
gcc/config/avr/avr-c.c
gcc/config/avr/avr.c
gcc/config/avr/avr.md
gcc/config/avr/libgcc.S
gcc/config/avr/t-avr
gcc/doc/extend.texi

index 2ef91ce3047ccedde5f8ae76e8c8df5fb661785f..bd353f4d2b159d9fff36ce1c3658a8ca93267158 100644 (file)
@@ -1,3 +1,20 @@
+2011-07-04  Georg-Johann Lay  <avr@gjlay.de>
+
+       * 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  <rguenther@suse.de>
 
        PR tree-optimization/49615
index ec314d2a1399a2107df07c2e340d5eab0c98aa15..aa1a51e538b9bf4e5eafe50d3faa11b61a9752e8 100644 (file)
@@ -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");
 }
index 407a40f8c5edd403eed76653ca4c1e94301d35bc..fa690fb683d6703dceb8f049aa8439a8e4dcbf5e 100644 (file)
@@ -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
index a07992389cb1d79506f370d307436bad6a3fac99..dc186c82bb06f7e3ee6931884eb35e17a609ef70 100644 (file)
    (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")]
   [(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")]
   [(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")]
   [(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")])
+
 \f
 ;; Some combiner patterns dealing with bits.
 ;; See PR42210
index 9d13d9611b4b6e4c65f0cd977ec231c1cd0c56da..c2459d00e6b3e431d9f71106aedef630c4f9d14a 100644 (file)
@@ -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
index 026ee10b10e95e8f2392ba0ac991061f441d465d..a5357f0ecf6e398ba0c846399d099217e22421b3 100644 (file)
@@ -78,7 +78,8 @@ LIB1ASMFUNCS = \
        _bswapdi2 \
        _ashldi3 \
        _ashrdi3 \
-       _lshrdi3
+       _lshrdi3 \
+       _fmul _fmuls _fmulsu
 
 LIB2FUNCS_EXCLUDE = \
        _clz
index 0e80590534c6c3c37957d568a336ae4576fcd00e..5b80616c9690959dad9a59d6286c21b1a8a3836c 100644 (file)
@@ -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)