diff gcc/config/avr/avr-fixed.md @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/config/avr/avr-fixed.md	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,524 @@
+;;   This file contains instructions that support fixed-point operations
+;;   for Atmel AVR micro controllers.
+;;   Copyright (C) 2012-2017 Free Software Foundation, Inc.
+;;
+;;   Contributed by Sean D'Epagnier  (sean@depagnier.com)
+;;                  Georg-Johann Lay (avr@gjlay.de)
+
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_mode_iterator ALL1Q  [QQ UQQ])
+(define_mode_iterator ALL2Q  [HQ UHQ])
+(define_mode_iterator ALL2A  [HA UHA])
+(define_mode_iterator ALL4A  [SA USA])
+(define_mode_iterator ALL2QA [HQ UHQ HA UHA])
+(define_mode_iterator ALL4QA [SQ USQ SA USA])
+(define_mode_iterator ALL124QA [ QQ   HQ  HA  SA  SQ
+                                UQQ  UHQ UHA USA USQ])
+
+(define_mode_iterator ALL2S [HQ HA])
+(define_mode_iterator ALL4S [SA SQ])
+(define_mode_iterator ALL24S  [     HQ  HA  SA  SQ])
+(define_mode_iterator ALL124S [ QQ  HQ  HA  SA  SQ])
+(define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ])
+
+;;; Conversions
+
+(define_mode_iterator FIXED_A
+  [QQ UQQ
+   HQ UHQ HA UHA
+   SQ USQ SA USA
+   DQ UDQ DA UDA
+   TA UTA
+   QI HI SI DI])
+
+;; Same so that be can build cross products
+
+(define_mode_iterator FIXED_B
+  [QQ UQQ
+   HQ UHQ HA UHA
+   SQ USQ SA USA
+   DQ UDQ DA UDA
+   TA UTA
+   QI HI SI DI])
+
+(define_insn "fract<FIXED_B:mode><FIXED_A:mode>2"
+  [(set (match_operand:FIXED_A 0 "register_operand" "=r")
+        (fract_convert:FIXED_A
+         (match_operand:FIXED_B 1 "register_operand" "r")))]
+  "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
+  {
+    return avr_out_fract (insn, operands, true, NULL);
+  }
+  [(set_attr "cc" "clobber")
+   (set_attr "adjust_len" "sfract")])
+
+(define_insn "fractuns<FIXED_B:mode><FIXED_A:mode>2"
+  [(set (match_operand:FIXED_A 0 "register_operand" "=r")
+        (unsigned_fract_convert:FIXED_A
+         (match_operand:FIXED_B 1 "register_operand" "r")))]
+  "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
+  {
+    return avr_out_fract (insn, operands, false, NULL);
+  }
+  [(set_attr "cc" "clobber")
+   (set_attr "adjust_len" "ufract")])
+
+;******************************************************************************
+;** Saturated Addition and Subtraction
+;******************************************************************************
+
+;; Fixme:  It would be nice if we could expand the 32-bit versions to a
+;;    transparent libgcc call if $2 is a REG.  Problem is that it is
+;;    not possible to describe that addition is commutative.
+;;    And defining register classes/constraintrs for the involved hard
+;;    registers and let IRA do the work, yields inacceptable bloated code.
+;;    Thus, we have to live with the up to 11 instructions that are output
+;;    for these 32-bit saturated operations.
+
+;; "ssaddqq3"  "ssaddhq3"  "ssaddha3"  "ssaddsq3"  "ssaddsa3"
+;; "sssubqq3"  "sssubhq3"  "sssubha3"  "sssubsq3"  "sssubsa3"
+(define_insn "<code_stdname><mode>3"
+  [(set (match_operand:ALL124S 0 "register_operand"                          "=??d,d")
+        (ss_addsub:ALL124S (match_operand:ALL124S 1 "register_operand" "<abelian>0,0")
+                           (match_operand:ALL124S 2 "nonmemory_operand"         "r,Ynn")))]
+  ""
+  {
+    return avr_out_plus (insn, operands);
+  }
+  [(set_attr "cc" "clobber")
+   (set_attr "adjust_len" "plus")])
+
+;; "usadduqq3"  "usadduhq3"  "usadduha3" "usaddusq3"  "usaddusa3"
+;; "ussubuqq3"  "ussubuhq3"  "ussubuha3" "ussubusq3"  "ussubusa3"
+(define_insn "<code_stdname><mode>3"
+  [(set (match_operand:ALL124U 0 "register_operand"                          "=??r,d")
+        (us_addsub:ALL124U (match_operand:ALL124U 1 "register_operand" "<abelian>0,0")
+                           (match_operand:ALL124U 2 "nonmemory_operand"         "r,Ynn")))]
+  ""
+  {
+    return avr_out_plus (insn, operands);
+  }
+  [(set_attr "cc" "clobber")
+   (set_attr "adjust_len" "plus")])
+
+;******************************************************************************
+;** Saturated Negation and Absolute Value
+;******************************************************************************
+
+;; Fixme: This will always result in 0.  Dunno why simplify-rtx.c says
+;;   "unknown" on how to optimize this.  libgcc call would be in order,
+;;   but the performance is *PLAIN* *HORROR* because the optimizers don't
+;;   manage to optimize out MEMCPY that's sprincled all over fixed-bit.c  */
+
+(define_expand "usneg<mode>2"
+  [(parallel [(match_operand:ALL124U 0 "register_operand" "")
+              (match_operand:ALL124U 1 "nonmemory_operand" "")])]
+  ""
+  {
+    emit_move_insn (operands[0], CONST0_RTX (<MODE>mode));
+    DONE;
+  })
+
+(define_insn "ssnegqq2"
+  [(set (match_operand:QQ 0 "register_operand"            "=r")
+        (ss_neg:QQ (match_operand:QQ 1 "register_operand"  "0")))]
+  ""
+  "neg %0\;brvc 0f\;dec %0\;0:"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "3")])
+
+(define_insn "ssabsqq2"
+  [(set (match_operand:QQ 0 "register_operand"            "=r")
+        (ss_abs:QQ (match_operand:QQ 1 "register_operand"  "0")))]
+  ""
+  "sbrc %0,7\;neg %0\;sbrc %0,7\;dec %0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "4")])
+
+;; "ssneghq2"  "ssnegha2"  "ssnegsq2"  "ssnegsa2"
+;; "ssabshq2"  "ssabsha2"  "ssabssq2"  "ssabssa2"
+(define_expand "<code_stdname><mode>2"
+  [(set (match_dup 2)
+        (match_operand:ALL24S 1 "register_operand" ""))
+   (set (match_dup 2)
+        (ss_abs_neg:ALL24S (match_dup 2)))
+   (set (match_operand:ALL24S 0 "register_operand" "")
+        (match_dup 2))]
+  ""
+  {
+    operands[2] = gen_rtx_REG (<MODE>mode, 26 - GET_MODE_SIZE (<MODE>mode));
+  })
+
+;; "*ssneghq2"  "*ssnegha2"
+;; "*ssabshq2"  "*ssabsha2"
+(define_insn "*<code_stdname><mode>2"
+  [(set (reg:ALL2S 24)
+        (ss_abs_neg:ALL2S (reg:ALL2S 24)))]
+  ""
+  "%~call __<code_stdname>_2"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;; "*ssnegsq2"  "*ssnegsa2"
+;; "*ssabssq2"  "*ssabssa2"
+(define_insn "*<code_stdname><mode>2"
+  [(set (reg:ALL4S 22)
+        (ss_abs_neg:ALL4S (reg:ALL4S 22)))]
+  ""
+  "%~call __<code_stdname>_4"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;******************************************************************************
+; mul
+
+;; "mulqq3" "muluqq3"
+(define_expand "mul<mode>3"
+  [(parallel [(match_operand:ALL1Q 0 "register_operand" "")
+              (match_operand:ALL1Q 1 "register_operand" "")
+              (match_operand:ALL1Q 2 "register_operand" "")])]
+  ""
+  {
+    emit_insn (AVR_HAVE_MUL
+      ? gen_mul<mode>3_enh (operands[0], operands[1], operands[2])
+      : gen_mul<mode>3_nomul (operands[0], operands[1], operands[2]));
+    DONE;
+  })
+
+(define_insn "mulqq3_enh"
+  [(set (match_operand:QQ 0 "register_operand"         "=r")
+        (mult:QQ (match_operand:QQ 1 "register_operand" "a")
+                 (match_operand:QQ 2 "register_operand" "a")))]
+  "AVR_HAVE_MUL"
+  "fmuls %1,%2\;dec r1\;brvs 0f\;inc r1\;0:\;mov %0,r1\;clr __zero_reg__"
+  [(set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+(define_insn "muluqq3_enh"
+  [(set (match_operand:UQQ 0 "register_operand"          "=r")
+        (mult:UQQ (match_operand:UQQ 1 "register_operand" "r")
+                  (match_operand:UQQ 2 "register_operand" "r")))]
+  "AVR_HAVE_MUL"
+  "mul %1,%2\;mov %0,r1\;clr __zero_reg__"
+  [(set_attr "length" "3")
+   (set_attr "cc" "clobber")])
+
+(define_expand "mulqq3_nomul"
+  [(set (reg:QQ 24)
+        (match_operand:QQ 1 "register_operand" ""))
+   (set (reg:QQ 25)
+        (match_operand:QQ 2 "register_operand" ""))
+   ;; "*mulqq3.call"
+   (parallel [(set (reg:QQ 23)
+                   (mult:QQ (reg:QQ 24)
+                            (reg:QQ 25)))
+              (clobber (reg:QI 22))
+              (clobber (reg:HI 24))])
+   (set (match_operand:QQ 0 "register_operand" "")
+        (reg:QQ 23))]
+  "!AVR_HAVE_MUL"
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (QQmode, 24));
+  })
+
+
+(define_expand "muluqq3_nomul"
+  [(set (reg:UQQ 22)
+        (match_operand:UQQ 1 "register_operand" ""))
+   (set (reg:UQQ 24)
+        (match_operand:UQQ 2 "register_operand" ""))
+   ;; "*umulqihi3.call"
+   (parallel [(set (reg:HI 24)
+                   (mult:HI (zero_extend:HI (reg:QI 22))
+                            (zero_extend:HI (reg:QI 24))))
+              (clobber (reg:QI 21))
+              (clobber (reg:HI 22))])
+   (set (match_operand:UQQ 0 "register_operand" "")
+        (reg:UQQ 25))]
+  "!AVR_HAVE_MUL"
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (UQQmode, 22));
+  })
+
+(define_insn "*mulqq3.call"
+  [(set (reg:QQ 23)
+        (mult:QQ (reg:QQ 24)
+                 (reg:QQ 25)))
+   (clobber (reg:QI 22))
+   (clobber (reg:HI 24))]
+  "!AVR_HAVE_MUL"
+  "%~call __mulqq3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+
+;; "mulhq3" "muluhq3"
+;; "mulha3" "muluha3"
+(define_expand "mul<mode>3"
+  [(set (reg:ALL2QA 18)
+        (match_operand:ALL2QA 1 "register_operand" ""))
+   (set (reg:ALL2QA 26)
+        (match_operand:ALL2QA 2 "register_operand" ""))
+   ;; "*mulhq3.call.enh"
+   (parallel [(set (reg:ALL2QA 24)
+                   (mult:ALL2QA (reg:ALL2QA 18)
+                                (reg:ALL2QA 26)))
+              (clobber (reg:HI 22))])
+   (set (match_operand:ALL2QA 0 "register_operand" "")
+        (reg:ALL2QA 24))]
+  "AVR_HAVE_MUL"
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 18));
+  })
+
+;; "*mulhq3.call"  "*muluhq3.call"
+;; "*mulha3.call"  "*muluha3.call"
+(define_insn "*mul<mode>3.call"
+  [(set (reg:ALL2QA 24)
+        (mult:ALL2QA (reg:ALL2QA 18)
+                     (reg:ALL2QA 26)))
+   (clobber (reg:HI 22))]
+  "AVR_HAVE_MUL"
+  "%~call __mul<mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+
+;; On the enhanced core, don't clobber either input and use a separate output
+
+;; "mulsa3" "mulusa3"
+(define_expand "mul<mode>3"
+  [(set (reg:ALL4A 16)
+        (match_operand:ALL4A 1 "register_operand" ""))
+   (set (reg:ALL4A 20)
+        (match_operand:ALL4A 2 "register_operand" ""))
+   (set (reg:ALL4A 24)
+        (mult:ALL4A (reg:ALL4A 16)
+                    (reg:ALL4A 20)))
+   (set (match_operand:ALL4A 0 "register_operand" "")
+        (reg:ALL4A 24))]
+  "AVR_HAVE_MUL"
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 16));
+  })
+
+;; "*mulsa3.call" "*mulusa3.call"
+(define_insn "*mul<mode>3.call"
+  [(set (reg:ALL4A 24)
+        (mult:ALL4A (reg:ALL4A 16)
+                    (reg:ALL4A 20)))]
+  "AVR_HAVE_MUL"
+  "%~call __mul<mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+; div
+
+(define_code_iterator usdiv [udiv div])
+
+;; "divqq3" "udivuqq3"
+(define_expand "<code><mode>3"
+  [(set (reg:ALL1Q 25)
+        (match_operand:ALL1Q 1 "register_operand" ""))
+   (set (reg:ALL1Q 22)
+        (match_operand:ALL1Q 2 "register_operand" ""))
+   (parallel [(set (reg:ALL1Q 24)
+                   (usdiv:ALL1Q (reg:ALL1Q 25)
+                                (reg:ALL1Q 22)))
+              (clobber (reg:QI 25))])
+   (set (match_operand:ALL1Q 0 "register_operand" "")
+        (reg:ALL1Q 24))]
+  ""
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 25));
+  })
+
+
+;; "*divqq3.call" "*udivuqq3.call"
+(define_insn "*<code><mode>3.call"
+  [(set (reg:ALL1Q 24)
+        (usdiv:ALL1Q (reg:ALL1Q 25)
+                     (reg:ALL1Q 22)))
+   (clobber (reg:QI 25))]
+  ""
+  "%~call __<code><mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;; "divhq3" "udivuhq3"
+;; "divha3" "udivuha3"
+(define_expand "<code><mode>3"
+  [(set (reg:ALL2QA 26)
+        (match_operand:ALL2QA 1 "register_operand" ""))
+   (set (reg:ALL2QA 22)
+        (match_operand:ALL2QA 2 "register_operand" ""))
+   (parallel [(set (reg:ALL2QA 24)
+                   (usdiv:ALL2QA (reg:ALL2QA 26)
+                                 (reg:ALL2QA 22)))
+              (clobber (reg:HI 26))
+              (clobber (reg:QI 21))])
+   (set (match_operand:ALL2QA 0 "register_operand" "")
+        (reg:ALL2QA 24))]
+  ""
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 26));
+  })
+
+;; "*divhq3.call" "*udivuhq3.call"
+;; "*divha3.call" "*udivuha3.call"
+(define_insn "*<code><mode>3.call"
+  [(set (reg:ALL2QA 24)
+        (usdiv:ALL2QA (reg:ALL2QA 26)
+                      (reg:ALL2QA 22)))
+   (clobber (reg:HI 26))
+   (clobber (reg:QI 21))]
+  ""
+  "%~call __<code><mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;; Note the first parameter gets passed in already offset by 2 bytes
+
+;; "divsa3" "udivusa3"
+(define_expand "<code><mode>3"
+  [(set (reg:ALL4A 24)
+        (match_operand:ALL4A 1 "register_operand" ""))
+   (set (reg:ALL4A 18)
+        (match_operand:ALL4A 2 "register_operand" ""))
+   (parallel [(set (reg:ALL4A 22)
+                   (usdiv:ALL4A (reg:ALL4A 24)
+                                (reg:ALL4A 18)))
+              (clobber (reg:HI 26))
+              (clobber (reg:HI 30))])
+   (set (match_operand:ALL4A 0 "register_operand" "")
+        (reg:ALL4A 22))]
+  ""
+  {
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 24));
+  })
+
+;; "*divsa3.call" "*udivusa3.call"
+(define_insn "*<code><mode>3.call"
+  [(set (reg:ALL4A 22)
+        (usdiv:ALL4A (reg:ALL4A 24)
+                     (reg:ALL4A 18)))
+   (clobber (reg:HI 26))
+   (clobber (reg:HI 30))]
+  ""
+  "%~call __<code><mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+
+;******************************************************************************
+;** Rounding
+;******************************************************************************
+
+;; "roundqq3"  "rounduqq3"
+;; "roundhq3"  "rounduhq3"  "roundha3"  "rounduha3"
+;; "roundsq3"  "roundusq3"  "roundsa3"  "roundusa3"
+(define_expand "round<mode>3"
+  [(set (match_dup 4)
+        (match_operand:ALL124QA 1 "register_operand" ""))
+   (set (reg:QI 24)
+        (match_dup 5))
+   (parallel [(set (match_dup 3)
+                   (unspec:ALL124QA [(match_dup 4)
+                                     (reg:QI 24)] UNSPEC_ROUND))
+              (clobber (match_dup 4))])
+   (set (match_operand:ALL124QA 0 "register_operand" "")
+        (match_dup 3))
+   (use (match_operand:HI 2 "nonmemory_operand" ""))]
+  ""
+  {
+    if (CONST_INT_P (operands[2])
+        && !(optimize_size
+             && 4 == GET_MODE_SIZE (<MODE>mode)))
+      {
+        emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2]));
+        DONE;
+      }
+
+    // Input and output of the libgcc function
+    const unsigned int regno_in[]  = { -1U, 22, 22, -1U, 18 };
+    const unsigned int regno_out[] = { -1U, 24, 24, -1U, 22 };
+
+    operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
+    operands[4] = gen_rtx_REG (<MODE>mode,  regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
+    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, REGNO (operands[4])));
+    operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
+    // $2 is no more needed, but is referenced for expand.
+    operands[2] = const0_rtx;
+  })
+
+;; Expand rounding with known rounding points inline so that the addend / mask
+;; will be consumed by operation with immediate operands and there is no
+;; need for a shift with variable offset.
+
+;; "roundqq3_const"  "rounduqq3_const"
+;; "roundhq3_const"  "rounduhq3_const"  "roundha3_const"  "rounduha3_const"
+;; "roundsq3_const"  "roundusq3_const"  "roundsa3_const"  "roundusa3_const"
+(define_insn "round<mode>3_const"
+  [(set (match_operand:ALL124QA 0 "register_operand"                  "=d")
+        (unspec:ALL124QA [(match_operand:ALL124QA 1 "register_operand" "0")
+                          (match_operand:HI 2 "const_int_operand"      "n")
+                          (const_int 0)]
+                         UNSPEC_ROUND))]
+  ""
+  {
+    return avr_out_round (insn, operands);
+  }
+  [(set_attr "cc" "clobber")
+   (set_attr "adjust_len" "round")])
+
+
+;; "*roundqq3.libgcc"  "*rounduqq3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+  [(set (reg:ALL1Q 24)
+        (unspec:ALL1Q [(reg:ALL1Q 22)
+                       (reg:QI 24)] UNSPEC_ROUND))
+   (clobber (reg:ALL1Q 22))]
+  ""
+  "%~call __round<mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;; "*roundhq3.libgcc"  "*rounduhq3.libgcc"
+;; "*roundha3.libgcc"  "*rounduha3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+  [(set (reg:ALL2QA 24)
+        (unspec:ALL2QA [(reg:ALL2QA 22)
+                        (reg:QI 24)] UNSPEC_ROUND))
+   (clobber (reg:ALL2QA 22))]
+  ""
+  "%~call __round<mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])
+
+;; "*roundsq3.libgcc"  "*roundusq3.libgcc"
+;; "*roundsa3.libgcc"  "*roundusa3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+  [(set (reg:ALL4QA 22)
+        (unspec:ALL4QA [(reg:ALL4QA 18)
+                        (reg:QI 24)] UNSPEC_ROUND))
+   (clobber (reg:ALL4QA 18))]
+  ""
+  "%~call __round<mode>3"
+  [(set_attr "type" "xcall")
+   (set_attr "cc" "clobber")])