2016-11-10 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / config / avr / avr-fixed.md
blobd5dad918de7a396c0e64b0a178fb877539b19dce
1 ;;   This file contains instructions that support fixed-point operations
2 ;;   for Atmel AVR micro controllers.
3 ;;   Copyright (C) 2012-2016 Free Software Foundation, Inc.
4 ;;
5 ;;   Contributed by Sean D'Epagnier  (sean@depagnier.com)
6 ;;                  Georg-Johann Lay (avr@gjlay.de)
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.
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.
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/>.
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])
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])
39 ;;; Conversions
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])
49 ;; Same so that be can build cross products
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])
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")])
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")])
81 ;******************************************************************************
82 ;** Saturated Addition and Subtraction
83 ;******************************************************************************
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.
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")])
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")])
119 ;******************************************************************************
120 ;** Saturated Negation and Absolute Value
121 ;******************************************************************************
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  */
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   })
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")])
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")])
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   })
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")])
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")])
187 ;******************************************************************************
188 ; mul
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   })
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")])
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")])
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     avr_fix_inputs (operands, 1 << 2, regmask (QQmode, 24));
237   })
240 (define_expand "muluqq3_nomul"
241   [(set (reg:UQQ 22)
242         (match_operand:UQQ 1 "register_operand" ""))
243    (set (reg:UQQ 24)
244         (match_operand:UQQ 2 "register_operand" ""))
245    ;; "*umulqihi3.call"
246    (parallel [(set (reg:HI 24)
247                    (mult:HI (zero_extend:HI (reg:QI 22))
248                             (zero_extend:HI (reg:QI 24))))
249               (clobber (reg:QI 21))
250               (clobber (reg:HI 22))])
251    (set (match_operand:UQQ 0 "register_operand" "")
252         (reg:UQQ 25))]
253   "!AVR_HAVE_MUL"
254   {
255     avr_fix_inputs (operands, 1 << 2, regmask (UQQmode, 22));
256   })
258 (define_insn "*mulqq3.call"
259   [(set (reg:QQ 23)
260         (mult:QQ (reg:QQ 24)
261                  (reg:QQ 25)))
262    (clobber (reg:QI 22))
263    (clobber (reg:HI 24))]
264   "!AVR_HAVE_MUL"
265   "%~call __mulqq3"
266   [(set_attr "type" "xcall")
267    (set_attr "cc" "clobber")])
270 ;; "mulhq3" "muluhq3"
271 ;; "mulha3" "muluha3"
272 (define_expand "mul<mode>3"
273   [(set (reg:ALL2QA 18)
274         (match_operand:ALL2QA 1 "register_operand" ""))
275    (set (reg:ALL2QA 26)
276         (match_operand:ALL2QA 2 "register_operand" ""))
277    ;; "*mulhq3.call.enh"
278    (parallel [(set (reg:ALL2QA 24)
279                    (mult:ALL2QA (reg:ALL2QA 18)
280                                 (reg:ALL2QA 26)))
281               (clobber (reg:HI 22))])
282    (set (match_operand:ALL2QA 0 "register_operand" "")
283         (reg:ALL2QA 24))]
284   "AVR_HAVE_MUL"
285   {
286     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 18));
287   })
289 ;; "*mulhq3.call"  "*muluhq3.call"
290 ;; "*mulha3.call"  "*muluha3.call"
291 (define_insn "*mul<mode>3.call"
292   [(set (reg:ALL2QA 24)
293         (mult:ALL2QA (reg:ALL2QA 18)
294                      (reg:ALL2QA 26)))
295    (clobber (reg:HI 22))]
296   "AVR_HAVE_MUL"
297   "%~call __mul<mode>3"
298   [(set_attr "type" "xcall")
299    (set_attr "cc" "clobber")])
302 ;; On the enhanced core, don't clobber either input and use a separate output
304 ;; "mulsa3" "mulusa3"
305 (define_expand "mul<mode>3"
306   [(set (reg:ALL4A 16)
307         (match_operand:ALL4A 1 "register_operand" ""))
308    (set (reg:ALL4A 20)
309         (match_operand:ALL4A 2 "register_operand" ""))
310    (set (reg:ALL4A 24)
311         (mult:ALL4A (reg:ALL4A 16)
312                     (reg:ALL4A 20)))
313    (set (match_operand:ALL4A 0 "register_operand" "")
314         (reg:ALL4A 24))]
315   "AVR_HAVE_MUL"
316   {
317     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 16));
318   })
320 ;; "*mulsa3.call" "*mulusa3.call"
321 (define_insn "*mul<mode>3.call"
322   [(set (reg:ALL4A 24)
323         (mult:ALL4A (reg:ALL4A 16)
324                     (reg:ALL4A 20)))]
325   "AVR_HAVE_MUL"
326   "%~call __mul<mode>3"
327   [(set_attr "type" "xcall")
328    (set_attr "cc" "clobber")])
330 ; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
331 ; div
333 (define_code_iterator usdiv [udiv div])
335 ;; "divqq3" "udivuqq3"
336 (define_expand "<code><mode>3"
337   [(set (reg:ALL1Q 25)
338         (match_operand:ALL1Q 1 "register_operand" ""))
339    (set (reg:ALL1Q 22)
340         (match_operand:ALL1Q 2 "register_operand" ""))
341    (parallel [(set (reg:ALL1Q 24)
342                    (usdiv:ALL1Q (reg:ALL1Q 25)
343                                 (reg:ALL1Q 22)))
344               (clobber (reg:QI 25))])
345    (set (match_operand:ALL1Q 0 "register_operand" "")
346         (reg:ALL1Q 24))]
347   ""
348   {
349     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 25));
350   })
353 ;; "*divqq3.call" "*udivuqq3.call"
354 (define_insn "*<code><mode>3.call"
355   [(set (reg:ALL1Q 24)
356         (usdiv:ALL1Q (reg:ALL1Q 25)
357                      (reg:ALL1Q 22)))
358    (clobber (reg:QI 25))]
359   ""
360   "%~call __<code><mode>3"
361   [(set_attr "type" "xcall")
362    (set_attr "cc" "clobber")])
364 ;; "divhq3" "udivuhq3"
365 ;; "divha3" "udivuha3"
366 (define_expand "<code><mode>3"
367   [(set (reg:ALL2QA 26)
368         (match_operand:ALL2QA 1 "register_operand" ""))
369    (set (reg:ALL2QA 22)
370         (match_operand:ALL2QA 2 "register_operand" ""))
371    (parallel [(set (reg:ALL2QA 24)
372                    (usdiv:ALL2QA (reg:ALL2QA 26)
373                                  (reg:ALL2QA 22)))
374               (clobber (reg:HI 26))
375               (clobber (reg:QI 21))])
376    (set (match_operand:ALL2QA 0 "register_operand" "")
377         (reg:ALL2QA 24))]
378   ""
379   {
380     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 26));
381   })
383 ;; "*divhq3.call" "*udivuhq3.call"
384 ;; "*divha3.call" "*udivuha3.call"
385 (define_insn "*<code><mode>3.call"
386   [(set (reg:ALL2QA 24)
387         (usdiv:ALL2QA (reg:ALL2QA 26)
388                       (reg:ALL2QA 22)))
389    (clobber (reg:HI 26))
390    (clobber (reg:QI 21))]
391   ""
392   "%~call __<code><mode>3"
393   [(set_attr "type" "xcall")
394    (set_attr "cc" "clobber")])
396 ;; Note the first parameter gets passed in already offset by 2 bytes
398 ;; "divsa3" "udivusa3"
399 (define_expand "<code><mode>3"
400   [(set (reg:ALL4A 24)
401         (match_operand:ALL4A 1 "register_operand" ""))
402    (set (reg:ALL4A 18)
403         (match_operand:ALL4A 2 "register_operand" ""))
404    (parallel [(set (reg:ALL4A 22)
405                    (usdiv:ALL4A (reg:ALL4A 24)
406                                 (reg:ALL4A 18)))
407               (clobber (reg:HI 26))
408               (clobber (reg:HI 30))])
409    (set (match_operand:ALL4A 0 "register_operand" "")
410         (reg:ALL4A 22))]
411   ""
412   {
413     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 24));
414   })
416 ;; "*divsa3.call" "*udivusa3.call"
417 (define_insn "*<code><mode>3.call"
418   [(set (reg:ALL4A 22)
419         (usdiv:ALL4A (reg:ALL4A 24)
420                      (reg:ALL4A 18)))
421    (clobber (reg:HI 26))
422    (clobber (reg:HI 30))]
423   ""
424   "%~call __<code><mode>3"
425   [(set_attr "type" "xcall")
426    (set_attr "cc" "clobber")])
429 ;******************************************************************************
430 ;** Rounding
431 ;******************************************************************************
433 ;; "roundqq3"  "rounduqq3"
434 ;; "roundhq3"  "rounduhq3"  "roundha3"  "rounduha3"
435 ;; "roundsq3"  "roundusq3"  "roundsa3"  "roundusa3"
436 (define_expand "round<mode>3"
437   [(set (match_dup 4)
438         (match_operand:ALL124QA 1 "register_operand" ""))
439    (set (reg:QI 24)
440         (match_dup 5))
441    (parallel [(set (match_dup 3)
442                    (unspec:ALL124QA [(match_dup 4)
443                                      (reg:QI 24)] UNSPEC_ROUND))
444               (clobber (match_dup 4))])
445    (set (match_operand:ALL124QA 0 "register_operand" "")
446         (match_dup 3))
447    (use (match_operand:HI 2 "nonmemory_operand" ""))]
448   ""
449   {
450     if (CONST_INT_P (operands[2])
451         && !(optimize_size
452              && 4 == GET_MODE_SIZE (<MODE>mode)))
453       {
454         emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2]));
455         DONE;
456       }
458     // Input and output of the libgcc function
459     const unsigned int regno_in[]  = { -1U, 22, 22, -1U, 18 };
460     const unsigned int regno_out[] = { -1U, 24, 24, -1U, 22 };
462     operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
463     operands[4] = gen_rtx_REG (<MODE>mode,  regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
464     avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, REGNO (operands[4])));
465     operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
466     // $2 is no more needed, but is referenced for expand.
467     operands[2] = const0_rtx;
468   })
470 ;; Expand rounding with known rounding points inline so that the addend / mask
471 ;; will be consumed by operation with immediate operands and there is no
472 ;; need for a shift with variable offset.
474 ;; "roundqq3_const"  "rounduqq3_const"
475 ;; "roundhq3_const"  "rounduhq3_const"  "roundha3_const"  "rounduha3_const"
476 ;; "roundsq3_const"  "roundusq3_const"  "roundsa3_const"  "roundusa3_const"
477 (define_insn "round<mode>3_const"
478   [(set (match_operand:ALL124QA 0 "register_operand"                  "=d")
479         (unspec:ALL124QA [(match_operand:ALL124QA 1 "register_operand" "0")
480                           (match_operand:HI 2 "const_int_operand"      "n")
481                           (const_int 0)]
482                          UNSPEC_ROUND))]
483   ""
484   {
485     return avr_out_round (insn, operands);
486   }
487   [(set_attr "cc" "clobber")
488    (set_attr "adjust_len" "round")])
491 ;; "*roundqq3.libgcc"  "*rounduqq3.libgcc"
492 (define_insn "*round<mode>3.libgcc"
493   [(set (reg:ALL1Q 24)
494         (unspec:ALL1Q [(reg:ALL1Q 22)
495                        (reg:QI 24)] UNSPEC_ROUND))
496    (clobber (reg:ALL1Q 22))]
497   ""
498   "%~call __round<mode>3"
499   [(set_attr "type" "xcall")
500    (set_attr "cc" "clobber")])
502 ;; "*roundhq3.libgcc"  "*rounduhq3.libgcc"
503 ;; "*roundha3.libgcc"  "*rounduha3.libgcc"
504 (define_insn "*round<mode>3.libgcc"
505   [(set (reg:ALL2QA 24)
506         (unspec:ALL2QA [(reg:ALL2QA 22)
507                         (reg:QI 24)] UNSPEC_ROUND))
508    (clobber (reg:ALL2QA 22))]
509   ""
510   "%~call __round<mode>3"
511   [(set_attr "type" "xcall")
512    (set_attr "cc" "clobber")])
514 ;; "*roundsq3.libgcc"  "*roundusq3.libgcc"
515 ;; "*roundsa3.libgcc"  "*roundusa3.libgcc"
516 (define_insn "*round<mode>3.libgcc"
517   [(set (reg:ALL4QA 22)
518         (unspec:ALL4QA [(reg:ALL4QA 18)
519                         (reg:QI 24)] UNSPEC_ROUND))
520    (clobber (reg:ALL4QA 18))]
521   ""
522   "%~call __round<mode>3"
523   [(set_attr "type" "xcall")
524    (set_attr "cc" "clobber")])