1 ;;- Machine description Acorn RISC Machine for GNU compiler
2 ;; Copyright (C) 1991 Free Software Foundation, Inc.
3 ;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
4 ;; and Martin Simmons (@harleqn.co.uk).
6 ;; This file is part of GNU CC.
8 ;; GNU CC 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 2, or (at your option)
13 ;; GNU CC 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.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU CC; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
24 ;; Every template must be output by arm_output_asm_insn, since this keeps
25 ;; track of the offset of labels within the text segment. This is needed to
26 ;; to be able to (correctly) output instructions for loading a value from a
27 ;; function's constant pool, since different instructions are needed when the
28 ;; constant pool is more than 4095 bytes away from the PC.
33 [(set (match_operand:DI 0 "di_operand" "=r")
34 (plus:DI (match_operand:DI 1 "di_operand" "%r")
35 (match_operand:DI 2 "di_operand" "r")))]
38 arm_output_asm_insn (\"adds\\t%0, %1, %2\", operands);
39 return (arm_output_asm_insn (\"adc\\t%R0, %R1, %R2\", operands));
43 [(set (match_operand:SI 0 "register_operand" "=r,r")
44 (plus:SI (match_operand:SI 1 "register_operand" "r,r")
45 (match_operand:SI 2 "general_operand" "r,n")))]
48 switch (which_alternative)
51 return (arm_output_asm_insn (\"add\\t%0, %1, %2\", operands));
53 return (output_add_immediate (operands));
58 [(set (match_operand:SF 0 "register_operand" "=f")
59 (plus:SF (match_operand:SF 1 "register_operand" "f")
60 (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
63 return (arm_output_asm_insn (\"adfs\\t%0, %1, %2\", operands));
67 [(set (match_operand:DF 0 "register_operand" "=f")
68 (plus:DF (match_operand:DF 1 "register_operand" "f")
69 (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
72 return (arm_output_asm_insn (\"adfd\\t%0, %1, %2\", operands));
76 [(set (match_operand:DI 0 "di_operand" "=r")
77 (minus:DI (match_operand:DI 1 "di_operand" "%r")
78 (match_operand:DI 2 "di_operand" "r")))]
81 arm_output_asm_insn (\"subs\\t%0, %1, %2\", operands);
82 return (arm_output_asm_insn (\"sbc\\t%R0, %R1, %R2\", operands));
86 [(set (match_operand:SI 0 "register_operand" "=r,r,r")
87 (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,r,I")
88 (match_operand:SI 2 "general_operand" "r,n,r")))]
91 switch (which_alternative)
94 return (arm_output_asm_insn (\"sub\\t%0, %1, %2\", operands));
96 operands[2] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[2]));
97 return (output_add_immediate (operands));
99 return (arm_output_asm_insn (\"rsb\\t%0, %2, %1\", operands));
103 (define_insn "subsf3"
104 [(set (match_operand:SF 0 "register_operand" "=f,f")
105 (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
106 (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
109 switch (which_alternative)
112 return (arm_output_asm_insn (\"sufs\\t%0, %1, %2\", operands));
114 return (arm_output_asm_insn (\"rsfs\\t%0, %2, %1\", operands));
118 (define_insn "subdf3"
119 [(set (match_operand:DF 0 "register_operand" "=f,f")
120 (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
121 (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
124 switch (which_alternative)
127 return (arm_output_asm_insn (\"sufd\\t%0, %1, %2\", operands));
129 return (arm_output_asm_insn (\"rsfd\\t%0, %2, %1\", operands));
133 ;; Multiplication insns
135 ;; The `&' is too strict, but at least generates correct code.
136 (define_insn "mulsi3"
137 [(set (match_operand:SI 0 "register_operand" "=&r")
138 (mult:SI (match_operand:SI 1 "register_operand" "%r")
139 (match_operand:SI 2 "register_operand" "r")))]
142 if (REGNO (operands[0]) == REGNO (operands[1]))
143 return (arm_output_asm_insn (\"mul\\t%0, %2, %1\", operands));
145 return (arm_output_asm_insn (\"mul\\t%0, %1, %2\", operands));
148 ;; Unnamed templates to match MLA instruction.
151 [(set (match_operand:SI 0 "register_operand" "=&r")
153 (mult:SI (match_operand:SI 1 "register_operand" "%r")
154 (match_operand:SI 2 "register_operand" "r"))
155 (match_operand:SI 3 "register_operand" "r")))]
158 if (REGNO (operands[0]) == REGNO (operands[1]))
159 return (arm_output_asm_insn (\"mla\\t%0, %2, %1, %3\", operands));
161 return (arm_output_asm_insn (\"mla\\t%0, %1, %2, %3\", operands));
165 [(set (match_operand:SI 0 "register_operand" "=&r")
167 (match_operand:SI 3 "register_operand" "r")
168 (mult:SI (match_operand:SI 1 "register_operand" "%r")
169 (match_operand:SI 2 "register_operand" "r"))))]
172 if (REGNO (operands[0]) == REGNO (operands[1]))
173 return (arm_output_asm_insn (\"mla\\t%0, %2, %1, %3\", operands));
175 return (arm_output_asm_insn (\"mla\\t%0, %1, %2, %3\", operands));
178 (define_insn "mulsf3"
179 [(set (match_operand:SF 0 "register_operand" "=f")
180 (mult:SF (match_operand:SF 1 "register_operand" "f")
181 (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
183 "*return (arm_output_asm_insn (\"mufs\\t%0, %1, %2\", operands));")
185 (define_insn "muldf3"
186 [(set (match_operand:DF 0 "register_operand" "=f")
187 (mult:DF (match_operand:DF 1 "register_operand" "f")
188 (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
191 return (arm_output_asm_insn (\"mufd\\t%0, %1, %2\", operands));
196 (define_insn "divsf3"
197 [(set (match_operand:SF 0 "register_operand" "=f,f")
198 (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
199 (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
202 switch (which_alternative)
205 return (arm_output_asm_insn (\"dvfs\\t%0, %1, %2\", operands));
207 return (arm_output_asm_insn (\"rdfs\\t%0, %2, %1\", operands));
211 (define_insn "divdf3"
212 [(set (match_operand:DF 0 "register_operand" "=f,f")
213 (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
214 (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
217 switch (which_alternative)
220 return (arm_output_asm_insn (\"dvfd\\t%0, %1, %2\", operands));
222 return (arm_output_asm_insn (\"rdfd\\t%0, %2, %1\", operands));
228 (define_insn "modsf3"
229 [(set (match_operand:SF 0 "register_operand" "=f")
230 (mod:SF (match_operand:SF 1 "register_operand" "f")
231 (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
234 return (arm_output_asm_insn (\"rmfs\\t%0, %1, %2\", operands));
237 (define_insn "moddf3"
238 [(set (match_operand:DF 0 "register_operand" "=f")
239 (mod:DF (match_operand:DF 1 "register_operand" "f")
240 (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
243 return (arm_output_asm_insn (\"rmfd\\t%0, %1, %2\", operands));
246 ;; Boolean and,ior,xor insns
248 (define_insn "anddi3"
249 [(set (match_operand:DI 0 "di_operand" "=r")
250 (and:DI (match_operand:DI 1 "di_operand" "%r")
251 (match_operand:DI 2 "di_operand" "r")))]
254 arm_output_asm_insn (\"and\\t%0, %1, %2\", operands);
255 return (arm_output_asm_insn (\"and\\t%R0, %R1, %R2\", operands));
258 (define_insn "andsi3"
259 [(set (match_operand:SI 0 "register_operand" "=r")
260 (and:SI (match_operand:SI 1 "register_operand" "r")
261 (match_operand:SI 2 "arm_rhs_operand" "rI")))]
264 return (arm_output_asm_insn (\"and\\t%0, %1, %2\", operands));
267 (define_insn "andcbsi3"
268 [(set (match_operand:SI 0 "register_operand" "=r")
269 (and:SI (match_operand:SI 1 "register_operand" "r")
270 (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))))]
273 return (arm_output_asm_insn (\"bic\\t%0, %1, %2\", operands));
276 (define_insn "iordi3"
277 [(set (match_operand:DI 0 "di_operand" "=r")
278 (ior:DI (match_operand:DI 1 "di_operand" "%r")
279 (match_operand:DI 2 "di_operand" "r")))]
282 arm_output_asm_insn (\"orr\\t%0, %1, %2\", operands);
283 return (arm_output_asm_insn (\"orr\\t%R0, %R1, %R2\", operands));
286 (define_insn "iorsi3"
287 [(set (match_operand:SI 0 "register_operand" "=r,r")
288 (ior:SI (match_operand:SI 1 "register_operand" "r,r")
289 (match_operand:SI 2 "nonmemory_operand" "r,n")))]
292 switch (which_alternative)
295 return (arm_output_asm_insn (\"orr\\t%0, %1, %2\", operands));
297 return (output_multi_immediate (operands,
298 \"orr\\t%0, %1, %2\", \"orr\\t%0, %0, %2\",
299 2, INTVAL (operands[2])));
303 (define_insn "xorsi3"
304 [(set (match_operand:SI 0 "register_operand" "=r,r")
305 (xor:SI (match_operand:SI 1 "register_operand" "r,r")
306 (match_operand:SI 2 "nonmemory_operand" "r,n")))]
309 switch (which_alternative)
312 return (arm_output_asm_insn (\"eor\\t%0, %1, %2\", operands));
314 return (output_multi_immediate (operands,
315 \"eor\\t%0, %1, %2\", \"eor\\t%0, %0, %2\",
316 2, INTVAL (operands[2])));
320 ;; Shift and rotation insns
322 (define_insn "ashlsi3"
323 [(set (match_operand:SI 0 "register_operand" "=r")
324 (ashift:SI (match_operand:SI 1 "register_operand" "r")
325 (match_operand:SI 2 "general_operand" "rn")))]
328 return (output_shifted_move (ASHIFT, operands));
331 (define_insn "ashrsi3"
332 [(set (match_operand:SI 0 "register_operand" "=r")
333 (ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
334 (match_operand:SI 2 "general_operand" "rn")))]
337 return (output_shifted_move (ASHIFTRT, operands));
340 ;; lshlsi3 is not defined because shift counts cannot be negative
341 ;; An unnamed pattern is needed for expansion of zero_extend.
344 [(set (match_operand:SI 0 "register_operand" "=r")
345 (lshift:SI (match_operand:SI 1 "register_operand" "r")
346 (match_operand:SI 2 "general_operand" "rn")))]
349 return (output_shifted_move (LSHIFT, operands));
352 (define_insn "lshrsi3"
353 [(set (match_operand:SI 0 "register_operand" "=r")
354 (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
355 (match_operand:SI 2 "general_operand" "rn")))]
358 return (output_shifted_move (LSHIFTRT, operands));
361 ;; rotlsi3 is not defined yet to see what happens
363 (define_insn "rotrsi3"
364 [(set (match_operand:SI 0 "register_operand" "=r,r")
365 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
366 (match_operand:SI 2 "general_operand" "r,n")))]
369 switch (which_alternative)
372 return (arm_output_asm_insn (\"mov\\t%0, %1,ror %2\", operands));
374 if (INTVAL(operands[2]) > 31)
375 operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 32);
376 return (arm_output_asm_insn (\"mov\\t%0, %1,ror%2\", operands));
380 ;; Unary arithmetic insns
382 (define_insn "negdi2"
383 [(set (match_operand:DI 0 "di_operand" "=r")
384 (neg:DI (match_operand:DI 1 "di_operand" "r")))]
387 arm_output_asm_insn (\"rsb\\t%0, %1, #0\", operands);
388 return (arm_output_asm_insn (\"rsc\\t%R0, %R1, #0\", operands));
391 (define_insn "negsi2"
392 [(set (match_operand:SI 0 "register_operand" "=r")
393 (neg:SI (match_operand:SI 1 "register_operand" "r")))]
396 return (arm_output_asm_insn (\"rsb\\t%0, %1, #0\", operands));
399 (define_insn "negsf2"
400 [(set (match_operand:SF 0 "register_operand" "=f")
401 (neg:SF (match_operand:SF 1 "register_operand" "f")))]
404 return (arm_output_asm_insn (\"mnfs\\t%0, %1\", operands));
407 (define_insn "negdf2"
408 [(set (match_operand:DF 0 "register_operand" "=f")
409 (neg:DF (match_operand:DF 1 "register_operand" "f")))]
412 return (arm_output_asm_insn (\"mnfd\\t%0, %1\", operands));
415 (define_insn "abssf2"
416 [(set (match_operand:SF 0 "register_operand" "=f")
417 (abs:SF (match_operand:SF 1 "register_operand" "f")))]
420 return (arm_output_asm_insn (\"abss\\t%0, %1\", operands));
423 (define_insn "absdf2"
424 [(set (match_operand:DF 0 "register_operand" "=f")
425 (abs:DF (match_operand:DF 1 "register_operand" "f")))]
428 return (arm_output_asm_insn (\"absd\\t%0, %1\", operands));
431 (define_insn "sqrtsf2"
432 [(set (match_operand:SF 0 "register_operand" "=f")
433 (sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
436 return (arm_output_asm_insn (\"sqts\\t%0, %1\", operands));
439 (define_insn "sqrtdf2"
440 [(set (match_operand:DF 0 "register_operand" "=f")
441 (sqrt:DF (match_operand:DF 1 "register_operand" "f")))]
444 return (arm_output_asm_insn (\"sqtd\\t%0, %1\", operands));
447 (define_insn "one_cmplsi2"
448 [(set (match_operand:SI 0 "register_operand" "=r")
449 (not:SI (match_operand:SI 1 "register_operand" "r")))]
452 return (arm_output_asm_insn (\"mvn\\t%0, %1\", operands));
455 ;; Fixed <--> Floating conversion insns
457 (define_insn "floatsisf2"
458 [(set (match_operand:SF 0 "register_operand" "=f")
459 (float:SF (match_operand:SI 1 "register_operand" "r")))]
462 return (arm_output_asm_insn (\"flts\\t%0, %1\", operands));
465 (define_insn "floatsidf2"
466 [(set (match_operand:DF 0 "register_operand" "=f")
467 (float:DF (match_operand:SI 1 "register_operand" "r")))]
470 return (arm_output_asm_insn (\"fltd\\t%0, %1\", operands));
475 (define_insn "truncdfsf2"
476 [(set (match_operand:SF 0 "register_operand" "=f")
478 (match_operand:DF 1 "register_operand" "f")))]
481 return (arm_output_asm_insn (\"mvfs\\t%0, %1\", operands));
484 ;; Zero extension instructions.
486 (define_expand "zero_extendhisi2"
487 [(set (match_operand:SI 0 "register_operand" "")
488 (ashift:SI (match_operand:HI 1 "register_operand" "")
491 (lshiftrt:SI (match_dup 0) (const_int 16)))]
494 if (GET_CODE (operands[1]) == SUBREG)
495 operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]),
496 SUBREG_WORD (operands[1]));
498 operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0);
501 (define_insn "zero_extendqihi2"
502 [(set (match_operand:HI 0 "register_operand" "=r")
504 (match_operand:QI 1 "register_operand" "r")))]
507 return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ zero_extendqihi2\", operands));
510 (define_insn "zero_extendqisi2"
511 [(set (match_operand:SI 0 "register_operand" "=r,r")
513 (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
516 switch (which_alternative)
519 return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ zero_extendqisi2\", operands));
521 return (arm_output_asm_insn (\"ldrb\\t%0, %1\\t@ zero_extendqisi2\", operands));
525 ;; Note that the ones starting from HImode come before those for QImode so
526 ;; that a constant operand will match HImode, not QImode.
528 (define_expand "extendhisi2"
529 [(set (match_operand:SI 0 "register_operand" "")
530 (ashift:SI (match_operand:HI 1 "register_operand" "")
533 (ashiftrt:SI (match_dup 0) (const_int 16)))]
536 if (GET_CODE (operands[1]) == SUBREG)
537 operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]),
538 SUBREG_WORD (operands[1]));
540 operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0);
543 ;; XXX Is this ever used?
545 (define_insn "extendqihi2"
546 [(set (match_operand:HI 0 "register_operand" "=r")
548 (match_operand:QI 1 "register_operand" "r")))]
551 arm_output_asm_insn (\"mov\\t%0, %1, lsl#24\\t@ extendqihi\", operands);
552 return (arm_output_asm_insn (\"mov\\t%0, %0, asr#24\", operands));
556 (define_expand "extendqisi2"
557 [(set (match_operand:SI 0 "register_operand" "")
558 (ashift:SI (match_operand:QI 1 "register_operand" "")
561 (ashiftrt:SI (match_dup 0) (const_int 24)))]
564 if (GET_CODE (operands[1]) == SUBREG)
565 operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]),
566 SUBREG_WORD(operands[1]));
568 operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0);
571 (define_insn "extendsfdf2"
572 [(set (match_operand:DF 0 "register_operand" "=f")
573 (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
576 return (arm_output_asm_insn (\"mvfd\\t%0, %1\", operands));
579 ;; Move insns (including loads and stores)
581 ;; XXX Just some ideas about movti.
583 ;;(define_expand "loadti"
584 ;; [(set (match_operand:TI 0 "register_operand" "")
585 ;; (mem:TI (match_operand:SI 1 "address_operand" "")))]
588 ;;(define_expand "storeti"
589 ;; [(set (mem:TI (match_operand:TI 0 "address_operand" ""))
590 ;; (match_operand:TI 1 "register_operand" ""))]
593 ;;(define_expand "movti"
594 ;; [(set (match_operand:TI 0 "general_operand" "")
595 ;; (match_operand:TI 1 "general_operand" ""))]
601 ;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
602 ;; operands[1] = copy_to_reg (operands[1]);
603 ;; if (GET_CODE (operands[0]) == MEM)
604 ;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]);
605 ;; else if (GET_CODE (operands[1]) == MEM)
606 ;; insn = gen_loadti (operands[0], XEXP (operands[1], 0));
614 ;; Recognise garbage generated above.
617 ;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m")
618 ;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))]
622 ;; register mem = (which_alternative < 3);
623 ;; register char *template;
625 ;; operands[mem] = XEXP (operands[mem], 0);
626 ;; switch (which_alternative)
628 ;; case 0: template = \"ldmdb\\t%1!, %M0\"; break;
629 ;; case 1: template = \"ldmia\\t%1!, %M0\"; break;
630 ;; case 2: template = \"ldmia\\t%1, %M0\"; break;
631 ;; case 3: template = \"stmdb\\t%0!, %M1\"; break;
632 ;; case 4: template = \"stmia\\t%0!, %M1\"; break;
633 ;; case 5: template = \"stmia\\t%0, %M1\"; break;
635 ;; return (arm_output_asm_insn (template, operands));
640 [(set (match_operand:DI 0 "di_operand" "=r,r,r,o,r")
641 (match_operand:DI 1 "di_operand" "r,n,o,r,F"))]
644 return (output_move_double (operands));
648 [(set (match_operand:SI 0 "general_operand" "=r,r,r,m")
649 (match_operand:SI 1 "general_operand" "r,n,m,r"))]
652 switch (which_alternative)
655 return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
657 return (output_mov_immediate (operands));
659 if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
660 && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0)))
661 return (arm_output_llc (operands));
663 return (arm_output_asm_insn (\"ldr\\t%0, %1\", operands));
665 return (arm_output_asm_insn (\"str\\t%1, %0\", operands));
669 ;; XXX The movhi stuff isn't as correct or as nice as it could be...
671 ;; Subroutine to load a half word into a register from memory.
672 ;; Operand 0 is the destination register (HImode).
673 ;; Operand 1 is the source address (SImode).
674 ;; Operand 2 is a temporary (SImode).
676 ;;(define_expand "loadhi"
677 ;; [;; load the whole word (ARM realigns it if not on word boundary)
678 ;; (set (match_operand:SI 2 "register_operand" "")
679 ;; (mem:SI (match_operand:SI 1 "address_operand" "")))
680 ;; ;; quietly forget the upper 16 bits
681 ;; (set (match_operand:HI 0 "register_operand" "")
682 ;; (subreg:HI (match_dup 2) 0))]
687 ;; Load op0 from mem:op1. Subroutine in case we're reloading and the normal
688 ;; loadhi is not allowed.
690 ;;(define_expand "reloadhi"
692 ;; (mem:SI (match_operand:SI 1 "address_operand" "")))
693 ;; (set (match_operand:HI 0 "register_operand" "")
694 ;; (subreg:HI (reg:SI 10) 0))]
697 ;; Store op0 into mem:op1. Subroutine in case we're reloading and the normal
698 ;; storehi is not allowed.
700 (define_expand "restorehi"
701 [(set (mem:QI (match_operand:SI 1 "address_operand" ""))
702 (truncate:QI (match_operand:HI 0 "register_operand" "")))
704 (ashiftrt:HI (match_dup 0) (const_int 8)))
705 (set (mem:QI (plus:SI (match_dup 1) (const_int 1)))
706 (truncate:QI (reg:HI 10)))]
709 ;; Subroutine to store a half word from a register into memory.
710 ;; Operand 0 is the source register (HImode)
711 ;; Operand 1 is the destination address (SImode)
712 ;; Operand 2 is a temporary (SImode).
713 ;; Operand 3 is a temporary (SImode).
714 ;; Operand 4 is a temporary (SImode).
716 (define_expand "storehi"
717 [;; compute the address into a register
718 (set (match_operand:SI 2 "register_operand" "")
719 (match_operand:SI 1 "address_operand" ""))
720 ;; get the half word into a full word register
721 (set (match_operand:SI 3 "register_operand" "")
722 (match_operand:HI 0 "register_operand" ""))
723 ;; store the low byte
724 (set (mem:QI (match_dup 2))
725 (truncate:QI (match_dup 3)))
726 ;; extract the high byte
727 (set (match_operand:SI 4 "register_operand" "")
728 (ashiftrt:SI (match_dup 3) (const_int 8)))
729 ;; store the high byte
730 (set (mem:QI (plus (match_dup 2) (const_int 1)))
731 (truncate:QI (match_dup 4)))]
734 operands[0] = gen_lowpart (SImode, operands[0]);
737 ;; Subroutine to store a half word integer constant into memory.
738 ;; Operand 0 is the constant
739 ;; Operand 1 is the destination address (SImode)
740 ;; Operand 2 is a temporary (SImode).
741 ;; Operand 3 is a temporary (QImode).
742 ;; Operand 4 is a temporary (QImode).
743 ;; Operand 5 is a local CONST_INT.
745 (define_expand "storeinthi"
746 [;; compute the address into a register
747 (set (match_operand:SI 2 "register_operand" "")
748 (match_operand:SI 1 "address_operand" ""))
750 (set (match_operand:QI 3 "register_operand" "")
751 (match_operand:SI 0 "" ""))
752 ;; store the low byte
753 (set (mem:QI (match_dup 2))
755 ;; load the high byte
756 (set (match_operand:QI 4 "register_operand" "")
758 ;; store the high byte
759 (set (mem:QI (plus (match_dup 2) (const_int 1)))
764 int value = INTVAL(operands[0]);
766 operands[0] = gen_rtx(CONST_INT, VOIDmode, value & 255);
767 operands[5] = gen_rtx(CONST_INT, VOIDmode,(value>>8) & 255);
771 (define_expand "movhi"
772 [(set (match_operand:HI 0 "general_operand" "")
773 (match_operand:HI 1 "general_operand" ""))]
779 if (reload_in_progress || reload_completed)
781 if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == REG)
782 insn = gen_restorehi (operands[1], XEXP (operands[0], 0));
784 insn = gen_rtx (SET, VOIDmode, operands[0], operands[1]);
788 if (GET_CODE (operands[0]) == MEM)
790 if (GET_CODE (operands[1]) == MEM)
791 operands[1] = copy_to_reg (operands[1]);
793 if (GET_CODE (operands[1]) == CONST_INT)
795 insn = gen_storeinthi (operands[1], XEXP (operands[0], 0),
796 gen_reg_rtx (SImode),
797 gen_reg_rtx (QImode),
798 gen_reg_rtx (QImode));
802 insn = gen_storehi (operands[1], XEXP (operands[0], 0),
803 gen_reg_rtx (SImode),
804 gen_reg_rtx (SImode),
805 gen_reg_rtx (SImode));
809 else if (GET_CODE (operands[1]) == MEM)
811 insn = gen_loadhi (operands[0], XEXP (operands[1], 0),
812 gen_reg_rtx (SImode));
816 insn = gen_rtx (SET, VOIDmode, operands[0], operands[1]);
823 ;; Pattern to recognise insn generated default case above
826 [(set (match_operand:HI 0 "general_operand" "=r,r,r,m")
827 (match_operand:HI 1 "general_operand" "r,n,m,r"))]
830 switch (which_alternative)
832 case 0: return (arm_output_asm_insn (\"mov\\t%0, %1\\t@movhi\", operands));
833 case 1: return (output_mov_immediate (operands));
834 case 2: return (arm_output_asm_insn (\"ldr\\t%0, %1\\t@movhi\", operands));
835 case 3: return (arm_output_asm_insn (\"str\\t%1, %0\\t@movhi\", operands));
840 [(set (match_operand:QI 0 "general_operand" "=r,r,r,m")
841 (match_operand:QI 1 "general_operand" "r,n,m,r"))]
844 switch (which_alternative)
847 return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
849 return (output_mov_immediate (operands));
851 return (arm_output_asm_insn (\"ldrb\\t%0, %1\", operands));
853 return (arm_output_asm_insn (\"strb\\t%1, %0\", operands));
859 [(set (match_operand:SF 0 "general_operand" "=f,f,m,f,r,r")
860 (match_operand:SF 1 "general_operand" "fG,m,f,r,f,r"))]
863 switch (which_alternative)
866 return (arm_output_asm_insn (\"mvfs\\t%0, %1\", operands));
868 return (arm_output_asm_insn (\"ldfs\\t%0, %1\", operands));
870 return (arm_output_asm_insn (\"stfs\\t%1, %0\", operands));
872 arm_output_asm_insn(\"stmfd\\tsp!, {%1}\", operands);
873 return (arm_output_asm_insn (\"ldfs\\t%0, [sp],#4\", operands));
875 arm_output_asm_insn(\"stfs\\t%1, [sp,#-4]!\", operands);
876 return (arm_output_asm_insn (\"ldmfd\\tsp!, {%0}\", operands));
878 return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
883 [(set (match_operand:DF 0 "general_operand" "=f,f,m,f,r,r")
884 (match_operand:DF 1 "general_operand" "fG,m,f,r,f,r"))]
887 switch (which_alternative)
889 case 0: return (arm_output_asm_insn (\"mvfd\\t%0, %1\", operands));
890 case 1: return (arm_output_asm_insn (\"ldfd\\t%0, %1\", operands));
891 case 2: return (arm_output_asm_insn (\"stfd\\t%1, %0\", operands));
892 case 3: return (output_mov_double_fpu_from_arm (operands));
893 case 4: return (output_mov_double_arm_from_fpu (operands));
894 case 5: return (output_move_double (operands));
898 ;; Comparison and test insns
902 (compare (match_operand:SI 0 "register_operand" "r")
903 (match_operand:SI 1 "arm_rhs_operand" "rI")))]
906 return (arm_output_asm_insn (\"cmp\\t%0, %1\", operands));
910 [(set (cc0) (match_operand:SI 0 "register_operand" "r"))]
913 return (arm_output_asm_insn (\"cmp\\t%0, #0\", operands));
918 (compare (match_operand:SI 0 "register_operand" "r")
919 (neg:SI (match_operand:SI 1 "arm_rhs_operand" "rI"))))]
922 return (arm_output_asm_insn (\"cmn\\t%0, %1\", operands));
927 (compare (match_operand:SF 0 "register_operand" "f")
928 (match_operand:SF 1 "fpu_rhs_operand" "fG")))]
931 return (arm_output_asm_insn (\"cmf\\t%0, %1\", operands));
936 (compare (match_operand:DF 0 "register_operand" "f")
937 (match_operand:DF 1 "fpu_rhs_operand" "fG")))]
940 return (arm_output_asm_insn (\"cmf\\t%0, %1\", operands));
943 ;; Conditional branch insns
947 (if_then_else (eq (cc0) (const_int 0))
948 (label_ref (match_operand 0 "" ""))
952 return (arm_output_asm_insn (\"beq\\t%l0\", operands));
957 (if_then_else (ne (cc0) (const_int 0))
958 (label_ref (match_operand 0 "" ""))
962 return (arm_output_asm_insn (\"bne\\t%l0\", operands));
967 (if_then_else (gt (cc0) (const_int 0))
968 (label_ref (match_operand 0 "" ""))
972 return (arm_output_asm_insn (\"bgt\\t%l0\", operands));
977 (if_then_else (le (cc0) (const_int 0))
978 (label_ref (match_operand 0 "" ""))
982 return (arm_output_asm_insn (\"ble\\t%l0\", operands));
987 (if_then_else (ge (cc0) (const_int 0))
988 (label_ref (match_operand 0 "" ""))
992 return (arm_output_asm_insn (\"bge\\t%l0\", operands));
997 (if_then_else (lt (cc0) (const_int 0))
998 (label_ref (match_operand 0 "" ""))
1002 return (arm_output_asm_insn (\"blt\\t%l0\", operands));
1007 (if_then_else (gtu (cc0) (const_int 0))
1008 (label_ref (match_operand 0 "" ""))
1012 return (arm_output_asm_insn (\"bhi\\t%l0\", operands));
1017 (if_then_else (leu (cc0) (const_int 0))
1018 (label_ref (match_operand 0 "" ""))
1022 return (arm_output_asm_insn (\"bls\\t%l0\", operands));
1027 (if_then_else (geu (cc0) (const_int 0))
1028 (label_ref (match_operand 0 "" ""))
1032 return (arm_output_asm_insn (\"bhs\\t%l0\", operands));
1037 (if_then_else (ltu (cc0) (const_int 0))
1038 (label_ref (match_operand 0 "" ""))
1042 return (arm_output_asm_insn (\"blo\\t%l0\", operands));
1045 ;; Inverted conditional branch insns
1049 (if_then_else (eq (cc0) (const_int 0))
1051 (label_ref (match_operand 0 "" ""))))]
1054 return (arm_output_asm_insn (\"bne\\t%l0\", operands));
1059 (if_then_else (ne (cc0) (const_int 0))
1061 (label_ref (match_operand 0 "" ""))))]
1064 return (arm_output_asm_insn (\"beq\\t%l0\", operands));
1069 (if_then_else (gt (cc0) (const_int 0))
1071 (label_ref (match_operand 0 "" ""))))]
1074 return (arm_output_asm_insn (\"ble\\t%l0\", operands));
1079 (if_then_else (le (cc0) (const_int 0))
1081 (label_ref (match_operand 0 "" ""))))]
1084 return (arm_output_asm_insn (\"bgt\\t%l0\", operands));
1089 (if_then_else (ge (cc0) (const_int 0))
1091 (label_ref (match_operand 0 "" ""))))]
1094 return (arm_output_asm_insn (\"blt\\t%l0\", operands));
1099 (if_then_else (lt (cc0) (const_int 0))
1101 (label_ref (match_operand 0 "" ""))))]
1104 return (arm_output_asm_insn (\"bge\\t%l0\", operands));
1109 (if_then_else (gtu (cc0) (const_int 0))
1111 (label_ref (match_operand 0 "" ""))))]
1114 return (arm_output_asm_insn (\"bls\\t%l0\", operands));
1119 (if_then_else (leu (cc0) (const_int 0))
1121 (label_ref (match_operand 0 "" ""))))]
1124 return (arm_output_asm_insn (\"bhi\\t%l0\", operands));
1129 (if_then_else (geu (cc0) (const_int 0))
1131 (label_ref (match_operand 0 "" ""))))]
1134 return (arm_output_asm_insn (\"blo\\t%l0\", operands));
1139 (if_then_else (ltu (cc0) (const_int 0))
1141 (label_ref (match_operand 0 "" ""))))]
1144 return (arm_output_asm_insn (\"bhs\\t%l0\", operands));
1147 ;; Jump and linkage insns
1148 ;; `return' is still a jump-to-epilogue...
1152 (label_ref (match_operand 0 "" "")))]
1155 return (arm_output_asm_insn (\"b\\t%l0\", operands));
1159 [(call (match_operand 0 "memory_operand" "m")
1160 (match_operand 1 "general_operand" "g"))
1161 (clobber (reg:SI 14))]
1164 return (output_call (operands));
1167 (define_insn "call_value"
1168 [(set (match_operand 0 "" "=rf")
1169 (call (match_operand 1 "memory_operand" "m")
1170 (match_operand 2 "general_operand" "g")))
1171 (clobber (reg:SI 14))]
1174 return (output_call (&operands[1]));
1177 ;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
1178 ;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
1181 [(call (mem:SI (match_operand:SI 0 "" "i"))
1182 (match_operand:SI 1 "general_operand" "g"))
1183 (clobber (reg:SI 14))]
1184 "GET_CODE (operands[0]) == SYMBOL_REF"
1186 return (arm_output_asm_insn (\"bl\\t%a0\", operands));
1190 [(set (match_operand 0 "register_operand" "=rf")
1191 (call (mem:SI (match_operand:SI 1 "" "i"))
1192 (match_operand:SI 2 "general_operand" "g")))
1193 (clobber (reg:SI 14))]
1194 "GET_CODE(operands[1]) == SYMBOL_REF"
1196 return (arm_output_asm_insn (\"bl\\t%a1\", operands));
1199 (define_insn "tablejump"
1201 (match_operand:SI 0 "register_operand" "r"))
1202 (use (label_ref (match_operand 1 "" "")))]
1205 return (arm_output_asm_insn (\"mov\\tpc, %0\\t@ table jump, label %l1\", operands));
1208 (define_insn "indirect_jump"
1210 (match_operand:SI 0 "register_operand" "r"))]
1213 return (arm_output_asm_insn (\"mov\\tpc, %0\\t@ indirect jump\", operands));
1222 return (arm_output_asm_insn (\"mov\\tr0, r0\\t@ nop\", operands));
1225 ;; Patterns to allow combination of arithmetic, cond code and shifts
1228 ; [(set (match_operand:SI 0 "register_operand" "=r")
1229 ; (match_operator:SI 1 "shiftable_operator"
1230 ; [(match_operand:SI 2 "register_operand" "r")
1231 ; (match_operator:SI 3 "shift_operator"
1232 ; [(match_operand:SI 4 "register_operand" "r")
1233 ; (match_operand:SI 5 "nonmemory_operand" "rn")])]))]
1236 ; return (output_arithmetic_with_shift (operands, FALSE, FALSE));
1241 ; [(set (match_operand:SI 0 "register_operand" "=r")
1242 ; (match_operator:SI 1 "shiftable_operator"
1243 ; [(match_operator:SI 3 "shift_operator"
1244 ; [(match_operand:SI 4 "register_operand" "r")
1245 ; (match_operand:SI 5 "nonmemory_operand" "rI")])
1246 ; (match_operand:SI 2 "register_operand" "r")]))]
1249 ; return (output_arithmetic_with_shift (operands, TRUE, FALSE));
1252 ;; Patterns to allow combination of arithmetic and multiplication
1255 ; [(set (match_operand:SI 0 "register_operand" "=r")
1256 ; (match_operator:SI 1 "shiftable_operator"
1257 ; [(match_operand:SI 2 "register_operand" "r")
1259 ; (match_operand:SI 3 "register_operand" "r")
1260 ; (match_operand:SI 4 "power_of_two_operand" "n"))]))]
1263 ; return (output_arithmetic_with_immediate_multiply (operands, FALSE));
1266 ; Uncomment this to show combiner problem (see ../COMBINER-PROBLEM).
1268 ; [(set (match_operand:SI 0 "register_operand" "=r")
1269 ; (match_operator:SI 1 "shiftable_operator"
1271 ; (match_operand:SI 3 "register_operand" "r")
1272 ; (match_operand:SI 4 "power_of_two_operand" "n"))
1273 ; (match_operand:SI 2 "register_operand" "r")]))]
1276 ; return (output_arithmetic_with_immediate_multiply (operands, TRUE));
1279 ;; Peephole optimizations.
1281 ;; When testing a bitset smaller than 9 bits for (un)equality, a
1282 ;; shift/and/cmp/b{eq,ne} sequence can be replaced by one tst and the same
1286 ;; [(set (match_operand:SI 0 "register_operand" "=r")
1287 ;; (lshiftrt:SI (match_dup 0)
1288 ;; (match_operand 1 "immediate_operand" "")))
1289 ;; (set (match_dup 0)
1290 ;; (and:SI (match_dup 0)
1291 ;; (match_operand 2 "immediate_operand" "")))
1292 ;; (set (cc0) (match_dup 0))
1294 ;; (if_then_else (ne (cc0) (const_int 0))
1295 ;; (label_ref (match_operand 3 "" ""))
1297 ;; "dead_or_set_p (PREV_INSN (insn), operands[0])
1298 ;; && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
1299 ;; && const_ok_for_arm (INTVAL (operands[2]) << INTVAL (operands[1]))"
1301 ;; operands[2] = gen_rtx (CONST_INT, VOIDmode,
1302 ;; INTVAL (operands[2]) << INTVAL (operands[1]));
1303 ;; arm_output_asm_insn (\"tst\\t%0, %2\\t\\t@ ph test bitfield\", operands);
1304 ;; return (arm_output_asm_insn (\"bne\\t%l3\", operands));
1308 ;; [(set (match_operand:SI 0 "register_operand" "=r")
1309 ;; (lshiftrt:SI (match_dup 0)
1310 ;; (match_operand 1 "immediate_operand" "")))
1311 ;; (set (match_dup 0)
1312 ;; (and:SI (match_dup 0)
1313 ;; (match_operand 2 "immediate_operand" "")))
1314 ;; (set (cc0) (match_dup 0))
1316 ;; (if_then_else (ne (cc0) (const_int 0))
1318 ;; (label_ref (match_operand 3 "" ""))))]
1319 ;; "dead_or_set_p (prev_real_insn (insn), operands[0])
1320 ;; && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
1321 ;; && const_ok_for_arm (INTVAL (operands[2]) << INTVAL (operands[1]))"
1323 ;; operands[2] = gen_rtx (CONST_INT, VOIDmode,
1324 ;; INTVAL (operands[2]) << INTVAL (operands[1]));
1325 ;; arm_output_asm_insn (\"tst\\t%0, %2\\t\\t@ ph test bitfield\", operands);
1326 ;; return (arm_output_asm_insn (\"beq\\t%l3\", operands));
1329 ;; This allows negative constants to be compared since GCC appears not to try
1330 ;; converting them with a NEG.
1333 ;; [(set (match_operand:SI 2 "register_operand" "=r")
1334 ;; (match_operand:SI 1 "immediate_operand" "n"))
1336 ;; (compare (match_operand:SI 0 "register_operand" "r")
1338 ;; "const_ok_for_arm (-INTVAL (operands[1]))
1339 ;; && dead_or_set_p (prev_real_insn (insn), operands[0])"
1341 ;; operands[1] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[1]));
1342 ;; return (arm_output_asm_insn (\"cmn\\t%0, %1\\t\\t@ ph negate comparison\", operands));
1347 ;; eval: (setq comment-start ";; ")
1348 ;; eval: (setq comment-end "")
1349 ;; eval: (setq comment-start-skip ";;+ *")
1350 ;; eval: (set-syntax-table (copy-sequence (syntax-table)))
1351 ;; eval: (modify-syntax-entry ?[ "(]")
1352 ;; eval: (modify-syntax-entry ?] ")[")
1353 ;; eval: (modify-syntax-entry ?{ "(}")
1354 ;; eval: (modify-syntax-entry ?} "){")