1 ;; Machine Description for TI MSP43* processors
2 ;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
3 ;; Contributed by Red Hat.
5 ;; This file is part of GCC.
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)
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.
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/>.
29 (define_c_enum "unspec"
31 UNS_PROLOGUE_START_MARKER
32 UNS_PROLOGUE_END_MARKER
33 UNS_EPILOGUE_START_MARKER
61 (include "predicates.md")
62 (include "constraints.md")
64 (define_mode_iterator QHI [QI HI PSI])
66 ;; There are two basic "family" tests we do here:
68 ;; msp430x - true if 430X instructions are available.
69 ;; TARGET_LARGE - true if pointers are 20-bits
71 ;; Note that there are three supported cases, since the base 430
72 ;; doesn't have 20-bit pointers:
74 ;; 1. MSP430 cpu, small model
75 ;; 2. MSP430X cpu, small model.
76 ;; 3. MSP430X cpu, large model.
78 ;;------------------------------------------------------------
81 ;; Push/Pop must be before the generic move patterns
84 [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO)))
85 (match_operand:HI 0 "register_operand" "r"))]
91 [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO)))
92 (match_operand:PSI 0 "register_operand" "r"))]
98 [(unspec_volatile [(match_operand 0 "register_operand" "r")
99 (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)]
105 [(set (match_operand:HI 0 "register_operand" "=r")
106 (mem:HI (post_inc:HI (reg:HI SP_REGNO))))]
112 [(set (match_operand:PSI 0 "register_operand" "=r")
113 (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))]
118 ;; This is nasty. Operand0 is bogus. It is only there so that we can get a
119 ;; mode for the %b0 to work. We should use operand1 for this, but that does
122 ;; Operand1 is actually a register, but we cannot accept (REG...) because the
123 ;; cprop_hardreg pass can and will renumber registers even inside
124 ;; unspec_volatiles. So we take an integer register number parameter and
125 ;; fudge it to be a register name when we generate the assembler.
127 ;; The pushm pattern does not have this problem because of all of the
128 ;; frame info cruft attached to it, so cprop_hardreg leaves it alone.
130 [(unspec_volatile [(match_operand 0 "register_operand" "r")
131 (match_operand 1 "immediate_operand" "i")
132 (match_operand 2 "immediate_operand" "i")] UNS_POPM)]
137 ;; The next two patterns are here to support a "feature" of how GCC implements
138 ;; varargs. When a function uses varargs and the *second* to last named
139 ;; argument is split between argument registers and the stack, gcc expects the
140 ;; callee to allocate space on the stack that can contain the register-based
141 ;; part of the argument. This space *has* to be just before the remaining
142 ;; arguments (ie the ones that are fully on the stack).
144 ;; The problem is that the MSP430 CALL instruction pushes the return address
145 ;; onto the stack in the exact place where the callee wants to allocate
146 ;; this extra space. So we need a sequence of instructions that can allocate
147 ;; the extra space and then move the return address down the stack, so that
148 ;; the extra space is now adjacent to the remaining arguments.
150 ;; This could be constructed through regular insns, but they might be split up
151 ;; by a misguided optimization, so an unspec volatile is used instead.
153 (define_insn "grow_and_swap"
154 [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP)]
158 return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\";
159 return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\";
163 (define_insn "swap_and_shrink"
164 [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK)]
166 "* return TARGET_LARGE
167 ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\"
168 : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\";
171 ; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a
172 ; zero_extend anyway. Catch it here.
173 (define_insn "movqihi"
174 [(set (match_operand:HI 0 "register_operand" "=r,r")
175 (zero_extend:HI (match_operand:QI 1 "memory_operand" "Ys,m")))]
182 (define_insn "movqi_topbyte"
183 [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r")
184 (subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))]
186 "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0"
190 [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
191 (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))]
199 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm")
200 (match_operand:HI 1 "msp_general_operand" "riYs,rmi"))]
207 (define_expand "movsi"
208 [(set (match_operand:SI 0 "nonimmediate_operand")
209 (match_operand:SI 1 "general_operand"))]
214 (define_insn_and_split "movsi_x"
215 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
216 (match_operand:SI 1 "general_operand" "rmi"))]
220 [(set (match_operand:HI 2 "nonimmediate_operand")
221 (match_operand:HI 4 "general_operand"))
222 (set (match_operand:HI 3 "nonimmediate_operand")
223 (match_operand:HI 5 "general_operand"))]
224 "msp430_split_movsi (operands);"
227 ;; Some MOVX.A cases can be done with MOVA, this is only a few of them.
228 (define_insn "movpsi"
229 [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,Ya,rm")
230 (match_operand:PSI 1 "msp_general_operand" "riYa,r,rmi"))]
237 ; This pattern is identical to the truncsipsi2 pattern except
238 ; that it uses a SUBREG instead of a TRUNC. It is needed in
239 ; order to prevent reload from converting (set:SI (SUBREG:PSI (SI)))
240 ; into (SET:PSI (PSI)).
242 ; Note: using POPM.A #1 is two bytes smaller than using POPX.A....
244 (define_insn "movsipsi2"
245 [(set (match_operand:PSI 0 "register_operand" "=r")
246 (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))]
248 "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0"
251 ;;------------------------------------------------------------
254 (define_insn "addpsi3"
255 [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,rm")
256 (plus:PSI (match_operand:PSI 1 "msp_nonimmediate_operand" "%0,0")
257 (match_operand:PSI 2 "msp_general_operand" "rLs,rmi")))]
264 (define_insn "addqi3"
265 [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
266 (plus:QI (match_operand:QI 1 "msp_nonimmediate_operand" "%0,0")
267 (match_operand:QI 2 "msp_general_operand" "riYs,rmi")))]
274 (define_insn "addhi3"
275 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm")
276 (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
277 (match_operand:HI 2 "msp_general_operand" "riYs,rmi")))]
284 ; This pattern is needed in order to avoid reload problems.
285 ; It takes an SI pair of registers, adds a value to them, and
286 ; then converts them into a single PSI register.
288 (define_insn "addsipsi3"
289 [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0)
290 (plus:SI (match_operand:SI 1 "register_operand" "0")
291 (match_operand 2 "general_operand" "rmi")))]
293 "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0"
296 (define_insn "addsi3"
297 [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm")
298 (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
299 (match_operand:SI 2 "general_operand" "r,mi")))]
302 ADD\t%L2, %L0 { ADDC\t%H2, %H0
303 ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0"
306 ; Version of addhi that exposes the carry operations, for SImode adds.
308 ; NOTE - we are playing a dangerous game with GCC here. We have these two
309 ; add patterns and the splitter that follows because our tests have shown
310 ; that this results in a significant reduction in code size - because GCC is
311 ; able to discard any unused part of the addition. We have to annotate the
312 ; patterns with the set and use of the carry flag because otherwise GCC will
313 ; discard parts of the addition when they are actually needed. But we have
314 ; not annotated all the other patterns that set the CARRY flag as doing so
315 ; results in an overall increase in code size[1]. Instead we just *hope*
316 ; that GCC will not move a carry-setting instruction in between the first
319 ; So far our experiments have shown that GCC is likely to move MOV and CMP
320 ; instructions in between the two adds, but not other instructions. MOV is
321 ; safe, CMP is not. So we have annotated the CMP patterns and left the
322 ; subtract, shift and other add patterns alone. At the moment this is
323 ; working, but with future changes to the generic parts of GCC that might
326 ; [1] It is not clear exactly why the code size increases. The cause appears
327 ; to be that reload is more prevelent to spilling a variable onto the stack
328 ; but why it does this is unknown. Possibly the additional CLOBBERs necessary
329 ; to correctly annotate the other patterns makes reload think that there is
330 ; increased register pressure. Or possibly reload does not handle ADD patterns
331 ; that are not single_set() very well.
333 (define_insn "addhi3_cy"
334 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
335 (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
336 (match_operand:HI 2 "msp_nonimmediate_operand" "r,rm")))
338 (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
339 (zero_extend:SI (match_dup 2)))
348 (define_insn "addhi3_cy_i"
349 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
350 (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
351 (match_operand:HI 2 "immediate_operand" "i,i")))
353 (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
354 (match_operand 3 "immediate_operand" "i,i"))
363 ; Version of addhi that adds the carry, for SImode adds.
364 (define_insn "addchi4_cy"
365 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
366 (plus:HI (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
367 (match_operand:HI 2 "msp_general_operand" "ri,rmi"))
368 (zero_extend:HI (reg:BI CARRY))))
376 ; Split an SImode add into two HImode adds, keeping track of the carry
377 ; so that gcc knows when it can and can't optimize away the two
380 [(set (match_operand:SI 0 "msp430_nonsubreg_operand")
381 (plus:SI (match_operand:SI 1 "msp430_nonsubreg_operand")
382 (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand")))
385 [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm")
386 (plus:HI (match_dup 4)
389 (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4))
393 (set (match_operand:HI 6 "nonimmediate_operand" "=&rm")
394 (plus:HI (plus:HI (match_dup 7)
396 (zero_extend:HI (reg:BI CARRY))))
399 operands[3] = msp430_subreg (HImode, operands[0], SImode, 0);
400 operands[4] = msp430_subreg (HImode, operands[1], SImode, 0);
401 operands[5] = msp430_subreg (HImode, operands[2], SImode, 0);
402 operands[6] = msp430_subreg (HImode, operands[0], SImode, 2);
403 operands[7] = msp430_subreg (HImode, operands[1], SImode, 2);
404 operands[8] = msp430_subreg (HImode, operands[2], SImode, 2);
406 /* BZ 64160: Do not use this splitter when the dest partially overlaps the source. */
407 if (reg_overlap_mentioned_p (operands[3], operands[7])
408 || reg_overlap_mentioned_p (operands[3], operands[8]))
411 if (GET_CODE (operands[5]) == CONST_INT)
412 operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff);
414 operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]);
419 ;; Alternatives 2 and 3 are to handle cases generated by reload.
420 (define_insn "subpsi3"
421 [(set (match_operand:PSI 0 "nonimmediate_operand" "=r, rm, &?r, ?&r")
422 (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i")
423 (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r")))]
428 MOVX.A\t%1, %0 { SUBX.A\t%2, %0
429 MOVX.A\t%1, %0 { SUBA\t%2, %0"
432 ;; Alternatives 2 and 3 are to handle cases generated by reload.
433 (define_insn "subqi3"
434 [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
435 (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i")
436 (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r")))]
441 MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0
442 MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0"
445 ;; Alternatives 2 and 3 are to handle cases generated by reload.
446 (define_insn "subhi3"
447 [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
448 (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i")
449 (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r")))]
454 MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0
455 MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0"
458 (define_insn "subsi3"
459 [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm")
460 (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0")
461 (match_operand:SI 2 "general_operand" "rmi")))]
463 "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0"
466 (define_insn "*bic<mode>_cg"
467 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
468 (and:QHI (match_operand:QHI 1 "msp_general_operand" "0,0")
469 (match_operand 2 "msp430_inv_constgen_operator" "n,n")))]
476 (define_insn "bic<mode>3"
477 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
478 (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn"))
479 (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))]
486 (define_insn "and<mode>3"
487 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
488 (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
489 (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
496 (define_insn "ior<mode>3"
497 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
498 (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
499 (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
506 (define_insn "xor<mode>3"
507 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
508 (xor:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
509 (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
516 ;; Macro : XOR #~0, %0
517 (define_insn "one_cmpl<mode>2"
518 [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
519 (not:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "0,0")))]
526 (define_insn "extendqihi2"
527 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m")
528 (sign_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))]
535 (define_insn "zero_extendqihi2"
536 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m")
537 (zero_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))]
544 ;; Eliminate extraneous zero-extends mysteriously created by gcc.
546 [(set (match_operand:HI 0 "register_operand")
547 (zero_extend:HI (match_operand:QI 1 "general_operand")))
548 (set (match_operand:HI 2 "register_operand")
549 (zero_extend:HI (match_operand:QI 3 "register_operand")))]
550 "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])"
552 (zero_extend:HI (match_dup 1)))]
555 (define_insn "zero_extendhipsi2"
556 [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,m")
557 (zero_extend:PSI (match_operand:HI 1 "msp_nonimmediate_operand" "rm,r")))]
562 (define_insn "truncpsihi2"
563 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
564 (truncate:HI (match_operand:PSI 1 "register_operand" "r")))]
569 (define_insn "extendhisi2"
570 [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
571 (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
573 { return msp430x_extendhisi (operands); }
576 (define_insn "extendhipsi2"
577 [(set (match_operand:PSI 0 "nonimmediate_operand" "=r")
578 (subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))]
580 "RLAM.A #4, %0 { RRAM.A #4, %0"
583 ;; Look for cases where integer/pointer conversions are suboptimal due
584 ;; to missing patterns, despite us not having opcodes for these
585 ;; patterns. Doing these manually allows for alternate optimization
587 (define_insn "zero_extendhisi2"
588 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
589 (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))]
594 (define_insn "zero_extendhisipsi2"
595 [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r")
596 (subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))]
603 (define_insn "extend_and_shift1_hipsi2"
604 [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
605 (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
608 "RLAM.A #4, %0 { RRAM.A #3, %0"
611 (define_insn "extend_and_shift2_hipsi2"
612 [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
613 (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
616 "RLAM.A #4, %0 { RRAM.A #2, %0"
619 ; Nasty - we are sign-extending a 20-bit PSI value in one register into
620 ; two adjacent 16-bit registers to make an SI value. There is no MSP430X
621 ; instruction that will do this, so we push the 20-bit value onto the stack
622 ; and then pop it off as two 16-bit values.
624 ; FIXME: The MSP430X documentation does not specify if zero-extension or
625 ; sign-extension happens when the 20-bit value is pushed onto the stack.
626 ; It is probably zero-extension, but if not this pattern will not work
627 ; when the PSI value is negative..
629 ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A....
631 ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused
632 ; about extending a single PSI mode register into a pair of SImode registers
633 ; with the same starting register. It thinks that the upper register of
634 ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c
635 ; at -O2 to see this.
637 (define_insn "zero_extendpsisi2"
638 [(set (match_operand:SI 0 "register_operand" "+r")
639 (zero_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
642 if (REGNO (operands[1]) == SP_REGNO)
643 /* If the source register is the stack pointer, the value
644 stored in the stack slot will be the value *after* the
645 stack pointer has been decremented. So allow for that
647 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\";
649 return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\";
653 ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t).
654 ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
655 ;; it, we use a different method here.
657 (define_insn "extendpsisi2"
658 [(set (match_operand:SI 0 "register_operand" "=r")
659 (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
662 /* The intention here is that we copy the bottom 16-bits of
663 %1 into %L0 (zeroing the top four bits). Then we copy the
664 entire 20-bits of %1 into %H0 and then arithmetically shift
665 it right by 16 bits, to get the top four bits of the pointer
666 sign-extended in %H0. */
667 if (REGNO (operands[0]) == REGNO (operands[1]))
668 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\";
670 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\";
674 ; See the movsipsi2 pattern above for another way that GCC performs this
676 (define_insn "truncsipsi2"
677 [(set (match_operand:PSI 0 "register_operand" "=r")
678 (truncate:PSI (match_operand:SI 1 "register_operand" "r")))]
680 "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0"
683 ;;------------------------------------------------------------
686 ;; Note: We do not use the RPT ... SHIFT instruction sequence
687 ;; when the repeat count is in a register, because even though RPT
688 ;; accepts counts in registers, it does not work if the count is
689 ;; zero, and the actual count in the register has to be one less
690 ;; than the required number of iterations. We could encode a
691 ;; seqeunce like this:
701 ;; But is longer than calling a helper function, and we are mostly
702 ;; concerned with code size. FIXME: Maybe enable a sequence like
703 ;; this at -O3 and above ?
705 ;; Note - we ignore shift counts of less than one or more than 15.
706 ;; This is permitted by the ISO C99 standard as such shifts result
707 ;; in "undefined" behaviour. [6.5.7 (3)]
711 (define_expand "ashlhi3"
712 [(set (match_operand:HI 0 "nonimmediate_operand")
713 (ashift:HI (match_operand:HI 1 "general_operand")
714 (match_operand:HI 2 "general_operand")))]
718 && REG_P (operands[0])
719 && REG_P (operands[1])
720 && CONST_INT_P (operands[2]))
721 emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2]));
723 msp430_expand_helper (operands, \"__mspabi_slli\", true);
728 (define_insn "slli_1"
729 [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
730 (ashift:HI (match_operand:HI 1 "general_operand" "0")
733 "RLA.W\t%0" ;; Note - this is a macro for ADD
736 (define_insn "430x_shift_left"
737 [(set (match_operand:HI 0 "register_operand" "=r")
738 (ashift:HI (match_operand:HI 1 "register_operand" "0")
739 (match_operand 2 "immediate_operand" "n")))]
742 if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16)
743 return \"rpt\t%2 { rlax.w\t%0\";
744 return \"# nop left shift\";
748 (define_insn "slll_1"
749 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
750 (ashift:SI (match_operand:SI 1 "general_operand" "0")
753 "RLA.W\t%L0 { RLC.W\t%H0"
756 (define_insn "slll_2"
757 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
758 (ashift:SI (match_operand:SI 1 "general_operand" "0")
761 "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0"
764 (define_expand "ashlsi3"
765 [(set (match_operand:SI 0 "nonimmediate_operand")
766 (ashift:SI (match_operand:SI 1 "general_operand")
767 (match_operand:SI 2 "general_operand")))]
769 "msp430_expand_helper (operands, \"__mspabi_slll\", true);
777 (define_expand "ashrhi3"
778 [(set (match_operand:HI 0 "nonimmediate_operand")
779 (ashiftrt:HI (match_operand:HI 1 "general_operand")
780 (match_operand:HI 2 "general_operand")))]
784 && REG_P (operands[0])
785 && REG_P (operands[1])
786 && CONST_INT_P (operands[2]))
787 emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2]));
789 msp430_expand_helper (operands, \"__mspabi_srai\", true);
794 (define_insn "srai_1"
795 [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
796 (ashiftrt:HI (match_operand:HI 1 "msp_general_operand" "0")
802 (define_insn "430x_arithmetic_shift_right"
803 [(set (match_operand:HI 0 "register_operand" "=r")
804 (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
805 (match_operand 2 "immediate_operand" "n")))]
808 if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16)
809 return \"rpt\t%2 { rrax.w\t%0\";
810 return \"# nop arith right shift\";
814 (define_insn "srap_1"
815 [(set (match_operand:PSI 0 "register_operand" "=r")
816 (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
822 (define_insn "srap_2"
823 [(set (match_operand:PSI 0 "register_operand" "=r")
824 (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
830 (define_insn "sral_1"
831 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
832 (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
835 "RRA.W\t%H0 { RRC.W\t%L0"
838 (define_insn "sral_2"
839 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
840 (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
843 "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0"
846 (define_expand "ashrsi3"
847 [(set (match_operand:SI 0 "nonimmediate_operand")
848 (ashiftrt:SI (match_operand:SI 1 "general_operand")
849 (match_operand:SI 2 "general_operand")))]
851 "msp430_expand_helper (operands, \"__mspabi_sral\", true);
859 (define_expand "lshrhi3"
860 [(set (match_operand:HI 0 "nonimmediate_operand")
861 (lshiftrt:HI (match_operand:HI 1 "general_operand")
862 (match_operand:HI 2 "general_operand")))]
866 && REG_P (operands[0])
867 && REG_P (operands[1])
868 && CONST_INT_P (operands[2]))
869 emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2]));
871 msp430_expand_helper (operands, \"__mspabi_srli\", true);
876 (define_insn "srli_1"
877 [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
878 (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
884 (define_insn "430x_logical_shift_right"
885 [(set (match_operand:HI 0 "register_operand" "=r")
886 (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
887 (match_operand 2 "immediate_operand" "n")))]
890 return msp430x_logical_shift_right (operands[2]);
894 (define_insn "srlp_1"
895 [(set (match_operand:PSI 0 "register_operand" "=r")
896 (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
902 (define_insn "srll_1"
903 [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
904 (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
907 "CLRC { RRC.W\t%H0 { RRC.W\t%L0"
910 (define_insn "srll_2x"
911 [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
912 (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
915 "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0"
918 (define_expand "lshrsi3"
919 [(set (match_operand:SI 0 "nonimmediate_operand")
920 (lshiftrt:SI (match_operand:SI 1 "general_operand")
921 (match_operand:SI 2 "general_operand")))]
923 "msp430_expand_helper (operands, \"__mspabi_srll\", true);
927 ;;------------------------------------------------------------
928 ;; Function Entry/Exit
930 (define_expand "prologue"
933 "msp430_expand_prologue (); DONE;"
936 (define_expand "epilogue"
939 "msp430_expand_epilogue (0); DONE;"
943 (define_insn "epilogue_helper"
944 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)]
946 "BR%Q0\t#__mspabi_func_epilog_%J0"
950 (define_insn "prologue_start_marker"
951 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)]
953 "; start of prologue"
956 (define_insn "prologue_end_marker"
957 [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)]
962 (define_insn "epilogue_start_marker"
963 [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)]
965 "; start of epilogue"
968 ;; This makes the linker add a call to exit() after the call to main()
970 (define_insn "msp430_refsym_need_exit"
971 [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)]
973 ".refsym\t__crt0_call_exit"
976 ;;------------------------------------------------------------
979 (define_expand "call"
980 [(call:HI (match_operand 0 "")
981 (match_operand 1 ""))]
986 (define_insn "call_internal"
987 [(call (mem:HI (match_operand 0 "general_operand" "rYci"))
988 (match_operand 1 ""))]
993 (define_expand "call_value"
994 [(set (match_operand 0 "register_operand")
995 (call:HI (match_operand 1 "general_operand")
996 (match_operand 2 "")))]
1001 (define_insn "call_value_internal"
1002 [(set (match_operand 0 "register_operand" "=r")
1003 (call (mem:HI (match_operand 1 "general_operand" "rYci"))
1004 (match_operand 2 "")))]
1009 (define_insn "msp_return"
1012 { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
1015 ;; This pattern is NOT, as expected, a return pattern. It's called
1016 ;; before reload and must only store its operands, and emit a
1017 ;; placeholder where the epilog needs to be. AFTER reload, the
1018 ;; placeholder should get expanded into a regular-type epilogue that
1019 ;; also does the EH return.
1020 (define_expand "eh_return"
1021 [(match_operand:HI 0 "")]
1023 "msp430_expand_eh_return (operands[0]);
1024 emit_jump_insn (gen_msp430_eh_epilogue ());
1029 ;; This is the actual EH epilogue. We emit it in the pattern above,
1030 ;; before reload, and convert it to a real epilogue after reload.
1031 (define_insn_and_split "msp430_eh_epilogue"
1037 "msp430_expand_epilogue (1); DONE;"
1042 (label_ref (match_operand 0 "" "")))]
1047 ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs
1048 ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c).
1049 (define_insn "indirect_jump"
1051 (match_operand 0 "nonimmediate_operand" "rYl"))]
1056 ;;------------------------------------------------------------
1057 ;; Various Conditionals
1059 (define_expand "cbranch<mode>4"
1060 [(parallel [(set (pc) (if_then_else
1061 (match_operator 0 ""
1062 [(match_operand:QHI 1 "nonimmediate_operand")
1063 (match_operand:QHI 2 "general_operand")])
1064 (label_ref (match_operand 3 "" ""))
1066 (clobber (reg:BI CARRY))]
1069 "msp430_fixup_compare_operands (<MODE>mode, operands);"
1072 (define_insn "cbranchpsi4_real"
1073 [(set (pc) (if_then_else
1074 (match_operator 0 "msp430_cmp_operator"
1075 [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm")
1076 (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")])
1077 (label_ref (match_operand 3 "" ""))
1079 (clobber (reg:BI CARRY))
1083 CMP%Q0\t%2, %1 { J%0\t%l3
1084 CMPX.A\t%2, %1 { J%0\t%l3
1085 CMPX.A\t%2, %1 { J%0\t%l3"
1088 (define_insn "cbranchqi4_real"
1089 [(set (pc) (if_then_else
1090 (match_operator 0 "msp430_cmp_operator"
1091 [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm")
1092 (match_operand:QI 2 "general_operand" "rYsi,rmi")])
1093 (label_ref (match_operand 3 "" ""))
1095 (clobber (reg:BI CARRY))
1099 CMP.B\t%2, %1 { J%0\t%l3
1100 CMP%X0.B\t%2, %1 { J%0\t%l3"
1103 (define_insn "cbranchhi4_real"
1104 [(set (pc) (if_then_else
1105 (match_operator 0 "msp430_cmp_operator"
1106 [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm")
1107 (match_operand:HI 2 "general_operand" "rYsi,rmi")])
1108 (label_ref (match_operand 3 "" ""))
1110 (clobber (reg:BI CARRY))
1114 CMP.W\t%2, %1 { J%0\t%l3
1115 CMP%X0.W\t%2, %1 { J%0\t%l3"
1118 (define_insn "cbranchpsi4_reversed"
1119 [(set (pc) (if_then_else
1120 (match_operator 0 "msp430_reversible_cmp_operator"
1121 [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi")
1122 (match_operand:PSI 2 "general_operand" "r,rYs,rm")])
1123 (label_ref (match_operand 3 "" ""))
1125 (clobber (reg:BI CARRY))
1129 CMP%Q0\t%1, %2 { J%R0\t%l3
1130 CMPX.A\t%1, %2 { J%R0\t%l3
1131 CMPX.A\t%1, %2 { J%R0\t%l3"
1134 (define_insn "cbranchqi4_reversed"
1135 [(set (pc) (if_then_else
1136 (match_operator 0 "msp430_reversible_cmp_operator"
1137 [(match_operand:QI 1 "general_operand" "rYsi,rmi")
1138 (match_operand:QI 2 "general_operand" "rYs,rm")])
1139 (label_ref (match_operand 3 "" ""))
1141 (clobber (reg:BI CARRY))
1145 CMP.B\t%1, %2 { J%R0\t%l3
1146 CMP%X0.B\t%1, %2 { J%R0\t%l3"
1149 (define_insn "cbranchhi4_reversed"
1150 [(set (pc) (if_then_else
1151 (match_operator 0 "msp430_reversible_cmp_operator"
1152 [(match_operand:HI 1 "general_operand" "rYsi,rmi")
1153 (match_operand:HI 2 "general_operand" "rYs,rm")])
1154 (label_ref (match_operand 3 "" ""))
1156 (clobber (reg:BI CARRY))
1160 CMP.W\t%1, %2 { J%R0\t%l3
1161 CMP%X0.W\t%1, %2 { J%R0\t%l3"
1164 (define_insn "*bitbranch<mode>4"
1165 [(set (pc) (if_then_else
1166 (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
1167 (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi"))
1169 (label_ref (match_operand 2 "" ""))
1171 (clobber (reg:BI CARRY))
1175 BIT%x0%b0\t%1, %0 { JNE\t%l2
1176 BIT%X0%b0\t%1, %0 { JNE\t%l2"
1179 (define_insn "*bitbranch<mode>4"
1180 [(set (pc) (if_then_else
1181 (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1182 (match_operand:QHI 1 "msp_general_operand" "rmi"))
1184 (label_ref (match_operand 2 "" ""))
1186 (clobber (reg:BI CARRY))
1189 "BIT%x0%b0\t%1, %0 { JEQ\t%l2"
1192 (define_insn "*bitbranch<mode>4"
1193 [(set (pc) (if_then_else
1194 (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1195 (match_operand:QHI 1 "msp_general_operand" "rmi"))
1198 (label_ref (match_operand 2 "" ""))))
1199 (clobber (reg:BI CARRY))
1202 "BIT%X0%b0\t%1, %0 { JNE\t%l2"
1205 (define_insn "*bitbranch<mode>4"
1206 [(set (pc) (if_then_else
1207 (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1208 (match_operand:QHI 1 "msp_general_operand" "rmi"))
1211 (label_ref (match_operand 2 "" ""))))
1212 (clobber (reg:BI CARRY))
1215 "BIT%X0%b0\t%1, %0 { JEQ\t%l2"
1218 ;;------------------------------------------------------------
1219 ;; zero-extract versions of the above
1221 (define_insn "*bitbranch<mode>4_z"
1222 [(set (pc) (if_then_else
1223 (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
1225 (match_operand 1 "msp430_bitpos" "i,i"))
1227 (label_ref (match_operand 2 "" ""))
1229 (clobber (reg:BI CARRY))
1233 BIT%x0%b0\t%p1, %0 { JNE\t%l2
1234 BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1237 (define_insn "*bitbranch<mode>4_z"
1238 [(set (pc) (if_then_else
1239 (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1241 (match_operand 1 "msp430_bitpos" "i"))
1243 (label_ref (match_operand 2 "" ""))
1245 (clobber (reg:BI CARRY))
1248 "BIT%x0%X0%b0\t%p1, %0 { JEQ\t%l2"
1251 (define_insn "*bitbranch<mode>4_z"
1252 [(set (pc) (if_then_else
1253 (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1255 (match_operand 1 "msp430_bitpos" "i"))
1258 (label_ref (match_operand 2 "" ""))))
1259 (clobber (reg:BI CARRY))
1262 "BIT%X0%b0\t%p1, %0 { JNE\t%l2"
1265 (define_insn "*bitbranch<mode>4_z"
1266 [(set (pc) (if_then_else
1267 (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
1269 (match_operand 1 "msp430_bitpos" "i"))
1272 (label_ref (match_operand 2 "" ""))))
1273 (clobber (reg:BI CARRY))
1276 "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
1279 ;;------------------------------------------------------------
1288 (define_insn "disable_interrupts"
1289 [(unspec_volatile [(const_int 0)] UNS_DINT)]
1294 (define_insn "enable_interrupts"
1295 [(unspec_volatile [(const_int 0)] UNS_EINT)]
1300 (define_insn "push_intr_state"
1301 [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
1306 (define_insn "pop_intr_state"
1307 [(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
1312 ;; Clear bits in the copy of the status register that is currently
1313 ;; saved on the stack at the top of the interrupt handler.
1314 (define_insn "bic_SR"
1315 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
1317 "BIC.W\t%0, %O0(SP)"
1320 ;; Set bits in the copy of the status register that is currently
1321 ;; saved on the stack at the top of the interrupt handler.
1322 (define_insn "bis_SR"
1323 [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
1325 "BIS.W\t%0, %O0(SP)"
1328 ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int)))
1329 ;; very late on in the compilation and not splitting it into separate
1330 ;; instructions, so we provide a pattern to support it here.
1331 (define_insn "andneghi3"
1332 [(set (match_operand:HI 0 "register_operand" "=r")
1333 (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r"))
1334 (match_operand 2 "immediate_operand" "n")))]
1337 if (REGNO (operands[0]) != REGNO (operands[1]))
1338 return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1340 return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\";
1344 (define_insn "delay_cycles_start"
1345 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1348 "; Begin %J0 cycle delay"
1351 (define_insn "delay_cycles_end"
1352 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
1355 "; End %J0 cycle delay"
1358 (define_insn "delay_cycles_32"
1359 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1360 (match_operand 1 "immediate_operand" "i")
1376 (define_insn "delay_cycles_32x"
1377 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1378 (match_operand 1 "immediate_operand" "i")
1392 (define_insn "delay_cycles_16"
1393 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1394 (match_operand 1 "immediate_operand" "i")
1404 (define_insn "delay_cycles_16x"
1405 [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
1406 (match_operand 1 "immediate_operand" "i")
1416 (define_insn "delay_cycles_2"
1417 [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)]
1422 (define_insn "delay_cycles_1"
1423 [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)]
1428 (define_insn "mulhisi3"
1429 [(set (match_operand:SI 0 "register_operand" "=r")
1430 (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1431 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1432 "optimize > 2 && msp430_hwmult_type != NONE"
1434 if (msp430_use_f5_series_hwmult ())
1435 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\";
1437 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\";
1441 (define_insn "umulhisi3"
1442 [(set (match_operand:SI 0 "register_operand" "=r")
1443 (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
1444 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
1445 "optimize > 2 && msp430_hwmult_type != NONE"
1447 if (msp430_use_f5_series_hwmult ())
1448 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\";
1450 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\";
1454 (define_insn "mulsidi3"
1455 [(set (match_operand:DI 0 "register_operand" "=r")
1456 (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1457 (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1458 "optimize > 2 && msp430_hwmult_type != NONE"
1460 if (msp430_use_f5_series_hwmult ())
1461 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\";
1463 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\";
1467 (define_insn "umulsidi3"
1468 [(set (match_operand:DI 0 "register_operand" "=r")
1469 (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
1470 (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
1471 "optimize > 2 && msp430_hwmult_type != NONE"
1473 if (msp430_use_f5_series_hwmult ())
1474 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\";
1476 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\";