]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/msp430/msp430.md
MSP430: Define extendqipsi2
[thirdparty/gcc.git] / gcc / config / msp430 / msp430.md
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 \f
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 (define_insn "extendqipsi2"
557 [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,m")
558 (sign_extend:PSI (match_operand:QI 1 "msp430_general_operand" "0,0")))]
559 ""
560 "@
561 SXT\t%0
562 SXTX.A\t%0"
563 )
564
565 ;; ------------------------
566 ;; ZERO EXTEND INSTRUCTIONS
567 ;; Byte-writes to registers clear bits 19:8
568 ;; * Byte-writes to memory do not affect bits 15:8
569 ;; Word-writes to registers clear bits 19:16
570 ;; PSImode writes to memory clear bits 15:4 of the second memory word
571 ;; We define all possible insns since that results in better code than if
572 ;; they are inferred.
573 ;; ------------------------
574
575 (define_insn "zero_extendqihi2"
576 [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,r,r,m")
577 (zero_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,rYs,m,0")))]
578 ""
579 "@
580 AND\t#0xff, %0
581 MOV.B\t%1, %0
582 MOV%X1.B\t%1, %0
583 AND%X0\t#0xff, %0"
584 )
585
586 (define_insn "zero_extendqipsi2"
587 [(set (match_operand:PSI 0 "register_operand" "=r,r")
588 (zero_extend:PSI (match_operand:QI 1 "general_operand" "rYs,m")))]
589 "msp430x"
590 "@
591 MOV.B\t%1, %0
592 MOV%X1.B\t%1, %0"
593 )
594
595 (define_insn "zero_extendqisi2"
596 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r,r")
597 (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,rm")))]
598 ""
599 "@
600 CLR\t%H0
601 MOV%X1.B\t%1,%L0 { CLR\t%H0"
602 )
603
604 (define_insn "zero_extendhipsi2"
605 [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,m")
606 (zero_extend:PSI (match_operand:HI 1 "msp430_general_operand" "rYs,m,r")))]
607 "msp430x"
608 "@
609 MOV.W\t%1, %0
610 MOV%X1\t%1, %0
611 MOVX.A\t%1, %0"
612 )
613
614 (define_insn "zero_extendhisi2"
615 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm,r")
616 (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")))]
617 ""
618 "@
619 MOV%X0.W\t#0,%H0
620 MOV.W\t%1,%L0 { MOV.W\t#0,%H0"
621 )
622
623 (define_insn "zero_extendhisipsi2"
624 [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r,r")
625 (subreg:PSI (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")) 0))]
626 "msp430x"
627 "@
628 AND.W\t#-1,%0
629 MOV.W\t%1,%0"
630 )
631
632 ; Nasty - we are sign-extending a 20-bit PSI value in one register into
633 ; two adjacent 16-bit registers to make an SI value. There is no MSP430X
634 ; instruction that will do this, so we push the 20-bit value onto the stack
635 ; and then pop it off as two 16-bit values.
636 ;
637 ; FIXME: The MSP430X documentation does not specify if zero-extension or
638 ; sign-extension happens when the 20-bit value is pushed onto the stack.
639 ; It is probably zero-extension, but if not this pattern will not work
640 ; when the PSI value is negative..
641 ;
642 ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A....
643 ;
644 ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused
645 ; about extending a single PSI mode register into a pair of SImode registers
646 ; with the same starting register. It thinks that the upper register of
647 ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c
648 ; at -O2 to see this.
649
650 ; FIXME we can use MOVA for r->m if m is &abs20 or z16(rdst)
651 (define_insn "zero_extendpsisi2"
652 [(set (match_operand:SI 0 "register_operand" "+r,m")
653 (zero_extend:SI (match_operand:PSI 1 "register_operand" "r,r")))]
654 ""
655 "@
656 * if (REGNO (operands[1]) == SP_REGNO) \
657 /* If the source register is the stack pointer, the value \
658 stored in the stack slot will be the value *after* the \
659 stack pointer has been decremented. So allow for that \
660 here. */ \
661 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\"; \
662 else \
663 return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\";
664 MOVX.A %1, %0"
665 )
666
667 ;; Below are unnamed insn patterns to catch pointer manipulation insns
668 ;; generated by combine.
669 ;; We get large code size bloat when a PSImode pointer is stored in
670 ;; memory, so we try to avoid that where possible and keep point manipulation
671 ;; between registers.
672 ; FIXME many of these should be unnnecessary once combine deals with
673 ; (sign_extend (zero_extend)) or (sign_extend (subreg)) BZ 91865.
674
675 ;; This is just another way of writing movqipsi/zero_extendqipsi
676 (define_insn ""
677 [(set (match_operand:PSI 0 "register_operand" "=r")
678 (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))]
679 "msp430x"
680 "MOV%X1.B\t%1, %0"
681 )
682
683 (define_insn ""
684 [(set (match_operand:PSI 0 "register_operand" "=r,r")
685 (sign_extend:PSI (zero_extend:HI (match_operand:QI 1 "general_operand" "rYs,m"))))]
686 "msp430x"
687 "@
688 MOV.B\t%1, %0
689 MOV%X1.B\t%1, %0"
690 )
691
692 (define_insn ""
693 [(set (match_operand:SI 0 "register_operand" "=r")
694 (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "rm"))
695 (match_operand:HI 2 "immediate_operand" "M")))]
696 "msp430x"
697 "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0"
698 )
699
700 ;; We are taking a char and shifting it and putting the result in 2 registers.
701 ;; the high register will always be for 0 shift counts < 8.
702 (define_insn ""
703 [(set (match_operand:SI 0 "register_operand" "=r")
704 (ashift:SI (zero_extend:SI (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 ;; Same as above but with a NOP sign_extend round the subreg
711 (define_insn ""
712 [(set (match_operand:SI 0 "register_operand" "=r")
713 (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))
714 (match_operand:HI 2 "immediate_operand" "M")))]
715 "msp430x"
716 "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0"
717 )
718
719 (define_insn ""
720 [(set (match_operand:SI 0 "register_operand" "=r")
721 (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))]
722 "msp430x"
723 "MOV%X1.B %1, %L0 { CLR %H0"
724 )
725
726 (define_insn ""
727 [(set (match_operand:PSI 0 "register_operand" "=r")
728 (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))
729 (match_operand:HI 2 "immediate_operand" "M")))]
730 "msp430x"
731 "MOV%X1.B %1, %0 { RLAM.W %2, %0"
732 )
733 ;; END msp430 pointer manipulation combine insn patterns
734
735 ;; Eliminate extraneous zero-extends mysteriously created by gcc.
736 (define_peephole2
737 [(set (match_operand:HI 0 "register_operand")
738 (zero_extend:HI (match_operand:QI 1 "general_operand")))
739 (set (match_operand:HI 2 "register_operand")
740 (zero_extend:HI (match_operand:QI 3 "register_operand")))]
741 "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])"
742 [(set (match_dup 0)
743 (zero_extend:HI (match_dup 1)))]
744 )
745
746 (define_insn "truncpsihi2"
747 [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm")
748 (truncate:HI (match_operand:PSI 1 "register_operand" "r")))]
749 ""
750 "MOVX\t%1, %0"
751 )
752
753 (define_insn "extendhisi2"
754 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r")
755 (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
756 ""
757 { return msp430x_extendhisi (operands); }
758 )
759
760 (define_insn "extendhipsi2"
761 [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r")
762 (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))]
763 "msp430x"
764 "RLAM.A #4, %0 { RRAM.A #4, %0"
765 )
766
767 ;; Look for cases where integer/pointer conversions are suboptimal due
768 ;; to missing patterns, despite us not having opcodes for these
769 ;; patterns. Doing these manually allows for alternate optimization
770 ;; paths.
771
772 (define_insn "extend_and_shift1_hipsi2"
773 [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0)
774 (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0"))
775 (const_int 1)))]
776 "msp430x"
777 "RLAM.A #4, %0 { RRAM.A #3, %0"
778 )
779
780 (define_insn "extend_and_shift2_hipsi2"
781 [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0)
782 (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0"))
783 (const_int 2)))]
784 "msp430x"
785 "RLAM.A #4, %0 { RRAM.A #2, %0"
786 )
787
788 ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t).
789 ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
790 ;; it, we use a different method here.
791
792 (define_insn "extendpsisi2"
793 [(set (match_operand:SI 0 "register_operand" "=r")
794 (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
795 "msp430x"
796 "*
797 /* The intention here is that we copy the bottom 16-bits of
798 %1 into %L0 (zeroing the top four bits). Then we copy the
799 entire 20-bits of %1 into %H0 and then arithmetically shift
800 it right by 16 bits, to get the top four bits of the pointer
801 sign-extended in %H0. */
802 if (REGNO (operands[0]) == REGNO (operands[1]))
803 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\";
804 else
805 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\";
806 "
807 )
808
809 ; See the movsipsi2 pattern above for another way that GCC performs this
810 ; conversion.
811 (define_insn "truncsipsi2"
812 [(set (match_operand:PSI 0 "register_operand" "=r")
813 (truncate:PSI (match_operand:SI 1 "register_operand" "r")))]
814 ""
815 "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0"
816 )
817
818 ;;------------------------------------------------------------
819 ;; Shift Functions
820
821 ;; Note: We do not use the RPT ... SHIFT instruction sequence
822 ;; when the repeat count is in a register, because even though RPT
823 ;; accepts counts in registers, it does not work if the count is
824 ;; zero, and the actual count in the register has to be one less
825 ;; than the required number of iterations. We could encode a
826 ;; seqeunce like this:
827 ;;
828 ;; bit #0xf, Rn
829 ;; bz 1f
830 ;; dec Rn
831 ;; rpt Rn
832 ;; <shift> Rm
833 ;; inc Rn
834 ;; 1:
835 ;;
836 ;; But is longer than calling a helper function, and we are mostly
837 ;; concerned with code size. FIXME: Maybe enable a sequence like
838 ;; this at -O3 and above ?
839 ;;
840 ;; Note - we ignore shift counts of less than one or more than 15.
841 ;; This is permitted by the ISO C99 standard as such shifts result
842 ;; in "undefined" behavior. [6.5.7 (3)]
843
844 ;; signed A << C
845
846 (define_expand "ashlhi3"
847 [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand")
848 (ashift:HI (match_operand:HI 1 "general_operand")
849 (match_operand:HI 2 "general_operand")))]
850 ""
851 {
852 if ((GET_CODE (operands[1]) == SUBREG
853 && REG_P (XEXP (operands[1], 0)))
854 || MEM_P (operands[1]))
855 operands[1] = force_reg (HImode, operands[1]);
856 if (msp430x
857 && REG_P (operands[0])
858 && REG_P (operands[1])
859 && CONST_INT_P (operands[2]))
860 emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2]));
861 else if (CONST_INT_P (operands[2])
862 && INTVAL (operands[2]) == 1)
863 emit_insn (gen_slli_1 (operands[0], operands[1]));
864 else
865 /* The const variants of mspabi shifts have larger code size than the
866 generic version, so use the generic version if optimizing for
867 size. */
868 msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size);
869 DONE;
870 }
871 )
872
873 (define_insn "slli_1"
874 [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm")
875 (ashift:HI (match_operand:HI 1 "general_operand" "0")
876 (const_int 1)))]
877 ""
878 "RLA%X0.W\t%0" ;; Note - this is a macro for ADD
879 )
880
881 (define_insn "430x_shift_left"
882 [(set (match_operand:HI 0 "register_operand" "=r")
883 (ashift:HI (match_operand:HI 1 "register_operand" "0")
884 (match_operand 2 "immediate_operand" "n")))]
885 "msp430x"
886 "*
887 if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5)
888 return \"RLAM.W\t%2, %0\";
889 else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16)
890 return \"RPT\t%2 { RLAX.W\t%0\";
891 return \"# nop left shift\";
892 "
893 )
894
895 (define_insn "slll_1"
896 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
897 (ashift:SI (match_operand:SI 1 "general_operand" "0")
898 (const_int 1)))]
899 ""
900 "RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
901 )
902
903 (define_insn "slll_2"
904 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
905 (ashift:SI (match_operand:SI 1 "general_operand" "0")
906 (const_int 2)))]
907 ""
908 "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
909 )
910
911 (define_expand "ashlsi3"
912 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand")
913 (ashift:SI (match_operand:SI 1 "general_operand")
914 (match_operand:SI 2 "general_operand")))]
915 ""
916 "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size);
917 DONE;"
918 )
919
920 (define_expand "ashldi3"
921 [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand")
922 (ashift:DI (match_operand:DI 1 "general_operand")
923 (match_operand:DI 2 "general_operand")))]
924 ""
925 {
926 /* No const_variant for 64-bit shifts. */
927 msp430_expand_helper (operands, \"__mspabi_sllll\", false);
928 DONE;
929 }
930 )
931
932 ;;----------
933
934 ;; signed A >> C
935
936 (define_expand "ashrhi3"
937 [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand")
938 (ashiftrt:HI (match_operand:HI 1 "general_operand")
939 (match_operand:HI 2 "general_operand")))]
940 ""
941 {
942 if ((GET_CODE (operands[1]) == SUBREG
943 && REG_P (XEXP (operands[1], 0)))
944 || MEM_P (operands[1]))
945 operands[1] = force_reg (HImode, operands[1]);
946 if (msp430x
947 && REG_P (operands[0])
948 && REG_P (operands[1])
949 && CONST_INT_P (operands[2]))
950 emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2]));
951 else if (CONST_INT_P (operands[2])
952 && INTVAL (operands[2]) == 1)
953 emit_insn (gen_srai_1 (operands[0], operands[1]));
954 else
955 msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size);
956 DONE;
957 }
958 )
959
960 (define_insn "srai_1"
961 [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm")
962 (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0")
963 (const_int 1)))]
964 ""
965 "RRA%X0.W\t%0"
966 )
967
968 (define_insn "430x_arithmetic_shift_right"
969 [(set (match_operand:HI 0 "register_operand" "=r")
970 (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
971 (match_operand 2 "immediate_operand" "n")))]
972 "msp430x"
973 "*
974 if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5)
975 return \"RRAM.W\t%2, %0\";
976 else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16)
977 return \"RPT\t%2 { RRAX.W\t%0\";
978 return \"# nop arith right shift\";
979 "
980 )
981
982 (define_insn "srap_1"
983 [(set (match_operand:PSI 0 "register_operand" "=r")
984 (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
985 (const_int 1)))]
986 "msp430x"
987 "RRAM.A #1,%0"
988 )
989
990 (define_insn "srap_2"
991 [(set (match_operand:PSI 0 "register_operand" "=r")
992 (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
993 (const_int 2)))]
994 "msp430x"
995 "RRAM.A #2,%0"
996 )
997
998 (define_insn "sral_1"
999 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
1000 (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
1001 (const_int 1)))]
1002 ""
1003 "RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
1004 )
1005
1006 (define_insn "sral_2"
1007 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
1008 (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
1009 (const_int 2)))]
1010 ""
1011 "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
1012 )
1013
1014 (define_expand "ashrsi3"
1015 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand")
1016 (ashiftrt:SI (match_operand:SI 1 "general_operand")
1017 (match_operand:SI 2 "general_operand")))]
1018 ""
1019 "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size);
1020 DONE;"
1021 )
1022
1023 (define_expand "ashrdi3"
1024 [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand")
1025 (ashift:DI (match_operand:DI 1 "general_operand")
1026 (match_operand:DI 2 "general_operand")))]
1027 ""
1028 {
1029 /* No const_variant for 64-bit shifts. */
1030 msp430_expand_helper (operands, \"__mspabi_srall\", false);
1031 DONE;
1032 }
1033 )
1034
1035 ;;----------
1036
1037 ;; unsigned A >> C
1038
1039 (define_expand "lshrhi3"
1040 [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand")
1041 (lshiftrt:HI (match_operand:HI 1 "general_operand")
1042 (match_operand:HI 2 "general_operand")))]
1043 ""
1044 {
1045 if ((GET_CODE (operands[1]) == SUBREG
1046 && REG_P (XEXP (operands[1], 0)))
1047 || MEM_P (operands[1]))
1048 operands[1] = force_reg (HImode, operands[1]);
1049 if (msp430x
1050 && REG_P (operands[0])
1051 && REG_P (operands[1])
1052 && CONST_INT_P (operands[2]))
1053 emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2]));
1054 else if (CONST_INT_P (operands[2])
1055 && INTVAL (operands[2]) == 1)
1056 emit_insn (gen_srli_1 (operands[0], operands[1]));
1057 else
1058 msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size);
1059 DONE;
1060 }
1061 )
1062
1063 (define_insn "srli_1"
1064 [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm")
1065 (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
1066 (const_int 1)))]
1067 ""
1068 "CLRC { RRC%X0.W\t%0"
1069 )
1070
1071 (define_insn "430x_logical_shift_right"
1072 [(set (match_operand:HI 0 "register_operand" "=r")
1073 (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
1074 (match_operand 2 "immediate_operand" "n")))]
1075 "msp430x"
1076 {
1077 return msp430x_logical_shift_right (operands[2]);
1078 }
1079 )
1080
1081 (define_insn "srlp_1"
1082 [(set (match_operand:PSI 0 "register_operand" "=r")
1083 (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
1084 (const_int 1)))]
1085 ""
1086 "RRUM.A #1,%0"
1087 )
1088
1089 (define_insn "srll_1"
1090 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm")
1091 (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
1092 (const_int 1)))]
1093 ""
1094 "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0"
1095 )
1096
1097 (define_insn "srll_2x"
1098 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r")
1099 (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
1100 (const_int 2)))]
1101 "msp430x"
1102 "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0"
1103 )
1104
1105 (define_expand "lshrsi3"
1106 [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand")
1107 (lshiftrt:SI (match_operand:SI 1 "general_operand")
1108 (match_operand:SI 2 "general_operand")))]
1109 ""
1110 "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size);
1111 DONE;"
1112 )
1113
1114 (define_expand "lshrdi3"
1115 [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand")
1116 (ashift:DI (match_operand:DI 1 "general_operand")
1117 (match_operand:DI 2 "general_operand")))]
1118 ""
1119 {
1120 /* No const_variant for 64-bit shifts. */
1121 msp430_expand_helper (operands, \"__mspabi_srlll\", false);
1122 DONE;
1123 }
1124 )
1125
1126 ;;------------------------------------------------------------
1127 ;; Function Entry/Exit
1128
1129 (define_expand "prologue"
1130 [(const_int 0)]
1131 ""
1132 "msp430_expand_prologue (); DONE;"
1133 )
1134
1135 (define_expand "epilogue"
1136 [(const_int 0)]
1137 ""
1138 "msp430_expand_epilogue (0); DONE;"
1139 )
1140
1141 (define_insn "epilogue_helper"
1142 [(set (pc)
1143 (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER))
1144 (return)]
1145 ""
1146 "BR%Q0\t#__mspabi_func_epilog_%J0"
1147 )
1148
1149 (define_insn "prologue_start_marker"
1150 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)]
1151 ""
1152 "; start of prologue"
1153 )
1154
1155 (define_insn "prologue_end_marker"
1156 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)]
1157 ""
1158 "; end of prologue"
1159 )
1160
1161 (define_insn "epilogue_start_marker"
1162 [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)]
1163 ""
1164 "; start of epilogue"
1165 )
1166
1167 ;; This makes the linker add a call to exit() after the call to main()
1168 ;; in crt0
1169 (define_insn "msp430_refsym_need_exit"
1170 [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)]
1171 ""
1172 ".refsym\t__crt0_call_exit"
1173 )
1174
1175 ;;------------------------------------------------------------
1176 ;; Jumps
1177
1178 (define_expand "call"
1179 [(call:HI (match_operand 0 "")
1180 (match_operand 1 ""))]
1181 ""
1182 ""
1183 )
1184
1185 (define_insn "call_internal"
1186 [(call (mem:HI (match_operand 0 "general_operand" "rYci"))
1187 (match_operand 1 ""))]
1188 ""
1189 "CALL%Q0\t%0"
1190 )
1191
1192 (define_expand "call_value"
1193 [(set (match_operand 0 "register_operand")
1194 (call:HI (match_operand 1 "general_operand")
1195 (match_operand 2 "")))]
1196 ""
1197 ""
1198 )
1199
1200 (define_insn "call_value_internal"
1201 [(set (match_operand 0 "register_operand" "=r")
1202 (call (mem:HI (match_operand 1 "general_operand" "rYci"))
1203 (match_operand 2 "")))]
1204 ""
1205 "CALL%Q0\t%1"
1206 )
1207
1208 (define_insn "msp430_return"
1209 [(return)]
1210 ""
1211 { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
1212 )
1213
1214 ;; This pattern is NOT, as expected, a return pattern. It's called
1215 ;; before reload and must only store its operands, and emit a
1216 ;; placeholder where the epilog needs to be. AFTER reload, the
1217 ;; placeholder should get expanded into a regular-type epilogue that
1218 ;; also does the EH return.
1219 (define_expand "eh_return"
1220 [(match_operand:HI 0 "")]
1221 ""
1222 "msp430_expand_eh_return (operands[0]);
1223 emit_jump_insn (gen_msp430_eh_epilogue ());
1224 emit_barrier ();
1225 DONE;"
1226 )
1227
1228 ;; This is the actual EH epilogue. We emit it in the pattern above,
1229 ;; before reload, and convert it to a real epilogue after reload.
1230 (define_insn_and_split "msp430_eh_epilogue"
1231 [(eh_return)]
1232 ""
1233 "#"
1234 "reload_completed"
1235 [(const_int 0)]
1236 "msp430_expand_epilogue (1); DONE;"
1237 )
1238
1239 (define_insn "jump"
1240 [(set (pc)
1241 (label_ref (match_operand 0 "" "")))]
1242 ""
1243 "BR%Q0\t#%l0"
1244 )
1245
1246 ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs
1247 ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c).
1248 (define_insn "indirect_jump"
1249 [(set (pc)
1250 (match_operand 0 "nonimmediate_operand" "rYl"))]
1251 ""
1252 "BR%Q0\t%0"
1253 )
1254
1255 ;;------------------------------------------------------------
1256 ;; Various Conditionals
1257
1258 (define_expand "cbranch<mode>4"
1259 [(parallel [(set (pc) (if_then_else
1260 (match_operator 0 ""
1261 [(match_operand:QHI 1 "msp430_general_dst_nonv_operand")
1262 (match_operand:QHI 2 "general_operand")])
1263 (label_ref (match_operand 3 "" ""))
1264 (pc)))
1265 (clobber (reg:BI CARRY))]
1266 )]
1267 ""
1268 "msp430_fixup_compare_operands (<MODE>mode, operands);"
1269 )
1270
1271 (define_insn "cbranchpsi4_real"
1272 [(set (pc) (if_then_else
1273 (match_operator 0 "msp430_cmp_operator"
1274 [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm")
1275 (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")])
1276 (label_ref (match_operand 3 "" ""))
1277 (pc)))
1278 (clobber (reg:BI CARRY))
1279 ]
1280 ""
1281 "@
1282 CMP%Q0\t%2, %1 { J%0\t%l3
1283 CMPX.A\t%2, %1 { J%0\t%l3
1284 CMPX.A\t%2, %1 { J%0\t%l3"
1285 )
1286
1287 (define_insn "cbranchqi4_real"
1288 [(set (pc) (if_then_else
1289 (match_operator 0 "msp430_cmp_operator"
1290 [(match_operand:QI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm")
1291 (match_operand:QI 2 "general_operand" "rYsYxi,rmi")])
1292 (label_ref (match_operand 3 "" ""))
1293 (pc)))
1294 (clobber (reg:BI CARRY))
1295 ]
1296 ""
1297 "@
1298 CMP.B\t%2, %1 { J%0\t%l3
1299 CMPX.B\t%2, %1 { J%0\t%l3"
1300 )
1301
1302 (define_insn "cbranchhi4_real"
1303 [(set (pc) (if_then_else
1304 (match_operator 0 "msp430_cmp_operator"
1305 [(match_operand:HI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm")
1306 (match_operand:HI 2 "general_operand" "rYsYxi,rmi")])
1307 (label_ref (match_operand 3 "" ""))
1308 (pc)))
1309 (clobber (reg:BI CARRY))
1310 ]
1311 ""
1312 "*
1313 /* This is nasty. If we are splitting code between low and high memory
1314 then we do not want the linker to increase the size of sections by
1315 relaxing out of range jump instructions. (Since relaxation occurs
1316 after section placement). So we have to generate pessimal branches
1317 here. But we only want to do this when really necessary.
1318
1319 FIXME: Do we need code in the other cbranch patterns ? */
1320 if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6)
1321 {
1322 return which_alternative == 0 ?
1323 \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" :
1324 \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\";
1325 }
1326
1327 return which_alternative == 0 ?
1328 \"CMP.W\t%2, %1 { J%0\t%l3\" :
1329 \"CMPX.W\t%2, %1 { J%0\t%l3\";
1330 "
1331 [(set (attr "length")
1332 (if_then_else
1333 (and (ge (minus (match_dup 3) (pc)) (const_int -510))
1334 (le (minus (match_dup 3) (pc)) (const_int 510)))
1335 (const_int 6)
1336 (const_int 10))
1337 )]
1338 )
1339
1340 (define_insn "cbranchpsi4_reversed"
1341 [(set (pc) (if_then_else
1342 (match_operator 0 "msp430_reversible_cmp_operator"
1343 [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi")
1344 (match_operand:PSI 2 "msp430_general_dst_nonv_operand" "r,rYs,rm")])
1345 (label_ref (match_operand 3 "" ""))
1346 (pc)))
1347 (clobber (reg:BI CARRY))
1348 ]
1349 ""
1350 "@
1351 CMP%Q0\t%1, %2 { J%R0\t%l3
1352 CMPX.A\t%1, %2 { J%R0\t%l3
1353 CMPX.A\t%1, %2 { J%R0\t%l3"
1354 )
1355
1356 (define_insn "cbranchqi4_reversed"
1357 [(set (pc) (if_then_else
1358 (match_operator 0 "msp430_reversible_cmp_operator"
1359 [(match_operand:QI 1 "general_operand" "rYsYxi,rmi")
1360 (match_operand:QI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")])
1361 (label_ref (match_operand 3 "" ""))
1362 (pc)))
1363 (clobber (reg:BI CARRY))
1364 ]
1365 ""
1366 "@
1367 CMP.B\t%1, %2 { J%R0\t%l3
1368 CMPX.B\t%1, %2 { J%R0\t%l3"
1369 )
1370
1371 (define_insn "cbranchhi4_reversed"
1372 [(set (pc) (if_then_else
1373 (match_operator 0 "msp430_reversible_cmp_operator"
1374 [(match_operand:HI 1 "general_operand" "rYsYxi,rmi")
1375 (match_operand:HI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")])
1376 (label_ref (match_operand 3 "" ""))
1377 (pc)))
1378 (clobber (reg:BI CARRY))
1379 ]
1380 ""
1381 "@
1382 CMP.W\t%1, %2 { J%R0\t%l3
1383 CMPX.W\t%1, %2 { J%R0\t%l3"
1384 )
1385
1386 (define_insn "*bitbranch<mode>4"
1387 [(set (pc) (if_then_else
1388 (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1389 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1390 (const_int 0))
1391 (label_ref (match_operand 2 "" ""))
1392 (pc)))
1393 (clobber (reg:BI CARRY))
1394 ]
1395 ""
1396 "@
1397 BIT%x0%b0\t%1, %0 { JNE\t%l2
1398 BITX%b0\t%1, %0 { JNE\t%l2"
1399 )
1400
1401 (define_insn "*bitbranch<mode>4"
1402 [(set (pc) (if_then_else
1403 (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1404 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1405 (const_int 0))
1406 (label_ref (match_operand 2 "" ""))
1407 (pc)))
1408 (clobber (reg:BI CARRY))
1409 ]
1410 ""
1411 "@
1412 BIT%x0%b0\t%1, %0 { JEQ\t%l2
1413 BITX%b0\t%1, %0 { JEQ\t%l2"
1414 )
1415
1416 (define_insn "*bitbranch<mode>4"
1417 [(set (pc) (if_then_else
1418 (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1419 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1420 (const_int 0))
1421 (pc)
1422 (label_ref (match_operand 2 "" ""))))
1423 (clobber (reg:BI CARRY))
1424 ]
1425 ""
1426 "@
1427 BIT%x0%b0\t%1, %0 { JNE\t%l2
1428 BITX%b0\t%1, %0 { JNE\t%l2"
1429 )
1430
1431 (define_insn "*bitbranch<mode>4"
1432 [(set (pc) (if_then_else
1433 (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1434 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1435 (const_int 0))
1436 (pc)
1437 (label_ref (match_operand 2 "" ""))))
1438 (clobber (reg:BI CARRY))
1439 ]
1440 ""
1441 "@
1442 BIT%x0%b0\t%1, %0 { JEQ\t%l2
1443 BITX%b0\t%1, %0 { JEQ\t%l2"
1444 )
1445
1446 ;;------------------------------------------------------------
1447 ;; zero-extract versions of the above
1448
1449 (define_insn "*bitbranch<mode>4_z"
1450 [(set (pc) (if_then_else
1451 (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm")
1452 (const_int 1)
1453 (match_operand 1 "msp430_bitpos" "i,i"))
1454 (const_int 0))
1455 (label_ref (match_operand 2 "" ""))
1456 (pc)))
1457 (clobber (reg:BI CARRY))
1458 ]
1459 ""
1460 "@
1461 BIT%x0%b0\t%p1, %0 { JNE\t%l2
1462 BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1463 )
1464
1465 (define_insn "*bitbranch<mode>4_z"
1466 [(set (pc) (if_then_else
1467 (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1468 (const_int 1)
1469 (match_operand 1 "msp430_bitpos" "i"))
1470 (const_int 0))
1471 (label_ref (match_operand 2 "" ""))
1472 (pc)))
1473 (clobber (reg:BI CARRY))
1474 ]
1475 ""
1476 "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1477 )
1478
1479 (define_insn "*bitbranch<mode>4_z"
1480 [(set (pc) (if_then_else
1481 (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1482 (const_int 1)
1483 (match_operand 1 "msp430_bitpos" "i"))
1484 (const_int 0))
1485 (pc)
1486 (label_ref (match_operand 2 "" ""))))
1487 (clobber (reg:BI CARRY))
1488 ]
1489 ""
1490 "BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1491 )
1492
1493 (define_insn "*bitbranch<mode>4_z"
1494 [(set (pc) (if_then_else
1495 (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1496 (const_int 1)
1497 (match_operand 1 "msp430_bitpos" "i"))
1498 (const_int 0))
1499 (pc)
1500 (label_ref (match_operand 2 "" ""))))
1501 (clobber (reg:BI CARRY))
1502 ]
1503 ""
1504 "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1505 )
1506
1507 ;;------------------------------------------------------------
1508 ;; Misc
1509
1510 (define_insn "nop"
1511 [(const_int 0)]
1512 "1"
1513 "NOP"
1514 )
1515
1516 (define_insn "disable_interrupts"
1517 [(unspec_volatile [(const_int 0)] UNS_DINT)]
1518 ""
1519 "DINT \; NOP"
1520 )
1521
1522 (define_insn "enable_interrupts"
1523 [(unspec_volatile [(const_int 0)] UNS_EINT)]
1524 ""
1525 "EINT"
1526 )
1527
1528 (define_insn "push_intr_state"
1529 [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
1530 ""
1531 "PUSH\tSR"
1532 )
1533
1534 (define_insn "pop_intr_state"
1535 [(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
1536 ""
1537 "POP\tSR"
1538 )
1539
1540 ;; Clear bits in the copy of the status register that is currently
1541 ;; saved on the stack at the top of the interrupt handler.
1542 (define_insn "bic_SR"
1543 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
1544 ""
1545 "BIC.W\t%0, %O0(SP)"
1546 )
1547
1548 ;; Set bits in the copy of the status register that is currently
1549 ;; saved on the stack at the top of the interrupt handler.
1550 (define_insn "bis_SR"
1551 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
1552 ""
1553 "BIS.W\t%0, %O0(SP)"
1554 )
1555
1556 ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int)))
1557 ;; very late on in the compilation and not splitting it into separate
1558 ;; instructions, so we provide a pattern to support it here.
1559 (define_insn "andneghi3"
1560 [(set (match_operand:HI 0 "register_operand" "=r")
1561 (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r"))
1562 (match_operand 2 "immediate_operand" "n")))]
1563 ""
1564 "*
1565 if (REGNO (operands[0]) != REGNO (operands[1]))
1566 return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1567 else
1568 return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1569 "
1570 )
1571
1572 (define_insn "delay_cycles_start"
1573 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1574 UNS_DELAY_START)]
1575 ""
1576 "; Begin %J0 cycle delay"
1577 )
1578
1579 (define_insn "delay_cycles_end"
1580 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1581 UNS_DELAY_END)]
1582 ""
1583 "; End %J0 cycle delay"
1584 )
1585
1586 (define_insn "delay_cycles_32"
1587 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1588 (match_operand 1 "immediate_operand" "i")
1589 ] UNS_DELAY_32)]
1590 ""
1591 "PUSH r13
1592 PUSH r14
1593 MOV.W %A0, r13
1594 MOV.W %B0, r14
1595 1: SUB.W #1, r13
1596 SUBC.W #0, r14
1597 JNE 1b
1598 TST.W r13
1599 JNE 1b
1600 POP r14
1601 POP r13"
1602 )
1603
1604 (define_insn "delay_cycles_32x"
1605 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1606 (match_operand 1 "immediate_operand" "i")
1607 ] UNS_DELAY_32X)]
1608 ""
1609 "PUSHM.A #2,r14
1610 MOV.W %A0, r13
1611 MOV.W %B0, r14
1612 1: SUB.W #1, r13
1613 SUBC.W #0, r14
1614 JNE 1b
1615 TST.W r13
1616 JNE 1b
1617 POPM.A #2,r14"
1618 )
1619
1620 (define_insn "delay_cycles_16"
1621 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1622 (match_operand 1 "immediate_operand" "i")
1623 ] UNS_DELAY_16)]
1624 ""
1625 "PUSH r13
1626 MOV.W %0, r13
1627 1: SUB.W #1, r13
1628 JNE 1b
1629 POP r13"
1630 )
1631
1632 (define_insn "delay_cycles_16x"
1633 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1634 (match_operand 1 "immediate_operand" "i")
1635 ] UNS_DELAY_16X)]
1636 ""
1637 "PUSHM.A #1,r13
1638 MOV.W %0, r13
1639 1: SUB.W #1, r13
1640 JNE 1b
1641 POPM.A #1,r13"
1642 )
1643
1644 (define_insn "delay_cycles_2"
1645 [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)]
1646 ""
1647 "JMP .+2"
1648 )
1649
1650 (define_insn "delay_cycles_1"
1651 [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)]
1652 ""
1653 "NOP"
1654 )
1655
1656 ; libgcc helper functions for widening multiplication aren't currently
1657 ; generated by gcc, so we can't catch them later and map them to the mspabi
1658 ; functions.
1659 ; We catch the patterns here and either generate a call to the helper function,
1660 ; or emit the hardware multiply instruction sequence inline.
1661 ;
1662 ; If we don't have hardware multiply support, it will generally be slower and
1663 ; result in larger code to call the mspabi library function to perform the
1664 ; widening multiplication than just leaving GCC to widen the arguments itself.
1665 ;
1666 ; We don't use library functions for SImode->DImode widening since its always
1667 ; larger and slower than letting GCC widen the arguments inline.
1668 (define_expand "mulhisi3"
1669 [(set (match_operand:SI 0 "register_operand" "=r")
1670 (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1671 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1672 "msp430_has_hwmult ()"
1673 {
1674 /* Leave the other case for the inline insn. */
1675 if (!(optimize > 2 && msp430_has_hwmult ()))
1676 {
1677 msp430_expand_helper (operands, "__mspabi_mpysl", false);
1678 DONE;
1679 }
1680 }
1681 )
1682
1683 (define_expand "umulhisi3"
1684 [(set (match_operand:SI 0 "register_operand" "=r")
1685 (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1686 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1687 "msp430_has_hwmult ()"
1688 {
1689 /* Leave the other case for the inline insn. */
1690 if (!(optimize > 2 && msp430_has_hwmult ()))
1691 {
1692 msp430_expand_helper (operands, "__mspabi_mpyul", false);
1693 DONE;
1694 }
1695 }
1696 )
1697
1698 (define_insn "*mulhisi3_inline"
1699 [(set (match_operand:SI 0 "register_operand" "=r")
1700 (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1701 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1702 "optimize > 2 && msp430_has_hwmult ()"
1703 "*
1704 if (msp430_use_f5_series_hwmult ())
1705 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\";
1706 else
1707 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\";
1708 "
1709 )
1710
1711 (define_insn "*umulhisi3_inline"
1712 [(set (match_operand:SI 0 "register_operand" "=r")
1713 (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1714 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1715 "optimize > 2 && msp430_has_hwmult ()"
1716 "*
1717 if (msp430_use_f5_series_hwmult ())
1718 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\";
1719 else
1720 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\";
1721 "
1722 )
1723
1724 (define_insn "mulsidi3"
1725 [(set (match_operand:DI 0 "register_operand" "=r")
1726 (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1727 (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1728 "optimize > 2 && msp430_has_hwmult ()"
1729 "*
1730 if (msp430_use_f5_series_hwmult ())
1731 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\";
1732 else
1733 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\";
1734 "
1735 )
1736
1737 (define_insn "umulsidi3"
1738 [(set (match_operand:DI 0 "register_operand" "=r")
1739 (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1740 (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1741 "optimize > 2 && msp430_has_hwmult ()"
1742 "*
1743 if (msp430_use_f5_series_hwmult ())
1744 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\";
1745 else
1746 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\";
1747 "
1748 )