]>
Commit | Line | Data |
---|---|---|
8c57e547 GJL |
1 | ;; Machine description for GNU compiler, |
2 | ;; for Atmel AVR micro controllers. | |
99dee823 | 3 | ;; Copyright (C) 1998-2021 Free Software Foundation, Inc. |
8c57e547 GJL |
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. | |
00892272 | 34 | ;; |
8c57e547 GJL |
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 | ||
e55e4056 | 49 | ;; Supported modes that are 8 bytes wide |
51526856 GJL |
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]) | |
e55e4056 | 54 | |
8c57e547 GJL |
55 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
56 | ;; Addition | |
57 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
58 | ||
e55e4056 GJL |
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" "")])] | |
8c57e547 GJL |
67 | "avr_have_dimode" |
68 | { | |
e55e4056 | 69 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 70 | |
00e641f1 | 71 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 GJL |
72 | emit_move_insn (acc_a, operands[1]); |
73 | ||
e55e4056 GJL |
74 | if (DImode == <MODE>mode |
75 | && s8_operand (operands[2], VOIDmode)) | |
8c57e547 GJL |
76 | { |
77 | emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); | |
78 | emit_insn (gen_adddi3_const8_insn ()); | |
00892272 | 79 | } |
e55e4056 | 80 | else if (const_operand (operands[2], GET_MODE (operands[2]))) |
8c57e547 | 81 | { |
e55e4056 | 82 | emit_insn (gen_add<mode>3_const_insn (operands[2])); |
8c57e547 GJL |
83 | } |
84 | else | |
85 | { | |
e55e4056 GJL |
86 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); |
87 | emit_insn (gen_add<mode>3_insn ()); | |
8c57e547 GJL |
88 | } |
89 | ||
90 | emit_move_insn (operands[0], acc_a); | |
91 | DONE; | |
92 | }) | |
93 | ||
e55e4056 GJL |
94 | ;; "adddi3_insn" |
95 | ;; "adddq3_insn" "addudq3_insn" | |
96 | ;; "addda3_insn" "adduda3_insn" | |
97 | ;; "addta3_insn" "adduta3_insn" | |
98 | (define_insn "add<mode>3_insn" | |
99 | [(set (reg:ALL8 ACC_A) | |
100 | (plus:ALL8 (reg:ALL8 ACC_A) | |
101 | (reg:ALL8 ACC_B)))] | |
8c57e547 GJL |
102 | "avr_have_dimode" |
103 | "%~call __adddi3" | |
104 | [(set_attr "adjust_len" "call") | |
105 | (set_attr "cc" "clobber")]) | |
106 | ||
107 | (define_insn "adddi3_const8_insn" | |
108 | [(set (reg:DI ACC_A) | |
109 | (plus:DI (reg:DI ACC_A) | |
110 | (sign_extend:DI (reg:QI REG_X))))] | |
111 | "avr_have_dimode" | |
112 | "%~call __adddi3_s8" | |
113 | [(set_attr "adjust_len" "call") | |
114 | (set_attr "cc" "clobber")]) | |
115 | ||
e55e4056 GJL |
116 | ;; "adddi3_const_insn" |
117 | ;; "adddq3_const_insn" "addudq3_const_insn" | |
118 | ;; "addda3_const_insn" "adduda3_const_insn" | |
119 | ;; "addta3_const_insn" "adduta3_const_insn" | |
120 | (define_insn "add<mode>3_const_insn" | |
121 | [(set (reg:ALL8 ACC_A) | |
122 | (plus:ALL8 (reg:ALL8 ACC_A) | |
123 | (match_operand:ALL8 0 "const_operand" "n Ynn")))] | |
8c57e547 GJL |
124 | "avr_have_dimode |
125 | && !s8_operand (operands[0], VOIDmode)" | |
126 | { | |
51526856 | 127 | return avr_out_plus (insn, operands); |
8c57e547 | 128 | } |
51526856 | 129 | [(set_attr "adjust_len" "plus") |
8c57e547 GJL |
130 | (set_attr "cc" "clobber")]) |
131 | ||
132 | ||
133 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
134 | ;; Subtraction | |
135 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
136 | ||
e55e4056 GJL |
137 | ;; "subdi3" |
138 | ;; "subdq3" "subudq3" | |
139 | ;; "subda3" "subuda3" | |
140 | ;; "subta3" "subuta3" | |
141 | (define_expand "sub<mode>3" | |
142 | [(parallel [(match_operand:ALL8 0 "general_operand" "") | |
143 | (match_operand:ALL8 1 "general_operand" "") | |
144 | (match_operand:ALL8 2 "general_operand" "")])] | |
8c57e547 GJL |
145 | "avr_have_dimode" |
146 | { | |
e55e4056 | 147 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 148 | |
00e641f1 | 149 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 | 150 | emit_move_insn (acc_a, operands[1]); |
e55e4056 GJL |
151 | |
152 | if (const_operand (operands[2], GET_MODE (operands[2]))) | |
153 | { | |
154 | emit_insn (gen_sub<mode>3_const_insn (operands[2])); | |
155 | } | |
156 | else | |
157 | { | |
158 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); | |
159 | emit_insn (gen_sub<mode>3_insn ()); | |
160 | } | |
161 | ||
8c57e547 GJL |
162 | emit_move_insn (operands[0], acc_a); |
163 | DONE; | |
164 | }) | |
165 | ||
e55e4056 GJL |
166 | ;; "subdi3_insn" |
167 | ;; "subdq3_insn" "subudq3_insn" | |
168 | ;; "subda3_insn" "subuda3_insn" | |
169 | ;; "subta3_insn" "subuta3_insn" | |
170 | (define_insn "sub<mode>3_insn" | |
171 | [(set (reg:ALL8 ACC_A) | |
172 | (minus:ALL8 (reg:ALL8 ACC_A) | |
173 | (reg:ALL8 ACC_B)))] | |
8c57e547 GJL |
174 | "avr_have_dimode" |
175 | "%~call __subdi3" | |
176 | [(set_attr "adjust_len" "call") | |
177 | (set_attr "cc" "set_czn")]) | |
178 | ||
e55e4056 GJL |
179 | ;; "subdi3_const_insn" |
180 | ;; "subdq3_const_insn" "subudq3_const_insn" | |
181 | ;; "subda3_const_insn" "subuda3_const_insn" | |
182 | ;; "subta3_const_insn" "subuta3_const_insn" | |
183 | (define_insn "sub<mode>3_const_insn" | |
184 | [(set (reg:ALL8 ACC_A) | |
185 | (minus:ALL8 (reg:ALL8 ACC_A) | |
186 | (match_operand:ALL8 0 "const_operand" "n Ynn")))] | |
187 | "avr_have_dimode" | |
188 | { | |
51526856 GJL |
189 | return avr_out_plus (insn, operands); |
190 | } | |
191 | [(set_attr "adjust_len" "plus") | |
192 | (set_attr "cc" "clobber")]) | |
193 | ||
194 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
195 | ;; Signed Saturating Addition and Subtraction | |
196 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
197 | ||
198 | (define_expand "<code_stdname><mode>3" | |
199 | [(set (match_operand:ALL8S 0 "general_operand" "") | |
200 | (ss_addsub:ALL8S (match_operand:ALL8S 1 "general_operand" "") | |
201 | (match_operand:ALL8S 2 "general_operand" "")))] | |
202 | "avr_have_dimode" | |
203 | { | |
204 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); | |
205 | ||
00e641f1 | 206 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
51526856 GJL |
207 | emit_move_insn (acc_a, operands[1]); |
208 | ||
209 | if (const_operand (operands[2], GET_MODE (operands[2]))) | |
210 | { | |
211 | emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2])); | |
212 | } | |
213 | else | |
214 | { | |
215 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); | |
216 | emit_insn (gen_<code_stdname><mode>3_insn ()); | |
217 | } | |
218 | ||
219 | emit_move_insn (operands[0], acc_a); | |
220 | DONE; | |
221 | }) | |
222 | ||
223 | (define_insn "<code_stdname><mode>3_insn" | |
224 | [(set (reg:ALL8S ACC_A) | |
225 | (ss_addsub:ALL8S (reg:ALL8S ACC_A) | |
226 | (reg:ALL8S ACC_B)))] | |
227 | "avr_have_dimode" | |
228 | "%~call __<code_stdname><mode>3" | |
229 | [(set_attr "adjust_len" "call") | |
230 | (set_attr "cc" "clobber")]) | |
231 | ||
232 | (define_insn "<code_stdname><mode>3_const_insn" | |
233 | [(set (reg:ALL8S ACC_A) | |
234 | (ss_addsub:ALL8S (reg:ALL8S ACC_A) | |
235 | (match_operand:ALL8S 0 "const_operand" "n Ynn")))] | |
236 | "avr_have_dimode" | |
237 | { | |
238 | return avr_out_plus (insn, operands); | |
e55e4056 | 239 | } |
51526856 GJL |
240 | [(set_attr "adjust_len" "plus") |
241 | (set_attr "cc" "clobber")]) | |
242 | ||
243 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
244 | ;; Unsigned Saturating Addition and Subtraction | |
245 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
246 | ||
247 | (define_expand "<code_stdname><mode>3" | |
248 | [(set (match_operand:ALL8U 0 "general_operand" "") | |
249 | (us_addsub:ALL8U (match_operand:ALL8U 1 "general_operand" "") | |
250 | (match_operand:ALL8U 2 "general_operand" "")))] | |
251 | "avr_have_dimode" | |
252 | { | |
253 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); | |
254 | ||
00e641f1 | 255 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
51526856 GJL |
256 | emit_move_insn (acc_a, operands[1]); |
257 | ||
258 | if (const_operand (operands[2], GET_MODE (operands[2]))) | |
259 | { | |
260 | emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2])); | |
261 | } | |
262 | else | |
263 | { | |
264 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); | |
265 | emit_insn (gen_<code_stdname><mode>3_insn ()); | |
266 | } | |
267 | ||
268 | emit_move_insn (operands[0], acc_a); | |
269 | DONE; | |
270 | }) | |
271 | ||
272 | (define_insn "<code_stdname><mode>3_insn" | |
273 | [(set (reg:ALL8U ACC_A) | |
274 | (us_addsub:ALL8U (reg:ALL8U ACC_A) | |
275 | (reg:ALL8U ACC_B)))] | |
276 | "avr_have_dimode" | |
277 | "%~call __<code_stdname><mode>3" | |
278 | [(set_attr "adjust_len" "call") | |
e55e4056 GJL |
279 | (set_attr "cc" "clobber")]) |
280 | ||
51526856 GJL |
281 | (define_insn "<code_stdname><mode>3_const_insn" |
282 | [(set (reg:ALL8U ACC_A) | |
283 | (us_addsub:ALL8U (reg:ALL8U ACC_A) | |
284 | (match_operand:ALL8U 0 "const_operand" "n Ynn")))] | |
285 | "avr_have_dimode" | |
286 | { | |
287 | return avr_out_plus (insn, operands); | |
288 | } | |
289 | [(set_attr "adjust_len" "plus") | |
290 | (set_attr "cc" "clobber")]) | |
8c57e547 GJL |
291 | |
292 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
293 | ;; Negation | |
294 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
295 | ||
296 | (define_expand "negdi2" | |
297 | [(parallel [(match_operand:DI 0 "general_operand" "") | |
298 | (match_operand:DI 1 "general_operand" "")])] | |
299 | "avr_have_dimode" | |
300 | { | |
301 | rtx acc_a = gen_rtx_REG (DImode, ACC_A); | |
302 | ||
303 | emit_move_insn (acc_a, operands[1]); | |
304 | emit_insn (gen_negdi2_insn ()); | |
305 | emit_move_insn (operands[0], acc_a); | |
306 | DONE; | |
307 | }) | |
308 | ||
309 | (define_insn "negdi2_insn" | |
310 | [(set (reg:DI ACC_A) | |
311 | (neg:DI (reg:DI ACC_A)))] | |
312 | "avr_have_dimode" | |
313 | "%~call __negdi2" | |
314 | [(set_attr "adjust_len" "call") | |
315 | (set_attr "cc" "clobber")]) | |
316 | ||
317 | ||
318 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
319 | ;; Comparison | |
320 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
321 | ||
322 | (define_expand "conditional_jump" | |
323 | [(set (pc) | |
324 | (if_then_else | |
325 | (match_operator 0 "ordered_comparison_operator" [(cc0) | |
326 | (const_int 0)]) | |
327 | (label_ref (match_operand 1 "" "")) | |
328 | (pc)))] | |
329 | "avr_have_dimode") | |
330 | ||
e55e4056 GJL |
331 | ;; "cbranchdi4" |
332 | ;; "cbranchdq4" "cbranchudq4" | |
333 | ;; "cbranchda4" "cbranchuda4" | |
334 | ;; "cbranchta4" "cbranchuta4" | |
335 | (define_expand "cbranch<mode>4" | |
336 | [(parallel [(match_operand:ALL8 1 "register_operand" "") | |
337 | (match_operand:ALL8 2 "nonmemory_operand" "") | |
8c57e547 GJL |
338 | (match_operator 0 "ordered_comparison_operator" [(cc0) |
339 | (const_int 0)]) | |
340 | (label_ref (match_operand 3 "" ""))])] | |
341 | "avr_have_dimode" | |
342 | { | |
e55e4056 | 343 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 344 | |
00e641f1 | 345 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 GJL |
346 | emit_move_insn (acc_a, operands[1]); |
347 | ||
348 | if (s8_operand (operands[2], VOIDmode)) | |
349 | { | |
350 | emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); | |
351 | emit_insn (gen_compare_const8_di2 ()); | |
00892272 | 352 | } |
e55e4056 | 353 | else if (const_operand (operands[2], GET_MODE (operands[2]))) |
8c57e547 | 354 | { |
e55e4056 | 355 | emit_insn (gen_compare_const_<mode>2 (operands[2])); |
8c57e547 GJL |
356 | } |
357 | else | |
358 | { | |
e55e4056 GJL |
359 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); |
360 | emit_insn (gen_compare_<mode>2 ()); | |
8c57e547 GJL |
361 | } |
362 | ||
363 | emit_jump_insn (gen_conditional_jump (operands[0], operands[3])); | |
364 | DONE; | |
365 | }) | |
366 | ||
e55e4056 GJL |
367 | ;; "compare_di2" |
368 | ;; "compare_dq2" "compare_udq2" | |
369 | ;; "compare_da2" "compare_uda2" | |
370 | ;; "compare_ta2" "compare_uta2" | |
371 | (define_insn "compare_<mode>2" | |
8c57e547 | 372 | [(set (cc0) |
e55e4056 GJL |
373 | (compare (reg:ALL8 ACC_A) |
374 | (reg:ALL8 ACC_B)))] | |
8c57e547 GJL |
375 | "avr_have_dimode" |
376 | "%~call __cmpdi2" | |
377 | [(set_attr "adjust_len" "call") | |
378 | (set_attr "cc" "compare")]) | |
379 | ||
380 | (define_insn "compare_const8_di2" | |
381 | [(set (cc0) | |
382 | (compare (reg:DI ACC_A) | |
383 | (sign_extend:DI (reg:QI REG_X))))] | |
384 | "avr_have_dimode" | |
385 | "%~call __cmpdi2_s8" | |
386 | [(set_attr "adjust_len" "call") | |
387 | (set_attr "cc" "compare")]) | |
388 | ||
e55e4056 GJL |
389 | ;; "compare_const_di2" |
390 | ;; "compare_const_dq2" "compare_const_udq2" | |
391 | ;; "compare_const_da2" "compare_const_uda2" | |
392 | ;; "compare_const_ta2" "compare_const_uta2" | |
393 | (define_insn "compare_const_<mode>2" | |
8c57e547 | 394 | [(set (cc0) |
e55e4056 GJL |
395 | (compare (reg:ALL8 ACC_A) |
396 | (match_operand:ALL8 0 "const_operand" "n Ynn"))) | |
8c57e547 GJL |
397 | (clobber (match_scratch:QI 1 "=&d"))] |
398 | "avr_have_dimode | |
399 | && !s8_operand (operands[0], VOIDmode)" | |
400 | { | |
401 | return avr_out_compare64 (insn, operands, NULL); | |
402 | } | |
403 | [(set_attr "adjust_len" "compare64") | |
404 | (set_attr "cc" "compare")]) | |
405 | ||
406 | ||
407 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
408 | ;; Shifts and Rotate | |
409 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
410 | ||
411 | (define_code_iterator di_shifts | |
412 | [ashift ashiftrt lshiftrt rotate]) | |
413 | ||
414 | ;; Shift functions from libgcc are called without defining these insns, | |
415 | ;; but with them we can describe their reduced register footprint. | |
416 | ||
e55e4056 GJL |
417 | ;; "ashldi3" "ashrdi3" "lshrdi3" "rotldi3" |
418 | ;; "ashldq3" "ashrdq3" "lshrdq3" "rotldq3" | |
419 | ;; "ashlda3" "ashrda3" "lshrda3" "rotlda3" | |
420 | ;; "ashlta3" "ashrta3" "lshrta3" "rotlta3" | |
421 | ;; "ashludq3" "ashrudq3" "lshrudq3" "rotludq3" | |
422 | ;; "ashluda3" "ashruda3" "lshruda3" "rotluda3" | |
423 | ;; "ashluta3" "ashruta3" "lshruta3" "rotluta3" | |
424 | (define_expand "<code_stdname><mode>3" | |
425 | [(parallel [(match_operand:ALL8 0 "general_operand" "") | |
426 | (di_shifts:ALL8 (match_operand:ALL8 1 "general_operand" "") | |
427 | (match_operand:QI 2 "general_operand" ""))])] | |
8c57e547 GJL |
428 | "avr_have_dimode" |
429 | { | |
e55e4056 | 430 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 431 | |
00e641f1 | 432 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 GJL |
433 | emit_move_insn (acc_a, operands[1]); |
434 | emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]); | |
e55e4056 | 435 | emit_insn (gen_<code_stdname><mode>3_insn ()); |
8c57e547 GJL |
436 | emit_move_insn (operands[0], acc_a); |
437 | DONE; | |
438 | }) | |
439 | ||
e55e4056 GJL |
440 | ;; "ashldi3_insn" "ashrdi3_insn" "lshrdi3_insn" "rotldi3_insn" |
441 | ;; "ashldq3_insn" "ashrdq3_insn" "lshrdq3_insn" "rotldq3_insn" | |
442 | ;; "ashlda3_insn" "ashrda3_insn" "lshrda3_insn" "rotlda3_insn" | |
443 | ;; "ashlta3_insn" "ashrta3_insn" "lshrta3_insn" "rotlta3_insn" | |
444 | ;; "ashludq3_insn" "ashrudq3_insn" "lshrudq3_insn" "rotludq3_insn" | |
445 | ;; "ashluda3_insn" "ashruda3_insn" "lshruda3_insn" "rotluda3_insn" | |
446 | ;; "ashluta3_insn" "ashruta3_insn" "lshruta3_insn" "rotluta3_insn" | |
447 | (define_insn "<code_stdname><mode>3_insn" | |
448 | [(set (reg:ALL8 ACC_A) | |
449 | (di_shifts:ALL8 (reg:ALL8 ACC_A) | |
450 | (reg:QI 16)))] | |
8c57e547 GJL |
451 | "avr_have_dimode" |
452 | "%~call __<code_stdname>di3" | |
453 | [(set_attr "adjust_len" "call") | |
454 | (set_attr "cc" "clobber")]) | |
e68a4ef6 GJL |
455 | |
456 | ;; "umulsidi3" | |
457 | ;; "mulsidi3" | |
458 | (define_expand "<extend_u>mulsidi3" | |
459 | [(parallel [(match_operand:DI 0 "register_operand" "") | |
460 | (match_operand:SI 1 "general_operand" "") | |
461 | (match_operand:SI 2 "general_operand" "") | |
462 | ;; Just to mention the iterator | |
463 | (clobber (any_extend:SI (match_dup 1)))])] | |
1f82f124 GJL |
464 | "avr_have_dimode |
465 | && AVR_HAVE_MUL" | |
e68a4ef6 | 466 | { |
00e641f1 | 467 | avr_fix_inputs (operands, 1 << 2, regmask (SImode, 22)); |
e68a4ef6 GJL |
468 | emit_move_insn (gen_rtx_REG (SImode, 22), operands[1]); |
469 | emit_move_insn (gen_rtx_REG (SImode, 18), operands[2]); | |
470 | emit_insn (gen_<extend_u>mulsidi3_insn()); | |
471 | // Use emit_move_insn and not open-coded expand because of missing movdi | |
472 | emit_move_insn (operands[0], gen_rtx_REG (DImode, ACC_A)); | |
473 | DONE; | |
474 | }) | |
475 | ||
476 | ;; "umulsidi3_insn" | |
477 | ;; "mulsidi3_insn" | |
478 | (define_insn "<extend_u>mulsidi3_insn" | |
479 | [(set (reg:DI ACC_A) | |
480 | (mult:DI (any_extend:DI (reg:SI 18)) | |
481 | (any_extend:DI (reg:SI 22)))) | |
482 | (clobber (reg:HI REG_X)) | |
483 | (clobber (reg:HI REG_Z))] | |
1f82f124 GJL |
484 | "avr_have_dimode |
485 | && AVR_HAVE_MUL" | |
e68a4ef6 GJL |
486 | "%~call __<extend_u>mulsidi3" |
487 | [(set_attr "adjust_len" "call") | |
488 | (set_attr "cc" "clobber")]) |