]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/msp430/msp430.md
msp430.c (msp430_expand_helper): Support expansion of calls to __mspabi_mpy* functions.
[thirdparty/gcc.git] / gcc / config / msp430 / msp430.md
1 ;; Machine Description for TI MSP43* processors
2 ;; Copyright (C) 2013-2019 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 ;; ------------------------
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 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)]
1134 ""
1135 "BR%Q0\t#__mspabi_func_epilog_%J0"
1136 )
1137
1138 (define_insn "prologue_start_marker"
1139 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)]
1140 ""
1141 "; start of prologue"
1142 )
1143
1144 (define_insn "prologue_end_marker"
1145 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)]
1146 ""
1147 "; end of prologue"
1148 )
1149
1150 (define_insn "epilogue_start_marker"
1151 [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)]
1152 ""
1153 "; start of epilogue"
1154 )
1155
1156 ;; This makes the linker add a call to exit() after the call to main()
1157 ;; in crt0
1158 (define_insn "msp430_refsym_need_exit"
1159 [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)]
1160 ""
1161 ".refsym\t__crt0_call_exit"
1162 )
1163
1164 ;;------------------------------------------------------------
1165 ;; Jumps
1166
1167 (define_expand "call"
1168 [(call:HI (match_operand 0 "")
1169 (match_operand 1 ""))]
1170 ""
1171 ""
1172 )
1173
1174 (define_insn "call_internal"
1175 [(call (mem:HI (match_operand 0 "general_operand" "rYci"))
1176 (match_operand 1 ""))]
1177 ""
1178 "CALL%Q0\t%0"
1179 )
1180
1181 (define_expand "call_value"
1182 [(set (match_operand 0 "register_operand")
1183 (call:HI (match_operand 1 "general_operand")
1184 (match_operand 2 "")))]
1185 ""
1186 ""
1187 )
1188
1189 (define_insn "call_value_internal"
1190 [(set (match_operand 0 "register_operand" "=r")
1191 (call (mem:HI (match_operand 1 "general_operand" "rYci"))
1192 (match_operand 2 "")))]
1193 ""
1194 "CALL%Q0\t%1"
1195 )
1196
1197 (define_insn "msp430_return"
1198 [(return)]
1199 ""
1200 { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
1201 )
1202
1203 ;; This pattern is NOT, as expected, a return pattern. It's called
1204 ;; before reload and must only store its operands, and emit a
1205 ;; placeholder where the epilog needs to be. AFTER reload, the
1206 ;; placeholder should get expanded into a regular-type epilogue that
1207 ;; also does the EH return.
1208 (define_expand "eh_return"
1209 [(match_operand:HI 0 "")]
1210 ""
1211 "msp430_expand_eh_return (operands[0]);
1212 emit_jump_insn (gen_msp430_eh_epilogue ());
1213 emit_barrier ();
1214 DONE;"
1215 )
1216
1217 ;; This is the actual EH epilogue. We emit it in the pattern above,
1218 ;; before reload, and convert it to a real epilogue after reload.
1219 (define_insn_and_split "msp430_eh_epilogue"
1220 [(eh_return)]
1221 ""
1222 "#"
1223 "reload_completed"
1224 [(const_int 0)]
1225 "msp430_expand_epilogue (1); DONE;"
1226 )
1227
1228 (define_insn "jump"
1229 [(set (pc)
1230 (label_ref (match_operand 0 "" "")))]
1231 ""
1232 "BR%Q0\t#%l0"
1233 )
1234
1235 ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs
1236 ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c).
1237 (define_insn "indirect_jump"
1238 [(set (pc)
1239 (match_operand 0 "nonimmediate_operand" "rYl"))]
1240 ""
1241 "BR%Q0\t%0"
1242 )
1243
1244 ;;------------------------------------------------------------
1245 ;; Various Conditionals
1246
1247 (define_expand "cbranch<mode>4"
1248 [(parallel [(set (pc) (if_then_else
1249 (match_operator 0 ""
1250 [(match_operand:QHI 1 "nonimmediate_operand")
1251 (match_operand:QHI 2 "general_operand")])
1252 (label_ref (match_operand 3 "" ""))
1253 (pc)))
1254 (clobber (reg:BI CARRY))]
1255 )]
1256 ""
1257 "msp430_fixup_compare_operands (<MODE>mode, operands);"
1258 )
1259
1260 (define_insn "cbranchpsi4_real"
1261 [(set (pc) (if_then_else
1262 (match_operator 0 "msp430_cmp_operator"
1263 [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm")
1264 (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")])
1265 (label_ref (match_operand 3 "" ""))
1266 (pc)))
1267 (clobber (reg:BI CARRY))
1268 ]
1269 ""
1270 "@
1271 CMP%Q0\t%2, %1 { J%0\t%l3
1272 CMPX.A\t%2, %1 { J%0\t%l3
1273 CMPX.A\t%2, %1 { J%0\t%l3"
1274 )
1275
1276 (define_insn "cbranchqi4_real"
1277 [(set (pc) (if_then_else
1278 (match_operator 0 "msp430_cmp_operator"
1279 [(match_operand:QI 1 "nonimmediate_operand" "rYsYx,rm")
1280 (match_operand:QI 2 "general_operand" "rYsYxi,rmi")])
1281 (label_ref (match_operand 3 "" ""))
1282 (pc)))
1283 (clobber (reg:BI CARRY))
1284 ]
1285 ""
1286 "@
1287 CMP.B\t%2, %1 { J%0\t%l3
1288 CMPX.B\t%2, %1 { J%0\t%l3"
1289 )
1290
1291 (define_insn "cbranchhi4_real"
1292 [(set (pc) (if_then_else
1293 (match_operator 0 "msp430_cmp_operator"
1294 [(match_operand:HI 1 "nonimmediate_operand" "rYsYx,rm")
1295 (match_operand:HI 2 "general_operand" "rYsYxi,rmi")])
1296 (label_ref (match_operand 3 "" ""))
1297 (pc)))
1298 (clobber (reg:BI CARRY))
1299 ]
1300 ""
1301 "*
1302 /* This is nasty. If we are splitting code between low and high memory
1303 then we do not want the linker to increase the size of sections by
1304 relaxing out of range jump instructions. (Since relaxation occurs
1305 after section placement). So we have to generate pessimal branches
1306 here. But we only want to do this when really necessary.
1307
1308 FIXME: Do we need code in the other cbranch patterns ? */
1309 if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6)
1310 {
1311 return which_alternative == 0 ?
1312 \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" :
1313 \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\";
1314 }
1315
1316 return which_alternative == 0 ?
1317 \"CMP.W\t%2, %1 { J%0\t%l3\" :
1318 \"CMPX.W\t%2, %1 { J%0\t%l3\";
1319 "
1320 [(set (attr "length")
1321 (if_then_else
1322 (and (ge (minus (match_dup 3) (pc)) (const_int -510))
1323 (le (minus (match_dup 3) (pc)) (const_int 510)))
1324 (const_int 6)
1325 (const_int 10))
1326 )]
1327 )
1328
1329 (define_insn "cbranchpsi4_reversed"
1330 [(set (pc) (if_then_else
1331 (match_operator 0 "msp430_reversible_cmp_operator"
1332 [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi")
1333 (match_operand:PSI 2 "general_operand" "r,rYs,rm")])
1334 (label_ref (match_operand 3 "" ""))
1335 (pc)))
1336 (clobber (reg:BI CARRY))
1337 ]
1338 ""
1339 "@
1340 CMP%Q0\t%1, %2 { J%R0\t%l3
1341 CMPX.A\t%1, %2 { J%R0\t%l3
1342 CMPX.A\t%1, %2 { J%R0\t%l3"
1343 )
1344
1345 (define_insn "cbranchqi4_reversed"
1346 [(set (pc) (if_then_else
1347 (match_operator 0 "msp430_reversible_cmp_operator"
1348 [(match_operand:QI 1 "general_operand" "rYsYxi,rmi")
1349 (match_operand:QI 2 "general_operand" "rYsYx,rm")])
1350 (label_ref (match_operand 3 "" ""))
1351 (pc)))
1352 (clobber (reg:BI CARRY))
1353 ]
1354 ""
1355 "@
1356 CMP.B\t%1, %2 { J%R0\t%l3
1357 CMPX.B\t%1, %2 { J%R0\t%l3"
1358 )
1359
1360 (define_insn "cbranchhi4_reversed"
1361 [(set (pc) (if_then_else
1362 (match_operator 0 "msp430_reversible_cmp_operator"
1363 [(match_operand:HI 1 "general_operand" "rYsYxi,rmi")
1364 (match_operand:HI 2 "general_operand" "rYsYx,rm")])
1365 (label_ref (match_operand 3 "" ""))
1366 (pc)))
1367 (clobber (reg:BI CARRY))
1368 ]
1369 ""
1370 "@
1371 CMP.W\t%1, %2 { J%R0\t%l3
1372 CMPX.W\t%1, %2 { J%R0\t%l3"
1373 )
1374
1375 (define_insn "*bitbranch<mode>4"
1376 [(set (pc) (if_then_else
1377 (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1378 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1379 (const_int 0))
1380 (label_ref (match_operand 2 "" ""))
1381 (pc)))
1382 (clobber (reg:BI CARRY))
1383 ]
1384 ""
1385 "@
1386 BIT%x0%b0\t%1, %0 { JNE\t%l2
1387 BITX%b0\t%1, %0 { JNE\t%l2"
1388 )
1389
1390 (define_insn "*bitbranch<mode>4"
1391 [(set (pc) (if_then_else
1392 (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1393 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1394 (const_int 0))
1395 (label_ref (match_operand 2 "" ""))
1396 (pc)))
1397 (clobber (reg:BI CARRY))
1398 ]
1399 ""
1400 "@
1401 BIT%x0%b0\t%1, %0 { JEQ\t%l2
1402 BITX%b0\t%1, %0 { JEQ\t%l2"
1403 )
1404
1405 (define_insn "*bitbranch<mode>4"
1406 [(set (pc) (if_then_else
1407 (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1408 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1409 (const_int 0))
1410 (pc)
1411 (label_ref (match_operand 2 "" ""))))
1412 (clobber (reg:BI CARRY))
1413 ]
1414 ""
1415 "@
1416 BIT%x0%b0\t%1, %0 { JNE\t%l2
1417 BITX%b0\t%1, %0 { JNE\t%l2"
1418 )
1419
1420 (define_insn "*bitbranch<mode>4"
1421 [(set (pc) (if_then_else
1422 (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm")
1423 (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
1424 (const_int 0))
1425 (pc)
1426 (label_ref (match_operand 2 "" ""))))
1427 (clobber (reg:BI CARRY))
1428 ]
1429 ""
1430 "@
1431 BIT%x0%b0\t%1, %0 { JEQ\t%l2
1432 BITX%b0\t%1, %0 { JEQ\t%l2"
1433 )
1434
1435 ;;------------------------------------------------------------
1436 ;; zero-extract versions of the above
1437
1438 (define_insn "*bitbranch<mode>4_z"
1439 [(set (pc) (if_then_else
1440 (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm")
1441 (const_int 1)
1442 (match_operand 1 "msp430_bitpos" "i,i"))
1443 (const_int 0))
1444 (label_ref (match_operand 2 "" ""))
1445 (pc)))
1446 (clobber (reg:BI CARRY))
1447 ]
1448 ""
1449 "@
1450 BIT%x0%b0\t%p1, %0 { JNE\t%l2
1451 BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1452 )
1453
1454 (define_insn "*bitbranch<mode>4_z"
1455 [(set (pc) (if_then_else
1456 (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1457 (const_int 1)
1458 (match_operand 1 "msp430_bitpos" "i"))
1459 (const_int 0))
1460 (label_ref (match_operand 2 "" ""))
1461 (pc)))
1462 (clobber (reg:BI CARRY))
1463 ]
1464 ""
1465 "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1466 )
1467
1468 (define_insn "*bitbranch<mode>4_z"
1469 [(set (pc) (if_then_else
1470 (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1471 (const_int 1)
1472 (match_operand 1 "msp430_bitpos" "i"))
1473 (const_int 0))
1474 (pc)
1475 (label_ref (match_operand 2 "" ""))))
1476 (clobber (reg:BI CARRY))
1477 ]
1478 ""
1479 "BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1480 )
1481
1482 (define_insn "*bitbranch<mode>4_z"
1483 [(set (pc) (if_then_else
1484 (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm")
1485 (const_int 1)
1486 (match_operand 1 "msp430_bitpos" "i"))
1487 (const_int 0))
1488 (pc)
1489 (label_ref (match_operand 2 "" ""))))
1490 (clobber (reg:BI CARRY))
1491 ]
1492 ""
1493 "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1494 )
1495
1496 ;;------------------------------------------------------------
1497 ;; Misc
1498
1499 (define_insn "nop"
1500 [(const_int 0)]
1501 "1"
1502 "NOP"
1503 )
1504
1505 (define_insn "disable_interrupts"
1506 [(unspec_volatile [(const_int 0)] UNS_DINT)]
1507 ""
1508 "DINT \; NOP"
1509 )
1510
1511 (define_insn "enable_interrupts"
1512 [(unspec_volatile [(const_int 0)] UNS_EINT)]
1513 ""
1514 "EINT"
1515 )
1516
1517 (define_insn "push_intr_state"
1518 [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
1519 ""
1520 "PUSH\tSR"
1521 )
1522
1523 (define_insn "pop_intr_state"
1524 [(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
1525 ""
1526 "POP\tSR"
1527 )
1528
1529 ;; Clear bits in the copy of the status register that is currently
1530 ;; saved on the stack at the top of the interrupt handler.
1531 (define_insn "bic_SR"
1532 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
1533 ""
1534 "BIC.W\t%0, %O0(SP)"
1535 )
1536
1537 ;; Set bits in the copy of the status register that is currently
1538 ;; saved on the stack at the top of the interrupt handler.
1539 (define_insn "bis_SR"
1540 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
1541 ""
1542 "BIS.W\t%0, %O0(SP)"
1543 )
1544
1545 ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int)))
1546 ;; very late on in the compilation and not splitting it into separate
1547 ;; instructions, so we provide a pattern to support it here.
1548 (define_insn "andneghi3"
1549 [(set (match_operand:HI 0 "register_operand" "=r")
1550 (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r"))
1551 (match_operand 2 "immediate_operand" "n")))]
1552 ""
1553 "*
1554 if (REGNO (operands[0]) != REGNO (operands[1]))
1555 return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1556 else
1557 return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1558 "
1559 )
1560
1561 (define_insn "delay_cycles_start"
1562 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1563 UNS_DELAY_START)]
1564 ""
1565 "; Begin %J0 cycle delay"
1566 )
1567
1568 (define_insn "delay_cycles_end"
1569 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1570 UNS_DELAY_END)]
1571 ""
1572 "; End %J0 cycle delay"
1573 )
1574
1575 (define_insn "delay_cycles_32"
1576 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1577 (match_operand 1 "immediate_operand" "i")
1578 ] UNS_DELAY_32)]
1579 ""
1580 "PUSH r13
1581 PUSH r14
1582 MOV.W %A0, r13
1583 MOV.W %B0, r14
1584 1: SUB.W #1, r13
1585 SUBC.W #0, r14
1586 JNE 1b
1587 TST.W r13
1588 JNE 1b
1589 POP r14
1590 POP r13"
1591 )
1592
1593 (define_insn "delay_cycles_32x"
1594 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1595 (match_operand 1 "immediate_operand" "i")
1596 ] UNS_DELAY_32X)]
1597 ""
1598 "PUSHM.A #2,r14
1599 MOV.W %A0, r13
1600 MOV.W %B0, r14
1601 1: SUB.W #1, r13
1602 SUBC.W #0, r14
1603 JNE 1b
1604 TST.W r13
1605 JNE 1b
1606 POPM.A #2,r14"
1607 )
1608
1609 (define_insn "delay_cycles_16"
1610 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1611 (match_operand 1 "immediate_operand" "i")
1612 ] UNS_DELAY_16)]
1613 ""
1614 "PUSH r13
1615 MOV.W %0, r13
1616 1: SUB.W #1, r13
1617 JNE 1b
1618 POP r13"
1619 )
1620
1621 (define_insn "delay_cycles_16x"
1622 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1623 (match_operand 1 "immediate_operand" "i")
1624 ] UNS_DELAY_16X)]
1625 ""
1626 "PUSHM.A #1,r13
1627 MOV.W %0, r13
1628 1: SUB.W #1, r13
1629 JNE 1b
1630 POPM.A #1,r13"
1631 )
1632
1633 (define_insn "delay_cycles_2"
1634 [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)]
1635 ""
1636 "JMP .+2"
1637 )
1638
1639 (define_insn "delay_cycles_1"
1640 [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)]
1641 ""
1642 "NOP"
1643 )
1644
1645 ; libgcc helper functions for widening multiplication aren't currently
1646 ; generated by gcc, so we can't catch them later and map them to the mspabi
1647 ; functions.
1648 ; We catch the patterns here and either generate a call to the helper function,
1649 ; or emit the hardware multiply instruction sequence inline.
1650 ;
1651 ; If we don't have hardware multiply support, it will generally be slower and
1652 ; result in larger code to call the mspabi library function to perform the
1653 ; widening multiplication than just leaving GCC to widen the arguments itself.
1654 ;
1655 ; We don't use library functions for SImode->DImode widening since its always
1656 ; larger and slower than letting GCC widen the arguments inline.
1657 (define_expand "mulhisi3"
1658 [(set (match_operand:SI 0 "register_operand" "=r")
1659 (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1660 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1661 "msp430_has_hwmult ()"
1662 {
1663 /* Leave the other case for the inline insn. */
1664 if (!(optimize > 2 && msp430_has_hwmult ()))
1665 {
1666 msp430_expand_helper (operands, "__mspabi_mpysl", false);
1667 DONE;
1668 }
1669 }
1670 )
1671
1672 (define_expand "umulhisi3"
1673 [(set (match_operand:SI 0 "register_operand" "=r")
1674 (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1675 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1676 "msp430_has_hwmult ()"
1677 {
1678 /* Leave the other case for the inline insn. */
1679 if (!(optimize > 2 && msp430_has_hwmult ()))
1680 {
1681 msp430_expand_helper (operands, "__mspabi_mpyul", false);
1682 DONE;
1683 }
1684 }
1685 )
1686
1687 (define_insn "*mulhisi3_inline"
1688 [(set (match_operand:SI 0 "register_operand" "=r")
1689 (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1690 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1691 "optimize > 2 && msp430_has_hwmult ()"
1692 "*
1693 if (msp430_use_f5_series_hwmult ())
1694 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\";
1695 else
1696 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\";
1697 "
1698 )
1699
1700 (define_insn "*umulhisi3_inline"
1701 [(set (match_operand:SI 0 "register_operand" "=r")
1702 (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1703 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1704 "optimize > 2 && msp430_has_hwmult ()"
1705 "*
1706 if (msp430_use_f5_series_hwmult ())
1707 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\";
1708 else
1709 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\";
1710 "
1711 )
1712
1713 (define_insn "mulsidi3"
1714 [(set (match_operand:DI 0 "register_operand" "=r")
1715 (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1716 (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1717 "optimize > 2 && msp430_has_hwmult ()"
1718 "*
1719 if (msp430_use_f5_series_hwmult ())
1720 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\";
1721 else
1722 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\";
1723 "
1724 )
1725
1726 (define_insn "umulsidi3"
1727 [(set (match_operand:DI 0 "register_operand" "=r")
1728 (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1729 (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1730 "optimize > 2 && msp430_has_hwmult ()"
1731 "*
1732 if (msp430_use_f5_series_hwmult ())
1733 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\";
1734 else
1735 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\";
1736 "
1737 )