xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/msp430/msp430.md (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1;;  Machine Description for TI MSP43* processors
2;;  Copyright (C) 2013-2020 Free Software Foundation, Inc.
3;;  Contributed by Red Hat.
4
5;; This file is part of GCC.
6
7;; GCC is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 3, or (at your option)
10;; any later version.
11
12;; GCC is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GCC; see the file COPYING3.  If not see
19;; <http://www.gnu.org/licenses/>.
20
21
22(define_constants
23  [
24   (PC_REGNO 0)
25   (SP_REGNO 1)
26   (CARRY 2)
27  ])
28
29(define_c_enum "unspec"
30  [
31   UNS_PROLOGUE_START_MARKER
32   UNS_PROLOGUE_END_MARKER
33   UNS_EPILOGUE_START_MARKER
34   UNS_EPILOGUE_HELPER
35
36   UNS_PUSHM
37   UNS_POPM
38
39   UNS_GROW_AND_SWAP
40   UNS_SWAP_AND_SHRINK
41
42   UNS_DINT
43   UNS_EINT
44   UNS_PUSH_INTR
45   UNS_POP_INTR
46   UNS_BIC_SR
47   UNS_BIS_SR
48
49   UNS_REFSYM_NEED_EXIT
50
51   UNS_DELAY_32
52   UNS_DELAY_32X
53   UNS_DELAY_16
54   UNS_DELAY_16X
55   UNS_DELAY_2
56   UNS_DELAY_1
57   UNS_DELAY_START
58   UNS_DELAY_END
59  ])
60
61;; This is an approximation.
62(define_attr "length" "" (const_int 4))
63
64(include "predicates.md")
65(include "constraints.md")
66
67(define_mode_iterator QHI [QI HI PSI])
68
69;; There are two basic "family" tests we do here:
70;;
71;; msp430x - true if 430X instructions are available.
72;; TARGET_LARGE - true if pointers are 20-bits
73;;
74;; Note that there are three supported cases, since the base 430
75;; doesn't have 20-bit pointers:
76;;
77;; 1. MSP430 cpu, small model
78;; 2. MSP430X cpu, small model.
79;; 3. MSP430X cpu, large model.
80
81;;------------------------------------------------------------
82;; Moves
83
84;; Push/Pop must be before the generic move patterns
85
86(define_insn "push"
87  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO)))
88	(match_operand:HI 0 "register_operand" "r"))]
89  ""
90  "PUSH\t%0"
91  )
92
93(define_insn "pusha"
94  [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO)))
95	(match_operand:PSI 0 "register_operand" "r"))]
96  "TARGET_LARGE"
97  "PUSHX.A\t%0"
98  )
99
100(define_insn "pushm"
101  [(unspec_volatile [(match_operand 0 "register_operand" "r")
102		     (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)]
103  ""
104  "PUSHM%b0\t%1, %0"
105  )
106
107(define_insn "pop"
108  [(set (match_operand:HI 0 "register_operand" "=r")
109	(mem:HI (post_inc:HI (reg:HI SP_REGNO))))]
110  ""
111  "POP\t%0"
112  )
113
114(define_insn "popa"
115  [(set (match_operand:PSI 0 "register_operand" "=r")
116	(mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))]
117  "TARGET_LARGE"
118  "POPX.A\t%0"
119  )
120
121;; This is nasty.  Operand0 is bogus.  It is only there so that we can get a
122;; mode for the %b0 to work.  We should use operand1 for this, but that does
123;; not have a mode.
124;;
125;; Operand1 is actually a register, but we cannot accept (REG...) because the
126;; cprop_hardreg pass can and will renumber registers even inside
127;; unspec_volatiles.  So we take an integer register number parameter and
128;; fudge it to be a register name when we generate the assembler.
129;;
130;; The pushm pattern does not have this problem because of all of the
131;; frame info cruft attached to it, so cprop_hardreg leaves it alone.
132(define_insn "popm"
133  [(unspec_volatile [(match_operand 0 "register_operand" "r")
134		     (match_operand 1 "immediate_operand" "i")
135		     (match_operand 2 "immediate_operand" "i")] UNS_POPM)]
136  ""
137  "POPM%b0\t%2, r%J1"
138  )
139
140;; The next two patterns are here to support a "feature" of how GCC implements
141;; varargs.  When a function uses varargs and the *second* to last named
142;; argument is split between argument registers and the stack, gcc expects the
143;; callee to allocate space on the stack that can contain the register-based
144;; part of the argument.  This space *has* to be just before the remaining
145;; arguments (ie the ones that are fully on the stack).
146;;
147;; The problem is that the MSP430 CALL instruction pushes the return address
148;; onto the stack in the exact place where the callee wants to allocate
149;; this extra space.  So we need a sequence of instructions that can allocate
150;; the extra space and then move the return address down the stack, so that
151;; the extra space is now adjacent to the remaining arguments.
152;;
153;; This could be constructed through regular insns, but they might be split up
154;; by a misguided optimization, so an unspec volatile is used instead.
155
156(define_insn "grow_and_swap"
157  [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP)]
158  ""
159  "*
160    if (TARGET_LARGE)
161      return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\";
162    return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\";
163  "
164)
165
166(define_insn "swap_and_shrink"
167  [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK)]
168  ""
169  "* return TARGET_LARGE
170	   ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\"
171	   : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\";
172  ")
173
174; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a
175; zero_extend anyway.  Catch it here.
176(define_insn "movqihi"
177  [(set (match_operand:HI                 0 "register_operand" "=r,r")
178	(zero_extend:HI (match_operand:QI 1 "memory_operand" "Ys,m")))]
179  ""
180  "@
181   MOV.B\t%1, %0
182   MOV%X1.B\t%1, %0"
183)
184
185(define_insn "movqi_topbyte"
186  [(set (match_operand:QI 0 "msp430_general_dst_operand" "=r")
187	(subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))]
188  "msp430x"
189  "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0"
190)
191
192(define_insn "movqi"
193  [(set (match_operand:QI 0 "msp430_general_dst_operand" "=rYsYx,rm")
194	(match_operand:QI 1 "msp430_general_operand" "riYsYx,rmi"))]
195  ""
196  "@
197  MOV.B\t%1, %0
198  MOVX.B\t%1, %0"
199)
200
201(define_insn "movhi"
202  [(set (match_operand:HI 0 "msp430_general_dst_operand" "=r,rYsYx,rm")
203	(match_operand:HI 1 "msp430_general_operand" "N,riYsYx,rmi"))]
204  ""
205  "@
206  MOV.B\t%1, %0
207  MOV.W\t%1, %0
208  MOVX.W\t%1, %0"
209)
210
211(define_expand "movsi"
212  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand")
213	(match_operand:SI 1 "general_operand"))]
214  ""
215  ""
216  )
217
218(define_insn_and_split "movsi_s"
219  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
220	(subreg:SI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))]
221  ""
222  ""
223  "reload_completed"
224  [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand")
225	(match_operand:HI 4 "general_operand"))
226   (set (match_operand:HI 3 "msp430_general_dst_nonv_operand")
227	(match_operand:HI 5 "general_operand"))]
228  "msp430_split_movsi (operands);"
229  )
230
231(define_insn_and_split "movsi_x"
232  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
233	(match_operand:SI 1 "general_operand" "rmi"))]
234  ""
235  "#"
236  "reload_completed"
237  [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand")
238	(match_operand:HI 4 "general_operand"))
239   (set (match_operand:HI 3 "msp430_general_dst_nonv_operand")
240	(match_operand:HI 5 "general_operand"))]
241  "msp430_split_movsi (operands);"
242)
243
244;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them.
245(define_insn "movpsi"
246  [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,r,Ya,rm")
247	(match_operand:PSI 1 "msp430_general_operand" "N,O,riYa,r,rmi"))]
248  ""
249  "@
250  MOV.B\t%1, %0
251  MOV.W\t%1, %0
252  MOVA\t%1, %0
253  MOVA\t%1, %0
254  MOVX.A\t%1, %0")
255
256; This pattern is identical to the truncsipsi2 pattern except
257; that it uses a SUBREG instead of a TRUNC.  It is needed in
258; order to prevent reload from converting (set:SI (SUBREG:PSI (SI)))
259; into (SET:PSI (PSI)).
260;
261; Note: using POPM.A #1 is two bytes smaller than using POPX.A....
262
263(define_insn "movsipsi2"
264  [(set (match_operand:PSI            0 "register_operand" "=r")
265	(subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))]
266  "msp430x"
267  "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0"
268)
269
270;; Produced when converting a pointer to an integer via a union, eg gcc.dg/pr47201.c.
271(define_insn "*movpsihi2_lo"
272  [(set (match_operand:HI             0 "register_operand" "=r")
273	(subreg:HI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))]
274  "msp430x"
275  "MOVA\t%1, %0"
276)
277
278;;------------------------------------------------------------
279;; Math
280
281(define_insn "addpsi3"
282  [(set (match_operand:PSI	     0 "msp430_general_dst_operand" "=r,rm")
283	(plus:PSI (match_operand:PSI 1 "msp430_general_operand" "%0,0")
284		  (match_operand:PSI 2 "msp430_general_operand"      "rLs,rmi")))]
285  ""
286  "@
287  ADDA\t%2, %0
288  ADDX.A\t%2, %0"
289)
290
291(define_insn "addqi3"
292  [(set (match_operand:QI	   0 "msp430_general_dst_operand" "=rYsYx,rm")
293	(plus:QI (match_operand:QI 1 "msp430_general_operand" "%0,0")
294		 (match_operand:QI 2 "msp430_general_operand"      "riYsYx,rmi")))]
295  ""
296  "@
297   ADD.B\t%2, %0
298   ADDX.B\t%2, %0"
299)
300
301(define_insn "addhi3"
302  [(set (match_operand:HI	    0 "msp430_general_dst_operand" "=rYsYx,rm")
303	(plus:HI (match_operand:HI  1 "msp430_general_operand" "%0,0")
304		  (match_operand:HI 2 "msp430_general_operand"      "riYsYx,rmi")))]
305  ""
306  "@
307   ADD.W\t%2, %0
308   ADDX.W\t%2, %0"
309)
310
311; This pattern is needed in order to avoid reload problems.
312; It takes an SI pair of registers, adds a value to them, and
313; then converts them into a single PSI register.
314
315(define_insn "addsipsi3"
316  [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0)
317	(plus:SI (match_operand:SI    1 "register_operand" "0")
318		 (match_operand       2 "general_operand" "rmi")))]
319  ""
320  "ADD%X2.W\t%L2, %L0 { ADDC%X2.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0"
321)
322
323(define_insn "addsi3"
324  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=&rYsYx,rm")
325	(plus:SI (match_operand:SI 1 "general_operand" "%0,0")
326		 (match_operand:SI 2 "general_operand" "rYsYxi,mi")))]
327  ""
328  "@
329   ADD\t%L2, %L0 { ADDC\t%H2, %H0
330   ADDX\t%L2, %L0 { ADDCX\t%H2, %H0"
331)
332
333; Version of addhi that exposes the carry operations, for SImode adds.
334;
335; NOTE - we are playing a dangerous game with GCC here.  We have these two
336; add patterns and the splitter that follows because our tests have shown
337; that this results in a significant reduction in code size - because GCC is
338; able to discard any unused part of the addition.  We have to annotate the
339; patterns with the set and use of the carry flag because otherwise GCC will
340; discard parts of the addition when they are actually needed.  But we have
341; not annotated all the other patterns that set the CARRY flag as doing so
342; results in an overall increase in code size[1].  Instead we just *hope*
343; that GCC will not move a carry-setting instruction in between the first
344; and second adds.
345;
346; So far our experiments have shown that GCC is likely to move MOV and CMP
347; instructions in between the two adds, but not other instructions.  MOV is
348; safe, CMP is not.  So we have annotated the CMP patterns and left the
349; subtract, shift and other add patterns alone.  At the moment this is
350; working, but with future changes to the generic parts of GCC that might
351; change.
352;
353; [1] It is not clear exactly why the code size increases.  The cause appears
354; to be that reload is more prevelent to spilling a variable onto the stack
355; but why it does this is unknown.  Possibly the additional CLOBBERs necessary
356; to correctly annotate the other patterns makes reload think that there is
357; increased register pressure.  Or possibly reload does not handle ADD patterns
358; that are not single_set() very well.
359
360; match_operand 3 is likely to be the same as op2 most of the time - except
361; when op2 is a post_inc and we have stripped the post_inc from match_operand 3
362
363(define_insn "addhi3_cy"
364  [(set (match_operand:HI	   0 "msp430_general_dst_operand" "=rYsYx,rm")
365	(plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0")
366		 (match_operand:HI 2 "msp430_nonimmediate_operand" "rYsYxi,rm")))
367   (set (reg:BI CARRY)
368	(truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
369					   (zero_extend:SI (match_operand:HI 3 "msp430_nonimmediate_operand" "rYsYxi,rm")))
370				  (const_int 16))))
371   ]
372  ""
373  "@
374   ADD\t%2, %1 ; cy
375   ADDX\t%2, %1 ; cy"
376  )
377
378(define_insn "addhi3_cy_i"
379  [(set (match_operand:HI	   0 "msp430_general_dst_nonv_operand" "=r,rm")
380	(plus:HI (match_operand:HI 1 "general_operand" "%0,0")
381		 (match_operand:HI 2 "immediate_operand"     "i,i")))
382   (set (reg:BI CARRY)
383	(truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
384					   (match_operand 3 "immediate_operand" "i,i"))
385				  (const_int 16))))
386   ]
387  ""
388  "@
389   ADD\t%2, %1 ; cy
390   ADD%X0\t%2, %1 ; cy"
391  )
392
393; Version of addhi that adds the carry, for SImode adds.
394(define_insn "addchi4_cy"
395  [(set (match_operand:HI		    0 "msp430_general_dst_operand" "=rYsYx,rm")
396	(plus:HI (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0")
397			  (match_operand:HI 2 "msp430_general_operand"      "riYsYx,rmi"))
398		 (zero_extend:HI (reg:BI CARRY))))
399   ]
400  ""
401  "@
402   ADDC\t%2, %1
403   ADDCX\t%2, %1"
404  )
405
406; Split an SImode add into two HImode adds, keeping track of the carry
407; so that gcc knows when it can and can't optimize away the two
408; halves.
409; We use the ugly predicate "msp430_nonsubregnonpostinc_or_imm_operand" to
410; enforce the position of a post_inc into op2 if present
411(define_split
412  [(set (match_operand:SI	   0 "msp430_nonsubreg_dst_operand")
413	(plus:SI (match_operand:SI 1 "msp430_nonsubregnonpostinc_or_imm_operand")
414		 (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand")))
415   ]
416  ""
417  [(parallel [(set (match_operand:HI 3 "msp430_general_dst_nonv_operand" "=&rm")
418		   (plus:HI (match_dup 4)
419			    (match_dup 5)))
420	      (set (reg:BI CARRY)
421		   (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4))
422						      (match_dup 9))
423					     (const_int 16))))
424	      ])
425   (set (match_operand:HI 6 "msp430_general_dst_nonv_operand" "=&rm")
426	(plus:HI (plus:HI (match_dup 7)
427			  (match_dup 8))
428		 (zero_extend:HI (reg:BI CARRY))))
429   ]
430  "
431  if (msp430_split_addsi (operands))
432    FAIL;
433  "
434  )
435
436
437;; Alternatives 2 and 3 are to handle cases generated by reload.
438(define_insn "subpsi3"
439  [(set (match_operand:PSI	      0 "msp430_general_dst_nonv_operand"	"=r,   rm, &?r, ?&r")
440	(minus:PSI (match_operand:PSI 1 "general_operand"			"0,   0,   !r,  !i")
441		   (match_operand:PSI 2 "general_operand"			"rLs, rmi, rmi,  r")))]
442  ""
443  "@
444  SUBA\t%2, %0
445  SUBX.A\t%2, %0
446  MOVX.A\t%1, %0 { SUBX.A\t%2, %0
447  MOVX.A\t%1, %0 { SUBA\t%2, %0"
448)
449
450;; Alternatives 2 and 3 are to handle cases generated by reload.
451(define_insn "subqi3"
452  [(set (match_operand:QI	    0 "msp430_general_dst_nonv_operand" "=rYsYx,  rm,  &?r, ?&r")
453	(minus:QI (match_operand:QI 1 "general_operand"       "0,    0,    !r,  !i")
454		  (match_operand:QI 2 "general_operand"      " riYsYx, rmi, rmi,   r")))]
455  ""
456  "@
457  SUB.B\t%2, %0
458  SUBX.B\t%2, %0
459  MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0
460  MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0"
461)
462
463;; Alternatives 2 and 3 are to handle cases generated by reload.
464(define_insn "subhi3"
465  [(set (match_operand:HI	    0 "msp430_general_dst_nonv_operand" "=rYsYx,  rm,  &?r, ?&r")
466	(minus:HI (match_operand:HI 1 "general_operand"       "0,    0,    !r,  !i")
467		  (match_operand:HI 2 "general_operand"      " riYsYx, rmi, rmi,   r")))]
468  ""
469  "@
470  SUB.W\t%2, %0
471  SUBX.W\t%2, %0
472  MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0
473  MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0"
474)
475
476(define_insn "subsi3"
477  [(set (match_operand:SI	    0 "msp430_general_dst_nonv_operand" "=&rYsYx,m")
478	(minus:SI (match_operand:SI 1 "general_operand"   "0,0")
479		  (match_operand:SI 2 "general_operand"        "riYsYx,mi")))]
480  ""
481  "@
482  SUB\t%L2, %L0 { SUBC\t%H2, %H0
483  SUBX\t%L2, %L0 { SUBCX\t%H2, %H0"
484)
485
486(define_insn "*bic<mode>_cg"
487  [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYs,m")
488	(and:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0")
489		 (match_operand 2 "msp430_inv_constgen_operator" "n,n")))]
490  ""
491  "@
492   BIC%x0%b0\t#%I2, %0
493   BIC%X0%b0\t#%I2, %0"
494)
495
496(define_insn "bic<mode>3"
497  [(set (match_operand:QHI		     0 "msp430_general_dst_operand" "=rYsYx,rm")
498	(and:QHI (not:QHI (match_operand:QHI 1 "msp430_general_operand"       "rYsYx,rmn"))
499		 (match_operand:QHI	     2 "msp430_general_operand"  "0,0")))]
500  ""
501  "@
502   BIC%x0%b0\t%1, %0
503   BICX%b0\t%1, %0"
504)
505
506(define_insn "and<mode>3"
507  [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=r,rYsYx,rm")
508	(and:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0,0")
509		 (match_operand:QHI 2 "msp430_general_operand" "N,riYsYx,rmi")))]
510  ""
511  "@
512   AND%x0.B\t%2, %0
513   AND%x0%b0\t%2, %0
514   ANDX%b0\t%2, %0"
515)
516
517(define_insn "ior<mode>3"
518  [(set (match_operand:QHI	    0 "msp430_general_dst_operand" "=rYsYx,rm")
519	(ior:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0")
520		 (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))]
521  ""
522  "@
523   BIS%x0%b0\t%2, %0
524   BISX%b0\t%2, %0"
525)
526
527(define_insn "xor<mode>3"
528  [(set (match_operand:QHI	    0 "msp430_general_dst_operand" "=rYsYx,rm")
529	(xor:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0")
530		 (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))]
531  ""
532  "@
533   XOR%x0%b0\t%2, %0
534   XORX%b0\t%2, %0"
535)
536
537;; Macro : XOR #~0, %0
538(define_insn "one_cmpl<mode>2"
539  [(set (match_operand:QHI	    0 "msp430_general_dst_operand" "=rYs,m")
540	(not:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0")))]
541  ""
542  "@
543   INV%x0%b0\t%0
544   INV%X0%b0\t%0"
545)
546
547(define_insn "extendqihi2"
548  [(set (match_operand:HI		  0 "msp430_general_dst_operand" "=rYs,m")
549	(sign_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,0")))]
550  ""
551  "@
552   SXT%X0\t%0
553   SXT%X0\t%0"
554)
555
556;; ------------------------
557;; ZERO EXTEND INSTRUCTIONS
558;; Byte-writes to registers clear bits 19:8
559;;   * Byte-writes to memory do not affect bits 15:8
560;; Word-writes to registers clear bits 19:16
561;; PSImode writes to memory clear bits 15:4 of the second memory word
562;; We define all possible insns since that results in better code than if
563;; they are inferred.
564;; ------------------------
565
566(define_insn "zero_extendqihi2"
567  [(set (match_operand:HI		  0 "msp430_general_dst_operand" "=rYs,r,r,m")
568	(zero_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,rYs,m,0")))]
569  ""
570  "@
571   AND\t#0xff, %0
572   MOV.B\t%1, %0
573   MOV%X1.B\t%1, %0
574   AND%X0\t#0xff, %0"
575)
576
577(define_insn "zero_extendqipsi2"
578  [(set (match_operand:PSI		   0 "register_operand" "=r,r")
579	(zero_extend:PSI (match_operand:QI 1 "general_operand" "rYs,m")))]
580  "msp430x"
581  "@
582   MOV.B\t%1, %0
583   MOV%X1.B\t%1, %0"
584)
585
586(define_insn "zero_extendqisi2"
587  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r,r")
588	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,rm")))]
589  ""
590  "@
591  CLR\t%H0
592  MOV%X1.B\t%1,%L0 { CLR\t%H0"
593)
594
595(define_insn "zero_extendhipsi2"
596  [(set (match_operand:PSI		   0 "msp430_general_dst_operand" "=r,r,m")
597	(zero_extend:PSI (match_operand:HI 1 "msp430_general_operand"     "rYs,m,r")))]
598  "msp430x"
599  "@
600  MOV.W\t%1, %0
601  MOV%X1\t%1, %0
602  MOVX.A\t%1, %0"
603)
604
605(define_insn "zero_extendhisi2"
606  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm,r")
607	(zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")))]
608  ""
609  "@
610  MOV%X0.W\t#0,%H0
611  MOV.W\t%1,%L0 { MOV.W\t#0,%H0"
612)
613
614(define_insn "zero_extendhisipsi2"
615  [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r,r")
616	(subreg:PSI (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")) 0))]
617  "msp430x"
618  "@
619   AND.W\t#-1,%0
620   MOV.W\t%1,%0"
621)
622
623; Nasty - we are sign-extending a 20-bit PSI value in one register into
624; two adjacent 16-bit registers to make an SI value.  There is no MSP430X
625; instruction that will do this, so we push the 20-bit value onto the stack
626; and then pop it off as two 16-bit values.
627;
628; FIXME: The MSP430X documentation does not specify if zero-extension or
629; sign-extension happens when the 20-bit value is pushed onto the stack.
630; It is probably zero-extension, but if not this pattern will not work
631; when the PSI value is negative..
632;
633; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A....
634;
635; Note: We use a + constraint on operand 0 as otherwise GCC gets confused
636; about extending a single PSI mode register into a pair of SImode registers
637; with the same starting register.  It thinks that the upper register of
638; the pair is unused and so it can clobber it.  Try compiling 20050826-2.c
639; at -O2 to see this.
640
641; FIXME we can use MOVA for r->m if m is &abs20 or z16(rdst)
642(define_insn "zero_extendpsisi2"
643  [(set (match_operand:SI		   0 "register_operand" "+r,m")
644	(zero_extend:SI (match_operand:PSI 1 "register_operand" "r,r")))]
645  ""
646  "@
647  * if (REGNO (operands[1]) == SP_REGNO) \
648      /* If the source register is the stack pointer, the value \
649	 stored in the stack slot will be the value *after* the \
650	 stack pointer has been decremented.  So allow for that \
651	 here.  */ \
652      return \"PUSHM.A\t#1, %1 { ADDX.W\t#4, @r1 { POPX.W\t%L0 { POPX.W\t%H0 ; get stack pointer into %L0:%H0\"; \
653    else \
654      return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\";
655  MOVX.A %1, %0"
656)
657
658;; Below are unnamed insn patterns to catch pointer manipulation insns
659;; generated by combine.
660;; We get large code size bloat when a PSImode pointer is stored in
661;; memory, so we try to avoid that where possible and keep point manipulation
662;; between registers.
663; FIXME many of these should be unnnecessary once combine deals with
664; (sign_extend (zero_extend)) or (sign_extend (subreg)) BZ 91865.
665
666;; This is just another way of writing movqipsi/zero_extendqipsi
667(define_insn ""
668  [(set (match_operand:PSI 0 "register_operand" "=r")
669	(sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))]
670  "msp430x"
671  "MOV%X1.B\t%1, %0"
672)
673
674(define_insn ""
675  [(set (match_operand:PSI				   0 "register_operand" "=r,r")
676	(sign_extend:PSI (zero_extend:HI (match_operand:QI 1 "general_operand" "rYs,m"))))]
677  "msp430x"
678  "@
679   MOV.B\t%1, %0
680   MOV%X1.B\t%1, %0"
681)
682
683(define_insn ""
684  [(set (match_operand:SI 0 "register_operand" "=r")
685	(ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "rm"))
686		   (match_operand:HI 2 "immediate_operand" "M")))]
687  "msp430x"
688  "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0"
689)
690
691;; We are taking a char and shifting it and putting the result in 2 registers.
692;; the high register will always be for 0 shift counts < 8.
693(define_insn ""
694  [(set (match_operand:SI 0 "register_operand" "=r")
695	(ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))
696		   (match_operand:HI 2 "immediate_operand" "M")))]
697  "msp430x"
698  "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0"
699)
700
701;; Same as above but with a NOP sign_extend round the subreg
702(define_insn ""
703  [(set (match_operand:SI 0 "register_operand" "=r")
704	(ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))
705		   (match_operand:HI 2 "immediate_operand" "M")))]
706  "msp430x"
707  "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0"
708)
709
710(define_insn ""
711  [(set (match_operand:SI 0 "register_operand" "=r")
712	(zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))]
713  "msp430x"
714  "MOV%X1.B %1, %L0 { CLR %H0"
715)
716
717(define_insn ""
718  [(set (match_operand:PSI 0 "register_operand" "=r")
719	(ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))
720		    (match_operand:HI 2 "immediate_operand" "M")))]
721  "msp430x"
722  "MOV%X1.B %1, %0 { RLAM.W %2, %0"
723)
724;; END msp430 pointer manipulation combine insn patterns
725
726;; Eliminate extraneous zero-extends mysteriously created by gcc.
727(define_peephole2
728  [(set (match_operand:HI 0 "register_operand")
729	(zero_extend:HI (match_operand:QI 1 "general_operand")))
730   (set (match_operand:HI 2 "register_operand")
731	(zero_extend:HI (match_operand:QI 3 "register_operand")))]
732  "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])"
733  [(set (match_dup 0)
734	(zero_extend:HI (match_dup 1)))]
735)
736
737(define_insn "truncpsihi2"
738  [(set (match_operand:HI		0 "msp430_general_dst_operand" "=rm")
739	(truncate:HI (match_operand:PSI 1 "register_operand"      "r")))]
740  ""
741  "MOVX\t%1, %0"
742)
743
744(define_insn "extendhisi2"
745  [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r")
746	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
747  ""
748  { return msp430x_extendhisi (operands); }
749)
750
751(define_insn "extendhipsi2"
752  [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r")
753	(subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))]
754  "msp430x"
755  "RLAM.A #4, %0 { RRAM.A #4, %0"
756)
757
758;; Look for cases where integer/pointer conversions are suboptimal due
759;; to missing patterns, despite us not having opcodes for these
760;; patterns.  Doing these manually allows for alternate optimization
761;; paths.
762
763(define_insn "extend_and_shift1_hipsi2"
764  [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0)
765	(ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0"))
766		   (const_int 1)))]
767  "msp430x"
768  "RLAM.A #4, %0 { RRAM.A #3, %0"
769)
770
771(define_insn "extend_and_shift2_hipsi2"
772  [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0)
773	(ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0"))
774		   (const_int 2)))]
775  "msp430x"
776  "RLAM.A #4, %0 { RRAM.A #2, %0"
777)
778
779;; We also need to be able to sign-extend pointer types (eg ptrdiff_t).
780;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
781;; it, we use a different method here.
782
783(define_insn "extendpsisi2"
784  [(set (match_operand:SI                  0 "register_operand" "=r")
785	(sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
786  "msp430x"
787  "*
788    /* The intention here is that we copy the bottom 16-bits of
789       %1 into %L0 (zeroing the top four bits).  Then we copy the
790       entire 20-bits of %1 into %H0 and then arithmetically shift
791       it right by 16 bits, to get the top four bits of the pointer
792       sign-extended in %H0.  */
793    if (REGNO (operands[0]) == REGNO (operands[1]))
794      return \"MOVX.A\t%1, %H0 { MOV.W\t%1, %L0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\";
795    else
796      return \"MOV.W\t%1, %L0 { MOVX.A\t%1, %H0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\";
797  "
798)
799
800; See the movsipsi2 pattern above for another way that GCC performs this
801; conversion.
802(define_insn "truncsipsi2"
803  [(set (match_operand:PSI              0 "register_operand" "=r")
804	(truncate:PSI (match_operand:SI 1 "register_operand" "r")))]
805  ""
806  "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0"
807)
808
809;;------------------------------------------------------------
810;; Shift Functions
811
812;; Note:  We do not use the RPT ... SHIFT instruction sequence
813;; when the repeat count is in a register, because even though RPT
814;; accepts counts in registers, it does not work if the count is
815;; zero, and the actual count in the register has to be one less
816;; than the required number of iterations.  We could encode a
817;; seqeunce like this:
818;;
819;;   bit #0xf, Rn
820;;   bz  1f
821;;   dec Rn
822;;   rpt Rn
823;;   <shift> Rm
824;;   inc Rn
825;; 1:
826;;
827;; But is longer than calling a helper function, and we are mostly
828;; concerned with code size.  FIXME: Maybe enable a sequence like
829;; this at -O3 and above ?
830;;
831;; Note - we ignore shift counts of less than one or more than 15.
832;; This is permitted by the ISO C99 standard as such shifts result
833;; in "undefined" behavior.  [6.5.7 (3)]
834
835;; signed A << C
836
837(define_expand "ashlhi3"
838  [(set (match_operand:HI	     0 "msp430_general_dst_nonv_operand")
839	(ashift:HI (match_operand:HI 1 "general_operand")
840		   (match_operand:HI 2 "general_operand")))]
841  ""
842  {
843    if ((GET_CODE (operands[1]) == SUBREG
844	 && REG_P (XEXP (operands[1], 0)))
845	|| MEM_P (operands[1]))
846      operands[1] = force_reg (HImode, operands[1]);
847    if (msp430x
848        && REG_P (operands[0])
849        && REG_P (operands[1])
850        && CONST_INT_P (operands[2]))
851      emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2]));
852    else if (CONST_INT_P (operands[2])
853	     && INTVAL (operands[2]) == 1)
854      emit_insn (gen_slli_1 (operands[0], operands[1]));
855    else
856      /* The const variants of mspabi shifts have larger code size than the
857	 generic version, so use the generic version if optimizing for
858	 size.  */
859      msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size);
860    DONE;
861  }
862)
863
864(define_insn "slli_1"
865  [(set (match_operand:HI	     0 "msp430_general_dst_nonv_operand" "=rm")
866	(ashift:HI (match_operand:HI 1 "general_operand"       "0")
867		   (const_int 1)))]
868  ""
869  "RLA%X0.W\t%0" ;; Note - this is a macro for ADD
870)
871
872(define_insn "430x_shift_left"
873  [(set (match_operand:HI            0 "register_operand" "=r")
874	(ashift:HI (match_operand:HI 1 "register_operand"  "0")
875		   (match_operand    2 "immediate_operand" "n")))]
876  "msp430x"
877  "*
878  if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5)
879    return \"RLAM.W\t%2, %0\";
880  else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16)
881    return \"RPT\t%2 { RLAX.W\t%0\";
882  return \"# nop left shift\";
883  "
884)
885
886(define_insn "slll_1"
887  [(set (match_operand:SI	     0 "msp430_general_dst_nonv_operand" "=rm")
888	(ashift:SI (match_operand:SI 1 "general_operand"       "0")
889		   (const_int 1)))]
890  ""
891  "RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
892)
893
894(define_insn "slll_2"
895  [(set (match_operand:SI	     0 "msp430_general_dst_nonv_operand" "=rm")
896	(ashift:SI (match_operand:SI 1 "general_operand"       "0")
897		   (const_int 2)))]
898  ""
899  "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
900)
901
902(define_expand "ashlsi3"
903  [(set (match_operand:SI	     0 "msp430_general_dst_nonv_operand")
904	(ashift:SI (match_operand:SI 1 "general_operand")
905		   (match_operand:SI 2 "general_operand")))]
906  ""
907  "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size);
908   DONE;"
909)
910
911(define_expand "ashldi3"
912  [(set (match_operand:DI	     0 "msp430_general_dst_nonv_operand")
913	(ashift:DI (match_operand:DI 1 "general_operand")
914		   (match_operand:DI 2 "general_operand")))]
915  ""
916  {
917    /* No const_variant for 64-bit shifts.  */
918    msp430_expand_helper (operands, \"__mspabi_sllll\", false);
919    DONE;
920  }
921)
922
923;;----------
924
925;; signed A >> C
926
927(define_expand "ashrhi3"
928  [(set (match_operand:HI	       0 "msp430_general_dst_nonv_operand")
929	(ashiftrt:HI (match_operand:HI 1 "general_operand")
930		     (match_operand:HI 2 "general_operand")))]
931  ""
932  {
933    if ((GET_CODE (operands[1]) == SUBREG
934	 && REG_P (XEXP (operands[1], 0)))
935	|| MEM_P (operands[1]))
936      operands[1] = force_reg (HImode, operands[1]);
937    if (msp430x
938        && REG_P (operands[0])
939        && REG_P (operands[1])
940        && CONST_INT_P (operands[2]))
941      emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2]));
942    else if (CONST_INT_P (operands[2])
943	     && INTVAL (operands[2]) == 1)
944      emit_insn (gen_srai_1 (operands[0], operands[1]));
945    else
946       msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size);
947   DONE;
948   }
949)
950
951(define_insn "srai_1"
952  [(set (match_operand:HI	       0 "msp430_general_dst_operand" "=rm")
953	(ashiftrt:HI (match_operand:HI 1 "msp430_general_operand"      "0")
954		     (const_int 1)))]
955  ""
956  "RRA%X0.W\t%0"
957)
958
959(define_insn "430x_arithmetic_shift_right"
960  [(set (match_operand:HI              0 "register_operand" "=r")
961	(ashiftrt:HI (match_operand:HI 1 "register_operand"  "0")
962		     (match_operand    2 "immediate_operand" "n")))]
963  "msp430x"
964  "*
965  if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5)
966    return \"RRAM.W\t%2, %0\";
967  else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16)
968    return \"RPT\t%2 { RRAX.W\t%0\";
969  return \"# nop arith right shift\";
970  "
971)
972
973(define_insn "srap_1"
974  [(set (match_operand:PSI              0 "register_operand" "=r")
975	(ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
976		      (const_int 1)))]
977  "msp430x"
978  "RRAM.A #1,%0"
979)
980
981(define_insn "srap_2"
982  [(set (match_operand:PSI              0 "register_operand" "=r")
983	(ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
984		      (const_int 2)))]
985  "msp430x"
986  "RRAM.A #2,%0"
987)
988
989(define_insn "sral_1"
990  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand" "=rm")
991	(ashiftrt:SI (match_operand:SI 1 "general_operand"       "0")
992		     (const_int 1)))]
993  ""
994  "RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
995)
996
997(define_insn "sral_2"
998  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand" "=rm")
999	(ashiftrt:SI (match_operand:SI 1 "general_operand"       "0")
1000		     (const_int 2)))]
1001  ""
1002  "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
1003)
1004
1005(define_expand "ashrsi3"
1006  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand")
1007	(ashiftrt:SI (match_operand:SI 1 "general_operand")
1008		     (match_operand:SI 2 "general_operand")))]
1009  ""
1010  "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size);
1011   DONE;"
1012)
1013
1014(define_expand "ashrdi3"
1015  [(set (match_operand:DI	     0 "msp430_general_dst_nonv_operand")
1016	(ashift:DI (match_operand:DI 1 "general_operand")
1017		   (match_operand:DI 2 "general_operand")))]
1018  ""
1019  {
1020    /* No const_variant for 64-bit shifts.  */
1021    msp430_expand_helper (operands, \"__mspabi_srall\", false);
1022    DONE;
1023  }
1024)
1025
1026;;----------
1027
1028;; unsigned A >> C
1029
1030(define_expand "lshrhi3"
1031  [(set (match_operand:HI	       0 "msp430_general_dst_nonv_operand")
1032	(lshiftrt:HI (match_operand:HI 1 "general_operand")
1033		     (match_operand:HI 2 "general_operand")))]
1034  ""
1035  {
1036    if ((GET_CODE (operands[1]) == SUBREG
1037	 && REG_P (XEXP (operands[1], 0)))
1038	|| MEM_P (operands[1]))
1039      operands[1] = force_reg (HImode, operands[1]);
1040    if (msp430x
1041        && REG_P (operands[0])
1042        && REG_P (operands[1])
1043        && CONST_INT_P (operands[2]))
1044      emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2]));
1045    else if (CONST_INT_P (operands[2])
1046	     && INTVAL (operands[2]) == 1)
1047      emit_insn (gen_srli_1 (operands[0], operands[1]));
1048    else
1049      msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size);
1050    DONE;
1051  }
1052)
1053
1054(define_insn "srli_1"
1055  [(set (match_operand:HI	       0 "msp430_general_dst_nonv_operand" "=rm")
1056	(lshiftrt:HI (match_operand:HI 1 "general_operand"       "0")
1057		     (const_int 1)))]
1058  ""
1059  "CLRC { RRC%X0.W\t%0"
1060)
1061
1062(define_insn "430x_logical_shift_right"
1063  [(set (match_operand:HI              0 "register_operand" "=r")
1064	(lshiftrt:HI (match_operand:HI 1 "register_operand"  "0")
1065		     (match_operand    2 "immediate_operand" "n")))]
1066  "msp430x"
1067  {
1068    return msp430x_logical_shift_right (operands[2]);
1069  }
1070)
1071
1072(define_insn "srlp_1"
1073  [(set (match_operand:PSI              0 "register_operand" "=r")
1074	(lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
1075		      (const_int 1)))]
1076  ""
1077  "RRUM.A #1,%0"
1078)
1079
1080(define_insn "srll_1"
1081  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand" "=rm")
1082	(lshiftrt:SI (match_operand:SI 1 "general_operand"       "0")
1083		     (const_int 1)))]
1084  ""
1085  "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0"
1086)
1087
1088(define_insn "srll_2x"
1089  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand" "=r")
1090	(lshiftrt:SI (match_operand:SI 1 "general_operand"       "0")
1091		     (const_int 2)))]
1092  "msp430x"
1093  "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0"
1094)
1095
1096(define_expand "lshrsi3"
1097  [(set (match_operand:SI	       0 "msp430_general_dst_nonv_operand")
1098	(lshiftrt:SI (match_operand:SI 1 "general_operand")
1099		     (match_operand:SI 2 "general_operand")))]
1100  ""
1101  "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size);
1102   DONE;"
1103)
1104
1105(define_expand "lshrdi3"
1106  [(set (match_operand:DI	     0 "msp430_general_dst_nonv_operand")
1107	(ashift:DI (match_operand:DI 1 "general_operand")
1108		   (match_operand:DI 2 "general_operand")))]
1109  ""
1110  {
1111    /* No const_variant for 64-bit shifts.  */
1112    msp430_expand_helper (operands, \"__mspabi_srlll\", false);
1113    DONE;
1114  }
1115)
1116
1117;;------------------------------------------------------------
1118;; Function Entry/Exit
1119
1120(define_expand "prologue"
1121  [(const_int 0)]
1122  ""
1123  "msp430_expand_prologue (); DONE;"
1124  )
1125
1126(define_expand "epilogue"
1127  [(const_int 0)]
1128  ""
1129  "msp430_expand_epilogue (0); DONE;"
1130  )
1131
1132(define_insn "epilogue_helper"
1133  [(set (pc)
1134        (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER))
1135   (return)]
1136  ""
1137  "BR%Q0\t#__mspabi_func_epilog_%J0"
1138  )
1139
1140(define_insn "prologue_start_marker"
1141  [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)]
1142  ""
1143  "; start of prologue"
1144  )
1145
1146(define_insn "prologue_end_marker"
1147  [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)]
1148  ""
1149  "; end of prologue"
1150  )
1151
1152(define_insn "epilogue_start_marker"
1153  [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)]
1154  ""
1155  "; start of epilogue"
1156  )
1157
1158;; This makes the linker add a call to exit() after the call to main()
1159;; in crt0
1160(define_insn "msp430_refsym_need_exit"
1161  [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)]
1162  ""
1163  ".refsym\t__crt0_call_exit"
1164  )
1165
1166;;------------------------------------------------------------
1167;; Jumps
1168
1169(define_expand "call"
1170  [(call:HI (match_operand 0 "")
1171	    (match_operand 1 ""))]
1172  ""
1173  ""
1174)
1175
1176(define_insn "call_internal"
1177  [(call (mem:HI (match_operand 0 "general_operand" "rYci"))
1178	 (match_operand 1 ""))]
1179  ""
1180  "CALL%Q0\t%0"
1181)
1182
1183(define_expand "call_value"
1184  [(set (match_operand          0 "register_operand")
1185	(call:HI (match_operand 1 "general_operand")
1186		 (match_operand 2 "")))]
1187  ""
1188  ""
1189)
1190
1191(define_insn "call_value_internal"
1192  [(set (match_operand               0 "register_operand" "=r")
1193	(call (mem:HI (match_operand 1 "general_operand" "rYci"))
1194	      (match_operand 2 "")))]
1195  ""
1196  "CALL%Q0\t%1"
1197)
1198
1199(define_insn "msp430_return"
1200  [(return)]
1201  ""
1202  { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
1203)
1204
1205;; This pattern is NOT, as expected, a return pattern.  It's called
1206;; before reload and must only store its operands, and emit a
1207;; placeholder where the epilog needs to be.  AFTER reload, the
1208;; placeholder should get expanded into a regular-type epilogue that
1209;; also does the EH return.
1210(define_expand "eh_return"
1211  [(match_operand:HI 0 "")]
1212  ""
1213  "msp430_expand_eh_return (operands[0]);
1214   emit_jump_insn (gen_msp430_eh_epilogue ());
1215   emit_barrier ();
1216   DONE;"
1217)
1218
1219;; This is the actual EH epilogue.  We emit it in the pattern above,
1220;; before reload, and convert it to a real epilogue after reload.
1221(define_insn_and_split "msp430_eh_epilogue"
1222  [(eh_return)]
1223  ""
1224  "#"
1225  "reload_completed"
1226  [(const_int 0)]
1227  "msp430_expand_epilogue (1); DONE;"
1228  )
1229
1230(define_insn "jump"
1231  [(set (pc)
1232	(label_ref (match_operand 0 "" "")))]
1233  ""
1234  "BR%Q0\t#%l0"
1235)
1236
1237;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs
1238;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c).
1239(define_insn "indirect_jump"
1240  [(set (pc)
1241	(match_operand 0 "nonimmediate_operand" "rYl"))]
1242  ""
1243  "BR%Q0\t%0"
1244)
1245
1246;;------------------------------------------------------------
1247;; Various Conditionals
1248
1249(define_expand "cbranch<mode>4"
1250  [(parallel [(set (pc) (if_then_else
1251			 (match_operator 0 ""
1252					 [(match_operand:QHI 1 "msp430_general_dst_nonv_operand")
1253					  (match_operand:QHI 2 "general_operand")])
1254			 (label_ref (match_operand 3 "" ""))
1255			 (pc)))
1256	      (clobber (reg:BI CARRY))]
1257  )]
1258  ""
1259  "msp430_fixup_compare_operands (<MODE>mode, operands);"
1260  )
1261
1262(define_insn "cbranchpsi4_real"
1263  [(set (pc) (if_then_else
1264	      (match_operator                     0 "msp430_cmp_operator"
1265			      [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm")
1266			       (match_operand:PSI 2 "general_operand"      "rLs,rYsi,rmi")])
1267              (label_ref (match_operand           3 "" ""))
1268	      (pc)))
1269   (clobber (reg:BI CARRY))
1270   ]
1271  ""
1272  "@
1273  CMP%Q0\t%2, %1 { J%0\t%l3
1274  CMPX.A\t%2, %1 { J%0\t%l3
1275  CMPX.A\t%2, %1 { J%0\t%l3"
1276  )
1277
1278(define_insn "cbranchqi4_real"
1279  [(set (pc) (if_then_else
1280	      (match_operator                    0 "msp430_cmp_operator"
1281			      [(match_operand:QI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm")
1282			       (match_operand:QI 2 "general_operand"      "rYsYxi,rmi")])
1283              (label_ref (match_operand          3 "" ""))
1284	      (pc)))
1285   (clobber (reg:BI CARRY))
1286   ]
1287  ""
1288  "@
1289   CMP.B\t%2, %1 { J%0\t%l3
1290   CMPX.B\t%2, %1 { J%0\t%l3"
1291  )
1292
1293(define_insn "cbranchhi4_real"
1294  [(set (pc) (if_then_else
1295	      (match_operator                    0 "msp430_cmp_operator"
1296			      [(match_operand:HI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm")
1297			       (match_operand:HI 2 "general_operand"      "rYsYxi,rmi")])
1298              (label_ref (match_operand          3 "" ""))
1299	      (pc)))
1300   (clobber (reg:BI CARRY))
1301   ]
1302  ""
1303  "*
1304    /* This is nasty.  If we are splitting code between low and high memory
1305       then we do not want the linker to increase the size of sections by
1306       relaxing out of range jump instructions.  (Since relaxation occurs
1307       after section placement).  So we have to generate pessimal branches
1308       here.  But we only want to do this when really necessary.
1309
1310       FIXME: Do we need code in the other cbranch patterns ?  */
1311    if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6)
1312      {
1313        return which_alternative == 0 ?
1314            \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" :
1315	    \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\";
1316      }
1317
1318    return which_alternative == 0 ?
1319         \"CMP.W\t%2, %1 { J%0\t%l3\" :
1320	 \"CMPX.W\t%2, %1 { J%0\t%l3\";
1321  "
1322  [(set (attr "length")
1323	(if_then_else
1324	  (and (ge (minus (match_dup 3) (pc)) (const_int -510))
1325	       (le (minus (match_dup 3) (pc)) (const_int 510)))
1326	  (const_int 6)
1327	  (const_int 10))
1328	)]
1329  )
1330
1331(define_insn "cbranchpsi4_reversed"
1332  [(set (pc) (if_then_else
1333	      (match_operator                     0 "msp430_reversible_cmp_operator"
1334			      [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi")
1335			       (match_operand:PSI 2 "msp430_general_dst_nonv_operand" "r,rYs,rm")])
1336              (label_ref (match_operand           3 "" ""))
1337	      (pc)))
1338   (clobber (reg:BI CARRY))
1339   ]
1340  ""
1341  "@
1342  CMP%Q0\t%1, %2 { J%R0\t%l3
1343  CMPX.A\t%1, %2 { J%R0\t%l3
1344  CMPX.A\t%1, %2 { J%R0\t%l3"
1345  )
1346
1347(define_insn "cbranchqi4_reversed"
1348  [(set (pc) (if_then_else
1349	      (match_operator                    0 "msp430_reversible_cmp_operator"
1350			      [(match_operand:QI 1 "general_operand" "rYsYxi,rmi")
1351			       (match_operand:QI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")])
1352              (label_ref (match_operand          3 "" ""))
1353	      (pc)))
1354   (clobber (reg:BI CARRY))
1355   ]
1356  ""
1357  "@
1358   CMP.B\t%1, %2 { J%R0\t%l3
1359   CMPX.B\t%1, %2 { J%R0\t%l3"
1360  )
1361
1362(define_insn "cbranchhi4_reversed"
1363  [(set (pc) (if_then_else
1364	      (match_operator                    0 "msp430_reversible_cmp_operator"
1365			      [(match_operand:HI 1 "general_operand" "rYsYxi,rmi")
1366			       (match_operand:HI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")])
1367              (label_ref (match_operand          3 "" ""))
1368	      (pc)))
1369   (clobber (reg:BI CARRY))
1370   ]
1371  ""
1372  "@
1373   CMP.W\t%1, %2 { J%R0\t%l3
1374   CMPX.W\t%1, %2 { J%R0\t%l3"
1375  )
1376
1377(define_insn "*bitbranch<mode>4"
1378  [(set (pc) (if_then_else
1379	      (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1380			   (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1381		  (const_int 0))
1382              (label_ref (match_operand 2 "" ""))
1383	      (pc)))
1384   (clobber (reg:BI CARRY))
1385   ]
1386  ""
1387  "@
1388   BIT%x0%b0\t%1, %0 { JNE\t%l2
1389   BITX%b0\t%1, %0 { JNE\t%l2"
1390  )
1391
1392(define_insn "*bitbranch<mode>4"
1393  [(set (pc) (if_then_else
1394	      (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1395			   (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1396		  (const_int 0))
1397              (label_ref (match_operand 2 "" ""))
1398	      (pc)))
1399   (clobber (reg:BI CARRY))
1400   ]
1401  ""
1402  "@
1403   BIT%x0%b0\t%1, %0 { JEQ\t%l2
1404   BITX%b0\t%1, %0 { JEQ\t%l2"
1405  )
1406
1407(define_insn "*bitbranch<mode>4"
1408  [(set (pc) (if_then_else
1409	      (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1410			   (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1411		  (const_int 0))
1412              (pc)
1413	      (label_ref (match_operand 2 "" ""))))
1414   (clobber (reg:BI CARRY))
1415   ]
1416  ""
1417  "@
1418  BIT%x0%b0\t%1, %0 { JNE\t%l2
1419  BITX%b0\t%1, %0 { JNE\t%l2"
1420  )
1421
1422(define_insn "*bitbranch<mode>4"
1423  [(set (pc) (if_then_else
1424	      (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1425			   (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1426		  (const_int 0))
1427              (pc)
1428	      (label_ref (match_operand 2 "" ""))))
1429   (clobber (reg:BI CARRY))
1430   ]
1431  ""
1432  "@
1433  BIT%x0%b0\t%1, %0 { JEQ\t%l2
1434  BITX%b0\t%1, %0 { JEQ\t%l2"
1435  )
1436
1437;;------------------------------------------------------------
1438;; zero-extract versions of the above
1439
1440(define_insn "*bitbranch<mode>4_z"
1441  [(set (pc) (if_then_else
1442	      (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm")
1443				    (const_int 1)
1444				    (match_operand 1 "msp430_bitpos" "i,i"))
1445		  (const_int 0))
1446              (label_ref (match_operand 2 "" ""))
1447	      (pc)))
1448   (clobber (reg:BI CARRY))
1449   ]
1450  ""
1451  "@
1452   BIT%x0%b0\t%p1, %0 { JNE\t%l2
1453   BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1454  )
1455
1456(define_insn "*bitbranch<mode>4_z"
1457  [(set (pc) (if_then_else
1458	      (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1459				   (const_int 1)
1460				   (match_operand 1 "msp430_bitpos" "i"))
1461		  (const_int 0))
1462              (label_ref (match_operand 2 "" ""))
1463	      (pc)))
1464   (clobber (reg:BI CARRY))
1465   ]
1466  ""
1467  "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1468  )
1469
1470(define_insn "*bitbranch<mode>4_z"
1471  [(set (pc) (if_then_else
1472	      (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1473				   (const_int 1)
1474				   (match_operand 1 "msp430_bitpos" "i"))
1475		  (const_int 0))
1476              (pc)
1477	      (label_ref (match_operand 2 "" ""))))
1478   (clobber (reg:BI CARRY))
1479   ]
1480  ""
1481  "BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1482  )
1483
1484(define_insn "*bitbranch<mode>4_z"
1485  [(set (pc) (if_then_else
1486	      (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1487				   (const_int 1)
1488				   (match_operand 1 "msp430_bitpos" "i"))
1489		  (const_int 0))
1490              (pc)
1491	      (label_ref (match_operand 2 "" ""))))
1492   (clobber (reg:BI CARRY))
1493   ]
1494  ""
1495  "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1496  )
1497
1498;;------------------------------------------------------------
1499;; Misc
1500
1501(define_insn "nop"
1502  [(const_int 0)]
1503  "1"
1504  "NOP"
1505)
1506
1507(define_insn "disable_interrupts"
1508  [(unspec_volatile [(const_int 0)] UNS_DINT)]
1509  ""
1510  "DINT \; NOP"
1511  )
1512
1513(define_insn "enable_interrupts"
1514  [(unspec_volatile [(const_int 0)] UNS_EINT)]
1515  ""
1516  "EINT"
1517  )
1518
1519(define_insn "push_intr_state"
1520  [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
1521  ""
1522  "PUSH\tSR"
1523  )
1524
1525(define_insn "pop_intr_state"
1526  [(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
1527  ""
1528  "POP\tSR"
1529  )
1530
1531;; Clear bits in the copy of the status register that is currently
1532;; saved on the stack at the top of the interrupt handler.
1533(define_insn "bic_SR"
1534  [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
1535  ""
1536  "BIC.W\t%0, %O0(SP)"
1537  )
1538
1539;; Set bits in the copy of the status register that is currently
1540;; saved on the stack at the top of the interrupt handler.
1541(define_insn "bis_SR"
1542  [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
1543  ""
1544  "BIS.W\t%0, %O0(SP)"
1545  )
1546
1547;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int)))
1548;; very late on in the compilation and not splitting it into separate
1549;; instructions, so we provide a pattern to support it here.
1550(define_insn "andneghi3"
1551  [(set (match_operand:HI                 0 "register_operand" "=r")
1552	(and:HI (neg:HI (match_operand:HI 1 "register_operand"  "r"))
1553		(match_operand            2 "immediate_operand" "n")))]
1554  ""
1555  "*
1556    if (REGNO (operands[0]) != REGNO (operands[1]))
1557      return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1558    else
1559      return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1560  "
1561  )
1562
1563(define_insn "delay_cycles_start"
1564  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1565		    UNS_DELAY_START)]
1566  ""
1567  "; Begin %J0 cycle delay"
1568  )
1569
1570(define_insn "delay_cycles_end"
1571  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1572		    UNS_DELAY_END)]
1573  ""
1574  "; End %J0 cycle delay"
1575  )
1576
1577(define_insn "delay_cycles_32"
1578  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1579		     (match_operand 1 "immediate_operand" "i")
1580		     ] UNS_DELAY_32)]
1581  ""
1582  "PUSH	r13
1583	PUSH	r14
1584	MOV.W	%A0, r13
1585	MOV.W	%B0, r14
15861:	SUB.W	#1, r13
1587	SUBC.W	#0, r14
1588	JNE	1b
1589	TST.W	r13
1590	JNE	1b
1591	POP	r14
1592	POP	r13"
1593  )
1594
1595(define_insn "delay_cycles_32x"
1596  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1597		     (match_operand 1 "immediate_operand" "i")
1598		     ] UNS_DELAY_32X)]
1599  ""
1600  "PUSHM.A	#2,r14
1601	MOV.W	%A0, r13
1602	MOV.W	%B0, r14
16031:	SUB.W	#1, r13
1604	SUBC.W	#0, r14
1605	JNE	1b
1606	TST.W	r13
1607	JNE	1b
1608	POPM.A	#2,r14"
1609  )
1610
1611(define_insn "delay_cycles_16"
1612  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1613		     (match_operand 1 "immediate_operand" "i")
1614		     ] UNS_DELAY_16)]
1615  ""
1616  "PUSH	r13
1617	MOV.W	%0, r13
16181:	SUB.W	#1, r13
1619	JNE	1b
1620	POP	r13"
1621  )
1622
1623(define_insn "delay_cycles_16x"
1624  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1625		     (match_operand 1 "immediate_operand" "i")
1626		     ] UNS_DELAY_16X)]
1627  ""
1628  "PUSHM.A	#1,r13
1629	MOV.W	%0, r13
16301:	SUB.W	#1, r13
1631	JNE	1b
1632	POPM.A	#1,r13"
1633  )
1634
1635(define_insn "delay_cycles_2"
1636  [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)]
1637  ""
1638  "JMP	.+2"
1639  )
1640
1641(define_insn "delay_cycles_1"
1642  [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)]
1643  ""
1644  "NOP"
1645  )
1646
1647; libgcc helper functions for widening multiplication aren't currently
1648; generated by gcc, so we can't catch them later and map them to the mspabi
1649; functions.
1650; We catch the patterns here and either generate a call to the helper function,
1651; or emit the hardware multiply instruction sequence inline.
1652;
1653; If we don't have hardware multiply support, it will generally be slower and
1654; result in larger code to call the mspabi library function to perform the
1655; widening multiplication than just leaving GCC to widen the arguments itself.
1656;
1657; We don't use library functions for SImode->DImode widening since its always
1658; larger and slower than letting GCC widen the arguments inline.
1659(define_expand "mulhisi3"
1660  [(set (match_operand:SI			   0 "register_operand" "=r")
1661	(mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1662		 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1663  "msp430_has_hwmult ()"
1664  {
1665    /* Leave the other case for the inline insn.  */
1666    if (!(optimize > 2 && msp430_has_hwmult ()))
1667    {
1668      msp430_expand_helper (operands, "__mspabi_mpysl", false);
1669      DONE;
1670    }
1671  }
1672)
1673
1674(define_expand "umulhisi3"
1675  [(set (match_operand:SI			   0 "register_operand" "=r")
1676	(mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1677		 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1678  "msp430_has_hwmult ()"
1679  {
1680    /* Leave the other case for the inline insn.  */
1681    if (!(optimize > 2 && msp430_has_hwmult ()))
1682    {
1683      msp430_expand_helper (operands, "__mspabi_mpyul", false);
1684      DONE;
1685    }
1686  }
1687)
1688
1689(define_insn "*mulhisi3_inline"
1690  [(set (match_operand:SI                          0 "register_operand" "=r")
1691	(mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1692		 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1693  "optimize > 2 && msp430_has_hwmult ()"
1694  "*
1695    if (msp430_use_f5_series_hwmult ())
1696      return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C2 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\";
1697    else
1698      return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\";
1699  "
1700)
1701
1702(define_insn "*umulhisi3_inline"
1703  [(set (match_operand:SI                          0 "register_operand" "=r")
1704	(mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1705		 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1706  "optimize > 2 && msp430_has_hwmult ()"
1707  "*
1708    if (msp430_use_f5_series_hwmult ())
1709      return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C0 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\";
1710    else
1711      return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\";
1712  "
1713)
1714
1715(define_insn "mulsidi3"
1716  [(set (match_operand:DI                          0 "register_operand" "=r")
1717	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1718		 (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1719  "optimize > 2 && msp430_has_hwmult ()"
1720  "*
1721    if (msp430_use_f5_series_hwmult ())
1722      return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D4 { MOV.W %H1, &0x04D6 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\";
1723    else
1724      return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\";
1725  "
1726)
1727
1728(define_insn "umulsidi3"
1729  [(set (match_operand:DI                          0 "register_operand" "=r")
1730	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1731		 (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1732  "optimize > 2 && msp430_has_hwmult ()"
1733  "*
1734    if (msp430_use_f5_series_hwmult ())
1735      return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D0 { MOV.W %H1, &0x04D2 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\";
1736    else
1737      return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0140 { MOV.W %H1, &0x0142 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\";
1738  "
1739)
1740