OSDN Git Service

General tidyup of header files.
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / thumb.md
1 ;; thumb.md     Machine description for ARM/Thumb processors
2 ;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
3 ;; The basis of this contribution was generated by
4 ;;              Richard Earnshaw, Advanced RISC Machines Ltd
5
6 ;; This file is part of GNU CC.
7
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)
11 ;; any later version.
12
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.
17
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, 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
22
23 ;; LENGTH of an instruction is 2 bytes
24 (define_attr "length" "" (const_int 2))
25
26 ;; CONDS is set to UNCHANGED when an insn does not affect the condition codes
27 ;; Most insns change the condition codes
28 (define_attr "conds" "changed,unchanged" (const_string "changed"))
29
30 ;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a
31 ;; distant label.
32 (define_attr "far_jump" "yes,no" (const_string "no"))
33
34 ;; Start with move insns
35
36 (define_expand "movsi"
37   [(set (match_operand:SI 0 "general_operand" "")
38         (match_operand:SI 1 "general_operand" ""))]
39   ""
40   "
41   if (! (reload_in_progress || reload_completed))
42     {
43       if (GET_CODE (operands[0]) != REG)
44         operands[1] = force_reg (SImode, operands[1]);
45     }
46 ")
47
48 (define_insn "*movsi_insn"
49   [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h")
50         (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))]
51   "register_operand (operands[0], SImode) 
52    || register_operand (operands[1], SImode)"
53   "@
54    add\\t%0, %1, #0
55    mov\\t%0, %1
56    #
57    #
58    ldmia\\t%1, {%0}
59    stmia\\t%0, {%1}
60    ldr\\t%0, %1
61    str\\t%1, %0
62    mov\\t%0, %1
63    mov\\t%0, %1"
64 [(set_attr "length" "2,2,4,4,2,2,2,2,2,2")])
65
66 (define_split 
67   [(set (match_operand:SI 0 "register_operand" "")
68         (match_operand:SI 1 "const_int_operand" ""))]
69   "thumb_shiftable_const (INTVAL (operands[1]))"
70   [(set (match_dup 0) (match_dup 1))
71    (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
72   "
73 {
74   unsigned HOST_WIDE_INT val = INTVAL (operands[1]);
75   unsigned HOST_WIDE_INT mask = 0xff;
76   int i;
77   for (i = 0; i < 25; i++)
78     if ((val & (mask << i)) == val)
79       break;
80
81   if (i == 0)
82     FAIL;
83
84   operands[1] = GEN_INT (val >> i);
85   operands[2] = GEN_INT (i);
86 }")
87
88 (define_split 
89   [(set (match_operand:SI 0 "register_operand" "")
90         (match_operand:SI 1 "const_int_operand" ""))]
91   "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256"
92   [(set (match_dup 0) (match_dup 1))
93    (set (match_dup 0) (neg:SI (match_dup 0)))]
94   "
95   operands[1] = GEN_INT (- INTVAL (operands[1]));
96 ")
97
98 ;;(define_expand "reload_outsi"
99 ;;  [(set (match_operand:SI 2 "register_operand" "=&l")
100 ;;      (match_operand:SI 1 "register_operand" "h"))
101 ;;   (set (match_operand:SI 0 "reload_memory_operand" "=o")
102 ;;      (match_dup 2))]
103 ;;  ""
104 ;;  "
105 ;;/*  thumb_reload_out_si (operands);
106 ;;  DONE; */
107 ;;")
108
109 (define_expand "movhi"
110   [(set (match_operand:HI 0 "general_operand" "")
111         (match_operand:HI 1 "general_operand" ""))]
112   ""
113   "
114 {
115   if (! (reload_in_progress || reload_completed))
116     {
117       if (GET_CODE (operands[0]) != REG)
118         operands[1] = force_reg (HImode, operands[1]);
119
120       /* ??? We shouldn't really get invalid addresses here, but this can
121          happen if we are passed a SP (never OK for HImode/QImode) or virtual
122         register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode)
123         relative address.  */
124       /* ??? This should perhaps be fixed elsewhere, for instance, in
125          fixup_stack_1, by checking for other kinds of invalid addresses,
126          e.g. a bare reference to a virtual register.  This may confuse the
127          alpha though, which must handle this case differently.  */
128       if (GET_CODE (operands[0]) == MEM
129           && ! memory_address_p (GET_MODE (operands[0]),
130                                  XEXP (operands[0], 0)))
131         {
132           rtx temp = copy_to_reg (XEXP (operands[0], 0));
133           operands[0] = change_address (operands[0], VOIDmode, temp);
134         }
135       if (GET_CODE (operands[1]) == MEM
136           && ! memory_address_p (GET_MODE (operands[1]),
137                                  XEXP (operands[1], 0)))
138         {
139           rtx temp = copy_to_reg (XEXP (operands[1], 0));
140           operands[1] = change_address (operands[1], VOIDmode, temp);
141         }
142     }
143   /* Handle loading a large integer during reload */
144   else if (GET_CODE (operands[1]) == CONST_INT
145            && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
146     {
147       /* Writing a constant to memory needs a scratch, which should
148          be handled with SECONDARY_RELOADs.  */
149       if (GET_CODE (operands[0]) != REG)
150         abort ();
151
152       operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0);
153       emit_insn (gen_movsi (operands[0], operands[1]));
154       DONE;
155     }
156 }")
157
158 (define_insn "*movhi_insn"
159   [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
160         (match_operand:HI 1 "general_operand"       "l,m,l,*h,*r,I"))]
161   "register_operand (operands[0], HImode)
162    || register_operand (operands[1], HImode)"
163   "@
164    add\\t%0, %1, #0
165    ldrh\\t%0, %1
166    strh\\t%1, %0
167    mov\\t%0, %1
168    mov\\t%0, %1
169    mov\\t%0, %1")
170
171 (define_expand "movqi"
172   [(set (match_operand:QI 0 "general_operand" "")
173         (match_operand:QI 1 "general_operand" ""))]
174   ""
175   "
176 {
177   if (! (reload_in_progress || reload_completed))
178     {
179       if (GET_CODE (operands[0]) != REG)
180         operands[1] = force_reg (QImode, operands[1]);
181
182       /* ??? We shouldn't really get invalid addresses here, but this can
183          happen if we are passed a SP (never OK for HImode/QImode) or virtual
184         register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode)
185         relative address.  */
186       /* ??? This should perhaps be fixed elsewhere, for instance, in
187          fixup_stack_1, by checking for other kinds of invalid addresses,
188          e.g. a bare reference to a virtual register.  This may confuse the
189          alpha though, which must handle this case differently.  */
190       if (GET_CODE (operands[0]) == MEM
191           && ! memory_address_p (GET_MODE (operands[0]),
192                                  XEXP (operands[0], 0)))
193         {
194           rtx temp = copy_to_reg (XEXP (operands[0], 0));
195           operands[0] = change_address (operands[0], VOIDmode, temp);
196         }
197       if (GET_CODE (operands[1]) == MEM
198           && ! memory_address_p (GET_MODE (operands[1]),
199                                  XEXP (operands[1], 0)))
200         {
201           rtx temp = copy_to_reg (XEXP (operands[1], 0));
202           operands[1] = change_address (operands[1], VOIDmode, temp);
203         }
204     }
205   /* Handle loading a large integer during reload */
206   else if (GET_CODE (operands[1]) == CONST_INT
207            && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
208     {
209       /* Writing a constant to memory needs a scratch, which should
210          be handled with SECONDARY_RELOADs.  */
211       if (GET_CODE (operands[0]) != REG)
212         abort ();
213
214       operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0);
215       emit_insn (gen_movsi (operands[0], operands[1]));
216       DONE;
217     }
218 }")
219
220 (define_insn "*movqi_insn"
221   [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
222         (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))]
223   "register_operand (operands[0], QImode)
224    || register_operand (operands[1], QImode)"
225   "@
226    add\\t%0, %1, #0
227    ldrb\\t%0, %1
228    strb\\t%1, %0
229    mov\\t%0, %1
230    mov\\t%0, %1
231    mov\\t%0, %1")
232
233 (define_expand "movdi"
234   [(set (match_operand:DI 0 "general_operand" "")
235         (match_operand:DI 1 "general_operand" ""))]
236   ""
237   "
238   if (! (reload_in_progress || reload_completed))
239     {
240       if (GET_CODE (operands[0]) != REG)
241         operands[1] = force_reg (DImode, operands[1]);
242     }
243 ")
244
245 ;;; ??? This should have alternatives for constants.
246 ;;; ??? This was originally identical to the movdf_insn pattern.
247 ;;; ??? The 'i' constraint looks funny, but it should always be replaced by
248 ;;; thumb_reorg with a memory reference.
249 (define_insn "*movdi_insn"
250   [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r")
251         (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))]
252   "register_operand (operands[0], DImode)
253    || register_operand (operands[1], DImode)"
254   "*
255 {
256   switch (which_alternative)
257     {
258     case 0:
259       if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
260         return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
261       return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
262     case 1:
263       return \"mov\\t%Q0, %1\;mov\\t%R0, #0\";
264     case 2:
265       operands[1] = GEN_INT (- INTVAL (operands[1]));
266       return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\";
267     case 3:
268       return \"ldmia\\t%1, {%0, %H0}\";
269     case 4:
270       return \"stmia\\t%0, {%1, %H1}\";
271     case 5:
272       return thumb_load_double_from_address (operands);
273     case 6:
274       operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4));
275       output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
276       return \"\";
277     case 7:
278       if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
279         return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
280       return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
281     }
282 }"[(set_attr "length" "4,4,6,2,2,6,4,4")])
283
284 (define_expand "movdf"
285   [(set (match_operand:DF 0 "general_operand" "")
286         (match_operand:DF 1 "general_operand" ""))]
287   ""
288   "
289   if (! (reload_in_progress || reload_completed))
290     {
291       if (GET_CODE (operands[0]) != REG)
292         operands[1] = force_reg (DFmode, operands[1]);
293     }
294 ")
295
296 ;;; ??? This should have alternatives for constants.
297 ;;; ??? This was originally identical to the movdi_insn pattern.
298 ;;; ??? The 'F' constraint looks funny, but it should always be replaced by
299 ;;; thumb_reorg with a memory reference.
300 (define_insn "*movdf_insn"
301   [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r")
302         (match_operand:DF 1 "general_operand"  "l,>,l,mF,l,*r"))]
303   "register_operand (operands[0], DFmode)
304    || register_operand (operands[1], DFmode)"
305   "*
306   switch (which_alternative)
307     {
308     case 0:
309       if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
310         return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
311       return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
312     case 1:
313       return \"ldmia\\t%1, {%0, %H0}\";
314     case 2:
315       return \"stmia\\t%0, {%1, %H1}\";
316     case 3:
317       return thumb_load_double_from_address (operands);
318     case 4:
319       operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4));
320       output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
321       return \"\";
322     case 5:
323       if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
324         return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
325       return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
326     }
327 "[(set_attr "length" "4,2,2,6,4,4")])
328
329 (define_expand "movsf"
330   [(set (match_operand:SF 0 "general_operand" "")
331         (match_operand:SF 1 "general_operand" ""))]
332   ""
333   "
334   if (! (reload_in_progress || reload_completed))
335     {
336       if (GET_CODE (operands[0]) != REG)
337         operands[1] = force_reg (SFmode, operands[1]);
338     }
339 ")
340
341 ;;; ??? This should have alternatives for constants.
342 (define_insn "*movsf_insn"
343   [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h")
344         (match_operand:SF 1 "general_operand"       "l,>,l,mF,l,*h,*r"))]
345   "register_operand (operands[0], SFmode) 
346    || register_operand (operands[1], SFmode)"
347   "@
348    add\\t%0, %1, #0
349    ldmia\\t%1, {%0}
350    stmia\\t%0, {%1}
351    ldr\\t%0, %1
352    str\\t%1, %0
353    mov\\t%0, %1
354    mov\\t%0, %1")
355
356 ;; Widening move insns
357
358 (define_expand "zero_extendhisi2"
359   [(set (match_operand:SI 0 "register_operand" "")
360         (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
361   ""
362   "
363   if (GET_CODE (operands[1]) != MEM)
364     {
365       rtx temp = gen_reg_rtx (SImode);
366       
367       operands[1] = force_reg (HImode, operands[1]);
368       operands[1] = gen_lowpart (SImode, operands[1]);
369       emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16)));
370       emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16)));
371       DONE;
372     }
373 ")
374
375 (define_insn "*zero_extendhisi2_insn"
376   [(set (match_operand:SI 0 "register_operand" "=l")
377         (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
378   ""
379   "ldrh\\t%0, %1")
380
381 (define_expand "zero_extendqisi2"
382   [(set (match_operand:SI 0 "register_operand" "")
383         (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
384   ""
385   "
386   if (GET_CODE (operands[1]) != MEM)
387     {
388       rtx temp = gen_reg_rtx (SImode);
389
390       operands[1] = force_reg (QImode, operands[1]);
391       operands[1] = gen_lowpart (SImode, operands[1]);
392       emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24)));
393       emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24)));
394       DONE;
395     }
396 ")
397
398 (define_insn "*zero_extendqisi2_insn"
399   [(set (match_operand:SI 0 "register_operand" "=l")
400         (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
401   ""
402   "ldrb\\t%0, %1")
403
404 (define_expand "extendhisi2"
405   [(parallel [(set (match_operand:SI 0 "register_operand" "")
406                    (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))
407               (clobber (match_scratch:SI 2 ""))])]
408   ""
409   "
410   if (GET_CODE (operands[1]) != MEM)
411     {
412       rtx temp = gen_reg_rtx (SImode);
413       
414       operands[1] = force_reg (HImode, operands[1]);
415       operands[1] = gen_lowpart (SImode, operands[1]);
416       emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16)));
417       emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16)));
418       DONE;
419     }
420 ")
421
422 (define_insn "*extendhisi2_insn"
423   [(set (match_operand:SI 0 "register_operand" "=l")
424         (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
425    (clobber (match_scratch:SI 2 "=&l"))]
426   ""
427   "*
428 {
429   rtx ops[4];
430   /* This code used to try to use 'V', and fix the address only if it was
431      offsettable, but this fails for e.g. REG+48 because 48 is outside the
432      range of QImode offsets, and offsettable_address_p does a QImode
433      address check.  */
434
435   if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
436     {
437       ops[1] = XEXP (XEXP (operands[1], 0), 0);
438       ops[2] = XEXP (XEXP (operands[1], 0), 1);
439     }
440   else
441     {
442       ops[1] = XEXP (operands[1], 0);
443       ops[2] = const0_rtx;
444     }
445   if (GET_CODE (ops[2]) == REG)
446     return \"ldrsh\\t%0, %1\";
447
448   ops[0] = operands[0];
449   ops[3] = operands[2];
450   output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
451   return \"\";
452 }"
453 [(set_attr "length" "4")])
454
455 (define_expand "extendqisi2"
456   [(set (match_operand:SI 0 "register_operand" "")
457         (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
458   ""
459   "
460   if (GET_CODE (operands[1]) != MEM)
461     {
462       rtx temp = gen_reg_rtx (SImode);
463
464       operands[1] = force_reg (QImode, operands[1]);
465       operands[1] = gen_lowpart (SImode, operands[1]);
466       emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24)));
467       emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24)));
468       DONE;
469     }
470 ")
471
472 (define_insn "*extendqisi2_insn"
473   [(set (match_operand:SI 0 "register_operand" "=l,l")
474         (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
475   ""
476   "*
477 {
478   rtx ops[3];
479
480   if (which_alternative == 0)
481     return \"ldrsb\\t%0, %1\";
482   ops[0] = operands[0];
483   if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
484     {
485       ops[1] = XEXP (XEXP (operands[1], 0), 0);
486       ops[2] = XEXP (XEXP (operands[1], 0), 1);
487       
488       if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG)
489         output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
490       else if (GET_CODE (ops[1]) == REG)
491         {
492           if (REGNO (ops[1]) == REGNO (operands[0]))
493             output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
494           else
495             output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
496         }
497       else
498         {
499           if (REGNO (ops[2]) == REGNO (operands[0]))
500             output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
501           else
502             output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
503         }
504     }
505   else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0)))
506     {
507       output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
508     }
509   else
510     {
511       ops[1] = XEXP (operands[1], 0);
512       ops[2] = const0_rtx;
513       output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
514     }
515   return \"\";
516 }"
517 [(set_attr "length" "2,6")])
518
519 ;; We don't really have extzv, but defining this using shifts helps
520 ;; to reduce register pressure later on.
521
522 (define_expand "extzv"
523   [(set (match_dup 4)
524         (ashift:SI (match_operand:SI 1 "register_operand" "")
525                    (match_operand:SI 2 "const_int_operand" "")))
526    (set (match_operand:SI 0 "register_operand" "")
527         (lshiftrt:SI (match_dup 4)
528                      (match_operand:SI 3 "const_int_operand" "")))]
529   ""
530   "
531 {
532   HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]);
533   HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]);
534   operands[3] = GEN_INT (rshift);
535   if (lshift == 0)
536     {
537       emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3]));
538       DONE;
539     }
540   operands[2] = GEN_INT (lshift);
541   operands[4] = gen_reg_rtx (SImode);
542 }
543 ")
544
545 ;; Block-move insns
546
547 (define_expand "movstrqi"
548   [(match_operand:BLK 0 "general_operand" "")
549    (match_operand:BLK 1 "general_operand" "")
550    (match_operand:SI 2 "" "")
551    (match_operand:SI 3 "const_int_operand" "")]
552   ""
553   "
554   if (INTVAL (operands[3]) != 4
555       || GET_CODE (operands[2]) != CONST_INT
556       || INTVAL (operands[2]) > 48)
557     FAIL;
558
559   thumb_expand_movstrqi (operands);
560   DONE;
561 ")
562
563 (define_insn "movmem12b"
564   [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l"))
565         (mem:SI (match_operand:SI 1 "register_operand" "+&l")))
566    (set (mem:SI (plus:SI (match_dup 0) (const_int 4)))
567         (mem:SI (plus:SI (match_dup 1) (const_int 4))))
568    (set (mem:SI (plus:SI (match_dup 0) (const_int 8)))
569         (mem:SI (plus:SI (match_dup 1) (const_int 8))))
570    (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12)))
571    (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12)))
572    (clobber (match_scratch:SI 2 "=&l"))
573    (clobber (match_scratch:SI 3 "=&l"))
574    (clobber (match_scratch:SI 4 "=&l"))]
575   ""
576   "* return output_move_mem_multiple (3, operands);"
577 [(set_attr "length" "4")])
578
579 (define_insn "movmem8b"
580   [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l"))
581         (mem:SI (match_operand:SI 1 "register_operand" "+&l")))
582    (set (mem:SI (plus:SI (match_dup 0) (const_int 4)))
583         (mem:SI (plus:SI (match_dup 1) (const_int 4))))
584    (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8)))
585    (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8)))
586    (clobber (match_scratch:SI 2 "=&l"))
587    (clobber (match_scratch:SI 3 "=&l"))]
588   ""
589   "* return output_move_mem_multiple (2, operands);"
590 [(set_attr "length" "4")])
591
592 ;; Arithmetic insns
593
594 (define_insn "adddi3"
595   [(set (match_operand:DI 0 "register_operand" "=l")
596         (plus:DI (match_operand:DI 1 "register_operand" "%0")
597                  (match_operand:DI 2 "register_operand" "l")))]
598   ""
599   "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2"
600 [(set_attr "conds" "changed")
601  (set_attr "length" "8")])
602
603 ;; register group 'k' is a single register group containing only the stack
604 ;; register.  Trying to reload it will always fail catastrophically,
605 ;; so never allow those alternatives to match if reloading is needed.
606 (define_insn "addsi3"
607   [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k")
608         (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k")
609                  (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))]
610   ""
611   "*
612    static char *asms[] = 
613 {
614   \"add\\t%0, %0, %2\",
615   \"sub\\t%0, %0, #%n2\",
616   \"add\\t%0, %1, %2\",
617   \"add\\t%0, %0, %2\",
618   \"add\\t%0, %0, %2\",
619   \"add\\t%0, %1, %2\",
620   \"add\\t%0, %1, %2\"
621 };
622   if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT
623       && INTVAL (operands[2]) < 0)
624     return \"sub\\t%0, %1, #%n2\";
625   return asms[which_alternative];
626 ")
627
628 ; reloading and elimination of the frame pointer can sometimes cause this
629 ; optimization to be missed.
630 (define_peephole
631   [(set (match_operand:SI 0 "register_operand" "=l")
632         (match_operand:SI 1 "const_int_operand" "M"))
633    (set (match_dup 0)
634         (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))]
635   "REGNO (operands[2]) == STACK_POINTER_REGNUM 
636    && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
637    && (INTVAL (operands[1]) & 3) == 0"
638   "add\\t%0, %2, %1")
639
640 (define_insn "subdi3"
641   [(set (match_operand:DI 0 "register_operand" "=l")
642         (minus:DI (match_operand:DI 1 "register_operand" "0")
643                  (match_operand:DI 2 "register_operand" "l")))]
644   ""
645   "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2"
646 [(set_attr "conds" "changed")
647  (set_attr "length" "8")])
648
649 (define_insn "subsi3"
650   [(set (match_operand:SI 0 "register_operand" "=l")
651         (minus:SI (match_operand:SI 1 "register_operand" "l")
652                   (match_operand:SI 2 "register_operand" "l")))]
653   ""
654   "sub\\t%0, %1, %2")
655
656 ;; We must ensure that one input matches the output, and that the other input
657 ;; does not match the output.  Using 0 satisfies the first, and using &
658 ;; satisfies the second.  Unfortunately, this fails when operands 1 and 2
659 ;; are the same, because reload will make operand 0 match operand 1 without
660 ;; realizing that this conflicts with operand 2.  We fix this by adding another
661 ;; alternative to match this case, and then `reload' it ourselves.  This
662 ;; alternative must come first.
663 (define_insn "mulsi3"
664   [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l")
665         (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0")
666                  (match_operand:SI 2 "register_operand" "l,l,l")))]
667   ""
668   "*
669 {
670   if (which_alternative < 2)
671     return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
672   else
673     return \"mul\\t%0, %0, %2\";
674 }"
675   [(set_attr "length" "4,4,2")])
676
677 (define_insn "negsi2"
678   [(set (match_operand:SI 0 "register_operand" "=l")
679         (neg:SI (match_operand:SI 1 "register_operand" "l")))]
680   ""
681   "neg\\t%0, %1")
682
683 ;; Logical insns
684
685 (define_expand "andsi3"
686   [(set (match_operand:SI 0 "register_operand" "")
687         (and:SI (match_operand:SI 1 "register_operand" "")
688                 (match_operand:SI 2 "nonmemory_operand" "")))]
689   ""
690   "
691   if (GET_CODE (operands[2]) != CONST_INT)
692     operands[2] = force_reg (SImode, operands[2]);
693   else
694     {
695       int i;
696       if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256)
697         {
698           operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2])));
699           emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1]));
700           DONE;
701         }
702
703       for (i = 9; i <= 31; i++)
704         if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2]))
705           {
706             emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i),
707                                   const0_rtx));
708             DONE;
709           }
710         else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2]))
711           {
712             rtx shift = GEN_INT (i);
713             rtx reg = gen_reg_rtx (SImode);
714             emit_insn (gen_lshrsi3 (reg, operands[1], shift));
715             emit_insn (gen_ashlsi3 (operands[0], reg, shift));
716             DONE;
717           }
718
719       operands[2] = force_reg (SImode, operands[2]);
720     }
721 ")
722
723 (define_insn "*andsi3_insn"
724   [(set (match_operand:SI 0 "register_operand" "=l")
725         (and:SI (match_operand:SI 1 "register_operand" "%0")
726                 (match_operand:SI 2 "register_operand" "l")))]
727   ""
728   "and\\t%0, %0, %2")
729
730 (define_insn "bicsi3"
731   [(set (match_operand:SI 0 "register_operand" "=l")
732         (and:SI (not:SI (match_operand:SI 1 "register_operand" "l"))
733                 (match_operand:SI 2 "register_operand" "0")))]
734   ""
735   "bic\\t%0, %0, %1")
736
737 (define_insn "iorsi3"
738   [(set (match_operand:SI 0 "register_operand" "=l")
739         (ior:SI (match_operand:SI 1 "register_operand" "%0")
740                 (match_operand:SI 2 "register_operand" "l")))]
741   ""
742   "orr\\t%0, %0, %2")
743
744 (define_insn "xorsi3"
745   [(set (match_operand:SI 0 "register_operand" "=l")
746         (xor:SI (match_operand:SI 1 "register_operand" "%0")
747                 (match_operand:SI 2 "register_operand" "l")))]
748   ""
749   "eor\\t%0, %0, %2")
750
751 (define_insn "one_cmplsi2"
752   [(set (match_operand:SI 0 "register_operand" "=l")
753         (not:SI (match_operand:SI 1 "register_operand" "l")))]
754   ""
755   "mvn\\t%0, %1")
756
757 ;; Shift and rotation insns
758
759 (define_insn "ashlsi3"
760   [(set (match_operand:SI 0 "register_operand" "=l,l")
761         (ashift:SI (match_operand:SI 1 "register_operand" "l,0")
762                    (match_operand:SI 2 "nonmemory_operand" "N,l")))]
763   ""
764   "@
765    lsl\\t%0, %1, %2
766    lsl\\t%0, %0, %2")
767
768 (define_insn "ashrsi3"
769   [(set (match_operand:SI 0 "register_operand" "=l,l")
770         (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
771                      (match_operand:SI 2 "nonmemory_operand" "N,l")))]
772   ""
773   "@
774    asr\\t%0, %1, %2
775    asr\\t%0, %0, %2")
776
777 (define_insn "lshrsi3"
778   [(set (match_operand:SI 0 "register_operand" "=l,l")
779         (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
780                      (match_operand:SI 2 "nonmemory_operand" "N,l")))]
781   ""
782   "@
783    lsr\\t%0, %1, %2
784    lsr\\t%0, %0, %2")
785
786 (define_insn "rotrsi3"
787   [(set (match_operand:SI 0 "register_operand" "=l")
788         (rotatert:SI (match_operand:SI 1 "register_operand" "0")
789                      (match_operand:SI 2 "register_operand" "l")))]
790   ""
791   "ror\\t%0, %0, %2")
792
793 ;; Comparison insns
794
795 (define_expand "cmpsi"
796   [(set (cc0) (compare (match_operand:SI 0 "register_operand" "")
797                        (match_operand:SI 1 "nonmemory_operand" "")))]
798   ""
799   "
800   if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG)
801     {
802       if (GET_CODE (operands[1]) != CONST_INT
803           || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256)
804         {
805           if (GET_CODE (operands[1]) != CONST_INT
806               || INTVAL (operands[1]) < -255
807               || INTVAL (operands[1]) > 0)
808             operands[1] = force_reg (SImode, operands[1]);
809           else
810             {
811               operands[1] = force_reg (SImode, 
812                                        GEN_INT (- INTVAL (operands[1])));
813               emit_insn (gen_cmnsi (operands[0], operands[1]));
814               DONE;
815             }
816         }
817     }
818 ")
819
820 (define_insn "*cmpsi_insn"
821   [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l,*r,*h")
822                        (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))]
823   ""
824   "@
825    cmp\\t%0, %1
826    cmp\\t%0, %1
827    cmp\\t%0, %1")
828
829 (define_insn "tstsi"
830   [(set (cc0) (match_operand:SI 0 "register_operand" "l"))]
831   ""
832   "cmp\\t%0, #0")
833
834 (define_insn "cmnsi"
835   [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l")
836                        (neg:SI (match_operand:SI 1 "register_operand" "l"))))]
837   ""
838   "cmn\\t%0, %1")
839
840 ;; Jump insns
841
842 (define_insn "jump"
843   [(set (pc) (label_ref (match_operand 0 "" "")))]
844   ""
845   "*
846   if (get_attr_length (insn) == 2)
847     return \"b\\t%l0\";
848   return \"bl\\t%l0\\t%@ far jump\";
849 "[(set (attr "far_jump")
850        (if_then_else (eq_attr "length" "4")
851                      (const_string "yes")
852                      (const_string "no")))
853   (set (attr "length") 
854        (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048))
855                           (le (minus (match_dup 0) (pc)) (const_int 2044)))
856                      (const_int 2)
857                      (const_int 4)))])
858
859
860 (define_expand "beq"
861   [(set (pc) (if_then_else (eq (cc0) (const_int 0))
862                            (label_ref (match_operand 0 "" ""))
863                            (pc)))]
864   ""
865   "")
866
867 (define_expand "bne"
868   [(set (pc) (if_then_else (ne (cc0) (const_int 0))
869                            (label_ref (match_operand 0 "" ""))
870                            (pc)))]
871   ""
872   "")
873
874 (define_expand "bge"
875   [(set (pc) (if_then_else (ge (cc0) (const_int 0))
876                            (label_ref (match_operand 0 "" ""))
877                            (pc)))]
878   ""
879   "")
880
881 (define_expand "ble"
882   [(set (pc) (if_then_else (le (cc0) (const_int 0))
883                            (label_ref (match_operand 0 "" ""))
884                            (pc)))]
885   ""
886   "")
887
888 (define_expand "bgt"
889   [(set (pc) (if_then_else (gt (cc0) (const_int 0))
890                            (label_ref (match_operand 0 "" ""))
891                            (pc)))]
892   ""
893   "")
894
895 (define_expand "blt"
896   [(set (pc) (if_then_else (lt (cc0) (const_int 0))
897                            (label_ref (match_operand 0 "" ""))
898                            (pc)))]
899   ""
900   "")
901
902 (define_expand "bgeu"
903   [(set (pc) (if_then_else (geu (cc0) (const_int 0))
904                            (label_ref (match_operand 0 "" ""))
905                            (pc)))]
906   ""
907   "")
908
909 (define_expand "bleu"
910   [(set (pc) (if_then_else (leu (cc0) (const_int 0))
911                            (label_ref (match_operand 0 "" ""))
912                            (pc)))]
913   ""
914   "")
915
916 (define_expand "bgtu"
917   [(set (pc) (if_then_else (gtu (cc0) (const_int 0))
918                            (label_ref (match_operand 0 "" ""))
919                            (pc)))]
920   ""
921   "")
922
923 (define_expand "bltu"
924   [(set (pc) (if_then_else (ltu (cc0) (const_int 0))
925                            (label_ref (match_operand 0 "" ""))
926                            (pc)))]
927   ""
928   "")
929
930 (define_insn "*cond_branch"
931   [(set (pc) (if_then_else (match_operator 1 "comparison_operator"
932                             [(cc0) (const_int 0)])
933                            (label_ref (match_operand 0 "" ""))
934                            (pc)))]
935   ""
936   "*
937   switch (get_attr_length (insn))
938     {
939     case 2:  return \"b%d1\\t%l0\\t%@cond_branch\";
940     case 4:  return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\";
941     default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\";
942     }
943 "[(set (attr "far_jump")
944        (if_then_else (eq_attr "length" "6")
945                      (const_string "yes")
946                      (const_string "no")))
947   (set (attr "length") 
948        (if_then_else
949         (and (ge (minus (match_dup 0) (pc)) (const_int -252))
950              (le (minus (match_dup 0) (pc)) (const_int 254)))
951         (const_int 2)
952         (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
953                            (le (minus (match_dup 0) (pc)) (const_int 2044)))
954                       (const_int 4)
955                       (const_int 6))))])
956
957 (define_insn "*cond_branch_reversed"
958   [(set (pc) (if_then_else (match_operator 1 "comparison_operator"
959                             [(cc0) (const_int 0)])
960                            (pc)
961                            (label_ref (match_operand 0 "" ""))))]
962   ""
963   "*
964   switch (get_attr_length (insn))
965     {
966     case 2:  return \"b%D1\\t%l0\\t%@cond_branch_reversed\";
967     case 4:  return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\";
968     default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\";
969     }
970   return \"\";
971 "[(set (attr "far_jump")
972        (if_then_else (eq_attr "length" "6")
973                      (const_string "yes")
974                      (const_string "no")))
975    (set (attr "length") 
976        (if_then_else
977         (and (ge (minus (match_dup 0) (pc)) (const_int -252))
978              (le (minus (match_dup 0) (pc)) (const_int 254)))
979         (const_int 2)
980         (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
981                            (le (minus (match_dup 0) (pc)) (const_int 2044)))
982                       (const_int 4)
983                       (const_int 6))))])
984
985 (define_insn "indirect_jump"
986   [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))]
987   ""
988   "mov\\tpc, %0")
989
990 (define_insn "tablejump"
991   [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
992    (use (label_ref (match_operand 1 "" "")))]
993   ""
994   "mov\\tpc, %0")
995
996 (define_insn "return"
997   [(return)]
998   "USE_RETURN"
999   "* return output_return ();"
1000 [(set_attr "length" "18")])
1001
1002 ;; Call insns
1003
1004 (define_expand "call"
1005   [(call (match_operand:SI 0 "memory_operand" "")
1006          (match_operand 1 "" ""))]
1007   ""
1008   "")
1009
1010 (define_insn "*call_indirect"
1011   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
1012          (match_operand 1 "" ""))]
1013   "! TARGET_CALLER_INTERWORKING"
1014   "bl\\t%__call_via_%0"
1015 [(set_attr "length" "4")])
1016 ;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version
1017 ;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set
1018 ;; the bottom bit of lr so that a function return (using bx)
1019 ;; would switch back into ARM mode...
1020
1021 (define_insn "*call_indirect_interwork"
1022   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
1023          (match_operand 1 "" ""))]
1024   "TARGET_CALLER_INTERWORKING"
1025   "bl\\t%__interwork_call_via_%0"
1026 [(set_attr "length" "4")])
1027
1028 (define_expand "call_value"
1029   [(set (match_operand 0 "" "")
1030         (call (match_operand 1 "memory_operand" "")
1031               (match_operand 2 "" "")))]
1032   ""
1033   "")
1034
1035 (define_insn "*call_value_indirect"
1036   [(set (match_operand 0 "" "=l")
1037         (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
1038               (match_operand 2 "" "")))]
1039   "! TARGET_CALLER_INTERWORKING"
1040   "bl\\t%__call_via_%1"
1041 [(set_attr "length" "4")])
1042 ;; See comment for call_indirect pattern
1043
1044 (define_insn "*call_value_indirect_interwork"
1045   [(set (match_operand 0 "" "=l")
1046         (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
1047               (match_operand 2 "" "")))]
1048   "TARGET_CALLER_INTERWORKING"
1049   "bl\\t%__interwork_call_via_%1"
1050 [(set_attr "length" "4")])
1051
1052
1053 (define_insn "*call_insn"
1054   [(call (mem:SI (match_operand:SI 0 "" "i"))
1055          (match_operand:SI 1 "" ""))]
1056   "GET_CODE (operands[0]) == SYMBOL_REF"
1057   "bl\\t%a0"
1058 [(set_attr "length" "4")])
1059
1060 (define_insn "*call_value_insn"
1061   [(set (match_operand 0 "register_operand" "=l")
1062         (call (mem:SI (match_operand 1 "" "i"))
1063               (match_operand 2 "" "")))]
1064   "GET_CODE (operands[1]) == SYMBOL_REF"
1065   "bl\\t%a1"
1066 [(set_attr "length" "4")])
1067
1068 ;; Untyped call not required, since all funcs return in r0
1069
1070 ;; Miscellaneous patterns
1071
1072 (define_insn "nop"
1073   [(clobber (const_int 0))]
1074   ""
1075   "mov\\tr8, r8")
1076
1077 (define_insn "blockage"
1078   [(unspec_volatile [(const_int 0)] 0)]
1079   ""
1080   ""
1081   [(set_attr "length" "0")])
1082
1083 (define_expand "prologue"
1084   [(const_int 0)]
1085   ""
1086   "
1087   thumb_expand_prologue ();
1088   DONE;
1089 ")
1090
1091 (define_expand "epilogue"
1092   [(unspec_volatile [(const_int 0)] 1)]
1093   "! thumb_trivial_epilogue ()"
1094   "
1095   thumb_expand_epilogue ();
1096 ")
1097
1098 (define_insn "*epilogue_insns"
1099   [(unspec_volatile [(const_int 0)] 1)]
1100   ""
1101   "*
1102   return thumb_unexpanded_epilogue ();
1103 "
1104 [(set_attr "length" "42")])
1105
1106 ;; Special patterns for dealing with the constant pool
1107
1108 (define_insn "consttable_4"
1109  [(unspec_volatile [(match_operand 0 "" "")] 2)]
1110  ""
1111  "*
1112 {
1113   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
1114     {
1115     case MODE_FLOAT:
1116     {
1117       union real_extract u;
1118       bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u);
1119       assemble_real (u.d, GET_MODE (operands[0]));
1120       break;
1121     }
1122     default:
1123       assemble_integer (operands[0], 4, 1);
1124       break;
1125     }
1126   return \"\";
1127 }"
1128 [(set_attr "length" "4")])
1129
1130 (define_insn "consttable_8"
1131  [(unspec_volatile [(match_operand 0 "" "")] 3)]
1132  ""
1133  "*
1134 {
1135   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
1136     {
1137     case MODE_FLOAT:
1138     {
1139       union real_extract u;
1140       bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u);
1141       assemble_real (u.d, GET_MODE (operands[0]));
1142       break;
1143     }
1144     default:
1145       assemble_integer (operands[0], 8, 1);
1146       break;
1147     }
1148   return \"\";
1149 }"
1150 [(set_attr "length" "8")])
1151
1152 (define_insn "consttable_end"
1153   [(unspec_volatile [(const_int 0)] 4)]
1154   ""
1155   "*
1156   /* Nothing to do (currently).  */
1157   return \"\";
1158 ")
1159
1160 (define_insn "align_4"
1161  [(unspec_volatile [(const_int 0)] 5)]
1162  ""
1163  "*
1164    assemble_align (32);
1165    return \"\";
1166 ")