|
|
1.1 root 1: /* Subroutines for insn-output.c for Sun SPARC. 1.1.1.9 root 2: Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. 1.1 root 3: Contributed by Michael Tiemann ([email protected]) 4: 5: This file is part of GNU CC. 6: 1.1.1.10! root 7: GNU CC 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 1, or (at your option) ! 10: any later version. ! 11: 1.1 root 12: GNU CC is distributed in the hope that it will be useful, 1.1.1.10! root 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 GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 1.1 root 20: 21: /* Global variables for machine-dependend things. */ 22: 23: /* This should go away if we pass floats to regs via 1.1.1.4 root 24: the stack instead of the frame, and if we learn how 25: to renumber all the registers when we don't do a save (hard!). */ 1.1 root 26: extern int frame_pointer_needed; 27: 28: static rtx find_addr_reg (); 29: 1.1.1.9 root 30: rtx next_real_insn_no_labels (); 31: 1.1.1.8 root 32: /* Return non-zero only if OP is a register of mode MODE, 33: or const0_rtx. */ 34: int 35: reg_or_0_operand (op, mode) 1.1.1.7 root 36: rtx op; 37: enum machine_mode mode; 38: { 1.1.1.8 root 39: return (op == const0_rtx || register_operand (op, mode)); 1.1.1.7 root 40: } 41: 1.1.1.9 root 42: /* Return non-zero if this pattern, can be evaluated safely, even if it 43: was not asked for. */ 44: int 45: safe_insn_src_p (op, mode) 46: rtx op; 47: enum machine_mode mode; 48: { 49: /* Just experimenting. */ 50: 51: /* No floating point src is safe if it contains an arithmetic 52: operation, since that operation may trap. */ 53: switch (GET_CODE (op)) 54: { 55: case CONST_INT: 56: case LABEL_REF: 57: case SYMBOL_REF: 58: case CONST: 59: return 1; 60: 61: case REG: 62: return 1; 63: 64: case MEM: 65: return CONSTANT_ADDRESS_P (XEXP (op, 0)); 66: 67: /* We never need to negate or complement constants. */ 68: case NEG: 69: return (mode != SFmode && mode != DFmode); 70: case NOT: 71: return 1; 72: 1.1.1.10! root 73: case COMPARE: 1.1.1.9 root 74: case MINUS: 75: case PLUS: 76: return (mode != SFmode && mode != DFmode); 77: case AND: 78: case IOR: 79: case XOR: 80: case LSHIFT: 81: case ASHIFT: 82: case ASHIFTRT: 83: case LSHIFTRT: 84: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) 85: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) 86: return 0; 87: return 1; 88: 89: default: 90: return 0; 91: } 92: } 93: 94: /* Return 1 if REG is clobbered in IN. 95: Return 0 if REG is used in IN (other than being clobbered). 96: Return 2 if REG does not appear in IN. */ 97: 98: static int 99: reg_clobbered_p (reg, in) 100: rtx reg; 101: rtx in; 102: { 103: register char *fmt; 104: register int i, result = 0; 105: 106: register enum rtx_code code; 107: 108: if (in == 0) 109: return 2; 110: 111: code = GET_CODE (in); 112: 113: switch (code) 114: { 115: /* Let these fail out quickly. */ 116: case CONST_INT: 117: case SYMBOL_REF: 118: case CONST: 119: return 2; 120: 121: case SUBREG: 122: if (SUBREG_WORD (in) != 0) 123: in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); 124: else 125: in = SUBREG_REG (in); 126: 127: case REG: 128: if (in == reg 129: || refers_to_regno_p (REGNO (reg), 130: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), 131: in, 0)) 132: return 0; 133: return 2; 134: 135: case SET: 136: if (SET_SRC (in) == reg 137: || refers_to_regno_p (REGNO (reg), 138: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), 139: SET_SRC (in), 0)) 140: return 0; 141: 142: if (SET_DEST (in) == reg) 143: return 1; 144: 145: if (refers_to_regno_p (REGNO (reg), 146: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), 147: SET_DEST (in), 0)) 148: if (GET_CODE (SET_DEST (in)) == REG 149: || GET_CODE (SET_DEST (in)) == SUBREG) 150: return 1; 151: else 152: return 0; 153: return 2; 154: 155: case USE: 156: if (XEXP (in, 0) == reg 157: || refers_to_regno_p (REGNO (reg), 158: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), 159: XEXP (in, 0), 0)) 160: return 0; 161: return 2; 162: 163: case CLOBBER: 164: if (XEXP (in, 0) == reg) 165: return 1; 166: /* If the CLOBBER expression is a SUBREG, accept that as a 167: clobber. But if it is some expression based on this register, 168: that is like a USE as far as this register is concerned, 169: so we won't take it. */ 170: if (refers_to_regno_p (REGNO (reg), 171: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), 172: XEXP (in, 0), 0)) 173: if (GET_CODE (XEXP (in, 0)) == REG 174: || GET_CODE (XEXP (in, 0)) == SUBREG) 175: return 1; 176: else 177: return 0; 178: return 2; 179: } 180: 181: fmt = GET_RTX_FORMAT (code); 182: 183: result = 2; 184: 185: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 186: { 187: if (fmt[i] == 'E') 188: { 189: register int j; 190: for (j = XVECLEN (in, i) - 1; j >= 0; j--) 191: switch (reg_clobbered_p (reg, XVECEXP (in, i, j))) 192: { 193: case 0: 194: return 0; 195: case 2: 196: continue; 197: case 1: 198: result = 1; 199: break; 200: } 201: } 202: else if (fmt[i] == 'e') 203: switch (reg_clobbered_p (reg, XEXP (in, i))) 204: { 205: case 0: 206: return 0; 207: case 2: 208: continue; 209: case 1: 210: result = 1; 211: break; 212: } 213: } 214: return result; 215: } 216: 217: /* Return non-zero if OP can be written to without screwing up 218: GCC's model of what's going on. It is assumed that this operand 219: appears in the dest position of a SET insn in a conditional 220: branch's delay slot. AFTER is the label to start looking from. */ 221: int 222: operand_clobbered_before_used_after (op, after) 223: rtx op; 224: rtx after; 225: { 226: extern char call_used_regs[]; 227: 228: /* Just experimenting. */ 229: if (GET_CODE (op) == CC0) 230: return 1; 231: if (GET_CODE (op) == REG) 232: { 233: rtx insn; 234: 235: if (op == stack_pointer_rtx) 236: return 0; 237: 238: for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) 239: { 240: if (GET_CODE (insn) == NOTE) 241: continue; 242: if (GET_CODE (insn) == INSN 243: || GET_CODE (insn) == JUMP_INSN 244: || GET_CODE (insn) == CALL_INSN) 245: { 246: switch (reg_clobbered_p (op, PATTERN (insn))) 247: { 248: case 0: 249: return 0; 250: case 2: 251: break; 252: case 1: 253: return 1; 254: } 255: if (dead_or_set_p (insn, op)) 256: return 1; 257: } 258: else if (GET_CODE (insn) == CODE_LABEL) 259: return 0; 260: if (GET_CODE (insn) == JUMP_INSN) 261: { 262: if (condjump_p (insn)) 263: return 0; 264: /* This is a jump insn which has already 265: been mangled. We can't tell what it does. */ 266: if (GET_CODE (PATTERN (insn)) == PARALLEL) 267: return 0; 268: if (! JUMP_LABEL (insn)) 269: return 0; 270: /* Keep following jumps. */ 271: insn = JUMP_LABEL (insn); 272: } 273: } 274: return 1; 275: } 276: 277: /* In both of these cases, the first insn executed 278: for this op will be a sethi %hi(whatever),%g1, 279: which is tolerable. */ 280: if (GET_CODE (op) == MEM) 281: return (CONSTANT_ADDRESS_P (XEXP (op, 0))); 282: 283: return 0; 284: } 285: 1.1.1.4 root 286: /* Return non-zero if this pattern, as a source to a "SET", 287: is known to yield an instruction of unit size. */ 288: int 289: single_insn_src_p (op, mode) 290: rtx op; 291: enum machine_mode mode; 1.1 root 292: { 1.1.1.4 root 293: switch (GET_CODE (op)) 294: { 295: case CONST_INT: 1.1.1.9 root 296: #if 1 297: /* This is not always a single insn src, technically, 298: but output_delayed_branch knows how to deal with it. */ 299: return 1; 300: #else 1.1.1.4 root 301: if (SMALL_INT (op)) 302: return 1; 1.1.1.9 root 303: /* We can put this set insn into delay slot, because this is one 304: insn; 'sethi'. */ 305: if ((INTVAL (op) & 0x3ff) == 0) 306: return 1; 307: 308: /* This is not a single insn src, technically, 309: but output_delayed_branch knows how to deal with it. */ 310: return 1; 311: #endif 312: 313: #if 1 314: case SYMBOL_REF: 315: /* This is not a single insn src, technically, 316: but output_delayed_branch knows how to deal with it. */ 317: return 1; 318: #else 1.1.1.4 root 319: return 0; 1.1.1.9 root 320: #endif 1.1.1.4 root 321: 322: case REG: 1.1.1.7 root 323: return 1; 324: 1.1.1.4 root 325: case MEM: 1.1.1.8 root 326: #if 0 327: /* This is not a single insn src, technically, 1.1.1.9 root 328: but output_delayed_branch knows how to deal with it. */ 1.1.1.7 root 329: if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) 330: return 0; 1.1.1.8 root 331: #endif 1.1.1.4 root 332: return 1; 333: 334: /* We never need to negate or complement constants. */ 335: case NEG: 1.1.1.9 root 336: return (mode != DFmode); 337: case NOT: 1.1.1.4 root 338: return 1; 339: 1.1.1.10! root 340: case COMPARE: 1.1.1.4 root 341: case MINUS: 1.1.1.9 root 342: /* If the target is cc0, then these insns will take 343: two insns (one being a nop). */ 344: return (mode != SFmode && mode != DFmode); 345: case PLUS: 1.1.1.4 root 346: case AND: 347: case IOR: 348: case XOR: 349: case LSHIFT: 350: case ASHIFT: 351: case ASHIFTRT: 352: case LSHIFTRT: 353: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) 354: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) 355: return 0; 356: return 1; 357: 358: case SUBREG: 359: if (SUBREG_WORD (op) != 0) 360: return 0; 361: return single_insn_src_p (SUBREG_REG (op), mode); 362: 363: case SIGN_EXTEND: 364: case ZERO_EXTEND: 1.1.1.9 root 365: /* Lazy... could check for more cases. */ 366: if (GET_CODE (XEXP (op, 0)) == MEM 367: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) 368: return 1; 369: return 0; 370: 371: /* Not doing floating point, since they probably 372: take longer than the branch slot they might fill. */ 373: case FLOAT_EXTEND: 374: case FLOAT_TRUNCATE: 375: case FLOAT: 376: case FIX: 377: case UNSIGNED_FLOAT: 378: case UNSIGNED_FIX: 379: return 0; 380: 381: default: 382: return 0; 383: } 384: } 385: 386: /* Nonzero only if this *really* is a single insn operand. */ 387: int 388: strict_single_insn_op_p (op, mode) 389: rtx op; 390: enum machine_mode mode; 391: { 392: if (mode == VOIDmode) 393: mode = GET_MODE (op); 394: 395: switch (GET_CODE (op)) 396: { 397: case CC0: 398: return 1; 399: 400: case CONST_INT: 401: if (SMALL_INT (op)) 402: return 1; 403: /* We can put this set insn into delay slot, because this is one 404: insn; 'sethi'. */ 405: if ((INTVAL (op) & 0x3ff) == 0) 406: return 1; 407: return 0; 408: 409: case SYMBOL_REF: 410: return 0; 411: 412: case REG: 413: return (mode != DFmode && mode != DImode); 414: 415: case MEM: 416: if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) 417: return (mode != DFmode && mode != DImode); 418: return 0; 419: 420: /* We never need to negate or complement constants. */ 421: case NEG: 422: return (mode != DFmode); 423: case NOT: 424: return 1; 425: 1.1.1.10! root 426: case COMPARE: 1.1.1.9 root 427: case MINUS: 428: /* If the target is cc0, then these insns will take 429: two insns (one being a nop). */ 430: return (mode != SFmode && mode != DFmode); 431: case PLUS: 432: case AND: 433: case IOR: 434: case XOR: 435: case LSHIFT: 436: case ASHIFT: 437: case ASHIFTRT: 438: case LSHIFTRT: 439: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) 440: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) 441: return 0; 442: return 1; 443: 444: case SUBREG: 445: if (SUBREG_WORD (op) != 0) 446: return 0; 447: return strict_single_insn_op_p (SUBREG_REG (op), mode); 448: 449: case SIGN_EXTEND: 450: case ZERO_EXTEND: 451: if (GET_CODE (XEXP (op, 0)) == MEM 452: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) 453: return 1; 1.1.1.4 root 454: return 0; 455: 456: /* Not doing floating point, since they probably 457: take longer than the branch slot they might fill. */ 458: case FLOAT_EXTEND: 459: case FLOAT_TRUNCATE: 460: case FLOAT: 461: case FIX: 462: case UNSIGNED_FLOAT: 463: case UNSIGNED_FIX: 464: return 0; 465: 466: default: 467: return 0; 468: } 1.1 root 469: } 1.1.1.4 root 470: 1.1.1.9 root 471: /* Return truth value of whether OP is a relational operator. */ 472: int 473: relop (op, mode) 474: rtx op; 475: enum machine_mode mode; 476: { 477: switch (GET_CODE (op)) 478: { 479: case EQ: 480: case NE: 481: case GT: 482: case GE: 483: case LT: 484: case LE: 485: case GTU: 486: case GEU: 487: case LTU: 488: case LEU: 489: return 1; 490: } 491: return 0; 492: } 493: 494: /* Return truth value of wheterh OP is EQ or NE. */ 495: int 496: eq_or_neq (op, mode) 497: rtx op; 498: enum machine_mode mode; 499: { 500: return (GET_CODE (op) == EQ || GET_CODE (op) == NE); 501: } 502: 1.1.1.5 root 503: /* Return truth value of whether OP can be used as an operands in a three 504: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */ 1.1 root 505: 506: int 507: arith_operand (op, mode) 508: rtx op; 509: enum machine_mode mode; 510: { 511: return (register_operand (op, mode) 512: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); 513: } 514: 1.1.1.5 root 515: /* Return truth value of whether OP can be used as an operand in a two 516: address arithmetic insn (such as set 123456,%o4) of mode MODE. */ 1.1.1.4 root 517: 1.1 root 518: int 519: arith32_operand (op, mode) 520: rtx op; 521: enum machine_mode mode; 522: { 523: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 524: } 525: 1.1.1.5 root 526: /* Return truth value of whether OP is a integer which fits the 527: range constraining immediate operands in three-address insns. */ 528: 1.1.1.3 root 529: int 530: small_int (op, mode) 531: rtx op; 532: enum machine_mode mode; 533: { 534: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 535: } 536: 1.1 root 537: /* Return the best assembler insn template 538: for moving operands[1] into operands[0] as a fullword. */ 539: 540: static char * 541: singlemove_string (operands) 542: rtx *operands; 543: { 544: if (GET_CODE (operands[0]) == MEM) 1.1.1.8 root 545: { 546: if (GET_CODE (operands[1]) != MEM) 547: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) 548: { 549: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 550: && cc_prev_status.mdep == XEXP (operands[0], 0))) 551: output_asm_insn ("sethi %%hi(%m0),%%g1", operands); 552: cc_status.flags |= CC_KNOW_HI_G1; 553: cc_status.mdep = XEXP (operands[0], 0); 554: return "st %1,[%%lo(%m0)+%%g1]"; 555: } 556: else 557: return "st %r1,%0"; 558: else 559: { 560: rtx xoperands[2]; 561: 562: cc_status.flags &= ~CC_F0_IS_0; 563: xoperands[0] = gen_rtx (REG, SFmode, 32); 564: xoperands[1] = operands[1]; 565: output_asm_insn (singlemove_string (xoperands), xoperands); 566: xoperands[1] = xoperands[0]; 567: xoperands[0] = operands[0]; 568: output_asm_insn (singlemove_string (xoperands), xoperands); 569: return ""; 570: } 571: } 1.1 root 572: if (GET_CODE (operands[1]) == MEM) 1.1.1.8 root 573: { 574: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) 575: { 576: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 577: && cc_prev_status.mdep == XEXP (operands[1], 0))) 578: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); 579: cc_status.flags |= CC_KNOW_HI_G1; 580: cc_status.mdep = XEXP (operands[1], 0); 581: return "ld [%%lo(%m1)+%%g1],%0"; 582: } 583: return "ld %1,%0"; 584: } 1.1.1.3 root 585: return "mov %1,%0"; 1.1 root 586: } 587: 588: /* Output assembler code to perform a doubleword move insn 589: with operands OPERANDS. */ 590: 591: char * 592: output_move_double (operands) 593: rtx *operands; 594: { 595: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 596: rtx latehalf[2]; 597: rtx addreg0 = 0, addreg1 = 0; 598: 599: /* First classify both operands. */ 600: 601: if (REG_P (operands[0])) 602: optype0 = REGOP; 603: else if (offsetable_memref_p (operands[0])) 604: optype0 = OFFSOP; 605: else if (GET_CODE (operands[0]) == MEM) 606: optype0 = MEMOP; 607: else 608: optype0 = RNDOP; 609: 610: if (REG_P (operands[1])) 611: optype1 = REGOP; 612: else if (CONSTANT_P (operands[1]) 613: || GET_CODE (operands[1]) == CONST_DOUBLE) 614: optype1 = CNSTOP; 615: else if (offsetable_memref_p (operands[1])) 616: optype1 = OFFSOP; 617: else if (GET_CODE (operands[1]) == MEM) 1.1.1.7 root 618: optype1 = MEMOP; 1.1 root 619: else 620: optype1 = RNDOP; 621: 622: /* Check for the cases that the operand constraints are not 623: supposed to allow to happen. Abort if we get one, 624: because generating code for these cases is painful. */ 625: 626: if (optype0 == RNDOP || optype1 == RNDOP) 627: abort (); 628: 629: /* If an operand is an unoffsettable memory ref, find a register 630: we can increment temporarily to make it refer to the second word. */ 631: 632: if (optype0 == MEMOP) 633: addreg0 = find_addr_reg (operands[0]); 634: 635: if (optype1 == MEMOP) 636: addreg1 = find_addr_reg (operands[1]); 637: 638: /* Ok, we can do one word at a time. 639: Normally we do the low-numbered word first, 640: but if either operand is autodecrementing then we 641: do the high-numbered word first. 642: 643: In either case, set up in LATEHALF the operands to use 644: for the high-numbered word and in some cases alter the 645: operands in OPERANDS to be suitable for the low-numbered word. */ 646: 647: if (optype0 == REGOP) 648: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 649: else if (optype0 == OFFSOP) 650: latehalf[0] = adj_offsetable_operand (operands[0], 4); 651: else 652: latehalf[0] = operands[0]; 653: 654: if (optype1 == REGOP) 655: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 656: else if (optype1 == OFFSOP) 657: latehalf[1] = adj_offsetable_operand (operands[1], 4); 658: else if (optype1 == CNSTOP) 659: { 660: if (CONSTANT_P (operands[1])) 661: latehalf[1] = const0_rtx; 662: else if (GET_CODE (operands[1]) == CONST_DOUBLE) 663: { 1.1.1.9 root 664: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 665: CONST_DOUBLE_HIGH (operands[1])); 666: operands[1] = gen_rtx (CONST_INT, VOIDmode, 667: CONST_DOUBLE_LOW (operands[1])); 1.1 root 668: } 669: } 670: else 671: latehalf[1] = operands[1]; 672: 673: /* If the first move would clobber the source of the second one, 1.1.1.3 root 674: do them in the other order. 675: 676: RMS says "This happens only for registers; 1.1 root 677: such overlap can't happen in memory unless the user explicitly 1.1.1.3 root 678: sets it up, and that is an undefined circumstance." 679: 680: but it happens on the sparc when loading parameter registers, 681: so I am going to define that circumstance, and make it work 682: as expected. */ 683: 684: /* Easy case: try moving both words at once. */ 1.1.1.8 root 685: /* First check for moving between an even/odd register pair 686: and a memory location. */ 687: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP 1.1.1.3 root 688: && (REGNO (operands[0]) & 1) == 0) 1.1.1.8 root 689: || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP 1.1.1.3 root 690: && (REGNO (operands[1]) & 1) == 0)) 691: { 692: rtx op1, op2; 693: rtx base = 0, offset = const0_rtx; 1.1 root 694: 1.1.1.8 root 695: /* OP1 gets the register pair, and OP2 gets the memory address. */ 1.1.1.3 root 696: if (optype0 == REGOP) 697: op1 = operands[0], op2 = XEXP (operands[1], 0); 698: else 699: op1 = operands[1], op2 = XEXP (operands[0], 0); 700: 1.1.1.8 root 701: /* Now see if we can trust the address to be 8-byte aligned. */ 1.1.1.4 root 702: /* Trust global variables. */ 1.1.1.8 root 703: if (CONSTANT_ADDRESS_P (op2)) 1.1.1.4 root 704: { 1.1.1.8 root 705: operands[0] = op1; 706: operands[1] = op2; 707: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 708: && cc_prev_status.mdep == op2)) 1.1.1.9 root 709: output_asm_insn ("sethi %%hi(%1),%%g1", operands); 1.1.1.8 root 710: cc_status.flags |= CC_KNOW_HI_G1; 711: cc_status.mdep = op2; 1.1.1.4 root 712: if (op1 == operands[0]) 1.1.1.9 root 713: return "ldd [%%lo(%1)+%%g1],%0"; 1.1.1.4 root 714: else 1.1.1.9 root 715: return "std [%%lo(%1)+%%g1],%0"; 1.1.1.4 root 716: } 1.1.1.3 root 717: 1.1.1.4 root 718: if (GET_CODE (op2) == PLUS) 719: { 720: if (GET_CODE (XEXP (op2, 0)) == REG) 721: base = XEXP (op2, 0), offset = XEXP (op2, 1); 722: else if (GET_CODE (XEXP (op2, 1)) == REG) 723: base = XEXP (op2, 1), offset = XEXP (op2, 0); 724: } 725: 726: /* Trust round enough offsets from the stack or frame pointer. */ 1.1.1.3 root 727: if (base 1.1.1.4 root 728: && (REGNO (base) == FRAME_POINTER_REGNUM 729: || REGNO (base) == STACK_POINTER_REGNUM)) 730: { 731: if (GET_CODE (offset) == CONST_INT 732: && (INTVAL (offset) & 0x7) == 0) 733: { 734: if (op1 == operands[0]) 735: return "ldd %1,%0"; 736: else 737: return "std %1,%0"; 738: } 739: } 740: else 741: { 1.1.1.8 root 742: /* We know structs not on the stack are properly aligned. 743: Since a double asks for 8-byte alignment, 744: we know it must have got that if it is in a struct. 745: But a DImode need not be 8-byte aligned, because it could be a 746: struct containing two ints or pointers. */ 747: if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode 748: && MEM_IN_STRUCT_P (operands[1])) 1.1.1.4 root 749: return "ldd %1,%0"; 1.1.1.8 root 750: else if (GET_CODE (operands[0]) == MEM 751: && GET_MODE (operands[0]) == DFmode 752: && MEM_IN_STRUCT_P (operands[0])) 1.1.1.4 root 753: return "std %1,%0"; 754: } 1.1.1.3 root 755: } 1.1.1.4 root 756: 1.1 root 757: if (optype0 == REGOP && optype1 == REGOP 758: && REGNO (operands[0]) == REGNO (latehalf[1])) 759: { 760: /* Make any unoffsetable addresses point at high-numbered word. */ 761: if (addreg0) 762: output_asm_insn ("add %0,0x4,%0", &addreg0); 763: if (addreg1) 764: output_asm_insn ("add %0,0x4,%0", &addreg1); 765: 766: /* Do that word. */ 767: output_asm_insn (singlemove_string (latehalf), latehalf); 768: 769: /* Undo the adds we just did. */ 770: if (addreg0) 771: output_asm_insn ("add %0,-0x4,%0", &addreg0); 772: if (addreg1) 773: output_asm_insn ("add %0,-0x4,%0", &addreg0); 774: 775: /* Do low-numbered word. */ 776: return singlemove_string (operands); 777: } 1.1.1.3 root 778: else if (optype0 == REGOP && optype1 != REGOP 1.1.1.8 root 779: && reg_overlap_mentioned_p (operands[0], operands[1])) 1.1.1.3 root 780: { 781: /* Do the late half first. */ 782: output_asm_insn (singlemove_string (latehalf), latehalf); 783: /* Then clobber. */ 784: return singlemove_string (operands); 785: } 1.1 root 786: 787: /* Normal case: do the two words, low-numbered first. */ 788: 789: output_asm_insn (singlemove_string (operands), operands); 790: 791: /* Make any unoffsetable addresses point at high-numbered word. */ 792: if (addreg0) 793: output_asm_insn ("add %0,0x4,%0", &addreg0); 794: if (addreg1) 795: output_asm_insn ("add %0,0x4,%0", &addreg1); 796: 797: /* Do that word. */ 798: output_asm_insn (singlemove_string (latehalf), latehalf); 799: 800: /* Undo the adds we just did. */ 801: if (addreg0) 802: output_asm_insn ("add %0,-0x4,%0", &addreg0); 803: if (addreg1) 804: output_asm_insn ("add %0,-0x4,%0", &addreg1); 805: 806: return ""; 807: } 808: 809: static char * 810: output_fp_move_double (operands) 811: rtx *operands; 812: { 813: if (FP_REG_P (operands[0])) 814: { 815: if (FP_REG_P (operands[1])) 816: { 817: output_asm_insn ("fmovs %1,%0", operands); 818: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); 819: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); 820: return "fmovs %1,%0"; 821: } 822: if (GET_CODE (operands[1]) == REG) 823: { 1.1.1.3 root 824: if ((REGNO (operands[1]) & 1) == 0) 825: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 826: else 827: { 828: rtx xoperands[3]; 829: xoperands[0] = operands[0]; 830: xoperands[1] = operands[1]; 831: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 832: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); 833: return ""; 834: } 1.1 root 835: } 1.1.1.4 root 836: if (GET_CODE (XEXP (operands[1], 0)) == PLUS 837: && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx 838: || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) 839: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT 840: && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0) 841: { 842: rtx xoperands[2]; 843: output_asm_insn ("ld %1,%0", operands); 844: xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), 845: REGNO (operands[0]) + 1); 846: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), 847: plus_constant (XEXP (operands[1], 0), 4)); 848: output_asm_insn ("ld %1,%0", xoperands); 849: return ""; 850: } 1.1.1.8 root 851: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) 852: { 853: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 854: && cc_prev_status.mdep == XEXP (operands[1], 0))) 855: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); 856: cc_status.flags |= CC_KNOW_HI_G1; 857: cc_status.mdep = XEXP (operands[1], 0); 858: return "ldd [%%lo(%m1)+%%g1],%0"; 859: } 1.1 root 860: return "ldd %1,%0"; 861: } 862: else if (FP_REG_P (operands[1])) 863: { 864: if (GET_CODE (operands[0]) == REG) 865: { 1.1.1.3 root 866: if ((REGNO (operands[0]) & 1) == 0) 867: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 868: else 869: { 870: rtx xoperands[3]; 871: xoperands[2] = operands[1]; 872: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 873: xoperands[0] = operands[0]; 874: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); 875: return ""; 876: } 1.1 root 877: } 1.1.1.4 root 878: if (GET_CODE (XEXP (operands[0], 0)) == PLUS 879: && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx 880: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) 881: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT 882: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0) 883: { 884: rtx xoperands[2]; 1.1.1.8 root 885: output_asm_insn ("st %r1,%0", operands); 1.1.1.4 root 886: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), 887: REGNO (operands[1]) + 1); 888: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), 889: plus_constant (XEXP (operands[0], 0), 4)); 1.1.1.8 root 890: output_asm_insn ("st %r1,%0", xoperands); 1.1.1.4 root 891: return ""; 892: } 1.1.1.8 root 893: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) 894: { 895: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 896: && cc_prev_status.mdep == XEXP (operands[0], 0))) 897: output_asm_insn ("sethi %%hi(%m0),%%g1", operands); 898: cc_status.flags |= CC_KNOW_HI_G1; 899: cc_status.mdep = XEXP (operands[0], 0); 900: return "std %1,[%%lo(%m0)+%%g1]"; 901: } 1.1 root 902: return "std %1,%0"; 903: } 1.1.1.3 root 904: else abort (); 1.1 root 905: } 906: 907: /* Return a REG that occurs in ADDR with coefficient 1. 908: ADDR can be effectively incremented by incrementing REG. */ 909: 910: static rtx 911: find_addr_reg (addr) 912: rtx addr; 913: { 914: while (GET_CODE (addr) == PLUS) 915: { 916: if (GET_CODE (XEXP (addr, 0)) == REG) 917: addr = XEXP (addr, 0); 918: if (GET_CODE (XEXP (addr, 1)) == REG) 919: addr = XEXP (addr, 1); 920: if (CONSTANT_P (XEXP (addr, 0))) 921: addr = XEXP (addr, 1); 922: if (CONSTANT_P (XEXP (addr, 1))) 923: addr = XEXP (addr, 0); 924: } 925: if (GET_CODE (addr) == REG) 926: return addr; 927: return 0; 928: } 929: 1.1.1.8 root 930: void 931: output_sized_memop (opname, mode) 932: char *opname; 933: enum machine_mode mode; 934: { 935: extern struct _iobuf *asm_out_file; 936: 937: static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" }; 938: static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; 939: char *modename 940: = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1]; 941: 942: fprintf (asm_out_file, "\t%s%s", opname, modename); 943: } 1.1.1.9 root 944: 945: /* Output a store-in-memory whose operands are OPERANDS[0,1]. 946: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */ 947: 948: char * 949: output_store (operands) 950: rtx *operands; 951: { 952: enum machine_mode mode = GET_MODE (operands[0]); 953: rtx address = XEXP (operands[0], 0); 954: 955: cc_status.flags |= CC_KNOW_HI_G1; 956: cc_status.mdep = address; 957: 958: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 959: && address == cc_prev_status.mdep)) 960: { 961: output_asm_insn ("sethi %%hi(%m0),%%g1", operands); 962: cc_prev_status.mdep = address; 963: } 964: 965: /* Store zero in two parts when appropriate. */ 966: if (mode == DFmode && operands[1] == dconst0_rtx) 967: { 968: /* We can't cross a page boundary here because the 969: SYMBOL_REF must be double word aligned, and for this 970: to be the case, SYMBOL_REF+4 cannot cross. */ 971: output_sized_memop ("st", SImode); 972: output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands); 973: output_sized_memop ("st", SImode); 974: return "%r1,[%%g1+%%lo(%m0)+4]"; 975: } 976: 977: /* Code below isn't smart enough to move a doubleword in two parts, 978: so use output_move_double to do that in the cases that require it. */ 979: if ((mode == DImode || mode == DFmode) 980: && (GET_CODE (operands[1]) == REG 981: && (REGNO (operands[1]) & 1))) 982: return output_move_double (operands); 983: 984: output_sized_memop ("st", mode); 985: return "%r1,[%%g1+%%lo(%m0)]"; 986: } 987: 988: /* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1]. 989: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */ 990: 991: char * 992: output_load_fixed (operands) 993: rtx *operands; 994: { 995: enum machine_mode mode = GET_MODE (operands[0]); 996: rtx address = XEXP (operands[1], 0); 997: 998: /* We don't bother trying to see if we know %hi(address). 999: This is because we are doing a load, and if we know the 1000: %hi value, we probably also know that value in memory. */ 1001: cc_status.flags |= CC_KNOW_HI_G1; 1002: cc_status.mdep = address; 1003: 1004: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 1005: && address == cc_prev_status.mdep 1006: && cc_prev_status.mdep == cc_status.mdep)) 1007: { 1008: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); 1009: cc_prev_status.mdep = address; 1010: } 1011: 1012: /* Code below isn't smart enough to do a doubleword in two parts. 1013: So handle that case the slow way. */ 1014: if (mode == DImode 1015: && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */ 1016: && (REGNO (operands[0]) & 1)) 1017: return output_move_double (operands); 1018: 1019: output_sized_memop ("ld", mode); 1020: if (GET_CODE (operands[0]) == REG) 1021: return "[%%g1+%%lo(%m1)],%0"; 1022: abort (); 1023: } 1024: 1025: /* Output a floating-point load-from-memory whose operands are OPERANDS[0,1]. 1026: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. 1027: We also handle the case where OPERANDS[0] is a mem. */ 1028: 1029: char * 1030: output_load_floating (operands) 1031: rtx *operands; 1032: { 1033: enum machine_mode mode = GET_MODE (operands[0]); 1034: rtx address = XEXP (operands[1], 0); 1.1.1.8 root 1035: 1.1.1.9 root 1036: /* We don't bother trying to see if we know %hi(address). 1037: This is because we are doing a load, and if we know the 1038: %hi value, we probably also know that value in memory. */ 1039: cc_status.flags |= CC_KNOW_HI_G1; 1040: cc_status.mdep = address; 1041: 1042: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 1043: && address == cc_prev_status.mdep 1044: && cc_prev_status.mdep == cc_status.mdep)) 1045: { 1046: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); 1047: cc_prev_status.mdep = address; 1048: } 1049: 1050: if (mode == DFmode) 1051: { 1052: if (REG_P (operands[0])) 1053: { 1054: if (REGNO (operands[0]) & 1) 1055: return output_move_double (operands); 1056: else 1057: return "ldd [%%g1+%%lo(%m1)],%0"; 1058: } 1059: cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0); 1060: output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands); 1061: operands[1] = gen_rtx (REG, DFmode, 32); 1062: return output_fp_move_double (operands); 1063: } 1064: 1065: if (GET_CODE (operands[0]) == MEM) 1066: { 1067: cc_status.flags &= ~CC_F1_IS_0; 1068: output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands); 1069: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) 1070: { 1071: cc_status.mdep = XEXP (operands[0], 0); 1072: return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]"; 1073: } 1074: else 1075: return "st %%f1,%0"; 1076: } 1077: return "ld [%%g1+%%lo(%m1)],%0"; 1078: } 1079: 1.1 root 1080: /* Load the address specified by OPERANDS[3] into the register 1081: specified by OPERANDS[0]. 1082: 1083: OPERANDS[3] may be the result of a sum, hence it could either be: 1084: 1085: (1) CONST 1086: (2) REG 1087: (2) REG + CONST_INT 1088: (3) REG + REG + CONST_INT 1.1.1.8 root 1089: (4) REG + REG (special case of 3). 1.1 root 1090: 1.1.1.5 root 1091: Note that (3) is not a legitimate address. 1.1 root 1092: All cases are handled here. */ 1093: 1094: void 1095: output_load_address (operands) 1096: rtx *operands; 1097: { 1098: rtx base, offset; 1099: 1100: if (CONSTANT_P (operands[3])) 1101: { 1102: output_asm_insn ("set %3,%0", operands); 1103: return; 1104: } 1105: 1106: if (REG_P (operands[3])) 1107: { 1108: if (REGNO (operands[0]) != REGNO (operands[3])) 1109: output_asm_insn ("mov %3,%0", operands); 1110: return; 1111: } 1112: 1.1.1.8 root 1113: if (GET_CODE (operands[3]) != PLUS) 1114: abort (); 1115: 1.1 root 1116: base = XEXP (operands[3], 0); 1117: offset = XEXP (operands[3], 1); 1118: 1119: if (GET_CODE (base) == CONST_INT) 1120: { 1121: rtx tmp = base; 1122: base = offset; 1123: offset = tmp; 1124: } 1125: 1126: if (GET_CODE (offset) != CONST_INT) 1.1.1.8 root 1127: { 1128: /* Operand is (PLUS (REG) (REG)). */ 1129: base = operands[3]; 1130: offset = const0_rtx; 1131: } 1.1 root 1132: 1133: if (REG_P (base)) 1134: { 1135: operands[6] = base; 1136: operands[7] = offset; 1137: if (SMALL_INT (offset)) 1138: output_asm_insn ("add %6,%7,%0", operands); 1139: else 1140: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); 1141: } 1.1.1.8 root 1142: else if (GET_CODE (base) == PLUS) 1.1 root 1143: { 1144: operands[6] = XEXP (base, 0); 1145: operands[7] = XEXP (base, 1); 1146: operands[8] = offset; 1147: 1148: if (SMALL_INT (offset)) 1149: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); 1150: else 1151: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); 1152: } 1.1.1.8 root 1153: else 1154: abort (); 1.1 root 1155: } 1156: 1.1.1.5 root 1157: /* Output code to place a size count SIZE in register REG. 1158: If SIZE is round, then assume that we can use alignment 1159: based on that roundness, and return an integer saying 1160: what alignment (roundness, transfer size) we will be using. 1161: 1162: Because block moves are pipelined, we don't include the 1163: first element in the transfer of SIZE to REG. */ 1164: 1165: static int 1166: output_size_for_block_move (size, reg) 1167: rtx size, reg; 1168: { 1169: int align; 1170: rtx xoperands[2]; 1171: xoperands[0] = reg; 1172: 1173: /* First, figure out best alignment we may assume. */ 1174: if (REG_P (size)) 1175: { 1176: xoperands[1] = size; 1177: output_asm_insn ("sub %1,1,%0", xoperands); 1178: align = 1; 1179: } 1180: else 1181: { 1182: int i = INTVAL (size); 1183: 1184: if (i & 1) 1185: align = 1; 1186: else if (i & 3) 1187: align = 2; 1188: else 1189: align = 4; 1190: 1191: /* predecrement count. */ 1192: i -= align; 1193: if (i < 0) abort (); 1194: 1195: xoperands[1] = gen_rtx (CONST_INT, VOIDmode, i); 1196: 1197: output_asm_insn ("set %1,%0", xoperands); 1198: } 1199: return align; 1200: } 1201: 1202: /* Emit code to perform a block move. 1203: 1204: OPERANDS[0] is the destination. 1205: OPERANDS[1] is the source. 1206: OPERANDS[2] is the size. 1.1.1.8 root 1207: OPERANDS[3..5] are pseudos we can safely clobber as temps. */ 1.1.1.5 root 1208: 1.1 root 1209: char * 1210: output_block_move (operands) 1211: rtx *operands; 1212: { 1.1.1.5 root 1213: /* A vector for our computed operands. Note that load_output_address 1.1.1.8 root 1214: makes use of (and can clobber) up to the 8th element of this vector. */ 1.1.1.5 root 1215: rtx xoperands[10]; 1.1.1.8 root 1216: rtx zoperands[10]; 1.1 root 1217: static int movstrsi_label = 0; 1.1.1.5 root 1218: int align = -1; /* not yet known */ 1.1 root 1219: int i, j; 1220: 1.1.1.8 root 1221: xoperands[0] = operands[0]; 1222: xoperands[1] = operands[1]; 1223: xoperands[2] = operands[3]; 1.1.1.5 root 1224: 1.1 root 1225: /* Since we clobber untold things, nix the condition codes. */ 1226: CC_STATUS_INIT; 1227: 1.1.1.5 root 1228: /* Recognize special cases of block moves. These occur 1229: when GNU C++ is forced to treat something as BLKmode 1230: to keep it in memory, when its mode could be represented 1.1.1.8 root 1231: with something smaller. 1232: 1233: We cannot do this for global variables, since we don't know 1234: what pages they don't cross. Sigh. */ 1.1.1.5 root 1235: if (GET_CODE (operands[2]) == CONST_INT 1.1.1.8 root 1236: && INTVAL (operands[2]) <= 16 1237: && ! CONSTANT_ADDRESS_P (operands[0]) 1238: && ! CONSTANT_ADDRESS_P (operands[1])) 1.1.1.5 root 1239: { 1240: int size = INTVAL (operands[2]); 1241: 1.1.1.8 root 1242: cc_status.flags &= ~CC_KNOW_HI_G1; 1.1.1.5 root 1243: if (size & 1) 1244: { 1245: if (memory_address_p (QImode, plus_constant (xoperands[0], size)) 1246: && memory_address_p (QImode, plus_constant (xoperands[1], size))) 1247: { 1.1.1.8 root 1248: /* We will store different integers into this particular RTX. */ 1249: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); 1.1.1.5 root 1250: for (i = size-1; i >= 0; i--) 1251: { 1252: INTVAL (xoperands[2]) = i; 1253: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", 1254: xoperands); 1255: } 1256: return ""; 1257: } 1258: } 1259: else if (size & 2) 1260: { 1261: if (memory_address_p (HImode, plus_constant (xoperands[0], size)) 1262: && memory_address_p (HImode, plus_constant (xoperands[1], size))) 1263: { 1.1.1.8 root 1264: /* We will store different integers into this particular RTX. */ 1265: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); 1.1.1.5 root 1266: for (i = (size>>1)-1; i >= 0; i--) 1267: { 1268: INTVAL (xoperands[2]) = i<<1; 1269: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", 1270: xoperands); 1271: } 1272: return ""; 1273: } 1274: } 1275: else 1276: { 1277: if (memory_address_p (SImode, plus_constant (xoperands[0], size)) 1278: && memory_address_p (SImode, plus_constant (xoperands[1], size))) 1279: { 1.1.1.8 root 1280: /* We will store different integers into this particular RTX. */ 1281: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); 1.1.1.5 root 1282: for (i = (size>>2)-1; i >= 0; i--) 1283: { 1284: INTVAL (xoperands[2]) = i<<2; 1285: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", 1286: xoperands); 1287: } 1288: return ""; 1289: } 1290: } 1291: } 1292: 1.1.1.8 root 1293: /* This is the size of the transfer. 1294: Either use the register which already contains the size, 1295: or use a free register (used by no operands). 1296: Also emit code to decrement the size value by ALIGN. */ 1297: align = output_size_for_block_move (operands[2], operands[3]); 1.1.1.5 root 1298: 1.1.1.8 root 1299: zoperands[0] = operands[0]; 1300: zoperands[3] = plus_constant (operands[0], align); 1301: output_load_address (zoperands); 1.1 root 1302: 1303: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); 1304: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); 1305: 1.1.1.5 root 1306: if (align == 1) 1307: output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands); 1308: else if (align == 2) 1309: output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands); 1310: else 1311: output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands); 1.1 root 1312: return ""; 1313: } 1.1.1.5 root 1314: 1315: /* What the sparc lacks in hardware, make up for in software. 1316: Compute a fairly good sequence of shift and add insns 1317: to make a multiply happen. */ 1.1 root 1318: 1319: #define ABS(x) ((x) < 0 ? -(x) : x) 1320: 1321: char * 1322: output_mul_by_constant (insn, operands, unsignedp) 1323: rtx insn; 1324: rtx *operands; 1325: int unsignedp; 1326: { 1327: int c; /* Size of constant */ 1328: int shifts[BITS_PER_WORD]; /* Table of shifts */ 1.1.1.4 root 1329: unsigned int p, log; /* A power of two, and its log */ 1.1 root 1330: int d1, d2; /* Differences of c and p */ 1331: int first = 1; /* True if dst has unknown data in it */ 1332: int i; 1333: 1.1.1.10! root 1334: CC_STATUS_INIT; ! 1335: 1.1 root 1336: c = INTVAL (operands[2]); 1337: if (c == 0) 1338: { 1339: /* should not happen. */ 1340: abort (); 1341: if (GET_CODE (operands[0]) == MEM) 1342: return "st %%g0,%0"; 1343: return "mov %%g0,%0"; 1344: } 1345: 1346: output_asm_insn ("! start open coded multiply"); 1347: 1348: /* Clear out the table of shifts. */ 1349: for (i = 0; i < BITS_PER_WORD; ++i) 1350: shifts[i] = 0; 1351: 1352: while (c) 1353: { 1354: /* Find the power of two nearest ABS(c) */ 1355: p = 1, log = 0; 1356: do 1357: { 1358: d1 = ABS(c) - p; 1359: p *= 2; 1360: ++log; 1361: } 1362: while (p < ABS(c)); 1363: d2 = p - ABS(c); 1364: 1365: /* Make an appropriate entry in shifts for p. */ 1366: if (d2 < d1) 1367: { 1368: shifts[log] = c < 0 ? -1 : 1; 1369: c = c < 0 ? d2 : -d2; 1370: } 1371: else 1372: { 1373: shifts[log - 1] = c < 0 ? -1 : 1; 1374: c = c < 0 ? -d1 : d1; 1375: } 1376: } 1377: 1378: /* Take care of the first insn in sequence. 1379: We know we have at least one. */ 1380: 1381: /* A value of -1 in shifts says to subtract that power of two, and a value 1382: of 1 says to add that power of two. */ 1383: for (i = 0; ; i++) 1384: if (shifts[i]) 1385: { 1386: if (i) 1387: { 1388: operands[2] = gen_rtx (CONST_INT, VOIDmode, i); 1.1.1.5 root 1389: output_asm_insn ("sll %1,%2,%%g1", operands); 1.1 root 1390: } 1.1.1.5 root 1391: else output_asm_insn ("mov %1,%%g1", operands); 1.1 root 1392: 1393: log = i; 1394: if (shifts[i] < 0) 1.1.1.5 root 1395: output_asm_insn ("sub %%g0,%%g1,%0", operands); 1.1 root 1396: else 1.1.1.5 root 1397: output_asm_insn ("mov %%g1,%0", operands); 1.1 root 1398: break; 1399: } 1400: 1401: /* A value of -1 in shifts says to subtract that power of two, and a value 1402: of 1 says to add that power of two--continued. */ 1403: for (i += 1; i < BITS_PER_WORD; ++i) 1404: if (shifts[i]) 1405: { 1406: if (i - log > 0) 1407: { 1408: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); 1.1.1.5 root 1409: output_asm_insn ("sll %%g1,%2,%%g1", operands); 1.1 root 1410: } 1411: else 1412: { 1413: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); 1.1.1.5 root 1414: output_asm_insn ("sra %%g1,%2,%%g1", operands); 1.1 root 1415: } 1416: log = i; 1417: if (shifts[i] < 0) 1.1.1.5 root 1418: output_asm_insn ("sub %0,%%g1,%0", operands); 1.1 root 1419: else 1.1.1.5 root 1420: output_asm_insn ("add %0,%%g1,%0", operands); 1.1 root 1421: } 1422: 1423: output_asm_insn ("! end open coded multiply"); 1424: 1425: return ""; 1426: } 1427: 1428: char * 1429: output_mul_insn (operands, unsignedp) 1430: rtx *operands; 1431: int unsignedp; 1432: { 1433: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; 1434: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; 1435: 1.1.1.10! root 1436: CC_STATUS_INIT; ! 1437: 1.1 root 1438: if (lucky1) 1.1.1.10! root 1439: { ! 1440: if (lucky2) ! 1441: { ! 1442: if (REGNO (operands[1]) == REGNO (operands[2])) ! 1443: { ! 1444: if (REGNO (operands[1]) == 8) ! 1445: output_asm_insn ("mov %%o0,%%o1"); ! 1446: else ! 1447: output_asm_insn ("mov %%o1,%%o0"); ! 1448: } ! 1449: output_asm_insn ("call .mul,2\n\tnop", operands); ! 1450: } ! 1451: else ! 1452: { ! 1453: rtx xoperands[2]; ! 1454: xoperands[0] = gen_rtx (REG, SImode, ! 1455: 8 ^ (REGNO (operands[1]) == 8)); ! 1456: xoperands[1] = operands[2]; ! 1457: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); ! 1458: } ! 1459: } 1.1 root 1460: else if (lucky2) 1461: { 1462: rtx xoperands[2]; 1463: xoperands[0] = gen_rtx (REG, SImode, 1464: 8 ^ (REGNO (operands[2]) == 8)); 1465: xoperands[1] = operands[1]; 1466: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 1467: } 1468: else 1469: { 1470: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", 1471: operands); 1472: } 1473: 1474: if (REGNO (operands[0]) == 8) 1475: return ""; 1476: return "mov %%o0,%0"; 1477: } 1478: 1479: /* Make floating point register f0 contain 0. 1480: SIZE is the number of registers (including f0) 1481: which should contain 0. */ 1482: 1483: void 1484: make_f0_contain_0 (size) 1485: int size; 1486: { 1487: if (size == 1) 1.1.1.8 root 1488: { 1489: if ((cc_status.flags & (CC_F0_IS_0)) == 0) 1490: output_asm_insn ("ld [%%fp-16],%%f0", 0); 1491: cc_status.flags |= CC_F0_IS_0; 1492: } 1.1 root 1493: else if (size == 2) 1.1.1.8 root 1494: { 1495: if ((cc_status.flags & CC_F0_IS_0) == 0) 1496: output_asm_insn ("ld [%%fp-16],%%f0", 0); 1497: if ((cc_status.flags & (CC_F1_IS_0)) == 0) 1498: output_asm_insn ("ld [%%fp-12],%%f1", 0); 1499: cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0; 1500: } 1501: } 1502: 1503: /* Since condition codes don't have logical links, we need to keep 1504: their setting and use together for set-cc insns. */ 1505: void 1506: gen_scc_insn (code, mode, operands) 1507: enum rtx_code code; 1508: enum machine_mode mode; 1509: rtx *operands; 1510: { 1511: extern rtx sequence_stack; 1512: rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0); 1513: rtx last_pat = PATTERN (last_insn); 1514: if (GET_CODE (last_pat) != SET 1515: || GET_CODE (SET_DEST (last_pat)) != CC0) 1516: abort (); 1517: SET_DEST (last_pat) = operands[0]; 1518: SET_SRC (last_pat) = gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx); 1.1 root 1519: } 1.1.1.4 root 1520: 1521: /* Output reasonable peephole for set-on-condition-code insns. 1522: Note that these insns assume a particular way of defining 1523: labels. Therefore, *both* tm-sparc.h and this function must 1524: be changed if a new syntax is needed. */ 1525: 1526: char * 1.1.1.8 root 1527: output_scc_insn (code, operand) 1.1.1.4 root 1528: enum rtx_code code; 1.1.1.8 root 1529: rtx operand; 1.1.1.4 root 1530: { 1531: rtx xoperands[2]; 1532: rtx label = gen_label_rtx (); 1.1.1.8 root 1533: int cc_in_fccr = cc_status.flags & CC_IN_FCCR; 1.1.1.4 root 1534: 1.1.1.8 root 1535: xoperands[0] = operand; 1.1.1.4 root 1536: xoperands[1] = label; 1537: 1538: switch (code) 1539: { 1540: case NE: 1.1.1.8 root 1541: if (cc_in_fccr) 1.1.1.5 root 1542: output_asm_insn ("fbne,a %l0", &label); 1.1.1.4 root 1543: else 1.1.1.5 root 1544: output_asm_insn ("bne,a %l0", &label); 1.1.1.4 root 1545: break; 1546: case EQ: 1.1.1.8 root 1547: if (cc_in_fccr) 1.1.1.5 root 1548: output_asm_insn ("fbe,a %l0", &label); 1.1.1.4 root 1549: else 1.1.1.5 root 1550: output_asm_insn ("be,a %l0", &label); 1.1.1.4 root 1551: break; 1552: case GE: 1.1.1.8 root 1553: if (cc_in_fccr) 1.1.1.5 root 1554: output_asm_insn ("fbge,a %l0", &label); 1.1.1.4 root 1555: else 1.1.1.5 root 1556: output_asm_insn ("bge,a %l0", &label); 1.1.1.4 root 1557: break; 1558: case GT: 1.1.1.8 root 1559: if (cc_in_fccr) 1.1.1.5 root 1560: output_asm_insn ("fbg,a %l0", &label); 1.1.1.4 root 1561: else 1.1.1.5 root 1562: output_asm_insn ("bg,a %l0", &label); 1.1.1.4 root 1563: break; 1564: case LE: 1.1.1.8 root 1565: if (cc_in_fccr) 1.1.1.5 root 1566: output_asm_insn ("fble,a %l0", &label); 1.1.1.4 root 1567: else 1.1.1.5 root 1568: output_asm_insn ("ble,a %l0", &label); 1.1.1.4 root 1569: break; 1570: case LT: 1.1.1.8 root 1571: if (cc_in_fccr) 1.1.1.5 root 1572: output_asm_insn ("fbl,a %l0", &label); 1.1.1.4 root 1573: else 1.1.1.5 root 1574: output_asm_insn ("bl,a %l0", &label); 1.1.1.4 root 1575: break; 1576: case GEU: 1.1.1.8 root 1577: if (cc_in_fccr) 1.1.1.4 root 1578: abort (); 1579: else 1.1.1.5 root 1580: output_asm_insn ("bgeu,a %l0", &label); 1.1.1.4 root 1581: break; 1582: case GTU: 1.1.1.8 root 1583: if (cc_in_fccr) 1.1.1.4 root 1584: abort (); 1585: else 1.1.1.5 root 1586: output_asm_insn ("bgu,a %l0", &label); 1.1.1.4 root 1587: break; 1588: case LEU: 1.1.1.8 root 1589: if (cc_in_fccr) 1.1.1.4 root 1590: abort (); 1591: else 1.1.1.5 root 1592: output_asm_insn ("bleu,a %l0", &label); 1.1.1.4 root 1593: break; 1594: case LTU: 1.1.1.8 root 1595: if (cc_in_fccr) 1.1.1.4 root 1596: abort (); 1597: else 1.1.1.5 root 1598: output_asm_insn ("blu,a %l0", &label); 1.1.1.4 root 1599: break; 1600: default: 1601: abort (); 1602: } 1.1.1.8 root 1603: output_asm_insn ("mov 1,%0\n\tmov 0,%0\n%l1:", xoperands); 1.1.1.4 root 1604: return ""; 1605: } 1606: 1.1.1.5 root 1607: /* Output a delayed branch insn with the delay insn in its 1608: branch slot. The delayed branch insn template is in TEMPLATE, 1.1.1.8 root 1609: with operands OPERANDS. The insn in its delay slot is INSN. 1610: 1611: As a special case, since we know that all memory transfers are via 1612: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory 1613: reference around the branch as 1614: 1615: sethi %hi(x),%%g1 1616: b ... 1617: ld/st [%g1+%lo(x)],... 1618: 1.1.1.9 root 1619: As another special case, we handle loading (SYMBOL_REF ...) and 1620: other large constants around branches as well: 1621: 1622: sethi %hi(x),%0 1623: b ... 1624: or %0,%lo(x),%1 1625: 1.1.1.8 root 1626: */ 1.1.1.4 root 1627: 1628: char * 1.1.1.9 root 1629: output_delayed_branch (template, operands, insn) 1.1.1.4 root 1630: char *template; 1631: rtx *operands; 1632: rtx insn; 1633: { 1.1.1.9 root 1634: extern rtx recog_operand[]; 1.1.1.8 root 1635: rtx src = XVECEXP (PATTERN (insn), 0, 1); 1636: rtx dest = XVECEXP (PATTERN (insn), 0, 0); 1637: 1.1.1.9 root 1638: if (GET_CODE (src) == SYMBOL_REF 1639: || (GET_CODE (src) == CONST_INT 1640: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0))) 1641: { 1642: rtx xoperands[2]; 1643: xoperands[0] = dest; 1644: xoperands[1] = src; 1645: 1646: /* Output the `sethi' insn. */ 1647: output_asm_insn ("sethi %%hi(%1),%0", xoperands); 1648: 1649: /* Output the branch instruction next. */ 1650: output_asm_insn (template, operands); 1651: 1652: /* Now output the `or' insn. */ 1653: output_asm_insn ("or %0,%%lo(%1),%0", xoperands); 1654: } 1655: else if ((GET_CODE (src) == MEM 1656: && CONSTANT_ADDRESS_P (XEXP (src, 0))) 1657: || (GET_CODE (dest) == MEM 1658: && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) 1.1.1.8 root 1659: { 1660: rtx xoperands[2]; 1661: char *split_template; 1662: xoperands[0] = dest; 1663: xoperands[1] = src; 1664: 1665: /* Output the `sethi' insn. */ 1666: if (GET_CODE (src) == MEM) 1667: { 1.1.1.9 root 1668: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 1669: && cc_prev_status.mdep == XEXP (operands[1], 0))) 1670: output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands); 1.1.1.8 root 1671: split_template = "ld [%%g1+%%lo(%m1)],%0"; 1672: } 1673: else 1674: { 1.1.1.9 root 1675: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) 1676: && cc_prev_status.mdep == XEXP (operands[0], 0))) 1677: output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands); 1.1.1.8 root 1678: split_template = "st %r1,[%%g1+%%lo(%m0)]"; 1679: } 1.1.1.4 root 1680: 1.1.1.8 root 1681: /* Output the branch instruction next. */ 1682: output_asm_insn (template, operands); 1683: 1684: /* Now output the load or store. 1685: No need to do a CC_STATUS_INIT, because we are branching anyway. */ 1686: output_asm_insn (split_template, xoperands); 1687: } 1688: else 1689: { 1690: extern char *insn_template[]; 1691: extern char *(*insn_outfun[])(); 1692: int insn_code_number; 1693: rtx pat = gen_rtx (SET, VOIDmode, dest, src); 1694: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); 1695: 1696: /* Output the branch instruction first. */ 1697: output_asm_insn (template, operands); 1698: 1699: /* Now recognize the insn which we put in its delay slot. 1700: We must do this after outputing the branch insn, 1.1.1.9 root 1701: since operands may just be a pointer to `recog_operand'. */ 1.1.1.8 root 1702: insn_code_number = recog (pat, delay_insn); 1703: if (insn_code_number == -1) 1704: abort (); 1705: 1706: /* Now get the template for what this insn would 1707: have been, without the branch. Its operands are 1708: exactly the same as they would be, so we don't 1709: need to do an insn_extract. */ 1710: template = insn_template[insn_code_number]; 1711: if (template == 0) 1.1.1.9 root 1712: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); 1713: output_asm_insn (template, recog_operand); 1.1.1.8 root 1714: } 1.1.1.9 root 1715: CC_STATUS_INIT; 1.1.1.4 root 1716: return ""; 1717: } 1.1.1.9 root 1718: 1719: /* Output a newly constructed insn DELAY_INSN. */ 1720: char * 1721: output_delay_insn (delay_insn) 1722: rtx delay_insn; 1723: { 1724: char *template; 1725: extern rtx recog_operand[]; 1726: extern char call_used_regs[]; 1727: extern char *insn_template[]; 1728: extern int insn_n_operands[]; 1729: extern char *(*insn_outfun[])(); 1730: extern rtx alter_subreg(); 1731: int insn_code_number; 1732: extern int insn_n_operands[]; 1733: int i; 1734: 1735: /* Now recognize the insn which we put in its delay slot. 1736: We must do this after outputing the branch insn, 1737: since operands may just be a pointer to `recog_operand'. */ 1738: insn_code_number = recog_memoized (delay_insn); 1739: if (insn_code_number == -1) 1740: abort (); 1741: 1742: /* Extract the operands of this delay insn. */ 1743: INSN_CODE (delay_insn) = insn_code_number; 1744: insn_extract (delay_insn); 1745: 1746: /* It is possible that this insn has not been properly scaned by final 1747: yet. If this insn's operands don't appear in the peephole's 1748: actual operands, then they won't be fixed up by final, so we 1749: make sure they get fixed up here. -- This is a kludge. */ 1750: for (i = 0; i < insn_n_operands[insn_code_number]; i++) 1751: { 1752: if (GET_CODE (recog_operand[i]) == SUBREG) 1753: recog_operand[i] = alter_subreg (recog_operand[i]); 1754: } 1755: 1756: #ifdef REGISTER_CONSTRAINTS 1757: if (! constrain_operands (insn_code_number)) 1758: abort (); 1759: #endif 1760: 1761: cc_prev_status = cc_status; 1762: 1763: /* Update `cc_status' for this instruction. 1764: The instruction's output routine may change it further. 1765: If the output routine for a jump insn needs to depend 1766: on the cc status, it should look at cc_prev_status. */ 1767: 1768: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); 1769: 1770: /* Now get the template for what this insn would 1771: have been, without the branch. */ 1772: 1773: template = insn_template[insn_code_number]; 1774: if (template == 0) 1775: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); 1776: output_asm_insn (template, recog_operand); 1777: return ""; 1778: } 1779: 1780: /* Output the insn HEAD, keeping OPERANDS protected (wherever they are). 1781: HEAD comes from the target of some branch, so before we output it, 1782: we delete it from the target, lest we execute it twice. The caller 1783: of this function promises that such code motion is permissable. */ 1784: char * 1785: output_eager_then_insn (head, operands) 1786: rtx head; 1787: rtx *operands; 1788: { 1789: extern rtx alter_subreg (); 1790: extern int insn_n_operands[]; 1791: extern rtx recog_operand[]; 1792: rtx xoperands[MAX_RECOG_OPERANDS]; 1793: int insn_code_number, i, nbytes; 1794: rtx nhead; 1795: 1796: /* Micro-hack: run peephole on head if it looks like a good idea. 1797: Right now there's only one such case worth doing... 1798: 1799: This could be made smarter if the peephole for ``2-insn combine'' 1800: were also made smarter. */ 1801: if (GET_CODE (PATTERN (head)) == SET 1802: && REG_P (SET_SRC (PATTERN (head))) 1803: && REG_P (SET_DEST (PATTERN (head))) 1804: && (nhead = next_real_insn_no_labels (head)) 1805: && GET_CODE (nhead) == INSN 1806: && GET_CODE (PATTERN (nhead)) == SET 1807: && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0 1808: && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head)) 1809: || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head)))) 1810: /* Something's wrong if this does not fly. */ 1811: if (! peephole (head)) 1812: abort (); 1813: 1814: /* Save our contents of `operands', since output_delay_insn sets them. */ 1815: insn_code_number = recog_memoized (head); 1816: nbytes = insn_n_operands[insn_code_number] * sizeof (rtx); 1817: bcopy (operands, xoperands, nbytes); 1818: 1819: /* Output the delay insn, and prevent duplication later. */ 1820: delete_insn (head); 1821: output_delay_insn (head); 1822: 1823: /* Restore this insn's operands. */ 1824: bcopy (xoperands, operands, nbytes); 1825: } 1826: 1827: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL; 1828: or 0, if there is none. Also return 0 if we cross a label. */ 1829: 1830: rtx 1831: next_real_insn_no_labels (label) 1832: rtx label; 1833: { 1834: register rtx insn = NEXT_INSN (label); 1835: register RTX_CODE code; 1836: 1837: while (insn) 1838: { 1839: code = GET_CODE (insn); 1840: if (code == INSN) 1841: { 1842: if (GET_CODE (PATTERN (insn)) != CLOBBER 1843: && GET_CODE (PATTERN (insn)) != USE) 1844: return insn; 1845: } 1846: if (code == CALL_INSN || code == JUMP_INSN) 1847: return insn; 1848: if (code == CODE_LABEL) 1849: return 0; 1850: insn = NEXT_INSN (insn); 1851: } 1852: 1853: return 0; 1854: } 1855: 1856: int 1857: operands_satisfy_eager_branch_peephole (operands, conditional) 1858: rtx *operands; 1859: int conditional; 1860: { 1861: rtx label; 1862: 1863: if (conditional) 1864: { 1865: if (GET_CODE (operands[0]) != IF_THEN_ELSE) 1866: return 0; 1867: 1868: if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF) 1869: label = XEXP (XEXP (operands[0], 1), 0); 1870: else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF) 1871: label = XEXP (XEXP (operands[0], 2), 0); 1872: else return 0; 1873: } 1874: else 1875: { 1876: label = operands[0]; 1877: } 1878: 1879: if (LABEL_NUSES (label) == 1) 1880: { 1881: rtx prev = PREV_INSN (label); 1882: while (prev && GET_CODE (prev) == NOTE) 1883: prev = PREV_INSN (prev); 1884: if (prev == 0 1885: || GET_CODE (prev) == BARRIER) 1886: { 1887: rtx head = next_real_insn_no_labels (label); 1888: 1889: if (head 1890: && ! INSN_DELETED_P (head) 1891: && GET_CODE (head) == INSN 1892: && GET_CODE (PATTERN (head)) == SET 1893: && strict_single_insn_op_p (SET_SRC (PATTERN (head)), 1894: GET_MODE (SET_DEST (PATTERN (head)))) 1895: && strict_single_insn_op_p (SET_DEST (PATTERN (head)), 1896: GET_MODE (SET_DEST (PATTERN (head))))) 1897: { 1898: if (conditional == 2) 1899: return (GET_CODE (operands[1]) != PC 1900: && safe_insn_src_p (operands[2], VOIDmode) 1901: && strict_single_insn_op_p (operands[2], VOIDmode) 1902: && operand_clobbered_before_used_after (operands[1], label)); 1903: return 1; 1904: } 1905: } 1906: } 1907: 1908: if (conditional == 1 1909: && GET_CODE (operands[1]) != PC 1910: && safe_insn_src_p (operands[2], VOIDmode) 1911: && strict_single_insn_op_p (operands[2], VOIDmode) 1912: && operand_clobbered_before_used_after (operands[1], label)) 1913: return 1; 1914: 1915: return 0; 1916: } 1917:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.