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")
1167