1;;   Machine description for GNU compiler,
2;;   for Atmel AVR micro controllers.
3;;   Copyright (C) 1998-2022 Free Software Foundation, Inc.
4;;   Contributed by Georg Lay (avr@gjlay.de)
5;;
6;; This file is part of GCC.
7;;
8;; GCC is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 3, or (at your option)
11;; any later version.
12;;
13;; GCC is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16;; GNU General Public License for more details.
17;;
18;; You should have received a copy of the GNU General Public License
19;; along with GCC; see the file COPYING3.  If not see
20;; <http://www.gnu.org/licenses/>.
21
22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
24;; The purpose of this file is to provide a light-weight DImode
25;; implementation for AVR.  The trouble with DImode is that tree -> RTL
26;; lowering leads to really unpleasant code for operations that don't
27;; work byte-wise like NEG, PLUS, MINUS, etc.  Defining optabs entries for
28;; them won't help because the optab machinery assumes these operations
29;; are cheap and does not check if a libgcc implementation is available.
30;;
31;; The DImode insns are all straight forward -- except movdi.  The approach
32;; of this implementation is to provide DImode insns without the burden of
33;; introducing movdi.
34;;
35;; The caveat is that if there are insns for some mode, there must also be a
36;; respective move insn that describes reloads.  Therefore, this
37;; implementation uses an accumulator-based model with two hard-coded,
38;; accumulator-like registers
39;;
40;;    A[] = reg:DI 18
41;;    B[] = reg:DI 10
42;;
43;; so that no DImode insn contains pseudos or needs reloading.
44
45(define_constants
46  [(ACC_A 18)
47   (ACC_B 10)])
48
49;; Supported modes that are 8 bytes wide
50(define_mode_iterator ALL8 [DI DQ UDQ DA UDA TA UTA])
51
52(define_mode_iterator ALL8U [UDQ UDA UTA])
53(define_mode_iterator ALL8S [ DQ  DA  TA])
54
55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56;; Addition
57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58
59;; "adddi3"
60;; "adddq3" "addudq3"
61;; "addda3" "adduda3"
62;; "addta3" "adduta3"
63(define_expand "add<mode>3"
64  [(parallel [(match_operand:ALL8 0 "general_operand" "")
65              (match_operand:ALL8 1 "general_operand" "")
66              (match_operand:ALL8 2 "general_operand" "")])]
67  "avr_have_dimode"
68  {
69    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
70
71    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
72    emit_move_insn (acc_a, operands[1]);
73
74    if (DImode == <MODE>mode
75        && s8_operand (operands[2], VOIDmode))
76      {
77        emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
78        emit_insn (gen_adddi3_const8_insn ());
79      }
80    else if (const_operand (operands[2], GET_MODE (operands[2])))
81      {
82        emit_insn (gen_add<mode>3_const_insn (operands[2]));
83      }
84    else
85      {
86        emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
87        emit_insn (gen_add<mode>3_insn ());
88      }
89
90    emit_move_insn (operands[0], acc_a);
91    DONE;
92  })
93
94;; "adddi3_insn"
95;; "adddq3_insn" "addudq3_insn"
96;; "addda3_insn" "adduda3_insn"
97;; "addta3_insn" "adduta3_insn"
98(define_insn_and_split "add<mode>3_insn"
99  [(set (reg:ALL8 ACC_A)
100        (plus:ALL8 (reg:ALL8 ACC_A)
101                   (reg:ALL8 ACC_B)))]
102  "avr_have_dimode"
103  "#"
104  "&& reload_completed"
105  [(parallel [(set (reg:ALL8 ACC_A)
106                   (plus:ALL8 (reg:ALL8 ACC_A)
107                              (reg:ALL8 ACC_B)))
108   (clobber (reg:CC REG_CC))])])
109
110(define_insn "*add<mode>3_insn"
111  [(set (reg:ALL8 ACC_A)
112        (plus:ALL8 (reg:ALL8 ACC_A)
113                   (reg:ALL8 ACC_B)))
114   (clobber (reg:CC REG_CC))]
115  "avr_have_dimode && reload_completed"
116  "%~call __adddi3"
117  [(set_attr "adjust_len" "call")])
118
119(define_insn_and_split "adddi3_const8_insn"
120  [(set (reg:DI ACC_A)
121        (plus:DI (reg:DI ACC_A)
122                 (sign_extend:DI (reg:QI REG_X))))]
123  "avr_have_dimode"
124  "#"
125  "&& reload_completed"
126  [(parallel [(set (reg:DI ACC_A)
127                   (plus:DI (reg:DI ACC_A)
128                            (sign_extend:DI (reg:QI REG_X))))
129              (clobber (reg:CC REG_CC))])])
130
131(define_insn "*adddi3_const8_insn"
132  [(set (reg:DI ACC_A)
133        (plus:DI (reg:DI ACC_A)
134                 (sign_extend:DI (reg:QI REG_X))))
135   (clobber (reg:CC REG_CC))]
136  "avr_have_dimode && reload_completed"
137  "%~call __adddi3_s8"
138  [(set_attr "adjust_len" "call")])
139
140;; "adddi3_const_insn"
141;; "adddq3_const_insn" "addudq3_const_insn"
142;; "addda3_const_insn" "adduda3_const_insn"
143;; "addta3_const_insn" "adduta3_const_insn"
144(define_insn_and_split "add<mode>3_const_insn"
145  [(set (reg:ALL8 ACC_A)
146        (plus:ALL8 (reg:ALL8 ACC_A)
147                   (match_operand:ALL8 0 "const_operand" "n Ynn")))]
148  "avr_have_dimode
149   && !s8_operand (operands[0], VOIDmode)"
150   "#"
151   "&& reload_completed"
152   [(parallel [(set (reg:ALL8 ACC_A)
153                    (plus:ALL8 (reg:ALL8 ACC_A)
154                               (match_dup 0)))
155               (clobber (reg:CC REG_CC))])])
156
157(define_insn "*add<mode>3_const_insn"
158  [(set (reg:ALL8 ACC_A)
159        (plus:ALL8 (reg:ALL8 ACC_A)
160                   (match_operand:ALL8 0 "const_operand" "n Ynn")))
161   (clobber (reg:CC REG_CC))]
162  "avr_have_dimode
163   && !s8_operand (operands[0], VOIDmode)
164   && reload_completed"
165  {
166    return avr_out_plus (insn, operands);
167  }
168  [(set_attr "adjust_len" "plus")])
169
170
171;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172;; Subtraction
173;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
174
175;; "subdi3"
176;; "subdq3" "subudq3"
177;; "subda3" "subuda3"
178;; "subta3" "subuta3"
179(define_expand "sub<mode>3"
180  [(parallel [(match_operand:ALL8 0 "general_operand" "")
181              (match_operand:ALL8 1 "general_operand" "")
182              (match_operand:ALL8 2 "general_operand" "")])]
183  "avr_have_dimode"
184  {
185    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
186
187    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
188    emit_move_insn (acc_a, operands[1]);
189
190    if (const_operand (operands[2], GET_MODE (operands[2])))
191      {
192        emit_insn (gen_sub<mode>3_const_insn (operands[2]));
193      }
194    else
195     {
196       emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
197       emit_insn (gen_sub<mode>3_insn ());
198     }
199
200    emit_move_insn (operands[0], acc_a);
201    DONE;
202  })
203
204;; "subdi3_insn"
205;; "subdq3_insn" "subudq3_insn"
206;; "subda3_insn" "subuda3_insn"
207;; "subta3_insn" "subuta3_insn"
208(define_insn_and_split "sub<mode>3_insn"
209  [(set (reg:ALL8 ACC_A)
210        (minus:ALL8 (reg:ALL8 ACC_A)
211                    (reg:ALL8 ACC_B)))]
212  "avr_have_dimode"
213  "#"
214  "&& reload_completed"
215  [(parallel [(set (reg:ALL8 ACC_A)
216                   (minus:ALL8 (reg:ALL8 ACC_A)
217                               (reg:ALL8 ACC_B)))
218              (clobber (reg:CC REG_CC))])])
219
220(define_insn "*sub<mode>3_insn"
221  [(set (reg:ALL8 ACC_A)
222        (minus:ALL8 (reg:ALL8 ACC_A)
223                    (reg:ALL8 ACC_B)))
224   (clobber (reg:CC REG_CC))]
225  "avr_have_dimode && reload_completed"
226  "%~call __subdi3"
227  [(set_attr "adjust_len" "call")])
228
229;; "subdi3_const_insn"
230;; "subdq3_const_insn" "subudq3_const_insn"
231;; "subda3_const_insn" "subuda3_const_insn"
232;; "subta3_const_insn" "subuta3_const_insn"
233(define_insn_and_split "sub<mode>3_const_insn"
234  [(set (reg:ALL8 ACC_A)
235        (minus:ALL8 (reg:ALL8 ACC_A)
236                    (match_operand:ALL8 0 "const_operand" "n Ynn")))]
237  "avr_have_dimode"
238  "#"
239  "&& reload_completed"
240  [(parallel [(set (reg:ALL8 ACC_A)
241                   (minus:ALL8 (reg:ALL8 ACC_A)
242                               (match_dup 0)))
243              (clobber (reg:CC REG_CC))])])
244
245(define_insn "*sub<mode>3_const_insn"
246  [(set (reg:ALL8 ACC_A)
247        (minus:ALL8 (reg:ALL8 ACC_A)
248                    (match_operand:ALL8 0 "const_operand" "n Ynn")))
249   (clobber (reg:CC REG_CC))]
250  "avr_have_dimode && reload_completed"
251  {
252    return avr_out_plus (insn, operands);
253  }
254  [(set_attr "adjust_len" "plus")])
255
256;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257;; Signed Saturating Addition and Subtraction
258;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
259
260(define_expand "<code_stdname><mode>3"
261  [(set (match_operand:ALL8S 0 "general_operand" "")
262        (ss_addsub:ALL8S (match_operand:ALL8S 1 "general_operand" "")
263                         (match_operand:ALL8S 2 "general_operand" "")))]
264  "avr_have_dimode"
265  {
266    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
267
268    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
269    emit_move_insn (acc_a, operands[1]);
270
271    if (const_operand (operands[2], GET_MODE (operands[2])))
272      {
273        emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2]));
274      }
275    else
276      {
277        emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
278        emit_insn (gen_<code_stdname><mode>3_insn ());
279      }
280
281    emit_move_insn (operands[0], acc_a);
282    DONE;
283  })
284
285(define_insn_and_split "<code_stdname><mode>3_insn"
286  [(set (reg:ALL8S ACC_A)
287        (ss_addsub:ALL8S (reg:ALL8S ACC_A)
288                         (reg:ALL8S ACC_B)))]
289  "avr_have_dimode"
290  "#"
291  "&& reload_completed"
292  [(parallel [(set (reg:ALL8S ACC_A)
293                   (ss_addsub:ALL8S (reg:ALL8S ACC_A)
294                                    (reg:ALL8S ACC_B)))
295             (clobber (reg:CC REG_CC))])])
296
297(define_insn "*<code_stdname><mode>3_insn"
298  [(set (reg:ALL8S ACC_A)
299        (ss_addsub:ALL8S (reg:ALL8S ACC_A)
300                         (reg:ALL8S ACC_B)))
301   (clobber (reg:CC REG_CC))]
302  "avr_have_dimode && reload_completed"
303  "%~call __<code_stdname><mode>3"
304  [(set_attr "adjust_len" "call")])
305
306(define_insn_and_split "<code_stdname><mode>3_const_insn"
307  [(set (reg:ALL8S ACC_A)
308        (ss_addsub:ALL8S (reg:ALL8S ACC_A)
309                         (match_operand:ALL8S 0 "const_operand" "n Ynn")))]
310  "avr_have_dimode"
311  "#"
312  "&& reload_completed"
313  [(parallel [(set (reg:ALL8S ACC_A)
314                   (ss_addsub:ALL8S (reg:ALL8S ACC_A)
315                                    (match_dup 0)))
316              (clobber (reg:CC REG_CC))])])
317
318(define_insn "*<code_stdname><mode>3_const_insn"
319  [(set (reg:ALL8S ACC_A)
320        (ss_addsub:ALL8S (reg:ALL8S ACC_A)
321                         (match_operand:ALL8S 0 "const_operand" "n Ynn")))
322   (clobber (reg:CC REG_CC))]
323  "avr_have_dimode && reload_completed"
324  {
325    return avr_out_plus (insn, operands);
326  }
327  [(set_attr "adjust_len" "plus")])
328
329;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
330;; Unsigned Saturating Addition and Subtraction
331;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
332
333(define_expand "<code_stdname><mode>3"
334  [(set (match_operand:ALL8U 0 "general_operand" "")
335        (us_addsub:ALL8U (match_operand:ALL8U 1 "general_operand" "")
336                         (match_operand:ALL8U 2 "general_operand" "")))]
337  "avr_have_dimode"
338  {
339    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
340
341    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
342    emit_move_insn (acc_a, operands[1]);
343
344    if (const_operand (operands[2], GET_MODE (operands[2])))
345      {
346        emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2]));
347      }
348    else
349      {
350        emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
351        emit_insn (gen_<code_stdname><mode>3_insn ());
352      }
353
354    emit_move_insn (operands[0], acc_a);
355    DONE;
356  })
357
358(define_insn_and_split "<code_stdname><mode>3_insn"
359  [(set (reg:ALL8U ACC_A)
360        (us_addsub:ALL8U (reg:ALL8U ACC_A)
361                         (reg:ALL8U ACC_B)))]
362  "avr_have_dimode"
363  "#"
364  "&& reload_completed"
365  [(parallel [(set (reg:ALL8U ACC_A)
366                   (us_addsub:ALL8U (reg:ALL8U ACC_A)
367                                    (reg:ALL8U ACC_B)))
368              (clobber (reg:CC REG_CC))])])
369
370(define_insn "*<code_stdname><mode>3_insn"
371  [(set (reg:ALL8U ACC_A)
372        (us_addsub:ALL8U (reg:ALL8U ACC_A)
373                         (reg:ALL8U ACC_B)))
374   (clobber (reg:CC REG_CC))]
375  "avr_have_dimode && reload_completed"
376  "%~call __<code_stdname><mode>3"
377  [(set_attr "adjust_len" "call")])
378
379(define_insn_and_split "<code_stdname><mode>3_const_insn"
380  [(set (reg:ALL8U ACC_A)
381        (us_addsub:ALL8U (reg:ALL8U ACC_A)
382                         (match_operand:ALL8U 0 "const_operand" "n Ynn")))]
383  "avr_have_dimode"
384  "#"
385  "&& reload_completed"
386  [(parallel [(set (reg:ALL8U ACC_A)
387                   (us_addsub:ALL8U (reg:ALL8U ACC_A)
388                                    (match_operand:ALL8U 0 "const_operand" "n Ynn")))
389              (clobber (reg:CC REG_CC))])])
390
391(define_insn "*<code_stdname><mode>3_const_insn"
392  [(set (reg:ALL8U ACC_A)
393        (us_addsub:ALL8U (reg:ALL8U ACC_A)
394                         (match_operand:ALL8U 0 "const_operand" "n Ynn")))
395   (clobber (reg:CC REG_CC))]
396  "avr_have_dimode && reload_completed"
397  {
398    return avr_out_plus (insn, operands);
399  }
400  [(set_attr "adjust_len" "plus")])
401
402;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
403;; Negation
404;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
405
406(define_expand "negdi2"
407  [(parallel [(match_operand:DI 0 "general_operand" "")
408              (match_operand:DI 1 "general_operand" "")])]
409  "avr_have_dimode"
410  {
411    rtx acc_a = gen_rtx_REG (DImode, ACC_A);
412
413    emit_move_insn (acc_a, operands[1]);
414    emit_insn (gen_negdi2_insn ());
415    emit_move_insn (operands[0], acc_a);
416    DONE;
417  })
418
419(define_insn_and_split "negdi2_insn"
420  [(set (reg:DI ACC_A)
421        (neg:DI (reg:DI ACC_A)))]
422  "avr_have_dimode"
423  "#"
424  "&& reload_completed"
425  [(parallel [(set (reg:DI ACC_A)
426                   (neg:DI (reg:DI ACC_A)))
427              (clobber (reg:CC REG_CC))])])
428
429(define_insn "*negdi2_insn"
430  [(set (reg:DI ACC_A)
431        (neg:DI (reg:DI ACC_A)))
432   (clobber (reg:CC REG_CC))]
433  "avr_have_dimode && reload_completed"
434  "%~call __negdi2"
435  [(set_attr "adjust_len" "call")])
436
437
438;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439;; Comparison
440;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
441
442(define_expand "conditional_jump"
443  [(set (pc)
444        (if_then_else
445         (match_operator 0 "ordered_comparison_operator" [(reg:CC REG_CC)
446                                                          (const_int 0)])
447         (label_ref (match_operand 1 "" ""))
448         (pc)))]
449  "avr_have_dimode")
450
451;; "cbranchdi4"
452;; "cbranchdq4" "cbranchudq4"
453;; "cbranchda4" "cbranchuda4"
454;; "cbranchta4" "cbranchuta4"
455(define_expand "cbranch<mode>4"
456  [(set (pc)
457        (if_then_else (match_operator 0 "ordered_comparison_operator"
458                        [(match_operand:ALL8 1 "register_operand")
459                         (match_operand:ALL8 2 "nonmemory_operand")])
460                      (label_ref (match_operand 3))
461                      (pc)))]
462  "avr_have_dimode"
463   {
464    int icode = (int) GET_CODE (operands[0]);
465
466    targetm.canonicalize_comparison (&icode, &operands[1], &operands[2], false);
467    operands[0] = gen_rtx_fmt_ee ((enum rtx_code) icode,
468                                  VOIDmode, operands[1], operands[2]);
469
470    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
471
472    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
473    emit_move_insn (acc_a, operands[1]);
474
475    if (s8_operand (operands[2], VOIDmode))
476      {
477        emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
478        emit_jump_insn (gen_cbranch_const8_di2_split (operands[0], operands[3]));
479      }
480    else if (const_operand (operands[2], GET_MODE (operands[2])))
481      {
482        emit_jump_insn (gen_cbranch_const_<mode>2_split (operands[0],
483                                                         operands[2],
484                                                         operands[3]));
485      }
486    else
487      {
488        emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
489        emit_jump_insn (gen_cbranch_<mode>2_split (operands[0], operands[3]));
490      }
491    DONE;
492   })
493
494(define_insn_and_split "cbranch_<mode>2_split"
495  [(set (pc)
496        (if_then_else (match_operator 0 "ordered_comparison_operator"
497                        [(reg:ALL8 ACC_A)
498                         (reg:ALL8 ACC_B)])
499                      (label_ref (match_operand 1))
500                      (pc)))]
501  "avr_have_dimode"
502  "#"
503  "&& reload_completed"
504  [(const_int 0)]
505  {
506    emit_insn (gen_compare_<mode>2 ());
507    emit_jump_insn (gen_conditional_jump (operands[0], operands[1]));
508    DONE;
509  })
510
511;; "compare_di2"
512;; "compare_dq2" "compare_udq2"
513;; "compare_da2" "compare_uda2"
514;; "compare_ta2" "compare_uta2"
515(define_insn "compare_<mode>2"
516  [(set (reg:CC REG_CC)
517        (compare:CC (reg:ALL8 ACC_A)
518                    (reg:ALL8 ACC_B)))]
519  "reload_completed && avr_have_dimode"
520  "%~call __cmpdi2"
521  [(set_attr "adjust_len" "call")])
522
523(define_insn_and_split "cbranch_const8_di2_split"
524  [(set (pc)
525        (if_then_else (match_operator 0 "ordered_comparison_operator"
526                        [(reg:DI ACC_A)
527                         (sign_extend:DI (reg:QI REG_X))])
528         (label_ref (match_operand 1 "" ""))
529         (pc)))]
530  "avr_have_dimode"
531  "#"
532  "&& reload_completed"
533  [(const_int 0)]
534  {
535    emit_insn (gen_compare_const8_di2 ());
536    emit_jump_insn (gen_conditional_jump (operands[0], operands[1]));
537    DONE;
538  })
539
540(define_insn "compare_const8_di2"
541  [(set (reg:CC REG_CC)
542        (compare:CC (reg:DI ACC_A)
543                    (sign_extend:DI (reg:QI REG_X))))]
544  "reload_completed && avr_have_dimode"
545  "%~call __cmpdi2_s8"
546  [(set_attr "adjust_len" "call")])
547
548(define_insn_and_split "cbranch_const_<mode>2_split"
549  [(set (pc)
550        (if_then_else (match_operator 0 "ordered_comparison_operator"
551                        [(reg:ALL8 ACC_A)
552                         (match_operand:ALL8 1 "const_operand" "n Ynn")])
553                      (label_ref (match_operand 2 "" ""))
554                      (pc)))
555   (clobber (match_scratch:QI 3 "=&d"))]
556  "avr_have_dimode
557   && !s8_operand (operands[1], VOIDmode)"
558  "#"
559  "&& reload_completed"
560  [(const_int 0)]
561  {
562    emit_insn (gen_compare_const_<mode>2 (operands[1], operands[3]));
563    emit_jump_insn (gen_conditional_jump (operands[0], operands[2]));
564    DONE;
565  })
566
567
568;; "compare_const_di2"
569;; "compare_const_dq2" "compare_const_udq2"
570;; "compare_const_da2" "compare_const_uda2"
571;; "compare_const_ta2" "compare_const_uta2"
572(define_insn "compare_const_<mode>2"
573  [(set (reg:CC REG_CC)
574        (compare:CC (reg:ALL8 ACC_A)
575                    (match_operand:ALL8 0 "const_operand" "n Ynn")))
576   (clobber (match_operand:QI 1 "register_operand" "=&d"))]
577  "reload_completed
578   && avr_have_dimode
579   && !s8_operand (operands[0], VOIDmode)"
580  {
581    return avr_out_compare64 (insn, operands, NULL);
582  }
583  [(set_attr "adjust_len" "compare64")])
584
585
586;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
587;; Shifts and Rotate
588;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
589
590(define_code_iterator di_shifts
591  [ashift ashiftrt lshiftrt rotate])
592
593;; Shift functions from libgcc are called without defining these insns,
594;; but with them we can describe their reduced register footprint.
595
596;; "ashldi3"   "ashrdi3"   "lshrdi3"   "rotldi3"
597;; "ashldq3"   "ashrdq3"   "lshrdq3"   "rotldq3"
598;; "ashlda3"   "ashrda3"   "lshrda3"   "rotlda3"
599;; "ashlta3"   "ashrta3"   "lshrta3"   "rotlta3"
600;; "ashludq3"  "ashrudq3"  "lshrudq3"  "rotludq3"
601;; "ashluda3"  "ashruda3"  "lshruda3"  "rotluda3"
602;; "ashluta3"  "ashruta3"  "lshruta3"  "rotluta3"
603(define_expand "<code_stdname><mode>3"
604  [(parallel [(match_operand:ALL8 0 "general_operand" "")
605              (di_shifts:ALL8 (match_operand:ALL8 1 "general_operand" "")
606                              (match_operand:QI 2 "general_operand" ""))])]
607  "avr_have_dimode"
608  {
609    rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
610
611    avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
612    emit_move_insn (acc_a, operands[1]);
613    emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]);
614    emit_insn (gen_<code_stdname><mode>3_insn ());
615    emit_move_insn (operands[0], acc_a);
616    DONE;
617  })
618
619;; "ashldi3_insn"   "ashrdi3_insn"   "lshrdi3_insn"   "rotldi3_insn"
620;; "ashldq3_insn"   "ashrdq3_insn"   "lshrdq3_insn"   "rotldq3_insn"
621;; "ashlda3_insn"   "ashrda3_insn"   "lshrda3_insn"   "rotlda3_insn"
622;; "ashlta3_insn"   "ashrta3_insn"   "lshrta3_insn"   "rotlta3_insn"
623;; "ashludq3_insn"  "ashrudq3_insn"  "lshrudq3_insn"  "rotludq3_insn"
624;; "ashluda3_insn"  "ashruda3_insn"  "lshruda3_insn"  "rotluda3_insn"
625;; "ashluta3_insn"  "ashruta3_insn"  "lshruta3_insn"  "rotluta3_insn"
626(define_insn_and_split "<code_stdname><mode>3_insn"
627  [(set (reg:ALL8 ACC_A)
628        (di_shifts:ALL8 (reg:ALL8 ACC_A)
629                        (reg:QI 16)))]
630  "avr_have_dimode"
631  "#"
632  "&& reload_completed"
633  [(parallel [(set (reg:ALL8 ACC_A)
634                   (di_shifts:ALL8 (reg:ALL8 ACC_A)
635                                   (reg:QI 16)))
636              (clobber (reg:CC REG_CC))])])
637
638(define_insn "*<code_stdname><mode>3_insn"
639  [(set (reg:ALL8 ACC_A)
640        (di_shifts:ALL8 (reg:ALL8 ACC_A)
641                        (reg:QI 16)))
642   (clobber (reg:CC REG_CC))]
643  "avr_have_dimode && reload_completed"
644  "%~call __<code_stdname>di3"
645  [(set_attr "adjust_len" "call")])
646
647;; "umulsidi3"
648;; "mulsidi3"
649(define_expand "<extend_u>mulsidi3"
650  [(parallel [(match_operand:DI 0 "register_operand" "")
651              (match_operand:SI 1 "general_operand" "")
652              (match_operand:SI 2 "general_operand" "")
653              ;; Just to mention the iterator
654              (clobber (any_extend:SI (match_dup 1)))])]
655  "avr_have_dimode
656   && AVR_HAVE_MUL"
657  {
658    avr_fix_inputs (operands, 1 << 2, regmask (SImode, 22));
659    emit_move_insn (gen_rtx_REG (SImode, 22), operands[1]);
660    emit_move_insn (gen_rtx_REG (SImode, 18), operands[2]);
661    emit_insn (gen_<extend_u>mulsidi3_insn());
662    // Use emit_move_insn and not open-coded expand because of missing movdi
663    emit_move_insn (operands[0], gen_rtx_REG (DImode, ACC_A));
664    DONE;
665  })
666
667;; "umulsidi3_insn"
668;; "mulsidi3_insn"
669
670(define_insn_and_split "<extend_u>mulsidi3_insn"
671  [(set (reg:DI ACC_A)
672        (mult:DI (any_extend:DI (reg:SI 18))
673                 (any_extend:DI (reg:SI 22))))
674   (clobber (reg:HI REG_X))
675   (clobber (reg:HI REG_Z))]
676  "avr_have_dimode
677   && AVR_HAVE_MUL"
678   "#"
679   "&& reload_completed"
680   [(parallel [(set (reg:DI ACC_A)
681                    (mult:DI (any_extend:DI (reg:SI 18))
682                             (any_extend:DI (reg:SI 22))))
683               (clobber (reg:HI REG_X))
684               (clobber (reg:HI REG_Z))
685               (clobber (reg:CC REG_CC))])])
686
687(define_insn "*<extend_u>mulsidi3_insn"
688  [(set (reg:DI ACC_A)
689        (mult:DI (any_extend:DI (reg:SI 18))
690                 (any_extend:DI (reg:SI 22))))
691   (clobber (reg:HI REG_X))
692   (clobber (reg:HI REG_Z))
693   (clobber (reg:CC REG_CC))]
694  "avr_have_dimode
695   && AVR_HAVE_MUL
696   && reload_completed"
697  "%~call __<extend_u>mulsidi3"
698  [(set_attr "adjust_len" "call")])
699