]>
Commit | Line | Data |
---|---|---|
8c57e547 GJL |
1 | ;; Machine description for GNU compiler, |
2 | ;; for Atmel AVR micro controllers. | |
aeee4812 | 3 | ;; Copyright (C) 1998-2023 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" | |
3ba781d3 | 98 | (define_insn_and_split "add<mode>3_insn" |
e55e4056 GJL |
99 | [(set (reg:ALL8 ACC_A) |
100 | (plus:ALL8 (reg:ALL8 ACC_A) | |
101 | (reg:ALL8 ACC_B)))] | |
8c57e547 | 102 | "avr_have_dimode" |
3ba781d3 SKS |
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" | |
8c57e547 | 116 | "%~call __adddi3" |
3ba781d3 | 117 | [(set_attr "adjust_len" "call")]) |
8c57e547 | 118 | |
3ba781d3 | 119 | (define_insn_and_split "adddi3_const8_insn" |
8c57e547 GJL |
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" | |
3ba781d3 SKS |
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" | |
8c57e547 | 137 | "%~call __adddi3_s8" |
3ba781d3 | 138 | [(set_attr "adjust_len" "call")]) |
8c57e547 | 139 | |
e55e4056 GJL |
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" | |
3ba781d3 | 144 | (define_insn_and_split "add<mode>3_const_insn" |
e55e4056 GJL |
145 | [(set (reg:ALL8 ACC_A) |
146 | (plus:ALL8 (reg:ALL8 ACC_A) | |
147 | (match_operand:ALL8 0 "const_operand" "n Ynn")))] | |
8c57e547 GJL |
148 | "avr_have_dimode |
149 | && !s8_operand (operands[0], VOIDmode)" | |
3ba781d3 SKS |
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" | |
8c57e547 | 165 | { |
51526856 | 166 | return avr_out_plus (insn, operands); |
8c57e547 | 167 | } |
3ba781d3 | 168 | [(set_attr "adjust_len" "plus")]) |
8c57e547 GJL |
169 | |
170 | ||
171 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
172 | ;; Subtraction | |
173 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
174 | ||
e55e4056 GJL |
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" "")])] | |
8c57e547 GJL |
183 | "avr_have_dimode" |
184 | { | |
e55e4056 | 185 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 186 | |
00e641f1 | 187 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 | 188 | emit_move_insn (acc_a, operands[1]); |
e55e4056 GJL |
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 | ||
8c57e547 GJL |
200 | emit_move_insn (operands[0], acc_a); |
201 | DONE; | |
202 | }) | |
203 | ||
e55e4056 GJL |
204 | ;; "subdi3_insn" |
205 | ;; "subdq3_insn" "subudq3_insn" | |
206 | ;; "subda3_insn" "subuda3_insn" | |
207 | ;; "subta3_insn" "subuta3_insn" | |
3ba781d3 | 208 | (define_insn_and_split "sub<mode>3_insn" |
e55e4056 GJL |
209 | [(set (reg:ALL8 ACC_A) |
210 | (minus:ALL8 (reg:ALL8 ACC_A) | |
211 | (reg:ALL8 ACC_B)))] | |
8c57e547 | 212 | "avr_have_dimode" |
3ba781d3 SKS |
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" | |
8c57e547 | 226 | "%~call __subdi3" |
3ba781d3 | 227 | [(set_attr "adjust_len" "call")]) |
8c57e547 | 228 | |
e55e4056 GJL |
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" | |
3ba781d3 | 233 | (define_insn_and_split "sub<mode>3_const_insn" |
e55e4056 GJL |
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" | |
3ba781d3 SKS |
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" | |
e55e4056 | 251 | { |
51526856 GJL |
252 | return avr_out_plus (insn, operands); |
253 | } | |
3ba781d3 | 254 | [(set_attr "adjust_len" "plus")]) |
51526856 GJL |
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 | ||
00e641f1 | 268 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
51526856 GJL |
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 | ||
3ba781d3 | 285 | (define_insn_and_split "<code_stdname><mode>3_insn" |
51526856 GJL |
286 | [(set (reg:ALL8S ACC_A) |
287 | (ss_addsub:ALL8S (reg:ALL8S ACC_A) | |
288 | (reg:ALL8S ACC_B)))] | |
289 | "avr_have_dimode" | |
3ba781d3 SKS |
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" | |
51526856 | 303 | "%~call __<code_stdname><mode>3" |
3ba781d3 | 304 | [(set_attr "adjust_len" "call")]) |
51526856 | 305 | |
3ba781d3 | 306 | (define_insn_and_split "<code_stdname><mode>3_const_insn" |
51526856 GJL |
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" | |
3ba781d3 SKS |
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" | |
51526856 GJL |
324 | { |
325 | return avr_out_plus (insn, operands); | |
e55e4056 | 326 | } |
3ba781d3 | 327 | [(set_attr "adjust_len" "plus")]) |
51526856 GJL |
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 | ||
00e641f1 | 341 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
51526856 GJL |
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 | ||
3ba781d3 | 358 | (define_insn_and_split "<code_stdname><mode>3_insn" |
51526856 GJL |
359 | [(set (reg:ALL8U ACC_A) |
360 | (us_addsub:ALL8U (reg:ALL8U ACC_A) | |
361 | (reg:ALL8U ACC_B)))] | |
362 | "avr_have_dimode" | |
3ba781d3 SKS |
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" | |
51526856 | 376 | "%~call __<code_stdname><mode>3" |
3ba781d3 | 377 | [(set_attr "adjust_len" "call")]) |
e55e4056 | 378 | |
3ba781d3 | 379 | (define_insn_and_split "<code_stdname><mode>3_const_insn" |
51526856 GJL |
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" | |
3ba781d3 SKS |
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" | |
51526856 GJL |
397 | { |
398 | return avr_out_plus (insn, operands); | |
399 | } | |
3ba781d3 | 400 | [(set_attr "adjust_len" "plus")]) |
8c57e547 GJL |
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 | ||
3ba781d3 | 419 | (define_insn_and_split "negdi2_insn" |
8c57e547 GJL |
420 | [(set (reg:DI ACC_A) |
421 | (neg:DI (reg:DI ACC_A)))] | |
422 | "avr_have_dimode" | |
3ba781d3 SKS |
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" | |
8c57e547 | 434 | "%~call __negdi2" |
3ba781d3 | 435 | [(set_attr "adjust_len" "call")]) |
8c57e547 GJL |
436 | |
437 | ||
438 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
439 | ;; Comparison | |
440 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
441 | ||
442 | (define_expand "conditional_jump" | |
443 | [(set (pc) | |
444 | (if_then_else | |
3ba781d3 | 445 | (match_operator 0 "ordered_comparison_operator" [(reg:CC REG_CC) |
8c57e547 GJL |
446 | (const_int 0)]) |
447 | (label_ref (match_operand 1 "" "")) | |
448 | (pc)))] | |
449 | "avr_have_dimode") | |
450 | ||
e55e4056 GJL |
451 | ;; "cbranchdi4" |
452 | ;; "cbranchdq4" "cbranchudq4" | |
453 | ;; "cbranchda4" "cbranchuda4" | |
454 | ;; "cbranchta4" "cbranchuta4" | |
455 | (define_expand "cbranch<mode>4" | |
3ba781d3 SKS |
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)))] | |
8c57e547 | 462 | "avr_have_dimode" |
3ba781d3 | 463 | { |
e55e4056 | 464 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 465 | |
00e641f1 | 466 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 GJL |
467 | emit_move_insn (acc_a, operands[1]); |
468 | ||
469 | if (s8_operand (operands[2], VOIDmode)) | |
470 | { | |
471 | emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); | |
3ba781d3 | 472 | emit_jump_insn (gen_cbranch_const8_di2_split (operands[0], operands[3])); |
00892272 | 473 | } |
e55e4056 | 474 | else if (const_operand (operands[2], GET_MODE (operands[2]))) |
8c57e547 | 475 | { |
3ba781d3 SKS |
476 | emit_jump_insn (gen_cbranch_const_<mode>2_split (operands[0], |
477 | operands[2], | |
478 | operands[3])); | |
8c57e547 GJL |
479 | } |
480 | else | |
481 | { | |
e55e4056 | 482 | emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]); |
3ba781d3 | 483 | emit_jump_insn (gen_cbranch_<mode>2_split (operands[0], operands[3])); |
8c57e547 | 484 | } |
3ba781d3 SKS |
485 | DONE; |
486 | }) | |
8c57e547 | 487 | |
3ba781d3 SKS |
488 | (define_insn_and_split "cbranch_<mode>2_split" |
489 | [(set (pc) | |
490 | (if_then_else (match_operator 0 "ordered_comparison_operator" | |
491 | [(reg:ALL8 ACC_A) | |
492 | (reg:ALL8 ACC_B)]) | |
493 | (label_ref (match_operand 1 "" "")) | |
494 | (pc)))] | |
495 | "avr_have_dimode" | |
496 | "#" | |
497 | "&& reload_completed" | |
498 | [(const_int 0)] | |
499 | { | |
500 | emit_insn (gen_compare_<mode>2 ()); | |
501 | emit_jump_insn (gen_conditional_jump (operands[0], operands[1])); | |
8c57e547 GJL |
502 | DONE; |
503 | }) | |
504 | ||
e55e4056 GJL |
505 | ;; "compare_di2" |
506 | ;; "compare_dq2" "compare_udq2" | |
507 | ;; "compare_da2" "compare_uda2" | |
508 | ;; "compare_ta2" "compare_uta2" | |
509 | (define_insn "compare_<mode>2" | |
3ba781d3 SKS |
510 | [(set (reg:CC REG_CC) |
511 | (compare:CC (reg:ALL8 ACC_A) | |
512 | (reg:ALL8 ACC_B)))] | |
513 | "reload_completed && avr_have_dimode" | |
8c57e547 | 514 | "%~call __cmpdi2" |
3ba781d3 | 515 | [(set_attr "adjust_len" "call")]) |
8c57e547 | 516 | |
3ba781d3 SKS |
517 | (define_insn_and_split "cbranch_const8_di2_split" |
518 | [(set (pc) | |
519 | (if_then_else (match_operator 0 "ordered_comparison_operator" | |
520 | [(reg:DI ACC_A) | |
521 | (sign_extend:DI (reg:QI REG_X))]) | |
522 | (label_ref (match_operand 1 "" "")) | |
523 | (pc)))] | |
8c57e547 | 524 | "avr_have_dimode" |
3ba781d3 SKS |
525 | "#" |
526 | "&& reload_completed" | |
527 | [(const_int 0)] | |
528 | { | |
529 | emit_insn (gen_compare_const8_di2 ()); | |
530 | emit_jump_insn (gen_conditional_jump (operands[0], operands[1])); | |
531 | DONE; | |
532 | }) | |
533 | ||
534 | (define_insn "compare_const8_di2" | |
535 | [(set (reg:CC REG_CC) | |
536 | (compare:CC (reg:DI ACC_A) | |
537 | (sign_extend:DI (reg:QI REG_X))))] | |
538 | "reload_completed && avr_have_dimode" | |
8c57e547 | 539 | "%~call __cmpdi2_s8" |
3ba781d3 SKS |
540 | [(set_attr "adjust_len" "call")]) |
541 | ||
542 | (define_insn_and_split "cbranch_const_<mode>2_split" | |
543 | [(set (pc) | |
544 | (if_then_else (match_operator 0 "ordered_comparison_operator" | |
545 | [(reg:ALL8 ACC_A) | |
546 | (match_operand:ALL8 1 "const_operand" "n Ynn")]) | |
547 | (label_ref (match_operand 2 "" "")) | |
548 | (pc))) | |
549 | (clobber (match_scratch:QI 3 "=&d"))] | |
550 | "avr_have_dimode | |
551 | && !s8_operand (operands[1], VOIDmode)" | |
552 | "#" | |
553 | "&& reload_completed" | |
554 | [(const_int 0)] | |
555 | { | |
556 | emit_insn (gen_compare_const_<mode>2 (operands[1], operands[3])); | |
557 | emit_jump_insn (gen_conditional_jump (operands[0], operands[2])); | |
558 | DONE; | |
559 | }) | |
560 | ||
8c57e547 | 561 | |
e55e4056 GJL |
562 | ;; "compare_const_di2" |
563 | ;; "compare_const_dq2" "compare_const_udq2" | |
564 | ;; "compare_const_da2" "compare_const_uda2" | |
565 | ;; "compare_const_ta2" "compare_const_uta2" | |
566 | (define_insn "compare_const_<mode>2" | |
3ba781d3 SKS |
567 | [(set (reg:CC REG_CC) |
568 | (compare:CC (reg:ALL8 ACC_A) | |
569 | (match_operand:ALL8 0 "const_operand" "n Ynn"))) | |
570 | (clobber (match_operand:QI 1 "register_operand" "=&d"))] | |
571 | "reload_completed | |
572 | && avr_have_dimode | |
8c57e547 GJL |
573 | && !s8_operand (operands[0], VOIDmode)" |
574 | { | |
575 | return avr_out_compare64 (insn, operands, NULL); | |
576 | } | |
3ba781d3 | 577 | [(set_attr "adjust_len" "compare64")]) |
8c57e547 GJL |
578 | |
579 | ||
580 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
581 | ;; Shifts and Rotate | |
582 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
583 | ||
584 | (define_code_iterator di_shifts | |
585 | [ashift ashiftrt lshiftrt rotate]) | |
586 | ||
587 | ;; Shift functions from libgcc are called without defining these insns, | |
588 | ;; but with them we can describe their reduced register footprint. | |
589 | ||
e55e4056 GJL |
590 | ;; "ashldi3" "ashrdi3" "lshrdi3" "rotldi3" |
591 | ;; "ashldq3" "ashrdq3" "lshrdq3" "rotldq3" | |
592 | ;; "ashlda3" "ashrda3" "lshrda3" "rotlda3" | |
593 | ;; "ashlta3" "ashrta3" "lshrta3" "rotlta3" | |
594 | ;; "ashludq3" "ashrudq3" "lshrudq3" "rotludq3" | |
595 | ;; "ashluda3" "ashruda3" "lshruda3" "rotluda3" | |
596 | ;; "ashluta3" "ashruta3" "lshruta3" "rotluta3" | |
597 | (define_expand "<code_stdname><mode>3" | |
598 | [(parallel [(match_operand:ALL8 0 "general_operand" "") | |
599 | (di_shifts:ALL8 (match_operand:ALL8 1 "general_operand" "") | |
600 | (match_operand:QI 2 "general_operand" ""))])] | |
8c57e547 GJL |
601 | "avr_have_dimode" |
602 | { | |
e55e4056 | 603 | rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A); |
8c57e547 | 604 | |
00e641f1 | 605 | avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A)); |
8c57e547 GJL |
606 | emit_move_insn (acc_a, operands[1]); |
607 | emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]); | |
e55e4056 | 608 | emit_insn (gen_<code_stdname><mode>3_insn ()); |
8c57e547 GJL |
609 | emit_move_insn (operands[0], acc_a); |
610 | DONE; | |
611 | }) | |
612 | ||
e55e4056 GJL |
613 | ;; "ashldi3_insn" "ashrdi3_insn" "lshrdi3_insn" "rotldi3_insn" |
614 | ;; "ashldq3_insn" "ashrdq3_insn" "lshrdq3_insn" "rotldq3_insn" | |
615 | ;; "ashlda3_insn" "ashrda3_insn" "lshrda3_insn" "rotlda3_insn" | |
616 | ;; "ashlta3_insn" "ashrta3_insn" "lshrta3_insn" "rotlta3_insn" | |
617 | ;; "ashludq3_insn" "ashrudq3_insn" "lshrudq3_insn" "rotludq3_insn" | |
618 | ;; "ashluda3_insn" "ashruda3_insn" "lshruda3_insn" "rotluda3_insn" | |
619 | ;; "ashluta3_insn" "ashruta3_insn" "lshruta3_insn" "rotluta3_insn" | |
3ba781d3 | 620 | (define_insn_and_split "<code_stdname><mode>3_insn" |
e55e4056 GJL |
621 | [(set (reg:ALL8 ACC_A) |
622 | (di_shifts:ALL8 (reg:ALL8 ACC_A) | |
623 | (reg:QI 16)))] | |
8c57e547 | 624 | "avr_have_dimode" |
3ba781d3 SKS |
625 | "#" |
626 | "&& reload_completed" | |
627 | [(parallel [(set (reg:ALL8 ACC_A) | |
628 | (di_shifts:ALL8 (reg:ALL8 ACC_A) | |
629 | (reg:QI 16))) | |
630 | (clobber (reg:CC REG_CC))])]) | |
631 | ||
632 | (define_insn "*<code_stdname><mode>3_insn" | |
633 | [(set (reg:ALL8 ACC_A) | |
634 | (di_shifts:ALL8 (reg:ALL8 ACC_A) | |
635 | (reg:QI 16))) | |
636 | (clobber (reg:CC REG_CC))] | |
637 | "avr_have_dimode && reload_completed" | |
8c57e547 | 638 | "%~call __<code_stdname>di3" |
3ba781d3 | 639 | [(set_attr "adjust_len" "call")]) |
e68a4ef6 GJL |
640 | |
641 | ;; "umulsidi3" | |
642 | ;; "mulsidi3" | |
643 | (define_expand "<extend_u>mulsidi3" | |
644 | [(parallel [(match_operand:DI 0 "register_operand" "") | |
645 | (match_operand:SI 1 "general_operand" "") | |
646 | (match_operand:SI 2 "general_operand" "") | |
647 | ;; Just to mention the iterator | |
648 | (clobber (any_extend:SI (match_dup 1)))])] | |
1f82f124 GJL |
649 | "avr_have_dimode |
650 | && AVR_HAVE_MUL" | |
e68a4ef6 | 651 | { |
00e641f1 | 652 | avr_fix_inputs (operands, 1 << 2, regmask (SImode, 22)); |
e68a4ef6 GJL |
653 | emit_move_insn (gen_rtx_REG (SImode, 22), operands[1]); |
654 | emit_move_insn (gen_rtx_REG (SImode, 18), operands[2]); | |
655 | emit_insn (gen_<extend_u>mulsidi3_insn()); | |
656 | // Use emit_move_insn and not open-coded expand because of missing movdi | |
657 | emit_move_insn (operands[0], gen_rtx_REG (DImode, ACC_A)); | |
658 | DONE; | |
659 | }) | |
660 | ||
661 | ;; "umulsidi3_insn" | |
662 | ;; "mulsidi3_insn" | |
3ba781d3 SKS |
663 | |
664 | (define_insn_and_split "<extend_u>mulsidi3_insn" | |
e68a4ef6 GJL |
665 | [(set (reg:DI ACC_A) |
666 | (mult:DI (any_extend:DI (reg:SI 18)) | |
667 | (any_extend:DI (reg:SI 22)))) | |
668 | (clobber (reg:HI REG_X)) | |
669 | (clobber (reg:HI REG_Z))] | |
1f82f124 GJL |
670 | "avr_have_dimode |
671 | && AVR_HAVE_MUL" | |
3ba781d3 SKS |
672 | "#" |
673 | "&& reload_completed" | |
674 | [(parallel [(set (reg:DI ACC_A) | |
675 | (mult:DI (any_extend:DI (reg:SI 18)) | |
676 | (any_extend:DI (reg:SI 22)))) | |
677 | (clobber (reg:HI REG_X)) | |
678 | (clobber (reg:HI REG_Z)) | |
679 | (clobber (reg:CC REG_CC))])]) | |
680 | ||
681 | (define_insn "*<extend_u>mulsidi3_insn" | |
682 | [(set (reg:DI ACC_A) | |
683 | (mult:DI (any_extend:DI (reg:SI 18)) | |
684 | (any_extend:DI (reg:SI 22)))) | |
685 | (clobber (reg:HI REG_X)) | |
686 | (clobber (reg:HI REG_Z)) | |
687 | (clobber (reg:CC REG_CC))] | |
688 | "avr_have_dimode | |
689 | && AVR_HAVE_MUL | |
690 | && reload_completed" | |
e68a4ef6 | 691 | "%~call __<extend_u>mulsidi3" |
3ba781d3 | 692 | [(set_attr "adjust_len" "call")]) |