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