Mercurial > hg > CbC > CbC_gcc
annotate gcc/config/avr/avr.md @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
rev | line source |
---|---|
0 | 1 ;; Machine description for GNU compiler, |
2 ;; for ATMEL AVR micro controllers. | |
131 | 3 ;; Copyright (C) 1998-2018 Free Software Foundation, Inc. |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
4 ;; Contributed by Denis Chertykov (chertykov@gmail.com) |
0 | 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 ;; Special characters after '%': | |
23 ;; A No effect (add 0). | |
24 ;; B Add 1 to REG number, MEM address or CONST_INT. | |
25 ;; C Add 2. | |
26 ;; D Add 3. | |
111 | 27 ;; E reg number in XEXP(x, 0). |
28 ;; F Add 1 to reg number. | |
29 ;; I reg number in XEXP(XEXP(x, 0), 0). | |
30 ;; J Add 1 to reg number. | |
0 | 31 ;; j Branch condition. |
32 ;; k Reverse branch condition. | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
33 ;;..m..Constant Direct Data memory address. |
111 | 34 ;; i Print the SFR address quivalent of a CONST_INT or a CONST_INT |
35 ;; RAM address. The resulting address is suitable to be used in IN/OUT. | |
0 | 36 ;; o Displacement for (mem (plus (reg) (const_int))) operands. |
37 ;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z) | |
38 ;; r POST_INC or PRE_DEC address as a register (r26, r28, r30) | |
111 | 39 ;; r Print a REG without the register prefix 'r'. |
40 ;; T/T Print operand suitable for BLD/BST instruction, i.e. register and | |
41 ;; bit number. This gets 2 operands: The first %T gets a REG_P and | |
42 ;; just cashes the operand for the next %T. The second %T gets | |
43 ;; a CONST_INT that represents a bit position. | |
44 ;; Example: With %0 = (reg:HI 18) and %1 = (const_int 13) | |
45 ;; "%T0%T1" it will print "r19,5". | |
46 ;; Notice that you must not write a comma between %T0 and %T1. | |
47 ;; T/t Similar to above, but don't print the comma and the bit number. | |
48 ;; Example: With %0 = (reg:HI 18) and %1 = (const_int 13) | |
49 ;; "%T0%t1" it will print "r19". | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
50 ;;..x..Constant Direct Program memory address. |
0 | 51 ;; ~ Output 'r' if not AVR_HAVE_JMP_CALL. |
52 ;; ! Output 'e' if AVR_HAVE_EIJMP_EICALL. | |
53 | |
111 | 54 |
55 (define_constants | |
56 [(REG_X 26) | |
57 (REG_Y 28) | |
58 (REG_Z 30) | |
59 (REG_W 24) | |
60 (REG_SP 32) | |
61 (LPM_REGNO 0) ; implicit target register of LPM | |
62 (TMP_REGNO 0) ; temporary register r0 | |
63 (ZERO_REGNO 1) ; zero register r1 | |
64 ]) | |
0 | 65 |
66 (define_constants | |
111 | 67 [(TMP_REGNO_TINY 16) ; r16 is temp register for AVR_TINY |
68 (ZERO_REGNO_TINY 17) ; r17 is zero register for AVR_TINY | |
69 ]) | |
70 | |
71 (define_c_enum "unspec" | |
72 [UNSPEC_STRLEN | |
73 UNSPEC_MOVMEM | |
74 UNSPEC_INDEX_JMP | |
75 UNSPEC_FMUL | |
76 UNSPEC_FMULS | |
77 UNSPEC_FMULSU | |
78 UNSPEC_COPYSIGN | |
79 UNSPEC_IDENTITY | |
80 UNSPEC_INSERT_BITS | |
81 UNSPEC_ROUND | |
82 ]) | |
83 | |
84 (define_c_enum "unspecv" | |
85 [UNSPECV_PROLOGUE_SAVES | |
86 UNSPECV_EPILOGUE_RESTORES | |
87 UNSPECV_WRITE_SP | |
88 UNSPECV_GASISR | |
89 UNSPECV_GOTO_RECEIVER | |
90 UNSPECV_ENABLE_IRQS | |
91 UNSPECV_MEMORY_BARRIER | |
92 UNSPECV_NOP | |
93 UNSPECV_SLEEP | |
94 UNSPECV_WDR | |
95 UNSPECV_DELAY_CYCLES | |
96 ]) | |
97 | |
98 ;; Chunk numbers for __gcc_isr are hard-coded in GAS. | |
99 (define_constants | |
100 [(GASISR_Prologue 1) | |
101 (GASISR_Epilogue 2) | |
102 (GASISR_Done 0) | |
103 ]) | |
0 | 104 |
105 (include "predicates.md") | |
106 (include "constraints.md") | |
111 | 107 |
0 | 108 ;; Condition code settings. |
111 | 109 (define_attr "cc" "none,set_czn,set_zn,set_vzn,set_n,compare,clobber, |
110 plus,ldi" | |
0 | 111 (const_string "none")) |
112 | |
113 (define_attr "type" "branch,branch1,arith,xcall" | |
114 (const_string "arith")) | |
115 | |
116 ;; The size of instructions in bytes. | |
117 ;; XXX may depend from "cc" | |
118 | |
119 (define_attr "length" "" | |
120 (cond [(eq_attr "type" "branch") | |
121 (if_then_else (and (ge (minus (pc) (match_dup 0)) | |
111 | 122 (const_int -62)) |
0 | 123 (le (minus (pc) (match_dup 0)) |
124 (const_int 62))) | |
125 (const_int 1) | |
126 (if_then_else (and (ge (minus (pc) (match_dup 0)) | |
111 | 127 (const_int -2044)) |
0 | 128 (le (minus (pc) (match_dup 0)) |
129 (const_int 2045))) | |
130 (const_int 2) | |
131 (const_int 3))) | |
132 (eq_attr "type" "branch1") | |
133 (if_then_else (and (ge (minus (pc) (match_dup 0)) | |
134 (const_int -62)) | |
135 (le (minus (pc) (match_dup 0)) | |
136 (const_int 61))) | |
137 (const_int 2) | |
138 (if_then_else (and (ge (minus (pc) (match_dup 0)) | |
139 (const_int -2044)) | |
140 (le (minus (pc) (match_dup 0)) | |
141 (const_int 2043))) | |
142 (const_int 3) | |
143 (const_int 4))) | |
111 | 144 (eq_attr "type" "xcall") |
145 (if_then_else (match_test "!AVR_HAVE_JMP_CALL") | |
146 (const_int 1) | |
147 (const_int 2))] | |
0 | 148 (const_int 2))) |
149 | |
111 | 150 ;; Lengths of several insns are adjusted in avr.c:adjust_insn_length(). |
151 ;; Following insn attribute tells if and how the adjustment has to be | |
152 ;; done: | |
153 ;; no No adjustment needed; attribute "length" is fine. | |
154 ;; Otherwise do special processing depending on the attribute. | |
155 | |
156 (define_attr "adjust_len" | |
157 "out_bitop, plus, addto_sp, sext, | |
158 tsthi, tstpsi, tstsi, compare, compare64, call, | |
159 mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, | |
160 ufract, sfract, round, | |
161 xload, movmem, | |
162 ashlqi, ashrqi, lshrqi, | |
163 ashlhi, ashrhi, lshrhi, | |
164 ashlsi, ashrsi, lshrsi, | |
165 ashlpsi, ashrpsi, lshrpsi, | |
166 insert_bits, insv_notbit, insv_notbit_0, insv_notbit_7, | |
167 no" | |
168 (const_string "no")) | |
169 | |
170 ;; Flavours of instruction set architecture (ISA), used in enabled attribute | |
171 | |
172 ;; mov : ISA has no MOVW movw : ISA has MOVW | |
173 ;; rjmp : ISA has no CALL/JMP jmp : ISA has CALL/JMP | |
174 ;; ijmp : ISA has no EICALL/EIJMP eijmp : ISA has EICALL/EIJMP | |
175 ;; lpm : ISA has no LPMX lpmx : ISA has LPMX | |
176 ;; elpm : ISA has ELPM but no ELPMX elpmx : ISA has ELPMX | |
177 ;; no_xmega: non-XMEGA core xmega : XMEGA core | |
178 ;; no_tiny: non-TINY core tiny : TINY core | |
179 | |
180 (define_attr "isa" | |
181 "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, no_tiny,tiny, | |
182 standard" | |
183 (const_string "standard")) | |
184 | |
185 (define_attr "enabled" "" | |
186 (cond [(eq_attr "isa" "standard") | |
187 (const_int 1) | |
188 | |
189 (and (eq_attr "isa" "mov") | |
190 (match_test "!AVR_HAVE_MOVW")) | |
191 (const_int 1) | |
192 | |
193 (and (eq_attr "isa" "movw") | |
194 (match_test "AVR_HAVE_MOVW")) | |
195 (const_int 1) | |
196 | |
197 (and (eq_attr "isa" "rjmp") | |
198 (match_test "!AVR_HAVE_JMP_CALL")) | |
199 (const_int 1) | |
200 | |
201 (and (eq_attr "isa" "jmp") | |
202 (match_test "AVR_HAVE_JMP_CALL")) | |
203 (const_int 1) | |
204 | |
205 (and (eq_attr "isa" "ijmp") | |
206 (match_test "!AVR_HAVE_EIJMP_EICALL")) | |
207 (const_int 1) | |
208 | |
209 (and (eq_attr "isa" "eijmp") | |
210 (match_test "AVR_HAVE_EIJMP_EICALL")) | |
211 (const_int 1) | |
212 | |
213 (and (eq_attr "isa" "lpm") | |
214 (match_test "!AVR_HAVE_LPMX")) | |
215 (const_int 1) | |
216 | |
217 (and (eq_attr "isa" "lpmx") | |
218 (match_test "AVR_HAVE_LPMX")) | |
219 (const_int 1) | |
220 | |
221 (and (eq_attr "isa" "elpm") | |
222 (match_test "AVR_HAVE_ELPM && !AVR_HAVE_ELPMX")) | |
223 (const_int 1) | |
224 | |
225 (and (eq_attr "isa" "elpmx") | |
226 (match_test "AVR_HAVE_ELPMX")) | |
227 (const_int 1) | |
228 | |
229 (and (eq_attr "isa" "xmega") | |
230 (match_test "AVR_XMEGA")) | |
231 (const_int 1) | |
232 | |
233 (and (eq_attr "isa" "tiny") | |
234 (match_test "AVR_TINY")) | |
235 (const_int 1) | |
236 | |
237 (and (eq_attr "isa" "no_xmega") | |
238 (match_test "!AVR_XMEGA")) | |
239 (const_int 1) | |
240 | |
241 (and (eq_attr "isa" "no_tiny") | |
242 (match_test "!AVR_TINY")) | |
243 (const_int 1) | |
244 | |
245 ] (const_int 0))) | |
246 | |
247 | |
248 ;; Define mode iterators | |
249 (define_mode_iterator QIHI [QI HI]) | |
250 (define_mode_iterator QIHI2 [QI HI]) | |
251 (define_mode_iterator QISI [QI HI PSI SI]) | |
252 (define_mode_iterator QIDI [QI HI PSI SI DI]) | |
253 (define_mode_iterator HISI [HI PSI SI]) | |
254 | |
255 (define_mode_iterator ALL1 [QI QQ UQQ]) | |
256 (define_mode_iterator ALL2 [HI HQ UHQ HA UHA]) | |
257 (define_mode_iterator ALL4 [SI SQ USQ SA USA]) | |
258 | |
259 ;; All supported move-modes | |
260 (define_mode_iterator MOVMODE [QI QQ UQQ | |
261 HI HQ UHQ HA UHA | |
262 SI SQ USQ SA USA | |
263 SF PSI]) | |
264 | |
265 ;; Supported ordered modes that are 2, 3, 4 bytes wide | |
266 (define_mode_iterator ORDERED234 [HI SI PSI | |
267 HQ UHQ HA UHA | |
268 SQ USQ SA USA]) | |
269 | |
270 ;; Post-reload split of 3, 4 bytes wide moves. | |
271 (define_mode_iterator SPLIT34 [SI SF PSI | |
272 SQ USQ SA USA]) | |
273 | |
274 ;; Define code iterators | |
275 ;; Define two incarnations so that we can build the cross product. | |
276 (define_code_iterator any_extend [sign_extend zero_extend]) | |
277 (define_code_iterator any_extend2 [sign_extend zero_extend]) | |
278 (define_code_iterator any_extract [sign_extract zero_extract]) | |
279 (define_code_iterator any_shiftrt [lshiftrt ashiftrt]) | |
280 | |
281 (define_code_iterator bitop [xor ior and]) | |
282 (define_code_iterator xior [xor ior]) | |
283 (define_code_iterator eqne [eq ne]) | |
284 | |
285 (define_code_iterator ss_addsub [ss_plus ss_minus]) | |
286 (define_code_iterator us_addsub [us_plus us_minus]) | |
287 (define_code_iterator ss_abs_neg [ss_abs ss_neg]) | |
288 | |
289 ;; Define code attributes | |
290 (define_code_attr extend_su | |
291 [(sign_extend "s") | |
292 (zero_extend "u")]) | |
293 | |
294 (define_code_attr extend_u | |
295 [(sign_extend "") | |
296 (zero_extend "u")]) | |
297 | |
298 (define_code_attr extend_s | |
299 [(sign_extend "s") | |
300 (zero_extend "")]) | |
301 | |
302 ;; Constrain input operand of widening multiply, i.e. MUL resp. MULS. | |
303 (define_code_attr mul_r_d | |
304 [(zero_extend "r") | |
305 (sign_extend "d")]) | |
306 | |
307 (define_code_attr abelian | |
308 [(ss_minus "") (us_minus "") | |
309 (ss_plus "%") (us_plus "%")]) | |
310 | |
311 ;; Map RTX code to its standard insn name | |
312 (define_code_attr code_stdname | |
313 [(ashift "ashl") | |
314 (ashiftrt "ashr") | |
315 (lshiftrt "lshr") | |
316 (ior "ior") | |
317 (xor "xor") | |
318 (rotate "rotl") | |
319 (ss_plus "ssadd") (ss_minus "sssub") (ss_neg "ssneg") (ss_abs "ssabs") | |
320 (us_plus "usadd") (us_minus "ussub") (us_neg "usneg") | |
321 ]) | |
0 | 322 |
323 ;;======================================================================== | |
324 ;; The following is used by nonlocal_goto and setjmp. | |
325 ;; The receiver pattern will create no instructions since internally | |
326 ;; virtual_stack_vars = hard_frame_pointer + 1 so the RTL become R28=R28 | |
327 ;; This avoids creating add/sub offsets in frame_pointer save/resore. | |
328 ;; The 'null' receiver also avoids problems with optimisation | |
329 ;; not recognising incoming jmp and removing code that resets frame_pointer. | |
330 ;; The code derived from builtins.c. | |
331 | |
332 (define_expand "nonlocal_goto_receiver" | |
111 | 333 [(set (reg:HI REG_Y) |
334 (unspec_volatile:HI [(const_int 0)] UNSPECV_GOTO_RECEIVER))] | |
335 "" | |
336 { | |
337 rtx offset = gen_int_mode (targetm.starting_frame_offset (), Pmode); | |
338 emit_move_insn (virtual_stack_vars_rtx, | |
339 gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, offset)); | |
340 /* ; This might change the hard frame pointer in ways that aren't | |
341 ; apparent to early optimization passes, so force a clobber. */ | |
0 | 342 emit_clobber (hard_frame_pointer_rtx); |
343 DONE; | |
344 }) | |
111 | 345 |
0 | 346 |
347 ;; Defining nonlocal_goto_receiver means we must also define this. | |
348 ;; even though its function is identical to that in builtins.c | |
349 | |
350 (define_expand "nonlocal_goto" | |
111 | 351 [(use (match_operand 0 "general_operand")) |
352 (use (match_operand 1 "general_operand")) | |
353 (use (match_operand 2 "general_operand")) | |
354 (use (match_operand 3 "general_operand"))] | |
355 "" | |
356 { | |
357 rtx r_label = copy_to_reg (operands[1]); | |
358 rtx r_fp = operands[3]; | |
359 rtx r_sp = operands[2]; | |
360 | |
361 emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))); | |
362 | |
363 emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx)); | |
364 | |
365 emit_move_insn (hard_frame_pointer_rtx, r_fp); | |
366 emit_stack_restore (SAVE_NONLOCAL, r_sp); | |
367 | |
368 emit_use (hard_frame_pointer_rtx); | |
369 emit_use (stack_pointer_rtx); | |
370 | |
371 emit_indirect_jump (r_label); | |
372 | |
373 DONE; | |
374 }) | |
375 | |
376 ;; "pushqi1" | |
377 ;; "pushqq1" "pushuqq1" | |
378 (define_insn "push<mode>1" | |
379 [(set (mem:ALL1 (post_dec:HI (reg:HI REG_SP))) | |
380 (match_operand:ALL1 0 "reg_or_0_operand" "r,Y00"))] | |
0 | 381 "" |
382 "@ | |
383 push %0 | |
384 push __zero_reg__" | |
385 [(set_attr "length" "1,1")]) | |
386 | |
111 | 387 (define_insn "pushhi1_insn" |
388 [(set (mem:HI (post_dec:HI (reg:HI REG_SP))) | |
389 (match_operand:HI 0 "register_operand" "r"))] | |
390 "" | |
391 "push %B0\;push %A0" | |
392 [(set_attr "length" "2")]) | |
393 | |
394 ;; All modes for a multi-byte push. We must include complex modes here too, | |
395 ;; lest emit_single_push_insn "helpfully" create the auto-inc itself. | |
396 (define_mode_iterator MPUSH | |
397 [CQI | |
398 HI CHI HA UHA HQ UHQ | |
399 SI CSI SA USA SQ USQ | |
400 DI CDI DA UDA DQ UDQ | |
401 TA UTA | |
402 SF SC | |
403 PSI]) | |
404 | |
405 (define_expand "push<mode>1" | |
406 [(match_operand:MPUSH 0 "" "")] | |
407 "" | |
408 { | |
409 if (MEM_P (operands[0]) | |
410 && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[0]))) | |
411 { | |
412 // Avoid (subreg (mem)) for non-generic address spaces. Because | |
413 // of the poor addressing capabilities of these spaces it's better to | |
414 // load them in one chunk. And it avoids PR61443. | |
415 | |
416 operands[0] = copy_to_mode_reg (<MODE>mode, operands[0]); | |
417 } | |
418 else if (REG_P (operands[0]) | |
419 && IN_RANGE (REGNO (operands[0]), FIRST_VIRTUAL_REGISTER, | |
420 LAST_VIRTUAL_REGISTER)) | |
421 { | |
422 // Byte-wise pushing of virtual regs might result in something like | |
423 // | |
424 // (set (mem:QI (post_dec:HI (reg:HI 32 SP))) | |
425 // (subreg:QI (plus:HI (reg:HI 28) | |
426 // (const_int 17)) 0)) | |
427 // | |
428 // after elimination. This cannot be handled by reload, cf. PR64452. | |
429 // Reload virtuals in one chunk. That way it's possible to reload | |
430 // above situation and finally | |
431 // | |
432 // (set (reg:HI **) | |
433 // (const_int 17)) | |
434 // (set (reg:HI **) | |
435 // (plus:HI (reg:HI **) | |
436 // (reg:HI 28))) | |
437 // (set (mem:HI (post_dec:HI (reg:HI 32 SP)) | |
438 // (reg:HI **))) | |
439 | |
440 emit_insn (gen_pushhi1_insn (operands[0])); | |
441 DONE; | |
442 } | |
443 | |
444 for (int i = GET_MODE_SIZE (<MODE>mode) - 1; i >= 0; --i) | |
445 { | |
446 rtx part = simplify_gen_subreg (QImode, operands[0], <MODE>mode, i); | |
447 if (part != const0_rtx) | |
448 part = force_reg (QImode, part); | |
449 emit_insn (gen_pushqi1 (part)); | |
450 } | |
451 DONE; | |
452 }) | |
453 | |
454 ;; Notice a special-case when adding N to SP where N results in a | |
455 ;; zero REG_ARGS_SIZE. This is equivalent to a move from FP. | |
456 (define_split | |
457 [(set (reg:HI REG_SP) | |
458 (match_operand:HI 0 "register_operand" ""))] | |
459 "reload_completed | |
460 && frame_pointer_needed | |
461 && !cfun->calls_alloca | |
462 && find_reg_note (insn, REG_ARGS_SIZE, const0_rtx)" | |
463 [(set (reg:HI REG_SP) | |
464 (reg:HI REG_Y))]) | |
465 | |
466 ;;======================================================================== | |
467 ;; Move stuff around | |
468 | |
469 ;; "loadqi_libgcc" | |
470 ;; "loadhi_libgcc" | |
471 ;; "loadpsi_libgcc" | |
472 ;; "loadsi_libgcc" | |
473 ;; "loadsf_libgcc" | |
474 (define_expand "load<mode>_libgcc" | |
475 [(set (match_dup 3) | |
476 (match_dup 2)) | |
477 (set (reg:MOVMODE 22) | |
478 (match_operand:MOVMODE 1 "memory_operand" "")) | |
479 (set (match_operand:MOVMODE 0 "register_operand" "") | |
480 (reg:MOVMODE 22))] | |
481 "avr_load_libgcc_p (operands[1])" | |
482 { | |
483 operands[3] = gen_rtx_REG (HImode, REG_Z); | |
484 operands[2] = force_operand (XEXP (operands[1], 0), NULL_RTX); | |
485 operands[1] = replace_equiv_address (operands[1], operands[3]); | |
486 set_mem_addr_space (operands[1], ADDR_SPACE_FLASH); | |
487 }) | |
488 | |
489 ;; "load_qi_libgcc" | |
490 ;; "load_hi_libgcc" | |
491 ;; "load_psi_libgcc" | |
492 ;; "load_si_libgcc" | |
493 ;; "load_sf_libgcc" | |
494 (define_insn "load_<mode>_libgcc" | |
495 [(set (reg:MOVMODE 22) | |
496 (match_operand:MOVMODE 0 "memory_operand" "m,m"))] | |
497 "avr_load_libgcc_p (operands[0]) | |
498 && REG_P (XEXP (operands[0], 0)) | |
499 && REG_Z == REGNO (XEXP (operands[0], 0))" | |
500 { | |
501 operands[0] = GEN_INT (GET_MODE_SIZE (<MODE>mode)); | |
502 return "%~call __load_%0"; | |
503 } | |
504 [(set_attr "length" "1,2") | |
505 (set_attr "isa" "rjmp,jmp") | |
506 (set_attr "cc" "clobber")]) | |
507 | |
508 | |
509 ;; "xload8qi_A" | |
510 ;; "xload8qq_A" "xload8uqq_A" | |
511 (define_insn_and_split "xload8<mode>_A" | |
512 [(set (match_operand:ALL1 0 "register_operand" "=r") | |
513 (match_operand:ALL1 1 "memory_operand" "m")) | |
514 (clobber (reg:HI REG_Z))] | |
515 "can_create_pseudo_p() | |
516 && !avr_xload_libgcc_p (<MODE>mode) | |
517 && avr_mem_memx_p (operands[1]) | |
518 && REG_P (XEXP (operands[1], 0))" | |
519 { gcc_unreachable(); } | |
520 "&& 1" | |
521 [(clobber (const_int 0))] | |
522 { | |
523 /* ; Split away the high part of the address. GCC's register allocator | |
524 ; in not able to allocate segment registers and reload the resulting | |
525 ; expressions. Notice that no address register can hold a PSImode. */ | |
526 | |
527 rtx_insn *insn; | |
528 rtx addr = XEXP (operands[1], 0); | |
529 rtx hi8 = gen_reg_rtx (QImode); | |
530 rtx reg_z = gen_rtx_REG (HImode, REG_Z); | |
531 | |
532 emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0)); | |
533 emit_move_insn (hi8, simplify_gen_subreg (QImode, addr, PSImode, 2)); | |
534 | |
535 insn = emit_insn (gen_xload<mode>_8 (operands[0], hi8)); | |
536 set_mem_addr_space (SET_SRC (single_set (insn)), | |
537 MEM_ADDR_SPACE (operands[1])); | |
538 DONE; | |
539 }) | |
540 | |
541 ;; "xloadqi_A" "xloadqq_A" "xloaduqq_A" | |
542 ;; "xloadhi_A" "xloadhq_A" "xloaduhq_A" "xloadha_A" "xloaduha_A" | |
543 ;; "xloadsi_A" "xloadsq_A" "xloadusq_A" "xloadsa_A" "xloadusa_A" | |
544 ;; "xloadpsi_A" | |
545 ;; "xloadsf_A" | |
546 (define_insn_and_split "xload<mode>_A" | |
547 [(set (match_operand:MOVMODE 0 "register_operand" "=r") | |
548 (match_operand:MOVMODE 1 "memory_operand" "m")) | |
549 (clobber (reg:MOVMODE 22)) | |
550 (clobber (reg:QI 21)) | |
551 (clobber (reg:HI REG_Z))] | |
552 "can_create_pseudo_p() | |
553 && avr_mem_memx_p (operands[1]) | |
554 && REG_P (XEXP (operands[1], 0))" | |
555 { gcc_unreachable(); } | |
556 "&& 1" | |
557 [(clobber (const_int 0))] | |
558 { | |
559 rtx addr = XEXP (operands[1], 0); | |
560 rtx reg_z = gen_rtx_REG (HImode, REG_Z); | |
561 rtx addr_hi8 = simplify_gen_subreg (QImode, addr, PSImode, 2); | |
562 addr_space_t as = MEM_ADDR_SPACE (operands[1]); | |
563 rtx_insn *insn; | |
564 | |
565 /* Split the address to R21:Z */ | |
566 emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0)); | |
567 emit_move_insn (gen_rtx_REG (QImode, 21), addr_hi8); | |
568 | |
569 /* Load with code from libgcc */ | |
570 insn = emit_insn (gen_xload_<mode>_libgcc ()); | |
571 set_mem_addr_space (SET_SRC (single_set (insn)), as); | |
572 | |
573 /* Move to destination */ | |
574 emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, 22)); | |
575 | |
576 DONE; | |
577 }) | |
578 | |
579 ;; Move value from address space memx to a register | |
580 ;; These insns must be prior to respective generic move insn. | |
581 | |
582 ;; "xloadqi_8" | |
583 ;; "xloadqq_8" "xloaduqq_8" | |
584 (define_insn "xload<mode>_8" | |
585 [(set (match_operand:ALL1 0 "register_operand" "=&r,r") | |
586 (mem:ALL1 (lo_sum:PSI (match_operand:QI 1 "register_operand" "r,r") | |
587 (reg:HI REG_Z))))] | |
588 "!avr_xload_libgcc_p (<MODE>mode)" | |
589 { | |
590 return avr_out_xload (insn, operands, NULL); | |
591 } | |
592 [(set_attr "length" "4,4") | |
593 (set_attr "adjust_len" "*,xload") | |
594 (set_attr "isa" "lpmx,lpm") | |
595 (set_attr "cc" "none")]) | |
596 | |
597 ;; R21:Z : 24-bit source address | |
598 ;; R22 : 1-4 byte output | |
599 | |
600 ;; "xload_qi_libgcc" "xload_qq_libgcc" "xload_uqq_libgcc" | |
601 ;; "xload_hi_libgcc" "xload_hq_libgcc" "xload_uhq_libgcc" "xload_ha_libgcc" "xload_uha_libgcc" | |
602 ;; "xload_si_libgcc" "xload_sq_libgcc" "xload_usq_libgcc" "xload_sa_libgcc" "xload_usa_libgcc" | |
603 ;; "xload_sf_libgcc" | |
604 ;; "xload_psi_libgcc" | |
605 (define_insn "xload_<mode>_libgcc" | |
606 [(set (reg:MOVMODE 22) | |
607 (mem:MOVMODE (lo_sum:PSI (reg:QI 21) | |
608 (reg:HI REG_Z)))) | |
609 (clobber (reg:QI 21)) | |
610 (clobber (reg:HI REG_Z))] | |
611 "avr_xload_libgcc_p (<MODE>mode)" | |
612 { | |
613 rtx x_bytes = GEN_INT (GET_MODE_SIZE (<MODE>mode)); | |
614 | |
615 output_asm_insn ("%~call __xload_%0", &x_bytes); | |
616 return ""; | |
617 } | |
618 [(set_attr "type" "xcall") | |
619 (set_attr "cc" "clobber")]) | |
620 | |
621 | |
622 ;; General move expanders | |
623 | |
624 ;; "movqi" "movqq" "movuqq" | |
625 ;; "movhi" "movhq" "movuhq" "movha" "movuha" | |
626 ;; "movsi" "movsq" "movusq" "movsa" "movusa" | |
627 ;; "movsf" | |
628 ;; "movpsi" | |
629 (define_expand "mov<mode>" | |
630 [(set (match_operand:MOVMODE 0 "nonimmediate_operand" "") | |
631 (match_operand:MOVMODE 1 "general_operand" ""))] | |
632 "" | |
633 { | |
634 rtx dest = operands[0]; | |
635 rtx src = avr_eval_addr_attrib (operands[1]); | |
636 | |
637 if (avr_mem_flash_p (dest)) | |
638 DONE; | |
639 | |
640 if (QImode == <MODE>mode | |
641 && SUBREG_P (src) | |
642 && CONSTANT_ADDRESS_P (SUBREG_REG (src)) | |
643 && can_create_pseudo_p()) | |
644 { | |
645 // store_bitfield may want to store a SYMBOL_REF or CONST in a | |
646 // structure that's represented as PSImode. As the upper 16 bits | |
647 // of PSImode cannot be expressed as an HImode subreg, the rhs is | |
648 // decomposed into QImode (word_mode) subregs of SYMBOL_REF, | |
649 // CONST or LABEL_REF; cf. PR71103. | |
650 | |
651 rtx const_addr = SUBREG_REG (src); | |
652 operands[1] = src = copy_rtx (src); | |
653 SUBREG_REG (src) = copy_to_mode_reg (GET_MODE (const_addr), const_addr); | |
654 } | |
655 | |
656 /* One of the operands has to be in a register. */ | |
657 if (!register_operand (dest, <MODE>mode) | |
658 && !reg_or_0_operand (src, <MODE>mode)) | |
659 { | |
660 operands[1] = src = copy_to_mode_reg (<MODE>mode, src); | |
661 } | |
662 | |
663 if (avr_mem_memx_p (src)) | |
664 { | |
665 rtx addr = XEXP (src, 0); | |
666 | |
667 if (!REG_P (addr)) | |
668 src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr)); | |
669 | |
670 if (!avr_xload_libgcc_p (<MODE>mode)) | |
671 /* ; No <mode> here because gen_xload8<mode>_A only iterates over ALL1. | |
672 ; insn-emit does not depend on the mode, it's all about operands. */ | |
673 emit_insn (gen_xload8qi_A (dest, src)); | |
674 else | |
675 emit_insn (gen_xload<mode>_A (dest, src)); | |
676 | |
677 DONE; | |
678 } | |
679 | |
680 if (avr_load_libgcc_p (src)) | |
681 { | |
682 /* For the small devices, do loads per libgcc call. */ | |
683 emit_insn (gen_load<mode>_libgcc (dest, src)); | |
684 DONE; | |
685 } | |
686 }) | |
0 | 687 |
688 ;;======================================================================== | |
689 ;; move byte | |
690 ;; The last alternative (any immediate constant to any register) is | |
691 ;; very expensive. It should be optimized by peephole2 if a scratch | |
692 ;; register is available, but then that register could just as well be | |
693 ;; allocated for the variable we are loading. But, most of NO_LD_REGS | |
694 ;; are call-saved registers, and most of LD_REGS are call-used registers, | |
695 ;; so this may still be a win for registers live across function calls. | |
696 | |
111 | 697 ;; "movqi_insn" |
698 ;; "movqq_insn" "movuqq_insn" | |
699 (define_insn "mov<mode>_insn" | |
700 [(set (match_operand:ALL1 0 "nonimmediate_operand" "=r ,d ,Qm ,r ,q,r,*r") | |
701 (match_operand:ALL1 1 "nox_general_operand" "r Y00,n Ynn,r Y00,Qm,r,q,i"))] | |
702 "register_operand (operands[0], <MODE>mode) | |
703 || reg_or_0_operand (operands[1], <MODE>mode)" | |
704 { | |
705 return output_movqi (insn, operands, NULL); | |
706 } | |
0 | 707 [(set_attr "length" "1,1,5,5,1,1,4") |
111 | 708 (set_attr "adjust_len" "mov8") |
709 (set_attr "cc" "ldi,none,clobber,clobber,none,none,clobber")]) | |
0 | 710 |
711 ;; This is used in peephole2 to optimize loading immediate constants | |
712 ;; if a scratch register from LD_REGS happens to be available. | |
713 | |
111 | 714 ;; "*reload_inqi" |
715 ;; "*reload_inqq" "*reload_inuqq" | |
716 (define_insn "*reload_in<mode>" | |
717 [(set (match_operand:ALL1 0 "register_operand" "=l") | |
718 (match_operand:ALL1 1 "const_operand" "i")) | |
0 | 719 (clobber (match_operand:QI 2 "register_operand" "=&d"))] |
720 "reload_completed" | |
721 "ldi %2,lo8(%1) | |
722 mov %0,%2" | |
723 [(set_attr "length" "2") | |
724 (set_attr "cc" "none")]) | |
725 | |
726 (define_peephole2 | |
727 [(match_scratch:QI 2 "d") | |
111 | 728 (set (match_operand:ALL1 0 "l_register_operand" "") |
729 (match_operand:ALL1 1 "const_operand" ""))] | |
730 ; No need for a clobber reg for 0x0, 0x01 or 0xff | |
731 "!satisfies_constraint_Y00 (operands[1]) | |
732 && !satisfies_constraint_Y01 (operands[1]) | |
733 && !satisfies_constraint_Ym1 (operands[1])" | |
734 [(parallel [(set (match_dup 0) | |
735 (match_dup 1)) | |
736 (clobber (match_dup 2))])]) | |
0 | 737 |
738 ;;============================================================================ | |
739 ;; move word (16 bit) | |
740 | |
111 | 741 ;; Move register $1 to the Stack Pointer register SP. |
742 ;; This insn is emit during function prologue/epilogue generation. | |
743 ;; $2 = 0: We know that IRQs are off | |
744 ;; $2 = 1: We know that IRQs are on | |
745 ;; $2 = 2: SP has 8 bits only, IRQ state does not matter | |
746 ;; $2 = -1: We don't know anything about IRQ on/off | |
747 ;; Always write SP via unspec, see PR50063 | |
748 | |
749 (define_insn "movhi_sp_r" | |
750 [(set (match_operand:HI 0 "stack_register_operand" "=q,q,q,q,q") | |
751 (unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r,r,r,r,r") | |
752 (match_operand:HI 2 "const_int_operand" "L,P,N,K,LPN")] | |
753 UNSPECV_WRITE_SP))] | |
754 "" | |
755 "@ | |
756 out %B0,%B1\;out %A0,%A1 | |
757 cli\;out %B0,%B1\;sei\;out %A0,%A1 | |
758 in __tmp_reg__,__SREG__\;cli\;out %B0,%B1\;out __SREG__,__tmp_reg__\;out %A0,%A1 | |
759 out %A0,%A1 | |
760 out %A0,%A1\;out %B0,%B1" | |
761 [(set_attr "length" "2,4,5,1,2") | |
762 (set_attr "isa" "no_xmega,no_xmega,no_xmega,*,xmega") | |
0 | 763 (set_attr "cc" "none")]) |
764 | |
765 (define_peephole2 | |
766 [(match_scratch:QI 2 "d") | |
111 | 767 (set (match_operand:ALL2 0 "l_register_operand" "") |
768 (match_operand:ALL2 1 "const_or_immediate_operand" ""))] | |
769 "operands[1] != CONST0_RTX (<MODE>mode)" | |
770 [(parallel [(set (match_dup 0) | |
771 (match_dup 1)) | |
772 (clobber (match_dup 2))])]) | |
0 | 773 |
774 ;; '*' because it is not used in rtl generation, only in above peephole | |
111 | 775 ;; "*reload_inhi" |
776 ;; "*reload_inhq" "*reload_inuhq" | |
777 ;; "*reload_inha" "*reload_inuha" | |
778 (define_insn "*reload_in<mode>" | |
779 [(set (match_operand:ALL2 0 "l_register_operand" "=l") | |
780 (match_operand:ALL2 1 "immediate_operand" "i")) | |
0 | 781 (clobber (match_operand:QI 2 "register_operand" "=&d"))] |
782 "reload_completed" | |
111 | 783 { |
784 return output_reload_inhi (operands, operands[2], NULL); | |
785 } | |
0 | 786 [(set_attr "length" "4") |
111 | 787 (set_attr "adjust_len" "reload_in16") |
788 (set_attr "cc" "clobber")]) | |
789 | |
790 ;; "*movhi" | |
791 ;; "*movhq" "*movuhq" | |
792 ;; "*movha" "*movuha" | |
793 (define_insn "*mov<mode>" | |
794 [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r ,r,m ,d,*r,q,r") | |
795 (match_operand:ALL2 1 "nox_general_operand" "r,Y00,m,r Y00,i,i ,r,q"))] | |
796 "register_operand (operands[0], <MODE>mode) | |
797 || reg_or_0_operand (operands[1], <MODE>mode)" | |
798 { | |
799 return output_movhi (insn, operands, NULL); | |
800 } | |
801 [(set_attr "length" "2,2,6,7,2,6,5,2") | |
802 (set_attr "adjust_len" "mov16") | |
803 (set_attr "cc" "none,none,clobber,clobber,none,clobber,none,none")]) | |
0 | 804 |
805 (define_peephole2 ; movw | |
111 | 806 [(set (match_operand:ALL1 0 "even_register_operand" "") |
807 (match_operand:ALL1 1 "even_register_operand" "")) | |
808 (set (match_operand:ALL1 2 "odd_register_operand" "") | |
809 (match_operand:ALL1 3 "odd_register_operand" ""))] | |
810 "AVR_HAVE_MOVW | |
811 && REGNO (operands[0]) == REGNO (operands[2]) - 1 | |
812 && REGNO (operands[1]) == REGNO (operands[3]) - 1" | |
813 [(set (match_dup 4) | |
814 (match_dup 5))] | |
0 | 815 { |
816 operands[4] = gen_rtx_REG (HImode, REGNO (operands[0])); | |
817 operands[5] = gen_rtx_REG (HImode, REGNO (operands[1])); | |
818 }) | |
819 | |
820 (define_peephole2 ; movw_r | |
111 | 821 [(set (match_operand:ALL1 0 "odd_register_operand" "") |
822 (match_operand:ALL1 1 "odd_register_operand" "")) | |
823 (set (match_operand:ALL1 2 "even_register_operand" "") | |
824 (match_operand:ALL1 3 "even_register_operand" ""))] | |
825 "AVR_HAVE_MOVW | |
826 && REGNO (operands[2]) == REGNO (operands[0]) - 1 | |
827 && REGNO (operands[3]) == REGNO (operands[1]) - 1" | |
828 [(set (match_dup 4) | |
829 (match_dup 5))] | |
0 | 830 { |
831 operands[4] = gen_rtx_REG (HImode, REGNO (operands[2])); | |
832 operands[5] = gen_rtx_REG (HImode, REGNO (operands[3])); | |
833 }) | |
834 | |
111 | 835 ;; For LPM loads from AS1 we split |
836 ;; R = *Z | |
837 ;; to | |
838 ;; R = *Z++ | |
839 ;; Z = Z - sizeof (R) | |
840 ;; | |
841 ;; so that the second instruction can be optimized out. | |
842 | |
843 (define_split ; "split-lpmx" | |
844 [(set (match_operand:HISI 0 "register_operand" "") | |
845 (match_operand:HISI 1 "memory_operand" ""))] | |
846 "reload_completed | |
847 && AVR_HAVE_LPMX" | |
848 [(set (match_dup 0) | |
849 (match_dup 2)) | |
850 (set (match_dup 3) | |
851 (plus:HI (match_dup 3) | |
852 (match_dup 4)))] | |
853 { | |
854 rtx addr = XEXP (operands[1], 0); | |
855 | |
856 if (!avr_mem_flash_p (operands[1]) | |
857 || !REG_P (addr) | |
858 || reg_overlap_mentioned_p (addr, operands[0])) | |
859 { | |
860 FAIL; | |
861 } | |
862 | |
863 operands[2] = replace_equiv_address (operands[1], | |
864 gen_rtx_POST_INC (Pmode, addr)); | |
865 operands[3] = addr; | |
866 operands[4] = gen_int_mode (-GET_MODE_SIZE (<MODE>mode), HImode); | |
867 }) | |
868 | |
869 ;;========================================================================== | |
870 ;; xpointer move (24 bit) | |
871 | |
872 (define_peephole2 ; *reload_inpsi | |
873 [(match_scratch:QI 2 "d") | |
874 (set (match_operand:PSI 0 "l_register_operand" "") | |
875 (match_operand:PSI 1 "immediate_operand" "")) | |
876 (match_dup 2)] | |
877 "operands[1] != const0_rtx | |
878 && operands[1] != constm1_rtx" | |
879 [(parallel [(set (match_dup 0) | |
880 (match_dup 1)) | |
881 (clobber (match_dup 2))])]) | |
882 | |
883 ;; '*' because it is not used in rtl generation. | |
884 (define_insn "*reload_inpsi" | |
885 [(set (match_operand:PSI 0 "register_operand" "=r") | |
886 (match_operand:PSI 1 "immediate_operand" "i")) | |
887 (clobber (match_operand:QI 2 "register_operand" "=&d"))] | |
888 "reload_completed" | |
889 { | |
890 return avr_out_reload_inpsi (operands, operands[2], NULL); | |
891 } | |
892 [(set_attr "length" "6") | |
893 (set_attr "adjust_len" "reload_in24") | |
894 (set_attr "cc" "clobber")]) | |
895 | |
896 (define_insn "*movpsi" | |
897 [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") | |
898 (match_operand:PSI 1 "nox_general_operand" "r,L,Qm,rL,i ,i"))] | |
899 "register_operand (operands[0], PSImode) | |
900 || register_operand (operands[1], PSImode) | |
901 || const0_rtx == operands[1]" | |
902 { | |
903 return avr_out_movpsi (insn, operands, NULL); | |
904 } | |
905 [(set_attr "length" "3,3,8,9,4,10") | |
906 (set_attr "adjust_len" "mov24") | |
907 (set_attr "cc" "none,none,clobber,clobber,none,clobber")]) | |
908 | |
0 | 909 ;;========================================================================== |
910 ;; move double word (32 bit) | |
911 | |
111 | 912 (define_peephole2 ; *reload_insi |
0 | 913 [(match_scratch:QI 2 "d") |
111 | 914 (set (match_operand:ALL4 0 "l_register_operand" "") |
915 (match_operand:ALL4 1 "immediate_operand" "")) | |
0 | 916 (match_dup 2)] |
111 | 917 "operands[1] != CONST0_RTX (<MODE>mode)" |
918 [(parallel [(set (match_dup 0) | |
919 (match_dup 1)) | |
920 (clobber (match_dup 2))])]) | |
0 | 921 |
922 ;; '*' because it is not used in rtl generation. | |
111 | 923 ;; "*reload_insi" |
924 ;; "*reload_insq" "*reload_inusq" | |
925 ;; "*reload_insa" "*reload_inusa" | |
0 | 926 (define_insn "*reload_insi" |
111 | 927 [(set (match_operand:ALL4 0 "register_operand" "=r") |
928 (match_operand:ALL4 1 "immediate_operand" "n Ynn")) | |
0 | 929 (clobber (match_operand:QI 2 "register_operand" "=&d"))] |
930 "reload_completed" | |
111 | 931 { |
932 return output_reload_insisf (operands, operands[2], NULL); | |
933 } | |
0 | 934 [(set_attr "length" "8") |
111 | 935 (set_attr "adjust_len" "reload_in32") |
936 (set_attr "cc" "clobber")]) | |
937 | |
938 | |
939 ;; "*movsi" | |
940 ;; "*movsq" "*movusq" | |
941 ;; "*movsa" "*movusa" | |
942 (define_insn "*mov<mode>" | |
943 [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r ,r ,Qm ,!d,r") | |
944 (match_operand:ALL4 1 "nox_general_operand" "r,Y00,Qm,r Y00,i ,i"))] | |
945 "register_operand (operands[0], <MODE>mode) | |
946 || reg_or_0_operand (operands[1], <MODE>mode)" | |
947 { | |
948 return output_movsisf (insn, operands, NULL); | |
949 } | |
0 | 950 [(set_attr "length" "4,4,8,9,4,10") |
111 | 951 (set_attr "adjust_len" "mov32") |
952 (set_attr "cc" "none,none,clobber,clobber,none,clobber")]) | |
0 | 953 |
954 ;; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff | |
955 ;; move floating point numbers (32 bit) | |
956 | |
957 (define_insn "*movsf" | |
111 | 958 [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") |
959 (match_operand:SF 1 "nox_general_operand" "r,G,Qm,rG,F ,F"))] | |
0 | 960 "register_operand (operands[0], SFmode) |
111 | 961 || reg_or_0_operand (operands[1], SFmode)" |
962 { | |
963 return output_movsisf (insn, operands, NULL); | |
964 } | |
0 | 965 [(set_attr "length" "4,4,8,9,4,10") |
111 | 966 (set_attr "adjust_len" "mov32") |
967 (set_attr "cc" "none,none,clobber,clobber,none,clobber")]) | |
968 | |
969 (define_peephole2 ; *reload_insf | |
970 [(match_scratch:QI 2 "d") | |
971 (set (match_operand:SF 0 "l_register_operand" "") | |
972 (match_operand:SF 1 "const_double_operand" "")) | |
973 (match_dup 2)] | |
974 "operands[1] != CONST0_RTX (SFmode)" | |
975 [(parallel [(set (match_dup 0) | |
976 (match_dup 1)) | |
977 (clobber (match_dup 2))])]) | |
978 | |
979 ;; '*' because it is not used in rtl generation. | |
980 (define_insn "*reload_insf" | |
981 [(set (match_operand:SF 0 "register_operand" "=r") | |
982 (match_operand:SF 1 "const_double_operand" "F")) | |
983 (clobber (match_operand:QI 2 "register_operand" "=&d"))] | |
984 "reload_completed" | |
985 { | |
986 return output_reload_insisf (operands, operands[2], NULL); | |
987 } | |
988 [(set_attr "length" "8") | |
989 (set_attr "adjust_len" "reload_in32") | |
990 (set_attr "cc" "clobber")]) | |
0 | 991 |
992 ;;========================================================================= | |
993 ;; move string (like memcpy) | |
994 | |
995 (define_expand "movmemhi" | |
996 [(parallel [(set (match_operand:BLK 0 "memory_operand" "") | |
111 | 997 (match_operand:BLK 1 "memory_operand" "")) |
998 (use (match_operand:HI 2 "const_int_operand" "")) | |
999 (use (match_operand:HI 3 "const_int_operand" ""))])] | |
1000 "" | |
1001 { | |
1002 if (avr_emit_movmemhi (operands)) | |
1003 DONE; | |
1004 | |
0 | 1005 FAIL; |
111 | 1006 }) |
1007 | |
1008 (define_mode_attr MOVMEM_r_d [(QI "r") | |
1009 (HI "wd")]) | |
1010 | |
1011 ;; $0 : Address Space | |
1012 ;; $1, $2 : Loop register | |
1013 ;; R30 : source address | |
1014 ;; R26 : destination address | |
1015 | |
1016 ;; "movmem_qi" | |
1017 ;; "movmem_hi" | |
1018 (define_insn "movmem_<mode>" | |
1019 [(set (mem:BLK (reg:HI REG_X)) | |
1020 (mem:BLK (reg:HI REG_Z))) | |
1021 (unspec [(match_operand:QI 0 "const_int_operand" "n")] | |
1022 UNSPEC_MOVMEM) | |
1023 (use (match_operand:QIHI 1 "register_operand" "<MOVMEM_r_d>")) | |
1024 (clobber (reg:HI REG_X)) | |
1025 (clobber (reg:HI REG_Z)) | |
1026 (clobber (reg:QI LPM_REGNO)) | |
1027 (clobber (match_operand:QIHI 2 "register_operand" "=1"))] | |
1028 "" | |
1029 { | |
1030 return avr_out_movmem (insn, operands, NULL); | |
1031 } | |
1032 [(set_attr "adjust_len" "movmem") | |
1033 (set_attr "cc" "clobber")]) | |
1034 | |
1035 | |
1036 ;; $0 : Address Space | |
1037 ;; $1 : RAMPZ RAM address | |
1038 ;; R24 : #bytes and loop register | |
1039 ;; R23:Z : 24-bit source address | |
1040 ;; R26 : 16-bit destination address | |
1041 | |
1042 ;; "movmemx_qi" | |
1043 ;; "movmemx_hi" | |
1044 (define_insn "movmemx_<mode>" | |
1045 [(set (mem:BLK (reg:HI REG_X)) | |
1046 (mem:BLK (lo_sum:PSI (reg:QI 23) | |
1047 (reg:HI REG_Z)))) | |
1048 (unspec [(match_operand:QI 0 "const_int_operand" "n")] | |
1049 UNSPEC_MOVMEM) | |
1050 (use (reg:QIHI 24)) | |
1051 (clobber (reg:HI REG_X)) | |
1052 (clobber (reg:HI REG_Z)) | |
1053 (clobber (reg:QI LPM_REGNO)) | |
1054 (clobber (reg:HI 24)) | |
1055 (clobber (reg:QI 23)) | |
1056 (clobber (mem:QI (match_operand:QI 1 "io_address_operand" "n")))] | |
1057 "" | |
1058 "%~call __movmemx_<mode>" | |
1059 [(set_attr "type" "xcall") | |
1060 (set_attr "cc" "clobber")]) | |
1061 | |
1062 | |
1063 ;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 | |
0 | 1064 ;; memset (%0, %2, %1) |
1065 | |
1066 (define_expand "setmemhi" | |
1067 [(parallel [(set (match_operand:BLK 0 "memory_operand" "") | |
111 | 1068 (match_operand 2 "const_int_operand" "")) |
1069 (use (match_operand:HI 1 "const_int_operand" "")) | |
1070 (use (match_operand:HI 3 "const_int_operand" "")) | |
1071 (clobber (match_scratch:HI 5 "")) | |
1072 (clobber (match_dup 4))])] | |
1073 "" | |
1074 { | |
1075 rtx addr0; | |
1076 machine_mode mode; | |
1077 | |
1078 /* If value to set is not zero, use the library routine. */ | |
1079 if (operands[2] != const0_rtx) | |
1080 FAIL; | |
1081 | |
1082 if (!CONST_INT_P (operands[1])) | |
1083 FAIL; | |
1084 | |
1085 mode = u8_operand (operands[1], VOIDmode) ? QImode : HImode; | |
1086 operands[4] = gen_rtx_SCRATCH (mode); | |
1087 operands[1] = copy_to_mode_reg (mode, | |
1088 gen_int_mode (INTVAL (operands[1]), mode)); | |
1089 addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); | |
1090 operands[0] = gen_rtx_MEM (BLKmode, addr0); | |
1091 }) | |
1092 | |
0 | 1093 |
1094 (define_insn "*clrmemqi" | |
1095 [(set (mem:BLK (match_operand:HI 0 "register_operand" "e")) | |
111 | 1096 (const_int 0)) |
0 | 1097 (use (match_operand:QI 1 "register_operand" "r")) |
1098 (use (match_operand:QI 2 "const_int_operand" "n")) | |
1099 (clobber (match_scratch:HI 3 "=0")) | |
1100 (clobber (match_scratch:QI 4 "=&1"))] | |
1101 "" | |
111 | 1102 "0:\;st %a0+,__zero_reg__\;dec %1\;brne 0b" |
0 | 1103 [(set_attr "length" "3") |
1104 (set_attr "cc" "clobber")]) | |
1105 | |
111 | 1106 |
0 | 1107 (define_insn "*clrmemhi" |
1108 [(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e")) | |
111 | 1109 (const_int 0)) |
0 | 1110 (use (match_operand:HI 1 "register_operand" "!w,d")) |
1111 (use (match_operand:HI 2 "const_int_operand" "n,n")) | |
1112 (clobber (match_scratch:HI 3 "=0,0")) | |
1113 (clobber (match_scratch:HI 4 "=&1,&1"))] | |
1114 "" | |
111 | 1115 "@ |
1116 0:\;st %a0+,__zero_reg__\;sbiw %A1,1\;brne 0b | |
1117 0:\;st %a0+,__zero_reg__\;subi %A1,1\;sbci %B1,0\;brne 0b" | |
0 | 1118 [(set_attr "length" "3,4") |
1119 (set_attr "cc" "clobber,clobber")]) | |
1120 | |
1121 (define_expand "strlenhi" | |
111 | 1122 [(set (match_dup 4) |
1123 (unspec:HI [(match_operand:BLK 1 "memory_operand" "") | |
1124 (match_operand:QI 2 "const_int_operand" "") | |
1125 (match_operand:HI 3 "immediate_operand" "")] | |
1126 UNSPEC_STRLEN)) | |
1127 (set (match_dup 4) | |
1128 (plus:HI (match_dup 4) | |
1129 (const_int -1))) | |
1130 (parallel [(set (match_operand:HI 0 "register_operand" "") | |
1131 (minus:HI (match_dup 4) | |
1132 (match_dup 5))) | |
1133 (clobber (scratch:QI))])] | |
1134 "" | |
1135 { | |
1136 rtx addr; | |
1137 if (operands[2] != const0_rtx) | |
1138 FAIL; | |
1139 addr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); | |
1140 operands[1] = gen_rtx_MEM (BLKmode, addr); | |
1141 operands[5] = addr; | |
1142 operands[4] = gen_reg_rtx (HImode); | |
1143 }) | |
0 | 1144 |
1145 (define_insn "*strlenhi" | |
111 | 1146 [(set (match_operand:HI 0 "register_operand" "=e") |
1147 (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "0")) | |
1148 (const_int 0) | |
1149 (match_operand:HI 2 "immediate_operand" "i")] | |
1150 UNSPEC_STRLEN))] | |
1151 "" | |
1152 "0:\;ld __tmp_reg__,%a0+\;tst __tmp_reg__\;brne 0b" | |
0 | 1153 [(set_attr "length" "3") |
1154 (set_attr "cc" "clobber")]) | |
1155 | |
1156 ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
1157 ; add bytes | |
1158 | |
111 | 1159 ;; "addqi3" |
1160 ;; "addqq3" "adduqq3" | |
1161 (define_insn "add<mode>3" | |
1162 [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r") | |
1163 (plus:ALL1 (match_operand:ALL1 1 "register_operand" "%0,0 ,0 ,0 ,0 ,0") | |
1164 (match_operand:ALL1 2 "nonmemory_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))] | |
0 | 1165 "" |
1166 "@ | |
1167 add %0,%2 | |
1168 subi %0,lo8(-(%2)) | |
1169 inc %0 | |
111 | 1170 dec %0 |
1171 inc %0\;inc %0 | |
1172 dec %0\;dec %0" | |
1173 [(set_attr "length" "1,1,1,1,2,2") | |
1174 (set_attr "cc" "set_czn,set_czn,set_vzn,set_vzn,set_vzn,set_vzn")]) | |
1175 | |
1176 ;; "addhi3" | |
1177 ;; "addhq3" "adduhq3" | |
1178 ;; "addha3" "adduha3" | |
1179 (define_expand "add<mode>3" | |
1180 [(set (match_operand:ALL2 0 "register_operand" "") | |
1181 (plus:ALL2 (match_operand:ALL2 1 "register_operand" "") | |
1182 (match_operand:ALL2 2 "nonmemory_or_const_operand" "")))] | |
1183 "" | |
1184 { | |
1185 if (CONST_INT_P (operands[2])) | |
1186 { | |
1187 operands[2] = gen_int_mode (INTVAL (operands[2]), HImode); | |
1188 | |
1189 if (can_create_pseudo_p() | |
1190 && !stack_register_operand (operands[0], HImode) | |
1191 && !stack_register_operand (operands[1], HImode) | |
1192 && !d_register_operand (operands[0], HImode) | |
1193 && !d_register_operand (operands[1], HImode)) | |
1194 { | |
1195 emit_insn (gen_addhi3_clobber (operands[0], operands[1], operands[2])); | |
1196 DONE; | |
1197 } | |
1198 } | |
1199 | |
1200 if (CONST_FIXED_P (operands[2])) | |
1201 { | |
1202 emit_insn (gen_add<mode>3_clobber (operands[0], operands[1], operands[2])); | |
1203 DONE; | |
1204 } | |
1205 }) | |
0 | 1206 |
1207 | |
1208 (define_insn "*addhi3_zero_extend" | |
111 | 1209 [(set (match_operand:HI 0 "register_operand" "=r,*?r") |
1210 (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r ,0")) | |
1211 (match_operand:HI 2 "register_operand" "0 ,r")))] | |
1212 "" | |
1213 "@ | |
1214 add %A0,%1\;adc %B0,__zero_reg__ | |
1215 add %A0,%A2\;mov %B0,%B2\;adc %B0,__zero_reg__" | |
1216 [(set_attr "length" "2,3") | |
0 | 1217 (set_attr "cc" "set_n")]) |
1218 | |
1219 (define_insn "*addhi3_zero_extend1" | |
111 | 1220 [(set (match_operand:HI 0 "register_operand" "=r") |
1221 (plus:HI (match_operand:HI 1 "register_operand" "0") | |
1222 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] | |
1223 "" | |
1224 "add %A0,%2\;adc %B0,__zero_reg__" | |
0 | 1225 [(set_attr "length" "2") |
1226 (set_attr "cc" "set_n")]) | |
1227 | |
111 | 1228 (define_insn "*addhi3.sign_extend1" |
1229 [(set (match_operand:HI 0 "register_operand" "=r") | |
1230 (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r")) | |
1231 (match_operand:HI 2 "register_operand" "0")))] | |
1232 "" | |
1233 { | |
1234 return reg_overlap_mentioned_p (operands[0], operands[1]) | |
1235 ? "mov __tmp_reg__,%1\;add %A0,%1\;adc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;dec %B0" | |
1236 : "add %A0,%1\;adc %B0,__zero_reg__\;sbrc %1,7\;dec %B0"; | |
1237 } | |
1238 [(set_attr "length" "5") | |
1239 (set_attr "cc" "clobber")]) | |
1240 | |
1241 (define_insn "*addhi3_zero_extend.const" | |
1242 [(set (match_operand:HI 0 "register_operand" "=d") | |
1243 (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0")) | |
1244 (match_operand:HI 2 "const_m255_to_m1_operand" "Cn8")))] | |
1245 "" | |
1246 "subi %A0,%n2\;sbc %B0,%B0" | |
1247 [(set_attr "length" "2") | |
1248 (set_attr "cc" "set_czn")]) | |
1249 | |
1250 (define_insn "*usum_widenqihi3" | |
1251 [(set (match_operand:HI 0 "register_operand" "=r") | |
1252 (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0")) | |
1253 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] | |
1254 "" | |
1255 "add %A0,%2\;clr %B0\;rol %B0" | |
1256 [(set_attr "length" "3") | |
1257 (set_attr "cc" "clobber")]) | |
1258 | |
1259 (define_insn "*udiff_widenqihi3" | |
1260 [(set (match_operand:HI 0 "register_operand" "=r") | |
1261 (minus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0")) | |
1262 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] | |
1263 "" | |
1264 "sub %A0,%2\;sbc %B0,%B0" | |
1265 [(set_attr "length" "2") | |
1266 (set_attr "cc" "set_czn")]) | |
1267 | |
1268 (define_insn "*addhi3_sp" | |
1269 [(set (match_operand:HI 1 "stack_register_operand" "=q") | |
1270 (plus:HI (match_operand:HI 2 "stack_register_operand" "q") | |
1271 (match_operand:HI 0 "avr_sp_immediate_operand" "Csp")))] | |
1272 "" | |
1273 { | |
1274 return avr_out_addto_sp (operands, NULL); | |
1275 } | |
1276 [(set_attr "length" "6") | |
1277 (set_attr "adjust_len" "addto_sp")]) | |
1278 | |
1279 ;; "*addhi3" | |
1280 ;; "*addhq3" "*adduhq3" | |
1281 ;; "*addha3" "*adduha3" | |
1282 (define_insn "*add<mode>3" | |
1283 [(set (match_operand:ALL2 0 "register_operand" "=??r,d,!w ,d") | |
1284 (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0,0,0 ,0") | |
1285 (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,s,IJ YIJ,n Ynn")))] | |
1286 "" | |
1287 { | |
1288 return avr_out_plus (insn, operands); | |
1289 } | |
1290 [(set_attr "length" "2") | |
1291 (set_attr "adjust_len" "plus") | |
1292 (set_attr "cc" "plus")]) | |
1293 | |
1294 ;; Adding a constant to NO_LD_REGS might have lead to a reload of | |
1295 ;; that constant to LD_REGS. We don't add a scratch to *addhi3 | |
1296 ;; itself because that insn is special to reload. | |
1297 | |
1298 (define_peephole2 ; addhi3_clobber | |
1299 [(set (match_operand:ALL2 0 "d_register_operand" "") | |
1300 (match_operand:ALL2 1 "const_operand" "")) | |
1301 (set (match_operand:ALL2 2 "l_register_operand" "") | |
1302 (plus:ALL2 (match_dup 2) | |
1303 (match_dup 0)))] | |
1304 "peep2_reg_dead_p (2, operands[0])" | |
1305 [(parallel [(set (match_dup 2) | |
1306 (plus:ALL2 (match_dup 2) | |
1307 (match_dup 1))) | |
1308 (clobber (match_dup 3))])] | |
1309 { | |
1310 operands[3] = simplify_gen_subreg (QImode, operands[0], <MODE>mode, 0); | |
1311 }) | |
1312 | |
1313 ;; Same, but with reload to NO_LD_REGS | |
1314 ;; Combine *reload_inhi with *addhi3 | |
1315 | |
1316 (define_peephole2 ; addhi3_clobber | |
1317 [(parallel [(set (match_operand:ALL2 0 "l_register_operand" "") | |
1318 (match_operand:ALL2 1 "const_operand" "")) | |
1319 (clobber (match_operand:QI 2 "d_register_operand" ""))]) | |
1320 (set (match_operand:ALL2 3 "l_register_operand" "") | |
1321 (plus:ALL2 (match_dup 3) | |
1322 (match_dup 0)))] | |
1323 "peep2_reg_dead_p (2, operands[0])" | |
1324 [(parallel [(set (match_dup 3) | |
1325 (plus:ALL2 (match_dup 3) | |
1326 (match_dup 1))) | |
1327 (clobber (match_dup 2))])]) | |
1328 | |
1329 ;; "addhi3_clobber" | |
1330 ;; "addhq3_clobber" "adduhq3_clobber" | |
1331 ;; "addha3_clobber" "adduha3_clobber" | |
1332 (define_insn "add<mode>3_clobber" | |
1333 [(set (match_operand:ALL2 0 "register_operand" "=!w ,d ,r") | |
1334 (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0 ,0 ,0") | |
1335 (match_operand:ALL2 2 "const_operand" "IJ YIJ,n Ynn,n Ynn"))) | |
1336 (clobber (match_scratch:QI 3 "=X ,X ,&d"))] | |
1337 "" | |
1338 { | |
1339 return avr_out_plus (insn, operands); | |
1340 } | |
1341 [(set_attr "length" "4") | |
1342 (set_attr "adjust_len" "plus") | |
1343 (set_attr "cc" "plus")]) | |
1344 | |
1345 | |
1346 ;; "addsi3" | |
1347 ;; "addsq3" "addusq3" | |
1348 ;; "addsa3" "addusa3" | |
1349 (define_insn "add<mode>3" | |
1350 [(set (match_operand:ALL4 0 "register_operand" "=??r,d ,r") | |
1351 (plus:ALL4 (match_operand:ALL4 1 "register_operand" "%0,0 ,0") | |
1352 (match_operand:ALL4 2 "nonmemory_operand" "r,i ,n Ynn"))) | |
1353 (clobber (match_scratch:QI 3 "=X,X ,&d"))] | |
1354 "" | |
1355 { | |
1356 return avr_out_plus (insn, operands); | |
1357 } | |
1358 [(set_attr "length" "4") | |
1359 (set_attr "adjust_len" "plus") | |
1360 (set_attr "cc" "plus")]) | |
1361 | |
1362 (define_insn "*addpsi3_zero_extend.qi" | |
1363 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1364 (plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r")) | |
1365 (match_operand:PSI 2 "register_operand" "0")))] | |
1366 "" | |
1367 "add %A0,%A1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__" | |
1368 [(set_attr "length" "3") | |
1369 (set_attr "cc" "set_n")]) | |
1370 | |
1371 (define_insn "*addpsi3_zero_extend.hi" | |
1372 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1373 (plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r")) | |
1374 (match_operand:PSI 2 "register_operand" "0")))] | |
1375 "" | |
1376 "add %A0,%A1\;adc %B0,%B1\;adc %C0,__zero_reg__" | |
1377 [(set_attr "length" "3") | |
1378 (set_attr "cc" "set_n")]) | |
1379 | |
1380 (define_insn "*addpsi3_sign_extend.hi" | |
1381 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1382 (plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r")) | |
1383 (match_operand:PSI 2 "register_operand" "0")))] | |
1384 "" | |
1385 "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;sbrc %B1,7\;dec %C0" | |
1386 [(set_attr "length" "5") | |
1387 (set_attr "cc" "set_n")]) | |
0 | 1388 |
1389 (define_insn "*addsi3_zero_extend" | |
111 | 1390 [(set (match_operand:SI 0 "register_operand" "=r") |
1391 (plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) | |
1392 (match_operand:SI 2 "register_operand" "0")))] | |
1393 "" | |
1394 "add %A0,%1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" | |
1395 [(set_attr "length" "4") | |
1396 (set_attr "cc" "set_n")]) | |
1397 | |
1398 (define_insn "*addsi3_zero_extend.hi" | |
1399 [(set (match_operand:SI 0 "register_operand" "=r") | |
1400 (plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) | |
1401 (match_operand:SI 2 "register_operand" "0")))] | |
1402 "" | |
1403 "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" | |
0 | 1404 [(set_attr "length" "4") |
1405 (set_attr "cc" "set_n")]) | |
1406 | |
111 | 1407 (define_insn "addpsi3" |
1408 [(set (match_operand:PSI 0 "register_operand" "=??r,d ,d,r") | |
1409 (plus:PSI (match_operand:PSI 1 "register_operand" "%0,0 ,0,0") | |
1410 (match_operand:PSI 2 "nonmemory_operand" "r,s ,n,n"))) | |
1411 (clobber (match_scratch:QI 3 "=X,X ,X,&d"))] | |
1412 "" | |
1413 { | |
1414 return avr_out_plus (insn, operands); | |
1415 } | |
1416 [(set_attr "length" "3") | |
1417 (set_attr "adjust_len" "plus") | |
1418 (set_attr "cc" "plus")]) | |
1419 | |
1420 (define_insn "subpsi3" | |
1421 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1422 (minus:PSI (match_operand:PSI 1 "register_operand" "0") | |
1423 (match_operand:PSI 2 "register_operand" "r")))] | |
1424 "" | |
1425 "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2" | |
1426 [(set_attr "length" "3") | |
1427 (set_attr "cc" "set_czn")]) | |
1428 | |
1429 (define_insn "*subpsi3_zero_extend.qi" | |
1430 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1431 (minus:PSI (match_operand:SI 1 "register_operand" "0") | |
1432 (zero_extend:PSI (match_operand:QI 2 "register_operand" "r"))))] | |
1433 "" | |
1434 "sub %A0,%2\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__" | |
1435 [(set_attr "length" "3") | |
1436 (set_attr "cc" "set_czn")]) | |
1437 | |
1438 (define_insn "*subpsi3_zero_extend.hi" | |
1439 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1440 (minus:PSI (match_operand:PSI 1 "register_operand" "0") | |
1441 (zero_extend:PSI (match_operand:HI 2 "register_operand" "r"))))] | |
1442 "" | |
1443 "sub %A0,%2\;sbc %B0,%B2\;sbc %C0,__zero_reg__" | |
1444 [(set_attr "length" "3") | |
1445 (set_attr "cc" "set_czn")]) | |
1446 | |
1447 (define_insn "*subpsi3_sign_extend.hi" | |
1448 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1449 (minus:PSI (match_operand:PSI 1 "register_operand" "0") | |
1450 (sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))] | |
1451 "" | |
1452 "sub %A0,%A2\;sbc %B0,%B2\;sbc %C0,__zero_reg__\;sbrc %B2,7\;inc %C0" | |
1453 [(set_attr "length" "5") | |
1454 (set_attr "cc" "set_czn")]) | |
1455 | |
0 | 1456 ;----------------------------------------------------------------------------- |
1457 ; sub bytes | |
111 | 1458 |
1459 ;; "subqi3" | |
1460 ;; "subqq3" "subuqq3" | |
1461 (define_insn "sub<mode>3" | |
1462 [(set (match_operand:ALL1 0 "register_operand" "=??r,d ,r ,r ,r ,r") | |
1463 (minus:ALL1 (match_operand:ALL1 1 "register_operand" "0,0 ,0 ,0 ,0 ,0") | |
1464 (match_operand:ALL1 2 "nonmemory_or_const_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))] | |
0 | 1465 "" |
1466 "@ | |
1467 sub %0,%2 | |
111 | 1468 subi %0,lo8(%2) |
1469 dec %0 | |
1470 inc %0 | |
1471 dec %0\;dec %0 | |
1472 inc %0\;inc %0" | |
1473 [(set_attr "length" "1,1,1,1,2,2") | |
1474 (set_attr "cc" "set_czn,set_czn,set_vzn,set_vzn,set_vzn,set_vzn")]) | |
1475 | |
1476 ;; "subhi3" | |
1477 ;; "subhq3" "subuhq3" | |
1478 ;; "subha3" "subuha3" | |
1479 (define_insn "sub<mode>3" | |
1480 [(set (match_operand:ALL2 0 "register_operand" "=??r,d ,*r") | |
1481 (minus:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,0") | |
1482 (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,i Ynn,Ynn"))) | |
1483 (clobber (match_scratch:QI 3 "=X,X ,&d"))] | |
1484 "" | |
1485 { | |
1486 return avr_out_plus (insn, operands); | |
1487 } | |
1488 [(set_attr "adjust_len" "plus") | |
1489 (set_attr "cc" "plus")]) | |
0 | 1490 |
1491 (define_insn "*subhi3_zero_extend1" | |
111 | 1492 [(set (match_operand:HI 0 "register_operand" "=r") |
1493 (minus:HI (match_operand:HI 1 "register_operand" "0") | |
1494 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] | |
1495 "" | |
1496 "sub %A0,%2\;sbc %B0,__zero_reg__" | |
0 | 1497 [(set_attr "length" "2") |
111 | 1498 (set_attr "cc" "set_czn")]) |
1499 | |
1500 (define_insn "*subhi3.sign_extend2" | |
1501 [(set (match_operand:HI 0 "register_operand" "=r") | |
1502 (minus:HI (match_operand:HI 1 "register_operand" "0") | |
1503 (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))] | |
1504 "" | |
1505 { | |
1506 return reg_overlap_mentioned_p (operands[0], operands[2]) | |
1507 ? "mov __tmp_reg__,%2\;sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;inc %B0" | |
1508 : "sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc %2,7\;inc %B0"; | |
1509 } | |
1510 [(set_attr "length" "5") | |
1511 (set_attr "cc" "clobber")]) | |
1512 | |
1513 ;; "subsi3" | |
1514 ;; "subsq3" "subusq3" | |
1515 ;; "subsa3" "subusa3" | |
1516 (define_insn "sub<mode>3" | |
1517 [(set (match_operand:ALL4 0 "register_operand" "=??r,d ,r") | |
1518 (minus:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,0") | |
1519 (match_operand:ALL4 2 "nonmemory_or_const_operand" "r,n Ynn,Ynn"))) | |
1520 (clobber (match_scratch:QI 3 "=X,X ,&d"))] | |
1521 "" | |
1522 { | |
1523 return avr_out_plus (insn, operands); | |
1524 } | |
1525 [(set_attr "adjust_len" "plus") | |
1526 (set_attr "cc" "plus")]) | |
0 | 1527 |
1528 (define_insn "*subsi3_zero_extend" | |
111 | 1529 [(set (match_operand:SI 0 "register_operand" "=r") |
1530 (minus:SI (match_operand:SI 1 "register_operand" "0") | |
1531 (zero_extend:SI (match_operand:QI 2 "register_operand" "r"))))] | |
1532 "" | |
1533 "sub %A0,%2\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__" | |
0 | 1534 [(set_attr "length" "4") |
111 | 1535 (set_attr "cc" "set_czn")]) |
1536 | |
1537 (define_insn "*subsi3_zero_extend.hi" | |
1538 [(set (match_operand:SI 0 "register_operand" "=r") | |
1539 (minus:SI (match_operand:SI 1 "register_operand" "0") | |
1540 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
1541 "" | |
1542 "sub %A0,%2\;sbc %B0,%B2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__" | |
1543 [(set_attr "length" "4") | |
1544 (set_attr "cc" "set_czn")]) | |
0 | 1545 |
1546 ;****************************************************************************** | |
1547 ; mul | |
1548 | |
1549 (define_expand "mulqi3" | |
1550 [(set (match_operand:QI 0 "register_operand" "") | |
111 | 1551 (mult:QI (match_operand:QI 1 "register_operand" "") |
1552 (match_operand:QI 2 "register_operand" "")))] | |
1553 "" | |
1554 { | |
1555 if (!AVR_HAVE_MUL) | |
1556 { | |
1557 emit_insn (gen_mulqi3_call (operands[0], operands[1], operands[2])); | |
1558 DONE; | |
1559 } | |
1560 }) | |
0 | 1561 |
1562 (define_insn "*mulqi3_enh" | |
1563 [(set (match_operand:QI 0 "register_operand" "=r") | |
111 | 1564 (mult:QI (match_operand:QI 1 "register_operand" "r") |
1565 (match_operand:QI 2 "register_operand" "r")))] | |
0 | 1566 "AVR_HAVE_MUL" |
1567 "mul %1,%2 | |
1568 mov %0,r0 | |
1569 clr r1" | |
1570 [(set_attr "length" "3") | |
1571 (set_attr "cc" "clobber")]) | |
1572 | |
1573 (define_expand "mulqi3_call" | |
1574 [(set (reg:QI 24) (match_operand:QI 1 "register_operand" "")) | |
1575 (set (reg:QI 22) (match_operand:QI 2 "register_operand" "")) | |
1576 (parallel [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22))) | |
111 | 1577 (clobber (reg:QI 22))]) |
0 | 1578 (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))] |
1579 "" | |
111 | 1580 { |
1581 avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); | |
1582 }) | |
0 | 1583 |
1584 (define_insn "*mulqi3_call" | |
1585 [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22))) | |
1586 (clobber (reg:QI 22))] | |
1587 "!AVR_HAVE_MUL" | |
1588 "%~call __mulqi3" | |
1589 [(set_attr "type" "xcall") | |
1590 (set_attr "cc" "clobber")]) | |
1591 | |
111 | 1592 ;; "umulqi3_highpart" |
1593 ;; "smulqi3_highpart" | |
1594 (define_insn "<extend_su>mulqi3_highpart" | |
1595 [(set (match_operand:QI 0 "register_operand" "=r") | |
1596 (truncate:QI | |
1597 (lshiftrt:HI (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "<mul_r_d>")) | |
1598 (any_extend:HI (match_operand:QI 2 "register_operand" "<mul_r_d>"))) | |
1599 (const_int 8))))] | |
0 | 1600 "AVR_HAVE_MUL" |
111 | 1601 "mul<extend_s> %1,%2 |
1602 mov %0,r1 | |
1603 clr __zero_reg__" | |
1604 [(set_attr "length" "3") | |
1605 (set_attr "cc" "clobber")]) | |
1606 | |
1607 | |
1608 ;; Used when expanding div or mod inline for some special values | |
1609 (define_insn "*subqi3.ashiftrt7" | |
1610 [(set (match_operand:QI 0 "register_operand" "=r") | |
1611 (minus:QI (match_operand:QI 1 "register_operand" "0") | |
1612 (ashiftrt:QI (match_operand:QI 2 "register_operand" "r") | |
1613 (const_int 7))))] | |
1614 "" | |
1615 "sbrc %2,7\;inc %0" | |
1616 [(set_attr "length" "2") | |
1617 (set_attr "cc" "clobber")]) | |
1618 | |
1619 (define_insn "*addqi3.lt0" | |
1620 [(set (match_operand:QI 0 "register_operand" "=r") | |
1621 (plus:QI (lt:QI (match_operand:QI 1 "register_operand" "r") | |
1622 (const_int 0)) | |
1623 (match_operand:QI 2 "register_operand" "0")))] | |
1624 "" | |
1625 "sbrc %1,7\;inc %0" | |
1626 [(set_attr "length" "2") | |
1627 (set_attr "cc" "clobber")]) | |
1628 | |
1629 (define_insn "*addhi3.lt0" | |
1630 [(set (match_operand:HI 0 "register_operand" "=w,r") | |
1631 (plus:HI (lt:HI (match_operand:QI 1 "register_operand" "r,r") | |
1632 (const_int 0)) | |
1633 (match_operand:HI 2 "register_operand" "0,0"))) | |
1634 (clobber (match_scratch:QI 3 "=X,&1"))] | |
1635 "" | |
1636 "@ | |
1637 sbrc %1,7\;adiw %0,1 | |
1638 lsl %1\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__" | |
1639 [(set_attr "length" "2,3") | |
1640 (set_attr "cc" "clobber")]) | |
1641 | |
1642 (define_insn "*addpsi3.lt0" | |
1643 [(set (match_operand:PSI 0 "register_operand" "=r") | |
1644 (plus:PSI (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "r") | |
1645 (const_int 23)) | |
1646 (match_operand:PSI 2 "register_operand" "0")))] | |
1647 "" | |
1648 "mov __tmp_reg__,%C1\;lsl __tmp_reg__ | |
1649 adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__" | |
1650 [(set_attr "length" "5") | |
1651 (set_attr "cc" "clobber")]) | |
1652 | |
1653 (define_insn "*addsi3.lt0" | |
1654 [(set (match_operand:SI 0 "register_operand" "=r") | |
1655 (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") | |
1656 (const_int 31)) | |
1657 (match_operand:SI 2 "register_operand" "0")))] | |
1658 "" | |
1659 "mov __tmp_reg__,%D1\;lsl __tmp_reg__ | |
1660 adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" | |
1661 [(set_attr "length" "6") | |
1662 (set_attr "cc" "clobber")]) | |
1663 | |
1664 (define_insn "*umulqihi3.call" | |
1665 [(set (reg:HI 24) | |
1666 (mult:HI (zero_extend:HI (reg:QI 22)) | |
1667 (zero_extend:HI (reg:QI 24)))) | |
1668 (clobber (reg:QI 21)) | |
1669 (clobber (reg:HI 22))] | |
1670 "!AVR_HAVE_MUL" | |
1671 "%~call __umulqihi3" | |
1672 [(set_attr "type" "xcall") | |
1673 (set_attr "cc" "clobber")]) | |
1674 | |
1675 ;; "umulqihi3" | |
1676 ;; "mulqihi3" | |
1677 (define_insn "<extend_u>mulqihi3" | |
1678 [(set (match_operand:HI 0 "register_operand" "=r") | |
1679 (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "<mul_r_d>")) | |
1680 (any_extend:HI (match_operand:QI 2 "register_operand" "<mul_r_d>"))))] | |
1681 "AVR_HAVE_MUL" | |
1682 "mul<extend_s> %1,%2 | |
0 | 1683 movw %0,r0 |
111 | 1684 clr __zero_reg__" |
1685 [(set_attr "length" "3") | |
1686 (set_attr "cc" "clobber")]) | |
1687 | |
1688 (define_insn "usmulqihi3" | |