Home | History | Annotate | Line # | Download | only in avr
avr-fixed.md revision 1.1.1.1
      1 ;;   This file contains instructions that support fixed-point operations
      2 ;;   for Atmel AVR micro controllers.
      3 ;;   Copyright (C) 2012-2013 Free Software Foundation, Inc.
      4 ;;
      5 ;;   Contributed by Sean D'Epagnier  (sean (a] depagnier.com)
      6 ;;                  Georg-Johann Lay (avr (a] gjlay.de)
      7 
      8 ;; This file is part of GCC.
      9 ;;
     10 ;; GCC is free software; you can redistribute it and/or modify
     11 ;; it under the terms of the GNU General Public License as published by
     12 ;; the Free Software Foundation; either version 3, or (at your option)
     13 ;; any later version.
     14 ;;
     15 ;; GCC is distributed in the hope that it will be useful,
     16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 ;; GNU General Public License for more details.
     19 ;;
     20 ;; You should have received a copy of the GNU General Public License
     21 ;; along with GCC; see the file COPYING3.  If not see
     22 ;; <http://www.gnu.org/licenses/>.
     23 
     24 (define_mode_iterator ALL1Q  [QQ UQQ])
     25 (define_mode_iterator ALL2Q  [HQ UHQ])
     26 (define_mode_iterator ALL2A  [HA UHA])
     27 (define_mode_iterator ALL4A  [SA USA])
     28 (define_mode_iterator ALL2QA [HQ UHQ HA UHA])
     29 (define_mode_iterator ALL4QA [SQ USQ SA USA])
     30 (define_mode_iterator ALL124QA [ QQ   HQ  HA  SA  SQ
     31                                 UQQ  UHQ UHA USA USQ])
     32 
     33 (define_mode_iterator ALL2S [HQ HA])
     34 (define_mode_iterator ALL4S [SA SQ])
     35 (define_mode_iterator ALL24S  [     HQ  HA  SA  SQ])
     36 (define_mode_iterator ALL124S [ QQ  HQ  HA  SA  SQ])
     37 (define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ])
     38 
     39 ;;; Conversions
     40 
     41 (define_mode_iterator FIXED_A
     42   [QQ UQQ
     43    HQ UHQ HA UHA
     44    SQ USQ SA USA
     45    DQ UDQ DA UDA
     46    TA UTA
     47    QI HI SI DI])
     48 
     49 ;; Same so that be can build cross products
     50 
     51 (define_mode_iterator FIXED_B
     52   [QQ UQQ
     53    HQ UHQ HA UHA
     54    SQ USQ SA USA
     55    DQ UDQ DA UDA
     56    TA UTA
     57    QI HI SI DI])
     58 
     59 (define_insn "fract<FIXED_B:mode><FIXED_A:mode>2"
     60   [(set (match_operand:FIXED_A 0 "register_operand" "=r")
     61         (fract_convert:FIXED_A
     62          (match_operand:FIXED_B 1 "register_operand" "r")))]
     63   "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
     64   {
     65     return avr_out_fract (insn, operands, true, NULL);
     66   }
     67   [(set_attr "cc" "clobber")
     68    (set_attr "adjust_len" "sfract")])
     69 
     70 (define_insn "fractuns<FIXED_B:mode><FIXED_A:mode>2"
     71   [(set (match_operand:FIXED_A 0 "register_operand" "=r")
     72         (unsigned_fract_convert:FIXED_A
     73          (match_operand:FIXED_B 1 "register_operand" "r")))]
     74   "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
     75   {
     76     return avr_out_fract (insn, operands, false, NULL);
     77   }
     78   [(set_attr "cc" "clobber")
     79    (set_attr "adjust_len" "ufract")])
     80 
     81 ;******************************************************************************
     82 ;** Saturated Addition and Subtraction
     83 ;******************************************************************************
     84 
     85 ;; Fixme:  It would be nice if we could expand the 32-bit versions to a
     86 ;;    transparent libgcc call if $2 is a REG.  Problem is that it is
     87 ;;    not possible to describe that addition is commutative.
     88 ;;    And defining register classes/constraintrs for the involved hard
     89 ;;    registers and let IRA do the work, yields inacceptable bloated code.
     90 ;;    Thus, we have to live with the up to 11 instructions that are output
     91 ;;    for these 32-bit saturated operations.
     92 
     93 ;; "ssaddqq3"  "ssaddhq3"  "ssaddha3"  "ssaddsq3"  "ssaddsa3"
     94 ;; "sssubqq3"  "sssubhq3"  "sssubha3"  "sssubsq3"  "sssubsa3"
     95 (define_insn "<code_stdname><mode>3"
     96   [(set (match_operand:ALL124S 0 "register_operand"                          "=??d,d")
     97         (ss_addsub:ALL124S (match_operand:ALL124S 1 "register_operand" "<abelian>0,0")
     98                            (match_operand:ALL124S 2 "nonmemory_operand"         "r,Ynn")))]
     99   ""
    100   {
    101     return avr_out_plus (insn, operands);
    102   }
    103   [(set_attr "cc" "clobber")
    104    (set_attr "adjust_len" "plus")])
    105 
    106 ;; "usadduqq3"  "usadduhq3"  "usadduha3" "usaddusq3"  "usaddusa3"
    107 ;; "ussubuqq3"  "ussubuhq3"  "ussubuha3" "ussubusq3"  "ussubusa3"
    108 (define_insn "<code_stdname><mode>3"
    109   [(set (match_operand:ALL124U 0 "register_operand"                          "=??r,d")
    110         (us_addsub:ALL124U (match_operand:ALL124U 1 "register_operand" "<abelian>0,0")
    111                            (match_operand:ALL124U 2 "nonmemory_operand"         "r,Ynn")))]
    112   ""
    113   {
    114     return avr_out_plus (insn, operands);
    115   }
    116   [(set_attr "cc" "clobber")
    117    (set_attr "adjust_len" "plus")])
    118 
    119 ;******************************************************************************
    120 ;** Saturated Negation and Absolute Value
    121 ;******************************************************************************
    122 
    123 ;; Fixme: This will always result in 0.  Dunno why simplify-rtx.c says
    124 ;;   "unknown" on how to optimize this.  libgcc call would be in order,
    125 ;;   but the performance is *PLAIN* *HORROR* because the optimizers don't
    126 ;;   manage to optimize out MEMCPY that's sprincled all over fixed-bit.c  */
    127 
    128 (define_expand "usneg<mode>2"
    129   [(parallel [(match_operand:ALL124U 0 "register_operand" "")
    130               (match_operand:ALL124U 1 "nonmemory_operand" "")])]
    131   ""
    132   {
    133     emit_move_insn (operands[0], CONST0_RTX (<MODE>mode));
    134     DONE;
    135   })
    136 
    137 (define_insn "ssnegqq2"
    138   [(set (match_operand:QQ 0 "register_operand"            "=r")
    139         (ss_neg:QQ (match_operand:QQ 1 "register_operand"  "0")))]
    140   ""
    141   "neg %0\;brvc 0f\;dec %0\;0:"
    142   [(set_attr "cc" "clobber")
    143    (set_attr "length" "3")])
    144 
    145 (define_insn "ssabsqq2"
    146   [(set (match_operand:QQ 0 "register_operand"            "=r")
    147         (ss_abs:QQ (match_operand:QQ 1 "register_operand"  "0")))]
    148   ""
    149   "sbrc %0,7\;neg %0\;sbrc %0,7\;dec %0"
    150   [(set_attr "cc" "clobber")
    151    (set_attr "length" "4")])
    152 
    153 ;; "ssneghq2"  "ssnegha2"  "ssnegsq2"  "ssnegsa2"
    154 ;; "ssabshq2"  "ssabsha2"  "ssabssq2"  "ssabssa2"
    155 (define_expand "<code_stdname><mode>2"
    156   [(set (match_dup 2)
    157         (match_operand:ALL24S 1 "register_operand" ""))
    158    (set (match_dup 2)
    159         (ss_abs_neg:ALL24S (match_dup 2)))
    160    (set (match_operand:ALL24S 0 "register_operand" "")
    161         (match_dup 2))]
    162   ""
    163   {
    164     operands[2] = gen_rtx_REG (<MODE>mode, 26 - GET_MODE_SIZE (<MODE>mode));
    165   })
    166 
    167 ;; "*ssneghq2"  "*ssnegha2"
    168 ;; "*ssabshq2"  "*ssabsha2"
    169 (define_insn "*<code_stdname><mode>2"
    170   [(set (reg:ALL2S 24)
    171         (ss_abs_neg:ALL2S (reg:ALL2S 24)))]
    172   ""
    173   "%~call __<code_stdname>_2"
    174   [(set_attr "type" "xcall")
    175    (set_attr "cc" "clobber")])
    176 
    177 ;; "*ssnegsq2"  "*ssnegsa2"
    178 ;; "*ssabssq2"  "*ssabssa2"
    179 (define_insn "*<code_stdname><mode>2"
    180   [(set (reg:ALL4S 22)
    181         (ss_abs_neg:ALL4S (reg:ALL4S 22)))]
    182   ""
    183   "%~call __<code_stdname>_4"
    184   [(set_attr "type" "xcall")
    185    (set_attr "cc" "clobber")])
    186 
    187 ;******************************************************************************
    188 ; mul
    189 
    190 ;; "mulqq3" "muluqq3"
    191 (define_expand "mul<mode>3"
    192   [(parallel [(match_operand:ALL1Q 0 "register_operand" "")
    193               (match_operand:ALL1Q 1 "register_operand" "")
    194               (match_operand:ALL1Q 2 "register_operand" "")])]
    195   ""
    196   {
    197     emit_insn (AVR_HAVE_MUL
    198       ? gen_mul<mode>3_enh (operands[0], operands[1], operands[2])
    199       : gen_mul<mode>3_nomul (operands[0], operands[1], operands[2]));
    200     DONE;
    201   })
    202 
    203 (define_insn "mulqq3_enh"
    204   [(set (match_operand:QQ 0 "register_operand"         "=r")
    205         (mult:QQ (match_operand:QQ 1 "register_operand" "a")
    206                  (match_operand:QQ 2 "register_operand" "a")))]
    207   "AVR_HAVE_MUL"
    208   "fmuls %1,%2\;dec r1\;brvs 0f\;inc r1\;0:\;mov %0,r1\;clr __zero_reg__"
    209   [(set_attr "length" "6")
    210    (set_attr "cc" "clobber")])
    211 
    212 (define_insn "muluqq3_enh"
    213   [(set (match_operand:UQQ 0 "register_operand"          "=r")
    214         (mult:UQQ (match_operand:UQQ 1 "register_operand" "r")
    215                   (match_operand:UQQ 2 "register_operand" "r")))]
    216   "AVR_HAVE_MUL"
    217   "mul %1,%2\;mov %0,r1\;clr __zero_reg__"
    218   [(set_attr "length" "3")
    219    (set_attr "cc" "clobber")])
    220 
    221 (define_expand "mulqq3_nomul"
    222   [(set (reg:QQ 24)
    223         (match_operand:QQ 1 "register_operand" ""))
    224    (set (reg:QQ 25)
    225         (match_operand:QQ 2 "register_operand" ""))
    226    ;; "*mulqq3.call"
    227    (parallel [(set (reg:QQ 23)
    228                    (mult:QQ (reg:QQ 24)
    229                             (reg:QQ 25)))
    230               (clobber (reg:QI 22))
    231               (clobber (reg:HI 24))])
    232    (set (match_operand:QQ 0 "register_operand" "")
    233         (reg:QQ 23))]
    234   "!AVR_HAVE_MUL")
    235 
    236 (define_expand "muluqq3_nomul"
    237   [(set (reg:UQQ 22)
    238         (match_operand:UQQ 1 "register_operand" ""))
    239    (set (reg:UQQ 24)
    240         (match_operand:UQQ 2 "register_operand" ""))
    241    ;; "*umulqihi3.call"
    242    (parallel [(set (reg:HI 24)
    243                    (mult:HI (zero_extend:HI (reg:QI 22))
    244                             (zero_extend:HI (reg:QI 24))))
    245               (clobber (reg:QI 21))
    246               (clobber (reg:HI 22))])
    247    (set (match_operand:UQQ 0 "register_operand" "")
    248         (reg:UQQ 25))]
    249   "!AVR_HAVE_MUL")
    250 
    251 (define_insn "*mulqq3.call"
    252   [(set (reg:QQ 23)
    253         (mult:QQ (reg:QQ 24)
    254                  (reg:QQ 25)))
    255    (clobber (reg:QI 22))
    256    (clobber (reg:HI 24))]
    257   "!AVR_HAVE_MUL"
    258   "%~call __mulqq3"
    259   [(set_attr "type" "xcall")
    260    (set_attr "cc" "clobber")])
    261 
    262 
    263 ;; "mulhq3" "muluhq3"
    264 ;; "mulha3" "muluha3"
    265 (define_expand "mul<mode>3"
    266   [(set (reg:ALL2QA 18)
    267         (match_operand:ALL2QA 1 "register_operand" ""))
    268    (set (reg:ALL2QA 26)
    269         (match_operand:ALL2QA 2 "register_operand" ""))
    270    ;; "*mulhq3.call.enh"
    271    (parallel [(set (reg:ALL2QA 24)
    272                    (mult:ALL2QA (reg:ALL2QA 18)
    273                                 (reg:ALL2QA 26)))
    274               (clobber (reg:HI 22))])
    275    (set (match_operand:ALL2QA 0 "register_operand" "")
    276         (reg:ALL2QA 24))]
    277   "AVR_HAVE_MUL")
    278 
    279 ;; "*mulhq3.call"  "*muluhq3.call"
    280 ;; "*mulha3.call"  "*muluha3.call"
    281 (define_insn "*mul<mode>3.call"
    282   [(set (reg:ALL2QA 24)
    283         (mult:ALL2QA (reg:ALL2QA 18)
    284                      (reg:ALL2QA 26)))
    285    (clobber (reg:HI 22))]
    286   "AVR_HAVE_MUL"
    287   "%~call __mul<mode>3"
    288   [(set_attr "type" "xcall")
    289    (set_attr "cc" "clobber")])
    290 
    291 
    292 ;; On the enhanced core, don't clobber either input and use a separate output
    293 
    294 ;; "mulsa3" "mulusa3"
    295 (define_expand "mul<mode>3"
    296   [(set (reg:ALL4A 16)
    297         (match_operand:ALL4A 1 "register_operand" ""))
    298    (set (reg:ALL4A 20)
    299         (match_operand:ALL4A 2 "register_operand" ""))
    300    (set (reg:ALL4A 24)
    301         (mult:ALL4A (reg:ALL4A 16)
    302                     (reg:ALL4A 20)))
    303    (set (match_operand:ALL4A 0 "register_operand" "")
    304         (reg:ALL4A 24))]
    305   "AVR_HAVE_MUL")
    306 
    307 ;; "*mulsa3.call" "*mulusa3.call"
    308 (define_insn "*mul<mode>3.call"
    309   [(set (reg:ALL4A 24)
    310         (mult:ALL4A (reg:ALL4A 16)
    311                     (reg:ALL4A 20)))]
    312   "AVR_HAVE_MUL"
    313   "%~call __mul<mode>3"
    314   [(set_attr "type" "xcall")
    315    (set_attr "cc" "clobber")])
    316 
    317 ; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
    318 ; div
    319 
    320 (define_code_iterator usdiv [udiv div])
    321 
    322 ;; "divqq3" "udivuqq3"
    323 (define_expand "<code><mode>3"
    324   [(set (reg:ALL1Q 25)
    325         (match_operand:ALL1Q 1 "register_operand" ""))
    326    (set (reg:ALL1Q 22)
    327         (match_operand:ALL1Q 2 "register_operand" ""))
    328    (parallel [(set (reg:ALL1Q 24)
    329                    (usdiv:ALL1Q (reg:ALL1Q 25)
    330                                 (reg:ALL1Q 22)))
    331               (clobber (reg:QI 25))])
    332    (set (match_operand:ALL1Q 0 "register_operand" "")
    333         (reg:ALL1Q 24))])
    334 
    335 ;; "*divqq3.call" "*udivuqq3.call"
    336 (define_insn "*<code><mode>3.call"
    337   [(set (reg:ALL1Q 24)
    338         (usdiv:ALL1Q (reg:ALL1Q 25)
    339                      (reg:ALL1Q 22)))
    340    (clobber (reg:QI 25))]
    341   ""
    342   "%~call __<code><mode>3"
    343   [(set_attr "type" "xcall")
    344    (set_attr "cc" "clobber")])
    345 
    346 ;; "divhq3" "udivuhq3"
    347 ;; "divha3" "udivuha3"
    348 (define_expand "<code><mode>3"
    349   [(set (reg:ALL2QA 26)
    350         (match_operand:ALL2QA 1 "register_operand" ""))
    351    (set (reg:ALL2QA 22)
    352         (match_operand:ALL2QA 2 "register_operand" ""))
    353    (parallel [(set (reg:ALL2QA 24)
    354                    (usdiv:ALL2QA (reg:ALL2QA 26)
    355                                  (reg:ALL2QA 22)))
    356               (clobber (reg:HI 26))
    357               (clobber (reg:QI 21))])
    358    (set (match_operand:ALL2QA 0 "register_operand" "")
    359         (reg:ALL2QA 24))])
    360 
    361 ;; "*divhq3.call" "*udivuhq3.call"
    362 ;; "*divha3.call" "*udivuha3.call"
    363 (define_insn "*<code><mode>3.call"
    364   [(set (reg:ALL2QA 24)
    365         (usdiv:ALL2QA (reg:ALL2QA 26)
    366                       (reg:ALL2QA 22)))
    367    (clobber (reg:HI 26))
    368    (clobber (reg:QI 21))]
    369   ""
    370   "%~call __<code><mode>3"
    371   [(set_attr "type" "xcall")
    372    (set_attr "cc" "clobber")])
    373 
    374 ;; Note the first parameter gets passed in already offset by 2 bytes
    375 
    376 ;; "divsa3" "udivusa3"
    377 (define_expand "<code><mode>3"
    378   [(set (reg:ALL4A 24)
    379         (match_operand:ALL4A 1 "register_operand" ""))
    380    (set (reg:ALL4A 18)
    381         (match_operand:ALL4A 2 "register_operand" ""))
    382    (parallel [(set (reg:ALL4A 22)
    383                    (usdiv:ALL4A (reg:ALL4A 24)
    384                                 (reg:ALL4A 18)))
    385               (clobber (reg:HI 26))
    386               (clobber (reg:HI 30))])
    387    (set (match_operand:ALL4A 0 "register_operand" "")
    388         (reg:ALL4A 22))])
    389 
    390 ;; "*divsa3.call" "*udivusa3.call"
    391 (define_insn "*<code><mode>3.call"
    392   [(set (reg:ALL4A 22)
    393         (usdiv:ALL4A (reg:ALL4A 24)
    394                      (reg:ALL4A 18)))
    395    (clobber (reg:HI 26))
    396    (clobber (reg:HI 30))]
    397   ""
    398   "%~call __<code><mode>3"
    399   [(set_attr "type" "xcall")
    400    (set_attr "cc" "clobber")])
    401 
    402 
    403 ;******************************************************************************
    404 ;** Rounding
    405 ;******************************************************************************
    406 
    407 ;; "roundqq3"  "rounduqq3"
    408 ;; "roundhq3"  "rounduhq3"  "roundha3"  "rounduha3"
    409 ;; "roundsq3"  "roundusq3"  "roundsa3"  "roundusa3"
    410 (define_expand "round<mode>3"
    411   [(set (match_dup 4)
    412         (match_operand:ALL124QA 1 "register_operand" ""))
    413    (set (reg:QI 24)
    414         (match_dup 5))
    415    (parallel [(set (match_dup 3)
    416                    (unspec:ALL124QA [(match_dup 4)
    417                                      (reg:QI 24)] UNSPEC_ROUND))
    418               (clobber (match_dup 4))])
    419    (set (match_operand:ALL124QA 0 "register_operand" "")
    420         (match_dup 3))
    421    (use (match_operand:HI 2 "nonmemory_operand" ""))]
    422   ""
    423   {
    424     if (CONST_INT_P (operands[2])
    425         && !(optimize_size
    426              && 4 == GET_MODE_SIZE (<MODE>mode)))
    427       {
    428         emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2]));
    429         DONE;
    430       }
    431 
    432     // Input and output of the libgcc function
    433     const unsigned int regno_in[]  = { -1U, 22, 22, -1U, 18 };
    434     const unsigned int regno_out[] = { -1U, 24, 24, -1U, 22 };
    435 
    436     operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
    437     operands[4] = gen_rtx_REG (<MODE>mode,  regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
    438     operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
    439     // $2 is no more needed, but is referenced for expand.
    440     operands[2] = const0_rtx;
    441   })
    442 
    443 ;; Expand rounding with known rounding points inline so that the addend / mask
    444 ;; will be consumed by operation with immediate operands and there is no
    445 ;; need for a shift with variable offset.
    446 
    447 ;; "roundqq3_const"  "rounduqq3_const"
    448 ;; "roundhq3_const"  "rounduhq3_const"  "roundha3_const"  "rounduha3_const"
    449 ;; "roundsq3_const"  "roundusq3_const"  "roundsa3_const"  "roundusa3_const"
    450 (define_insn "round<mode>3_const"
    451   [(set (match_operand:ALL124QA 0 "register_operand"                  "=d")
    452         (unspec:ALL124QA [(match_operand:ALL124QA 1 "register_operand" "0")
    453                           (match_operand:HI 2 "const_int_operand"      "n")
    454                           (const_int 0)]
    455                          UNSPEC_ROUND))]
    456   ""
    457   {
    458     return avr_out_round (insn, operands);
    459   }
    460   [(set_attr "cc" "clobber")
    461    (set_attr "adjust_len" "round")])
    462 
    463 
    464 ;; "*roundqq3.libgcc"  "*rounduqq3.libgcc"
    465 (define_insn "*round<mode>3.libgcc"
    466   [(set (reg:ALL1Q 24)
    467         (unspec:ALL1Q [(reg:ALL1Q 22)
    468                        (reg:QI 24)] UNSPEC_ROUND))
    469    (clobber (reg:ALL1Q 22))]
    470   ""
    471   "%~call __round<mode>3"
    472   [(set_attr "type" "xcall")
    473    (set_attr "cc" "clobber")])
    474 
    475 ;; "*roundhq3.libgcc"  "*rounduhq3.libgcc"
    476 ;; "*roundha3.libgcc"  "*rounduha3.libgcc"
    477 (define_insn "*round<mode>3.libgcc"
    478   [(set (reg:ALL2QA 24)
    479         (unspec:ALL2QA [(reg:ALL2QA 22)
    480                         (reg:QI 24)] UNSPEC_ROUND))
    481    (clobber (reg:ALL2QA 22))]
    482   ""
    483   "%~call __round<mode>3"
    484   [(set_attr "type" "xcall")
    485    (set_attr "cc" "clobber")])
    486 
    487 ;; "*roundsq3.libgcc"  "*roundusq3.libgcc"
    488 ;; "*roundsa3.libgcc"  "*roundusa3.libgcc"
    489 (define_insn "*round<mode>3.libgcc"
    490   [(set (reg:ALL4QA 22)
    491         (unspec:ALL4QA [(reg:ALL4QA 18)
    492                         (reg:QI 24)] UNSPEC_ROUND))
    493    (clobber (reg:ALL4QA 18))]
    494   ""
    495   "%~call __round<mode>3"
    496   [(set_attr "type" "xcall")
    497    (set_attr "cc" "clobber")])
    498