1;; thumb.md Machine description for ARM/Thumb processors 2;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. 3;; The basis of this contribution was generated by 4;; Richard Earnshaw, Advanced RISC Machines Ltd 5 6;; This file is part of GNU CC. 7 8;; GNU CC is free software; you can redistribute it and/or modify 9;; it under the terms of the GNU General Public License as published by 10;; the Free Software Foundation; either version 2, or (at your option) 11;; any later version. 12 13;; GNU CC is distributed in the hope that it will be useful, 14;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16;; GNU General Public License for more details. 17 18;; You should have received a copy of the GNU General Public License 19;; along with GNU CC; see the file COPYING. If not, write to 20;; the Free Software Foundation, 59 Temple Place - Suite 330, 21;; Boston, MA 02111-1307, USA. 22 23;; LENGTH of an instruction is 2 bytes 24(define_attr "length" "" (const_int 2)) 25 26;; CONDS is set to UNCHANGED when an insn does not affect the condition codes 27;; Most insns change the condition codes 28(define_attr "conds" "changed,unchanged" (const_string "changed")) 29 30;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a 31;; distant label. 32(define_attr "far_jump" "yes,no" (const_string "no")) 33 34;; Start with move insns 35 36(define_expand "movsi" 37 [(set (match_operand:SI 0 "general_operand" "") 38 (match_operand:SI 1 "general_operand" ""))] 39 "" 40 " 41 if (! (reload_in_progress || reload_completed)) 42 { 43 if (GET_CODE (operands[0]) != REG) 44 operands[1] = force_reg (SImode, operands[1]); 45 } 46") 47 48(define_insn "*movsi_insn" 49 [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") 50 (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] 51 "register_operand (operands[0], SImode) 52 || register_operand (operands[1], SImode)" 53 "@ 54 add\\t%0, %1, #0 55 mov\\t%0, %1 56 # 57 # 58 ldmia\\t%1, {%0} 59 stmia\\t%0, {%1} 60 ldr\\t%0, %1 61 str\\t%1, %0 62 mov\\t%0, %1 63 mov\\t%0, %1" 64[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) 65 66(define_split 67 [(set (match_operand:SI 0 "register_operand" "") 68 (match_operand:SI 1 "const_int_operand" ""))] 69 "thumb_shiftable_const (INTVAL (operands[1]))" 70 [(set (match_dup 0) (match_dup 1)) 71 (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] 72 " 73{ 74 unsigned HOST_WIDE_INT val = INTVAL (operands[1]); 75 unsigned HOST_WIDE_INT mask = 0xff; 76 int i; 77 for (i = 0; i < 25; i++) 78 if ((val & (mask << i)) == val) 79 break; 80 81 if (i == 0) 82 FAIL; 83 84 operands[1] = GEN_INT (val >> i); 85 operands[2] = GEN_INT (i); 86}") 87 88(define_split 89 [(set (match_operand:SI 0 "register_operand" "") 90 (match_operand:SI 1 "const_int_operand" ""))] 91 "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" 92 [(set (match_dup 0) (match_dup 1)) 93 (set (match_dup 0) (neg:SI (match_dup 0)))] 94 " 95 operands[1] = GEN_INT (- INTVAL (operands[1])); 96") 97 98;;(define_expand "reload_outsi" 99;; [(set (match_operand:SI 2 "register_operand" "=&l") 100;; (match_operand:SI 1 "register_operand" "h")) 101;; (set (match_operand:SI 0 "reload_memory_operand" "=o") 102;; (match_dup 2))] 103;; "" 104;; " 105;;/* thumb_reload_out_si (operands); 106;; DONE; */ 107;;") 108 109(define_expand "movhi" 110 [(set (match_operand:HI 0 "general_operand" "") 111 (match_operand:HI 1 "general_operand" ""))] 112 "" 113 " 114{ 115 if (! (reload_in_progress || reload_completed)) 116 { 117 if (GET_CODE (operands[0]) != REG) 118 operands[1] = force_reg (HImode, operands[1]); 119 120 /* ??? We shouldn't really get invalid addresses here, but this can 121 happen if we are passed a SP (never OK for HImode/QImode) or virtual 122 register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) 123 relative address. */ 124 /* ??? This should perhaps be fixed elsewhere, for instance, in 125 fixup_stack_1, by checking for other kinds of invalid addresses, 126 e.g. a bare reference to a virtual register. This may confuse the 127 alpha though, which must handle this case differently. */ 128 if (GET_CODE (operands[0]) == MEM 129 && ! memory_address_p (GET_MODE (operands[0]), 130 XEXP (operands[0], 0))) 131 { 132 rtx temp = copy_to_reg (XEXP (operands[0], 0)); 133 operands[0] = change_address (operands[0], VOIDmode, temp); 134 } 135 if (GET_CODE (operands[1]) == MEM 136 && ! memory_address_p (GET_MODE (operands[1]), 137 XEXP (operands[1], 0))) 138 { 139 rtx temp = copy_to_reg (XEXP (operands[1], 0)); 140 operands[1] = change_address (operands[1], VOIDmode, temp); 141 } 142 } 143 /* Handle loading a large integer during reload */ 144 else if (GET_CODE (operands[1]) == CONST_INT 145 && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) 146 { 147 /* Writing a constant to memory needs a scratch, which should 148 be handled with SECONDARY_RELOADs. */ 149 if (GET_CODE (operands[0]) != REG) 150 abort (); 151 152 operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); 153 emit_insn (gen_movsi (operands[0], operands[1])); 154 DONE; 155 } 156}") 157 158(define_insn "*movhi_insn" 159 [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") 160 (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] 161 "register_operand (operands[0], HImode) 162 || register_operand (operands[1], HImode)" 163 "@ 164 add\\t%0, %1, #0 165 ldrh\\t%0, %1 166 strh\\t%1, %0 167 mov\\t%0, %1 168 mov\\t%0, %1 169 mov\\t%0, %1") 170 171(define_expand "movqi" 172 [(set (match_operand:QI 0 "general_operand" "") 173 (match_operand:QI 1 "general_operand" ""))] 174 "" 175 " 176{ 177 if (! (reload_in_progress || reload_completed)) 178 { 179 if (GET_CODE (operands[0]) != REG) 180 operands[1] = force_reg (QImode, operands[1]); 181 182 /* ??? We shouldn't really get invalid addresses here, but this can 183 happen if we are passed a SP (never OK for HImode/QImode) or virtual 184 register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) 185 relative address. */ 186 /* ??? This should perhaps be fixed elsewhere, for instance, in 187 fixup_stack_1, by checking for other kinds of invalid addresses, 188 e.g. a bare reference to a virtual register. This may confuse the 189 alpha though, which must handle this case differently. */ 190 if (GET_CODE (operands[0]) == MEM 191 && ! memory_address_p (GET_MODE (operands[0]), 192 XEXP (operands[0], 0))) 193 { 194 rtx temp = copy_to_reg (XEXP (operands[0], 0)); 195 operands[0] = change_address (operands[0], VOIDmode, temp); 196 } 197 if (GET_CODE (operands[1]) == MEM 198 && ! memory_address_p (GET_MODE (operands[1]), 199 XEXP (operands[1], 0))) 200 { 201 rtx temp = copy_to_reg (XEXP (operands[1], 0)); 202 operands[1] = change_address (operands[1], VOIDmode, temp); 203 } 204 } 205 /* Handle loading a large integer during reload */ 206 else if (GET_CODE (operands[1]) == CONST_INT 207 && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) 208 { 209 /* Writing a constant to memory needs a scratch, which should 210 be handled with SECONDARY_RELOADs. */ 211 if (GET_CODE (operands[0]) != REG) 212 abort (); 213 214 operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); 215 emit_insn (gen_movsi (operands[0], operands[1])); 216 DONE; 217 } 218}") 219 220(define_insn "*movqi_insn" 221 [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") 222 (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] 223 "register_operand (operands[0], QImode) 224 || register_operand (operands[1], QImode)" 225 "@ 226 add\\t%0, %1, #0 227 ldrb\\t%0, %1 228 strb\\t%1, %0 229 mov\\t%0, %1 230 mov\\t%0, %1 231 mov\\t%0, %1") 232 233(define_expand "movdi" 234 [(set (match_operand:DI 0 "general_operand" "") 235 (match_operand:DI 1 "general_operand" ""))] 236 "" 237 " 238 if (! (reload_in_progress || reload_completed)) 239 { 240 if (GET_CODE (operands[0]) != REG) 241 operands[1] = force_reg (DImode, operands[1]); 242 } 243") 244 245;;; ??? This should have alternatives for constants. 246;;; ??? This was originally identical to the movdf_insn pattern. 247;;; ??? The 'i' constraint looks funny, but it should always be replaced by 248;;; thumb_reorg with a memory reference. 249(define_insn "*movdi_insn" 250 [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") 251 (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] 252 "register_operand (operands[0], DImode) 253 || register_operand (operands[1], DImode)" 254 "* 255{ 256 switch (which_alternative) 257 { 258 case 0: 259 if (REGNO (operands[1]) == REGNO (operands[0]) + 1) 260 return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; 261 return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; 262 case 1: 263 return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; 264 case 2: 265 operands[1] = GEN_INT (- INTVAL (operands[1])); 266 return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; 267 case 3: 268 return \"ldmia\\t%1, {%0, %H0}\"; 269 case 4: 270 return \"stmia\\t%0, {%1, %H1}\"; 271 case 5: 272 return thumb_load_double_from_address (operands); 273 case 6: 274 operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); 275 output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); 276 return \"\"; 277 case 7: 278 if (REGNO (operands[1]) == REGNO (operands[0]) + 1) 279 return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; 280 return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; 281 } 282}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) 283 284(define_expand "movdf" 285 [(set (match_operand:DF 0 "general_operand" "") 286 (match_operand:DF 1 "general_operand" ""))] 287 "" 288 " 289 if (! (reload_in_progress || reload_completed)) 290 { 291 if (GET_CODE (operands[0]) != REG) 292 operands[1] = force_reg (DFmode, operands[1]); 293 } 294") 295 296;;; ??? This should have alternatives for constants. 297;;; ??? This was originally identical to the movdi_insn pattern. 298;;; ??? The 'F' constraint looks funny, but it should always be replaced by 299;;; thumb_reorg with a memory reference. 300(define_insn "*movdf_insn" 301 [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") 302 (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] 303 "register_operand (operands[0], DFmode) 304 || register_operand (operands[1], DFmode)" 305 "* 306 switch (which_alternative) 307 { 308 case 0: 309 if (REGNO (operands[1]) == REGNO (operands[0]) + 1) 310 return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; 311 return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; 312 case 1: 313 return \"ldmia\\t%1, {%0, %H0}\"; 314 case 2: 315 return \"stmia\\t%0, {%1, %H1}\"; 316 case 3: 317 return thumb_load_double_from_address (operands); 318 case 4: 319 operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); 320 output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); 321 return \"\"; 322 case 5: 323 if (REGNO (operands[1]) == REGNO (operands[0]) + 1) 324 return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; 325 return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; 326 } 327"[(set_attr "length" "4,2,2,6,4,4")]) 328 329(define_expand "movsf" 330 [(set (match_operand:SF 0 "general_operand" "") 331 (match_operand:SF 1 "general_operand" ""))] 332 "" 333 " 334 if (! (reload_in_progress || reload_completed)) 335 { 336 if (GET_CODE (operands[0]) != REG) 337 operands[1] = force_reg (SFmode, operands[1]); 338 } 339") 340 341;;; ??? This should have alternatives for constants. 342(define_insn "*movsf_insn" 343 [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") 344 (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] 345 "register_operand (operands[0], SFmode) 346 || register_operand (operands[1], SFmode)" 347 "@ 348 add\\t%0, %1, #0 349 ldmia\\t%1, {%0} 350 stmia\\t%0, {%1} 351 ldr\\t%0, %1 352 str\\t%1, %0 353 mov\\t%0, %1 354 mov\\t%0, %1") 355 356;; Widening move insns 357 358(define_expand "zero_extendhisi2" 359 [(set (match_operand:SI 0 "register_operand" "") 360 (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] 361 "" 362 " 363 if (GET_CODE (operands[1]) != MEM) 364 { 365 rtx temp = gen_reg_rtx (SImode); 366 367 operands[1] = force_reg (HImode, operands[1]); 368 operands[1] = gen_lowpart (SImode, operands[1]); 369 emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); 370 emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); 371 DONE; 372 } 373") 374 375(define_insn "*zero_extendhisi2_insn" 376 [(set (match_operand:SI 0 "register_operand" "=l") 377 (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] 378 "" 379 "ldrh\\t%0, %1") 380 381(define_expand "zero_extendqisi2" 382 [(set (match_operand:SI 0 "register_operand" "") 383 (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] 384 "" 385 " 386 if (GET_CODE (operands[1]) != MEM) 387 { 388 rtx temp = gen_reg_rtx (SImode); 389 390 operands[1] = force_reg (QImode, operands[1]); 391 operands[1] = gen_lowpart (SImode, operands[1]); 392 emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); 393 emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); 394 DONE; 395 } 396") 397 398(define_insn "*zero_extendqisi2_insn" 399 [(set (match_operand:SI 0 "register_operand" "=l") 400 (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] 401 "" 402 "ldrb\\t%0, %1") 403 404(define_expand "extendhisi2" 405 [(parallel [(set (match_operand:SI 0 "register_operand" "") 406 (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) 407 (clobber (match_scratch:SI 2 ""))])] 408 "" 409 " 410 if (GET_CODE (operands[1]) != MEM) 411 { 412 rtx temp = gen_reg_rtx (SImode); 413 414 operands[1] = force_reg (HImode, operands[1]); 415 operands[1] = gen_lowpart (SImode, operands[1]); 416 emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); 417 emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); 418 DONE; 419 } 420") 421 422(define_insn "*extendhisi2_insn" 423 [(set (match_operand:SI 0 "register_operand" "=l") 424 (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) 425 (clobber (match_scratch:SI 2 "=&l"))] 426 "" 427 "* 428{ 429 rtx ops[4]; 430 /* This code used to try to use 'V', and fix the address only if it was 431 offsettable, but this fails for e.g. REG+48 because 48 is outside the 432 range of QImode offsets, and offsettable_address_p does a QImode 433 address check. */ 434 435 if (GET_CODE (XEXP (operands[1], 0)) == PLUS) 436 { 437 ops[1] = XEXP (XEXP (operands[1], 0), 0); 438 ops[2] = XEXP (XEXP (operands[1], 0), 1); 439 } 440 else 441 { 442 ops[1] = XEXP (operands[1], 0); 443 ops[2] = const0_rtx; 444 } 445 if (GET_CODE (ops[2]) == REG) 446 return \"ldrsh\\t%0, %1\"; 447 448 ops[0] = operands[0]; 449 ops[3] = operands[2]; 450 output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); 451 return \"\"; 452}" 453[(set_attr "length" "4")]) 454 455(define_expand "extendqisi2" 456 [(set (match_operand:SI 0 "register_operand" "") 457 (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] 458 "" 459 " 460 if (GET_CODE (operands[1]) != MEM) 461 { 462 rtx temp = gen_reg_rtx (SImode); 463 464 operands[1] = force_reg (QImode, operands[1]); 465 operands[1] = gen_lowpart (SImode, operands[1]); 466 emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); 467 emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); 468 DONE; 469 } 470") 471 472(define_insn "*extendqisi2_insn" 473 [(set (match_operand:SI 0 "register_operand" "=l,l") 474 (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] 475 "" 476 "* 477{ 478 rtx ops[3]; 479 480 if (which_alternative == 0) 481 return \"ldrsb\\t%0, %1\"; 482 ops[0] = operands[0]; 483 if (GET_CODE (XEXP (operands[1], 0)) == PLUS) 484 { 485 ops[1] = XEXP (XEXP (operands[1], 0), 0); 486 ops[2] = XEXP (XEXP (operands[1], 0), 1); 487 488 if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) 489 output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); 490 else if (GET_CODE (ops[1]) == REG) 491 { 492 if (REGNO (ops[1]) == REGNO (operands[0])) 493 output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); 494 else 495 output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); 496 } 497 else 498 { 499 if (REGNO (ops[2]) == REGNO (operands[0])) 500 output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); 501 else 502 output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); 503 } 504 } 505 else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) 506 { 507 output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); 508 } 509 else 510 { 511 ops[1] = XEXP (operands[1], 0); 512 ops[2] = const0_rtx; 513 output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); 514 } 515 return \"\"; 516}" 517[(set_attr "length" "2,6")]) 518 519;; We don't really have extzv, but defining this using shifts helps 520;; to reduce register pressure later on. 521 522(define_expand "extzv" 523 [(set (match_dup 4) 524 (ashift:SI (match_operand:SI 1 "register_operand" "") 525 (match_operand:SI 2 "const_int_operand" ""))) 526 (set (match_operand:SI 0 "register_operand" "") 527 (lshiftrt:SI (match_dup 4) 528 (match_operand:SI 3 "const_int_operand" "")))] 529 "" 530 " 531{ 532 HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); 533 HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); 534 operands[3] = GEN_INT (rshift); 535 if (lshift == 0) 536 { 537 emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); 538 DONE; 539 } 540 operands[2] = GEN_INT (lshift); 541 operands[4] = gen_reg_rtx (SImode); 542} 543") 544 545;; Block-move insns 546 547(define_expand "movstrqi" 548 [(match_operand:BLK 0 "general_operand" "") 549 (match_operand:BLK 1 "general_operand" "") 550 (match_operand:SI 2 "" "") 551 (match_operand:SI 3 "const_int_operand" "")] 552 "" 553 " 554 if (INTVAL (operands[3]) != 4 555 || GET_CODE (operands[2]) != CONST_INT 556 || INTVAL (operands[2]) > 48) 557 FAIL; 558 559 thumb_expand_movstrqi (operands); 560 DONE; 561") 562 563(define_insn "movmem12b" 564 [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) 565 (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) 566 (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) 567 (mem:SI (plus:SI (match_dup 1) (const_int 4)))) 568 (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) 569 (mem:SI (plus:SI (match_dup 1) (const_int 8)))) 570 (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) 571 (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) 572 (clobber (match_scratch:SI 2 "=&l")) 573 (clobber (match_scratch:SI 3 "=&l")) 574 (clobber (match_scratch:SI 4 "=&l"))] 575 "" 576 "* return output_move_mem_multiple (3, operands);" 577[(set_attr "length" "4")]) 578 579(define_insn "movmem8b" 580 [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) 581 (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) 582 (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) 583 (mem:SI (plus:SI (match_dup 1) (const_int 4)))) 584 (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) 585 (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) 586 (clobber (match_scratch:SI 2 "=&l")) 587 (clobber (match_scratch:SI 3 "=&l"))] 588 "" 589 "* return output_move_mem_multiple (2, operands);" 590[(set_attr "length" "4")]) 591 592;; Arithmetic insns 593 594(define_insn "adddi3" 595 [(set (match_operand:DI 0 "register_operand" "=l") 596 (plus:DI (match_operand:DI 1 "register_operand" "%0") 597 (match_operand:DI 2 "register_operand" "l")))] 598 "" 599 "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" 600[(set_attr "conds" "changed") 601 (set_attr "length" "8")]) 602 603;; register group 'k' is a single register group containing only the stack 604;; register. Trying to reload it will always fail catastrophically, 605;; so never allow those alternatives to match if reloading is needed. 606(define_insn "addsi3" 607 [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k") 608 (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k") 609 (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] 610 "" 611 "* 612 static char *asms[] = 613{ 614 \"add\\t%0, %0, %2\", 615 \"sub\\t%0, %0, #%n2\", 616 \"add\\t%0, %1, %2\", 617 \"add\\t%0, %0, %2\", 618 \"add\\t%0, %0, %2\", 619 \"add\\t%0, %1, %2\", 620 \"add\\t%0, %1, %2\" 621}; 622 if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT 623 && INTVAL (operands[2]) < 0) 624 return \"sub\\t%0, %1, #%n2\"; 625 return asms[which_alternative]; 626") 627 628; reloading and elimination of the frame pointer can sometimes cause this 629; optimization to be missed. 630(define_peephole 631 [(set (match_operand:SI 0 "register_operand" "=l") 632 (match_operand:SI 1 "const_int_operand" "M")) 633 (set (match_dup 0) 634 (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] 635 "REGNO (operands[2]) == STACK_POINTER_REGNUM 636 && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 637 && (INTVAL (operands[1]) & 3) == 0" 638 "add\\t%0, %2, %1") 639 640(define_insn "subdi3" 641 [(set (match_operand:DI 0 "register_operand" "=l") 642 (minus:DI (match_operand:DI 1 "register_operand" "0") 643 (match_operand:DI 2 "register_operand" "l")))] 644 "" 645 "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" 646[(set_attr "conds" "changed") 647 (set_attr "length" "8")]) 648 649(define_insn "subsi3" 650 [(set (match_operand:SI 0 "register_operand" "=l") 651 (minus:SI (match_operand:SI 1 "register_operand" "l") 652 (match_operand:SI 2 "register_operand" "l")))] 653 "" 654 "sub\\t%0, %1, %2") 655 656;; We must ensure that one input matches the output, and that the other input 657;; does not match the output. Using 0 satisfies the first, and using & 658;; satisfies the second. Unfortunately, this fails when operands 1 and 2 659;; are the same, because reload will make operand 0 match operand 1 without 660;; realizing that this conflicts with operand 2. We fix this by adding another 661;; alternative to match this case, and then `reload' it ourselves. This 662;; alternative must come first. 663(define_insn "mulsi3" 664 [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") 665 (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") 666 (match_operand:SI 2 "register_operand" "l,l,l")))] 667 "" 668 "* 669{ 670 if (which_alternative < 2) 671 return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; 672 else 673 return \"mul\\t%0, %0, %2\"; 674}" 675 [(set_attr "length" "4,4,2")]) 676 677(define_insn "negsi2" 678 [(set (match_operand:SI 0 "register_operand" "=l") 679 (neg:SI (match_operand:SI 1 "register_operand" "l")))] 680 "" 681 "neg\\t%0, %1") 682 683;; Logical insns 684 685(define_expand "andsi3" 686 [(set (match_operand:SI 0 "register_operand" "") 687 (and:SI (match_operand:SI 1 "register_operand" "") 688 (match_operand:SI 2 "nonmemory_operand" "")))] 689 "" 690 " 691 if (GET_CODE (operands[2]) != CONST_INT) 692 operands[2] = force_reg (SImode, operands[2]); 693 else 694 { 695 int i; 696 if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) 697 { 698 operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); 699 emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); 700 DONE; 701 } 702 703 for (i = 9; i <= 31; i++) 704 if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) 705 { 706 emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), 707 const0_rtx)); 708 DONE; 709 } 710 else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) 711 { 712 rtx shift = GEN_INT (i); 713 rtx reg = gen_reg_rtx (SImode); 714 emit_insn (gen_lshrsi3 (reg, operands[1], shift)); 715 emit_insn (gen_ashlsi3 (operands[0], reg, shift)); 716 DONE; 717 } 718 719 operands[2] = force_reg (SImode, operands[2]); 720 } 721") 722 723(define_insn "*andsi3_insn" 724 [(set (match_operand:SI 0 "register_operand" "=l") 725 (and:SI (match_operand:SI 1 "register_operand" "%0") 726 (match_operand:SI 2 "register_operand" "l")))] 727 "" 728 "and\\t%0, %0, %2") 729 730(define_insn "bicsi3" 731 [(set (match_operand:SI 0 "register_operand" "=l") 732 (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) 733 (match_operand:SI 2 "register_operand" "0")))] 734 "" 735 "bic\\t%0, %0, %1") 736 737(define_insn "iorsi3" 738 [(set (match_operand:SI 0 "register_operand" "=l") 739 (ior:SI (match_operand:SI 1 "register_operand" "%0") 740 (match_operand:SI 2 "register_operand" "l")))] 741 "" 742 "orr\\t%0, %0, %2") 743 744(define_insn "xorsi3" 745 [(set (match_operand:SI 0 "register_operand" "=l") 746 (xor:SI (match_operand:SI 1 "register_operand" "%0") 747 (match_operand:SI 2 "register_operand" "l")))] 748 "" 749 "eor\\t%0, %0, %2") 750 751(define_insn "one_cmplsi2" 752 [(set (match_operand:SI 0 "register_operand" "=l") 753 (not:SI (match_operand:SI 1 "register_operand" "l")))] 754 "" 755 "mvn\\t%0, %1") 756 757;; Shift and rotation insns 758 759(define_insn "ashlsi3" 760 [(set (match_operand:SI 0 "register_operand" "=l,l") 761 (ashift:SI (match_operand:SI 1 "register_operand" "l,0") 762 (match_operand:SI 2 "nonmemory_operand" "N,l")))] 763 "" 764 "@ 765 lsl\\t%0, %1, %2 766 lsl\\t%0, %0, %2") 767 768(define_insn "ashrsi3" 769 [(set (match_operand:SI 0 "register_operand" "=l,l") 770 (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") 771 (match_operand:SI 2 "nonmemory_operand" "N,l")))] 772 "" 773 "@ 774 asr\\t%0, %1, %2 775 asr\\t%0, %0, %2") 776 777(define_insn "lshrsi3" 778 [(set (match_operand:SI 0 "register_operand" "=l,l") 779 (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") 780 (match_operand:SI 2 "nonmemory_operand" "N,l")))] 781 "" 782 "@ 783 lsr\\t%0, %1, %2 784 lsr\\t%0, %0, %2") 785 786(define_insn "rotrsi3" 787 [(set (match_operand:SI 0 "register_operand" "=l") 788 (rotatert:SI (match_operand:SI 1 "register_operand" "0") 789 (match_operand:SI 2 "register_operand" "l")))] 790 "" 791 "ror\\t%0, %0, %2") 792 793;; Comparison insns 794 795(define_expand "cmpsi" 796 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") 797 (match_operand:SI 1 "nonmemory_operand" "")))] 798 "" 799 " 800 if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) 801 { 802 if (GET_CODE (operands[1]) != CONST_INT 803 || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) 804 { 805 if (GET_CODE (operands[1]) != CONST_INT 806 || INTVAL (operands[1]) < -255 807 || INTVAL (operands[1]) > 0) 808 operands[1] = force_reg (SImode, operands[1]); 809 else 810 { 811 operands[1] = force_reg (SImode, 812 GEN_INT (- INTVAL (operands[1]))); 813 emit_insn (gen_cmnsi (operands[0], operands[1])); 814 DONE; 815 } 816 } 817 } 818") 819 820(define_insn "*cmpsi_insn" 821 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l,*r,*h") 822 (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] 823 "" 824 "@ 825 cmp\\t%0, %1 826 cmp\\t%0, %1 827 cmp\\t%0, %1") 828 829(define_insn "tstsi" 830 [(set (cc0) (match_operand:SI 0 "register_operand" "l"))] 831 "" 832 "cmp\\t%0, #0") 833 834(define_insn "cmnsi" 835 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l") 836 (neg:SI (match_operand:SI 1 "register_operand" "l"))))] 837 "" 838 "cmn\\t%0, %1") 839 840;; Jump insns 841 842(define_insn "jump" 843 [(set (pc) (label_ref (match_operand 0 "" "")))] 844 "" 845 "* 846 if (get_attr_length (insn) == 2) 847 return \"b\\t%l0\"; 848 return \"bl\\t%l0\\t%@ far jump\"; 849"[(set (attr "far_jump") 850 (if_then_else (eq_attr "length" "4") 851 (const_string "yes") 852 (const_string "no"))) 853 (set (attr "length") 854 (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) 855 (le (minus (match_dup 0) (pc)) (const_int 2044))) 856 (const_int 2) 857 (const_int 4)))]) 858 859 860(define_expand "beq" 861 [(set (pc) (if_then_else (eq (cc0) (const_int 0)) 862 (label_ref (match_operand 0 "" "")) 863 (pc)))] 864 "" 865 "") 866 867(define_expand "bne" 868 [(set (pc) (if_then_else (ne (cc0) (const_int 0)) 869 (label_ref (match_operand 0 "" "")) 870 (pc)))] 871 "" 872 "") 873 874(define_expand "bge" 875 [(set (pc) (if_then_else (ge (cc0) (const_int 0)) 876 (label_ref (match_operand 0 "" "")) 877 (pc)))] 878 "" 879 "") 880 881(define_expand "ble" 882 [(set (pc) (if_then_else (le (cc0) (const_int 0)) 883 (label_ref (match_operand 0 "" "")) 884 (pc)))] 885 "" 886 "") 887 888(define_expand "bgt" 889 [(set (pc) (if_then_else (gt (cc0) (const_int 0)) 890 (label_ref (match_operand 0 "" "")) 891 (pc)))] 892 "" 893 "") 894 895(define_expand "blt" 896 [(set (pc) (if_then_else (lt (cc0) (const_int 0)) 897 (label_ref (match_operand 0 "" "")) 898 (pc)))] 899 "" 900 "") 901 902(define_expand "bgeu" 903 [(set (pc) (if_then_else (geu (cc0) (const_int 0)) 904 (label_ref (match_operand 0 "" "")) 905 (pc)))] 906 "" 907 "") 908 909(define_expand "bleu" 910 [(set (pc) (if_then_else (leu (cc0) (const_int 0)) 911 (label_ref (match_operand 0 "" "")) 912 (pc)))] 913 "" 914 "") 915 916(define_expand "bgtu" 917 [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) 918 (label_ref (match_operand 0 "" "")) 919 (pc)))] 920 "" 921 "") 922 923(define_expand "bltu" 924 [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) 925 (label_ref (match_operand 0 "" "")) 926 (pc)))] 927 "" 928 "") 929 930(define_insn "*cond_branch" 931 [(set (pc) (if_then_else (match_operator 1 "comparison_operator" 932 [(cc0) (const_int 0)]) 933 (label_ref (match_operand 0 "" "")) 934 (pc)))] 935 "" 936 "* 937 switch (get_attr_length (insn)) 938 { 939 case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; 940 case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; 941 default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; 942 } 943"[(set (attr "far_jump") 944 (if_then_else (eq_attr "length" "6") 945 (const_string "yes") 946 (const_string "no"))) 947 (set (attr "length") 948 (if_then_else 949 (and (ge (minus (match_dup 0) (pc)) (const_int -252)) 950 (le (minus (match_dup 0) (pc)) (const_int 254))) 951 (const_int 2) 952 (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) 953 (le (minus (match_dup 0) (pc)) (const_int 2044))) 954 (const_int 4) 955 (const_int 6))))]) 956 957(define_insn "*cond_branch_reversed" 958 [(set (pc) (if_then_else (match_operator 1 "comparison_operator" 959 [(cc0) (const_int 0)]) 960 (pc) 961 (label_ref (match_operand 0 "" ""))))] 962 "" 963 "* 964 switch (get_attr_length (insn)) 965 { 966 case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; 967 case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; 968 default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; 969 } 970 return \"\"; 971"[(set (attr "far_jump") 972 (if_then_else (eq_attr "length" "6") 973 (const_string "yes") 974 (const_string "no"))) 975 (set (attr "length") 976 (if_then_else 977 (and (ge (minus (match_dup 0) (pc)) (const_int -252)) 978 (le (minus (match_dup 0) (pc)) (const_int 254))) 979 (const_int 2) 980 (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) 981 (le (minus (match_dup 0) (pc)) (const_int 2044))) 982 (const_int 4) 983 (const_int 6))))]) 984 985(define_insn "indirect_jump" 986 [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] 987 "" 988 "mov\\tpc, %0") 989 990(define_insn "tablejump" 991 [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) 992 (use (label_ref (match_operand 1 "" "")))] 993 "" 994 "mov\\tpc, %0") 995 996(define_insn "return" 997 [(return)] 998 "USE_RETURN" 999 "* return output_return ();" 1000[(set_attr "length" "18")]) 1001 1002;; Call insns 1003 1004(define_expand "call" 1005 [(call (match_operand:SI 0 "memory_operand" "") 1006 (match_operand 1 "" ""))] 1007 "" 1008 "") 1009 1010(define_insn "*call_indirect" 1011 [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) 1012 (match_operand 1 "" ""))] 1013 "! TARGET_CALLER_INTERWORKING" 1014 "bl\\t%__call_via_%0" 1015[(set_attr "length" "4")]) 1016;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version 1017;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set 1018;; the bottom bit of lr so that a function return (using bx) 1019;; would switch back into ARM mode... 1020 1021(define_insn "*call_indirect_interwork" 1022 [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) 1023 (match_operand 1 "" ""))] 1024 "TARGET_CALLER_INTERWORKING" 1025 "bl\\t%__interwork_call_via_%0" 1026[(set_attr "length" "4")]) 1027 1028(define_expand "call_value" 1029 [(set (match_operand 0 "" "") 1030 (call (match_operand 1 "memory_operand" "") 1031 (match_operand 2 "" "")))] 1032 "" 1033 "") 1034 1035(define_insn "*call_value_indirect" 1036 [(set (match_operand 0 "" "=l") 1037 (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) 1038 (match_operand 2 "" "")))] 1039 "! TARGET_CALLER_INTERWORKING" 1040 "bl\\t%__call_via_%1" 1041[(set_attr "length" "4")]) 1042;; See comment for call_indirect pattern 1043 1044(define_insn "*call_value_indirect_interwork" 1045 [(set (match_operand 0 "" "=l") 1046 (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) 1047 (match_operand 2 "" "")))] 1048 "TARGET_CALLER_INTERWORKING" 1049 "bl\\t%__interwork_call_via_%1" 1050[(set_attr "length" "4")]) 1051 1052 1053(define_insn "*call_insn" 1054 [(call (mem:SI (match_operand:SI 0 "" "i")) 1055 (match_operand:SI 1 "" ""))] 1056 "GET_CODE (operands[0]) == SYMBOL_REF" 1057 "bl\\t%a0" 1058[(set_attr "length" "4")]) 1059 1060(define_insn "*call_value_insn" 1061 [(set (match_operand 0 "register_operand" "=l") 1062 (call (mem:SI (match_operand 1 "" "i")) 1063 (match_operand 2 "" "")))] 1064 "GET_CODE (operands[1]) == SYMBOL_REF" 1065 "bl\\t%a1" 1066[(set_attr "length" "4")]) 1067 1068;; Untyped call not required, since all funcs return in r0 1069 1070;; Miscellaneous patterns 1071 1072(define_insn "nop" 1073 [(clobber (const_int 0))] 1074 "" 1075 "mov\\tr8, r8") 1076 1077(define_insn "blockage" 1078 [(unspec_volatile [(const_int 0)] 0)] 1079 "" 1080 "" 1081 [(set_attr "length" "0")]) 1082 1083(define_expand "prologue" 1084 [(const_int 0)] 1085 "" 1086 " 1087 thumb_expand_prologue (); 1088 DONE; 1089") 1090 1091(define_expand "epilogue" 1092 [(unspec_volatile [(const_int 0)] 1)] 1093 "! thumb_trivial_epilogue ()" 1094 " 1095 thumb_expand_epilogue (); 1096") 1097 1098(define_insn "*epilogue_insns" 1099 [(unspec_volatile [(const_int 0)] 1)] 1100 "" 1101 "* 1102 return thumb_unexpanded_epilogue (); 1103" 1104[(set_attr "length" "42")]) 1105 1106;; Special patterns for dealing with the constant pool 1107 1108(define_insn "consttable_4" 1109 [(unspec_volatile [(match_operand 0 "" "")] 2)] 1110 "" 1111 "* 1112{ 1113 switch (GET_MODE_CLASS (GET_MODE (operands[0]))) 1114 { 1115 case MODE_FLOAT: 1116 { 1117 union real_extract u; 1118 bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); 1119 assemble_real (u.d, GET_MODE (operands[0])); 1120 break; 1121 } 1122 default: 1123 assemble_integer (operands[0], 4, 1); 1124 break; 1125 } 1126 return \"\"; 1127}" 1128[(set_attr "length" "4")]) 1129 1130(define_insn "consttable_8" 1131 [(unspec_volatile [(match_operand 0 "" "")] 3)] 1132 "" 1133 "* 1134{ 1135 switch (GET_MODE_CLASS (GET_MODE (operands[0]))) 1136 { 1137 case MODE_FLOAT: 1138 { 1139 union real_extract u; 1140 bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); 1141 assemble_real (u.d, GET_MODE (operands[0])); 1142 break; 1143 } 1144 default: 1145 assemble_integer (operands[0], 8, 1); 1146 break; 1147 } 1148 return \"\"; 1149}" 1150[(set_attr "length" "8")]) 1151 1152(define_insn "consttable_end" 1153 [(unspec_volatile [(const_int 0)] 4)] 1154 "" 1155 "* 1156 /* Nothing to do (currently). */ 1157 return \"\"; 1158") 1159 1160(define_insn "align_4" 1161 [(unspec_volatile [(const_int 0)] 5)] 1162 "" 1163 "* 1164 assemble_align (32); 1165 return \"\"; 1166") 1167