|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Sun SPARC. ! 2: Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. ! 3: Contributed by Michael Tiemann ([email protected]) ! 4: ! 5: This file is part of GNU CC. ! 6: ! 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: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: /* Global variables for machine-dependend things. */ ! 22: ! 23: /* This should go away if we pass floats to regs via ! 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!). */ ! 26: extern int frame_pointer_needed; ! 27: ! 28: static rtx find_addr_reg (); ! 29: ! 30: rtx next_real_insn_no_labels (); ! 31: ! 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) ! 36: rtx op; ! 37: enum machine_mode mode; ! 38: { ! 39: return (op == const0_rtx || register_operand (op, mode)); ! 40: } ! 41: ! 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: ! 73: case COMPARE: ! 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: ! 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; ! 292: { ! 293: switch (GET_CODE (op)) ! 294: { ! 295: case CONST_INT: ! 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 ! 301: if (SMALL_INT (op)) ! 302: return 1; ! 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 ! 319: return 0; ! 320: #endif ! 321: ! 322: case REG: ! 323: return 1; ! 324: ! 325: case MEM: ! 326: #if 0 ! 327: /* This is not a single insn src, technically, ! 328: but output_delayed_branch knows how to deal with it. */ ! 329: if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) ! 330: return 0; ! 331: #endif ! 332: return 1; ! 333: ! 334: /* We never need to negate or complement constants. */ ! 335: case NEG: ! 336: return (mode != DFmode); ! 337: case NOT: ! 338: return 1; ! 339: ! 340: case COMPARE: ! 341: case MINUS: ! 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: ! 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: ! 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: ! 426: case COMPARE: ! 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; ! 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: } ! 469: } ! 470: ! 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: ! 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. */ ! 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: ! 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. */ ! 517: ! 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: ! 526: /* Return truth value of whether OP is a integer which fits the ! 527: range constraining immediate operands in three-address insns. */ ! 528: ! 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: ! 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) ! 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: } ! 572: if (GET_CODE (operands[1]) == MEM) ! 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: } ! 585: return "mov %1,%0"; ! 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 (offsettable_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 (offsettable_memref_p (operands[1])) ! 616: optype1 = OFFSOP; ! 617: else if (GET_CODE (operands[1]) == MEM) ! 618: optype1 = MEMOP; ! 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 (XEXP (operands[0], 0)); ! 634: ! 635: if (optype1 == MEMOP) ! 636: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 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_offsettable_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_offsettable_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: { ! 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])); ! 668: } ! 669: } ! 670: else ! 671: latehalf[1] = operands[1]; ! 672: ! 673: /* If the first move would clobber the source of the second one, ! 674: do them in the other order. ! 675: ! 676: RMS says "This happens only for registers; ! 677: such overlap can't happen in memory unless the user explicitly ! 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. */ ! 685: /* First check for moving between an even/odd register pair ! 686: and a memory location. */ ! 687: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP ! 688: && (REGNO (operands[0]) & 1) == 0) ! 689: || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP ! 690: && (REGNO (operands[1]) & 1) == 0)) ! 691: { ! 692: rtx op1, op2; ! 693: rtx base = 0, offset = const0_rtx; ! 694: ! 695: /* OP1 gets the register pair, and OP2 gets the memory address. */ ! 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: ! 701: /* Now see if we can trust the address to be 8-byte aligned. */ ! 702: /* Trust global variables. */ ! 703: if (CONSTANT_ADDRESS_P (op2)) ! 704: { ! 705: operands[0] = op1; ! 706: operands[1] = op2; ! 707: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 708: && cc_prev_status.mdep == op2)) ! 709: output_asm_insn ("sethi %%hi(%1),%%g1", operands); ! 710: cc_status.flags |= CC_KNOW_HI_G1; ! 711: cc_status.mdep = op2; ! 712: if (op1 == operands[0]) ! 713: return "ldd [%%lo(%1)+%%g1],%0"; ! 714: else ! 715: return "std [%%lo(%1)+%%g1],%0"; ! 716: } ! 717: ! 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. */ ! 727: if (base ! 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: { ! 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: ! 748: /* Sun fucks us here. We cannot trust references ! 749: to doubles via varying addresses. It might be on the stack ! 750: even if we don't know that it is; and then it might not be ! 751: double-word aligned. */ ! 752: #if 0 ! 753: if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode ! 754: && MEM_IN_STRUCT_P (operands[1])) ! 755: return "ldd %1,%0"; ! 756: else if (GET_CODE (operands[0]) == MEM ! 757: && GET_MODE (operands[0]) == DFmode ! 758: && MEM_IN_STRUCT_P (operands[0])) ! 759: return "std %1,%0"; ! 760: #endif ! 761: } ! 762: } ! 763: ! 764: if (optype0 == REGOP && optype1 == REGOP ! 765: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 766: { ! 767: /* Make any unoffsettable addresses point at high-numbered word. */ ! 768: if (addreg0) ! 769: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 770: if (addreg1) ! 771: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 772: ! 773: /* Do that word. */ ! 774: output_asm_insn (singlemove_string (latehalf), latehalf); ! 775: ! 776: /* Undo the adds we just did. */ ! 777: if (addreg0) ! 778: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 779: if (addreg1) ! 780: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 781: ! 782: /* Do low-numbered word. */ ! 783: return singlemove_string (operands); ! 784: } ! 785: else if (optype0 == REGOP && optype1 != REGOP ! 786: && reg_overlap_mentioned_p (operands[0], operands[1])) ! 787: { ! 788: /* Do the late half first. */ ! 789: output_asm_insn (singlemove_string (latehalf), latehalf); ! 790: /* Then clobber. */ ! 791: return singlemove_string (operands); ! 792: } ! 793: ! 794: /* Normal case: do the two words, low-numbered first. */ ! 795: ! 796: output_asm_insn (singlemove_string (operands), operands); ! 797: ! 798: /* Make any unoffsettable addresses point at high-numbered word. */ ! 799: if (addreg0) ! 800: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 801: if (addreg1) ! 802: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 803: ! 804: /* Do that word. */ ! 805: output_asm_insn (singlemove_string (latehalf), latehalf); ! 806: ! 807: /* Undo the adds we just did. */ ! 808: if (addreg0) ! 809: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 810: if (addreg1) ! 811: output_asm_insn ("add %0,-0x4,%0", &addreg1); ! 812: ! 813: return ""; ! 814: } ! 815: ! 816: static char * ! 817: output_fp_move_double (operands) ! 818: rtx *operands; ! 819: { ! 820: if (FP_REG_P (operands[0])) ! 821: { ! 822: if (FP_REG_P (operands[1])) ! 823: { ! 824: output_asm_insn ("fmovs %1,%0", operands); ! 825: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); ! 826: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); ! 827: return "fmovs %1,%0"; ! 828: } ! 829: if (GET_CODE (operands[1]) == REG) ! 830: { ! 831: if ((REGNO (operands[1]) & 1) == 0) ! 832: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; ! 833: else ! 834: { ! 835: rtx xoperands[3]; ! 836: xoperands[0] = operands[0]; ! 837: xoperands[1] = operands[1]; ! 838: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 839: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); ! 840: return ""; ! 841: } ! 842: } ! 843: if (GET_CODE (XEXP (operands[1], 0)) == PLUS ! 844: && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx ! 845: || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) ! 846: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT ! 847: && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0) ! 848: { ! 849: rtx xoperands[2]; ! 850: output_asm_insn ("ld %1,%0", operands); ! 851: xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), ! 852: REGNO (operands[0]) + 1); ! 853: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), ! 854: plus_constant (XEXP (operands[1], 0), 4)); ! 855: output_asm_insn ("ld %1,%0", xoperands); ! 856: return ""; ! 857: } ! 858: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) ! 859: { ! 860: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 861: && cc_prev_status.mdep == XEXP (operands[1], 0))) ! 862: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); ! 863: cc_status.flags |= CC_KNOW_HI_G1; ! 864: cc_status.mdep = XEXP (operands[1], 0); ! 865: return "ldd [%%lo(%m1)+%%g1],%0"; ! 866: } ! 867: return "ldd %1,%0"; ! 868: } ! 869: else if (FP_REG_P (operands[1])) ! 870: { ! 871: if (GET_CODE (operands[0]) == REG) ! 872: { ! 873: if ((REGNO (operands[0]) & 1) == 0) ! 874: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; ! 875: else ! 876: { ! 877: rtx xoperands[3]; ! 878: xoperands[2] = operands[1]; ! 879: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 880: xoperands[0] = operands[0]; ! 881: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); ! 882: return ""; ! 883: } ! 884: } ! 885: /* Use std if we can be sure it is well-aligned. */ ! 886: if (GET_CODE (XEXP (operands[0], 0)) == PLUS ! 887: && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx ! 888: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) ! 889: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT ! 890: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0) ! 891: /* Arrays are known to be aligned, ! 892: and reg+reg addresses are used (on this machine) ! 893: only for array accesses. */ ! 894: || (REG_P (XEXP (XEXP (operands[0], 0), 0)) ! 895: && REG_P (XEXP (XEXP (operands[0], 0), 1))))) ! 896: return "std %1,%0"; ! 897: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) ! 898: { ! 899: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 900: && cc_prev_status.mdep == XEXP (operands[0], 0))) ! 901: output_asm_insn ("sethi %%hi(%m0),%%g1", operands); ! 902: cc_status.flags |= CC_KNOW_HI_G1; ! 903: cc_status.mdep = XEXP (operands[0], 0); ! 904: return "std %1,[%%lo(%m0)+%%g1]"; ! 905: } ! 906: /* Otherwise use two st insns. */ ! 907: { ! 908: rtx xoperands[2]; ! 909: output_asm_insn ("st %r1,%0", operands); ! 910: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), ! 911: REGNO (operands[1]) + 1); ! 912: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), ! 913: plus_constant (XEXP (operands[0], 0), 4)); ! 914: output_asm_insn ("st %r1,%0", xoperands); ! 915: return ""; ! 916: } ! 917: } ! 918: else abort (); ! 919: } ! 920: ! 921: /* Return a REG that occurs in ADDR with coefficient 1. ! 922: ADDR can be effectively incremented by incrementing REG. */ ! 923: ! 924: static rtx ! 925: find_addr_reg (addr) ! 926: rtx addr; ! 927: { ! 928: while (GET_CODE (addr) == PLUS) ! 929: { ! 930: if (GET_CODE (XEXP (addr, 0)) == REG) ! 931: addr = XEXP (addr, 0); ! 932: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 933: addr = XEXP (addr, 1); ! 934: else if (CONSTANT_P (XEXP (addr, 0))) ! 935: addr = XEXP (addr, 1); ! 936: else if (CONSTANT_P (XEXP (addr, 1))) ! 937: addr = XEXP (addr, 0); ! 938: else ! 939: abort (); ! 940: } ! 941: if (GET_CODE (addr) == REG) ! 942: return addr; ! 943: abort (); ! 944: } ! 945: ! 946: void ! 947: output_sized_memop (opname, mode) ! 948: char *opname; ! 949: enum machine_mode mode; ! 950: { ! 951: extern struct _iobuf *asm_out_file; ! 952: ! 953: static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" }; ! 954: static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; ! 955: char *modename ! 956: = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1]; ! 957: ! 958: fprintf (asm_out_file, "\t%s%s", opname, modename); ! 959: } ! 960: ! 961: /* Output a store-in-memory whose operands are OPERANDS[0,1]. ! 962: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */ ! 963: ! 964: char * ! 965: output_store (operands) ! 966: rtx *operands; ! 967: { ! 968: enum machine_mode mode = GET_MODE (operands[0]); ! 969: rtx address = XEXP (operands[0], 0); ! 970: ! 971: cc_status.flags |= CC_KNOW_HI_G1; ! 972: cc_status.mdep = address; ! 973: ! 974: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 975: && address == cc_prev_status.mdep)) ! 976: { ! 977: output_asm_insn ("sethi %%hi(%m0),%%g1", operands); ! 978: cc_prev_status.mdep = address; ! 979: } ! 980: ! 981: /* Store zero in two parts when appropriate. */ ! 982: if (mode == DFmode && operands[1] == dconst0_rtx) ! 983: { ! 984: /* We can't cross a page boundary here because the ! 985: SYMBOL_REF must be double word aligned, and for this ! 986: to be the case, SYMBOL_REF+4 cannot cross. */ ! 987: output_sized_memop ("st", SImode); ! 988: output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands); ! 989: output_sized_memop ("st", SImode); ! 990: return "%r1,[%%g1+%%lo(%m0)+4]"; ! 991: } ! 992: ! 993: /* Code below isn't smart enough to move a doubleword in two parts, ! 994: so use output_move_double to do that in the cases that require it. */ ! 995: if ((mode == DImode || mode == DFmode) ! 996: && (GET_CODE (operands[1]) == REG ! 997: && (REGNO (operands[1]) & 1))) ! 998: return output_move_double (operands); ! 999: ! 1000: output_sized_memop ("st", mode); ! 1001: return "%r1,[%%g1+%%lo(%m0)]"; ! 1002: } ! 1003: ! 1004: /* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1]. ! 1005: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */ ! 1006: ! 1007: char * ! 1008: output_load_fixed (operands) ! 1009: rtx *operands; ! 1010: { ! 1011: enum machine_mode mode = GET_MODE (operands[0]); ! 1012: rtx address = XEXP (operands[1], 0); ! 1013: ! 1014: /* We don't bother trying to see if we know %hi(address). ! 1015: This is because we are doing a load, and if we know the ! 1016: %hi value, we probably also know that value in memory. */ ! 1017: cc_status.flags |= CC_KNOW_HI_G1; ! 1018: cc_status.mdep = address; ! 1019: ! 1020: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 1021: && address == cc_prev_status.mdep ! 1022: && cc_prev_status.mdep == cc_status.mdep)) ! 1023: { ! 1024: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); ! 1025: cc_prev_status.mdep = address; ! 1026: } ! 1027: ! 1028: /* Code below isn't smart enough to do a doubleword in two parts. ! 1029: So handle that case the slow way. */ ! 1030: if (mode == DImode ! 1031: && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */ ! 1032: && (REGNO (operands[0]) & 1)) ! 1033: return output_move_double (operands); ! 1034: ! 1035: output_sized_memop ("ld", mode); ! 1036: if (GET_CODE (operands[0]) == REG) ! 1037: return "[%%g1+%%lo(%m1)],%0"; ! 1038: abort (); ! 1039: } ! 1040: ! 1041: /* Output a floating-point load-from-memory whose operands are OPERANDS[0,1]. ! 1042: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. ! 1043: We also handle the case where OPERANDS[0] is a mem. */ ! 1044: ! 1045: char * ! 1046: output_load_floating (operands) ! 1047: rtx *operands; ! 1048: { ! 1049: enum machine_mode mode = GET_MODE (operands[0]); ! 1050: rtx address = XEXP (operands[1], 0); ! 1051: ! 1052: /* We don't bother trying to see if we know %hi(address). ! 1053: This is because we are doing a load, and if we know the ! 1054: %hi value, we probably also know that value in memory. */ ! 1055: cc_status.flags |= CC_KNOW_HI_G1; ! 1056: cc_status.mdep = address; ! 1057: ! 1058: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 1059: && address == cc_prev_status.mdep ! 1060: && cc_prev_status.mdep == cc_status.mdep)) ! 1061: { ! 1062: output_asm_insn ("sethi %%hi(%m1),%%g1", operands); ! 1063: cc_prev_status.mdep = address; ! 1064: } ! 1065: ! 1066: if (mode == DFmode) ! 1067: { ! 1068: if (REG_P (operands[0])) ! 1069: { ! 1070: if (REGNO (operands[0]) & 1) ! 1071: return output_move_double (operands); ! 1072: else ! 1073: return "ldd [%%g1+%%lo(%m1)],%0"; ! 1074: } ! 1075: cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0); ! 1076: output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands); ! 1077: operands[1] = gen_rtx (REG, DFmode, 32); ! 1078: return output_fp_move_double (operands); ! 1079: } ! 1080: ! 1081: if (GET_CODE (operands[0]) == MEM) ! 1082: { ! 1083: cc_status.flags &= ~CC_F1_IS_0; ! 1084: output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands); ! 1085: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) ! 1086: { ! 1087: cc_status.mdep = XEXP (operands[0], 0); ! 1088: return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]"; ! 1089: } ! 1090: else ! 1091: return "st %%f1,%0"; ! 1092: } ! 1093: return "ld [%%g1+%%lo(%m1)],%0"; ! 1094: } ! 1095: ! 1096: /* Load the address specified by OPERANDS[3] into the register ! 1097: specified by OPERANDS[0]. ! 1098: ! 1099: OPERANDS[3] may be the result of a sum, hence it could either be: ! 1100: ! 1101: (1) CONST ! 1102: (2) REG ! 1103: (2) REG + CONST_INT ! 1104: (3) REG + REG + CONST_INT ! 1105: (4) REG + REG (special case of 3). ! 1106: ! 1107: Note that (3) is not a legitimate address. ! 1108: All cases are handled here. */ ! 1109: ! 1110: void ! 1111: output_load_address (operands) ! 1112: rtx *operands; ! 1113: { ! 1114: rtx base, offset; ! 1115: ! 1116: if (CONSTANT_P (operands[3])) ! 1117: { ! 1118: output_asm_insn ("set %3,%0", operands); ! 1119: return; ! 1120: } ! 1121: ! 1122: if (REG_P (operands[3])) ! 1123: { ! 1124: if (REGNO (operands[0]) != REGNO (operands[3])) ! 1125: output_asm_insn ("mov %3,%0", operands); ! 1126: return; ! 1127: } ! 1128: ! 1129: if (GET_CODE (operands[3]) != PLUS) ! 1130: abort (); ! 1131: ! 1132: base = XEXP (operands[3], 0); ! 1133: offset = XEXP (operands[3], 1); ! 1134: ! 1135: if (GET_CODE (base) == CONST_INT) ! 1136: { ! 1137: rtx tmp = base; ! 1138: base = offset; ! 1139: offset = tmp; ! 1140: } ! 1141: ! 1142: if (GET_CODE (offset) != CONST_INT) ! 1143: { ! 1144: /* Operand is (PLUS (REG) (REG)). */ ! 1145: base = operands[3]; ! 1146: offset = const0_rtx; ! 1147: } ! 1148: ! 1149: if (REG_P (base)) ! 1150: { ! 1151: operands[6] = base; ! 1152: operands[7] = offset; ! 1153: if (SMALL_INT (offset)) ! 1154: output_asm_insn ("add %6,%7,%0", operands); ! 1155: else ! 1156: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); ! 1157: } ! 1158: else if (GET_CODE (base) == PLUS) ! 1159: { ! 1160: operands[6] = XEXP (base, 0); ! 1161: operands[7] = XEXP (base, 1); ! 1162: operands[8] = offset; ! 1163: ! 1164: if (SMALL_INT (offset)) ! 1165: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); ! 1166: else ! 1167: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); ! 1168: } ! 1169: else ! 1170: abort (); ! 1171: } ! 1172: ! 1173: /* Output code to place a size count SIZE in register REG. ! 1174: ALIGN is the size of the unit of transfer. ! 1175: ! 1176: Because block moves are pipelined, we don't include the ! 1177: first element in the transfer of SIZE to REG. */ ! 1178: ! 1179: static void ! 1180: output_size_for_block_move (size, reg, align) ! 1181: rtx size, reg; ! 1182: rtx align; ! 1183: { ! 1184: rtx xoperands[3]; ! 1185: ! 1186: xoperands[0] = reg; ! 1187: xoperands[1] = size; ! 1188: xoperands[2] = align; ! 1189: if (GET_CODE (size) == REG) ! 1190: output_asm_insn ("sub %1,%2,%0", xoperands); ! 1191: else ! 1192: { ! 1193: xoperands[1] ! 1194: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); ! 1195: cc_status.flags &= ~ CC_KNOW_HI_G1; ! 1196: output_asm_insn ("set %1,%0", xoperands); ! 1197: } ! 1198: } ! 1199: ! 1200: /* Emit code to perform a block move. ! 1201: ! 1202: OPERANDS[0] is the destination. ! 1203: OPERANDS[1] is the source. ! 1204: OPERANDS[2] is the size. ! 1205: OPERANDS[3] is the alignment safe to use. ! 1206: OPERANDS[4] is a register we can safely clobber as a temp. */ ! 1207: ! 1208: char * ! 1209: output_block_move (operands) ! 1210: rtx *operands; ! 1211: { ! 1212: /* A vector for our computed operands. Note that load_output_address ! 1213: makes use of (and can clobber) up to the 8th element of this vector. */ ! 1214: rtx xoperands[10]; ! 1215: rtx zoperands[10]; ! 1216: static int movstrsi_label = 0; ! 1217: int i, j; ! 1218: rtx temp1 = operands[4]; ! 1219: rtx alignrtx = operands[3]; ! 1220: int align = INTVAL (alignrtx); ! 1221: ! 1222: xoperands[0] = operands[0]; ! 1223: xoperands[1] = operands[1]; ! 1224: xoperands[2] = temp1; ! 1225: ! 1226: /* We can't move more than four bytes at a time ! 1227: because we have only one register to move them through. */ ! 1228: if (align > 4) ! 1229: { ! 1230: align = 4; ! 1231: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); ! 1232: } ! 1233: ! 1234: /* Since we clobber untold things, nix the condition codes. */ ! 1235: CC_STATUS_INIT; ! 1236: ! 1237: /* Recognize special cases of block moves. These occur ! 1238: when GNU C++ is forced to treat something as BLKmode ! 1239: to keep it in memory, when its mode could be represented ! 1240: with something smaller. ! 1241: ! 1242: We cannot do this for global variables, since we don't know ! 1243: what pages they don't cross. Sigh. */ ! 1244: if (GET_CODE (operands[2]) == CONST_INT ! 1245: && INTVAL (operands[2]) <= 16 ! 1246: && ! CONSTANT_ADDRESS_P (operands[0]) ! 1247: && ! CONSTANT_ADDRESS_P (operands[1])) ! 1248: { ! 1249: int size = INTVAL (operands[2]); ! 1250: ! 1251: cc_status.flags &= ~CC_KNOW_HI_G1; ! 1252: if (align == 1) ! 1253: { ! 1254: if (memory_address_p (QImode, plus_constant (xoperands[0], size)) ! 1255: && memory_address_p (QImode, plus_constant (xoperands[1], size))) ! 1256: { ! 1257: /* We will store different integers into this particular RTX. */ ! 1258: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); ! 1259: for (i = size-1; i >= 0; i--) ! 1260: { ! 1261: INTVAL (xoperands[2]) = i; ! 1262: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", ! 1263: xoperands); ! 1264: } ! 1265: return ""; ! 1266: } ! 1267: } ! 1268: else if (align == 2) ! 1269: { ! 1270: if (memory_address_p (HImode, plus_constant (xoperands[0], size)) ! 1271: && memory_address_p (HImode, plus_constant (xoperands[1], size))) ! 1272: { ! 1273: /* We will store different integers into this particular RTX. */ ! 1274: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); ! 1275: for (i = (size>>1)-1; i >= 0; i--) ! 1276: { ! 1277: INTVAL (xoperands[2]) = i<<1; ! 1278: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", ! 1279: xoperands); ! 1280: } ! 1281: return ""; ! 1282: } ! 1283: } ! 1284: else ! 1285: { ! 1286: if (memory_address_p (SImode, plus_constant (xoperands[0], size)) ! 1287: && memory_address_p (SImode, plus_constant (xoperands[1], size))) ! 1288: { ! 1289: /* We will store different integers into this particular RTX. */ ! 1290: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); ! 1291: for (i = (size>>2)-1; i >= 0; i--) ! 1292: { ! 1293: INTVAL (xoperands[2]) = i<<2; ! 1294: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", ! 1295: xoperands); ! 1296: } ! 1297: return ""; ! 1298: } ! 1299: } ! 1300: } ! 1301: ! 1302: /* This is the size of the transfer. ! 1303: Either use the register which already contains the size, ! 1304: or use a free register (used by no operands). ! 1305: Also emit code to decrement the size value by ALIGN. */ ! 1306: output_size_for_block_move (operands[2], temp1, alignrtx); ! 1307: ! 1308: zoperands[0] = operands[0]; ! 1309: zoperands[3] = plus_constant (operands[0], align); ! 1310: output_load_address (zoperands); ! 1311: ! 1312: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1313: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); ! 1314: ! 1315: if (align == 1) ! 1316: 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); ! 1317: else if (align == 2) ! 1318: 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); ! 1319: else ! 1320: 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); ! 1321: return ""; ! 1322: } ! 1323: ! 1324: /* What the sparc lacks in hardware, make up for in software. ! 1325: Compute a fairly good sequence of shift and add insns ! 1326: to make a multiply happen. */ ! 1327: ! 1328: #define ABS(x) ((x) < 0 ? -(x) : x) ! 1329: ! 1330: char * ! 1331: output_mul_by_constant (insn, operands, unsignedp) ! 1332: rtx insn; ! 1333: rtx *operands; ! 1334: int unsignedp; ! 1335: { ! 1336: int c; /* Size of constant */ ! 1337: int shifts[BITS_PER_WORD]; /* Table of shifts */ ! 1338: unsigned int p, log; /* A power of two, and its log */ ! 1339: int d1, d2; /* Differences of c and p */ ! 1340: int first = 1; /* True if dst has unknown data in it */ ! 1341: int i; ! 1342: ! 1343: CC_STATUS_INIT; ! 1344: ! 1345: c = INTVAL (operands[2]); ! 1346: if (c == 0) ! 1347: { ! 1348: /* should not happen. */ ! 1349: abort (); ! 1350: if (GET_CODE (operands[0]) == MEM) ! 1351: return "st %%g0,%0"; ! 1352: return "mov %%g0,%0"; ! 1353: } ! 1354: ! 1355: output_asm_insn ("! start open coded multiply"); ! 1356: ! 1357: /* Clear out the table of shifts. */ ! 1358: for (i = 0; i < BITS_PER_WORD; ++i) ! 1359: shifts[i] = 0; ! 1360: ! 1361: while (c) ! 1362: { ! 1363: /* Find the power of two nearest ABS(c) */ ! 1364: p = 1, log = 0; ! 1365: do ! 1366: { ! 1367: d1 = ABS(c) - p; ! 1368: p *= 2; ! 1369: ++log; ! 1370: } ! 1371: while (p < ABS(c)); ! 1372: d2 = p - ABS(c); ! 1373: ! 1374: /* Make an appropriate entry in shifts for p. */ ! 1375: if (d2 < d1) ! 1376: { ! 1377: shifts[log] = c < 0 ? -1 : 1; ! 1378: c = c < 0 ? d2 : -d2; ! 1379: } ! 1380: else ! 1381: { ! 1382: shifts[log - 1] = c < 0 ? -1 : 1; ! 1383: c = c < 0 ? -d1 : d1; ! 1384: } ! 1385: } ! 1386: ! 1387: /* Take care of the first insn in sequence. ! 1388: We know we have at least one. */ ! 1389: ! 1390: /* A value of -1 in shifts says to subtract that power of two, and a value ! 1391: of 1 says to add that power of two. */ ! 1392: for (i = 0; ; i++) ! 1393: if (shifts[i]) ! 1394: { ! 1395: if (i) ! 1396: { ! 1397: operands[2] = gen_rtx (CONST_INT, VOIDmode, i); ! 1398: output_asm_insn ("sll %1,%2,%%g1", operands); ! 1399: } ! 1400: else output_asm_insn ("mov %1,%%g1", operands); ! 1401: ! 1402: log = i; ! 1403: if (shifts[i] < 0) ! 1404: output_asm_insn ("sub %%g0,%%g1,%0", operands); ! 1405: else ! 1406: output_asm_insn ("mov %%g1,%0", operands); ! 1407: break; ! 1408: } ! 1409: ! 1410: /* A value of -1 in shifts says to subtract that power of two, and a value ! 1411: of 1 says to add that power of two--continued. */ ! 1412: for (i += 1; i < BITS_PER_WORD; ++i) ! 1413: if (shifts[i]) ! 1414: { ! 1415: if (i - log > 0) ! 1416: { ! 1417: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); ! 1418: output_asm_insn ("sll %%g1,%2,%%g1", operands); ! 1419: } ! 1420: else ! 1421: { ! 1422: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); ! 1423: output_asm_insn ("sra %%g1,%2,%%g1", operands); ! 1424: } ! 1425: log = i; ! 1426: if (shifts[i] < 0) ! 1427: output_asm_insn ("sub %0,%%g1,%0", operands); ! 1428: else ! 1429: output_asm_insn ("add %0,%%g1,%0", operands); ! 1430: } ! 1431: ! 1432: output_asm_insn ("! end open coded multiply"); ! 1433: ! 1434: return ""; ! 1435: } ! 1436: ! 1437: char * ! 1438: output_mul_insn (operands, unsignedp) ! 1439: rtx *operands; ! 1440: int unsignedp; ! 1441: { ! 1442: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; ! 1443: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; ! 1444: ! 1445: CC_STATUS_INIT; ! 1446: ! 1447: if (lucky1) ! 1448: { ! 1449: if (lucky2) ! 1450: { ! 1451: if (REGNO (operands[1]) == REGNO (operands[2])) ! 1452: { ! 1453: if (REGNO (operands[1]) == 8) ! 1454: output_asm_insn ("mov %%o0,%%o1"); ! 1455: else ! 1456: output_asm_insn ("mov %%o1,%%o0"); ! 1457: } ! 1458: output_asm_insn ("call .mul,2\n\tnop", operands); ! 1459: } ! 1460: else ! 1461: { ! 1462: rtx xoperands[2]; ! 1463: xoperands[0] = gen_rtx (REG, SImode, ! 1464: 8 ^ (REGNO (operands[1]) == 8)); ! 1465: xoperands[1] = operands[2]; ! 1466: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); ! 1467: } ! 1468: } ! 1469: else if (lucky2) ! 1470: { ! 1471: rtx xoperands[2]; ! 1472: xoperands[0] = gen_rtx (REG, SImode, ! 1473: 8 ^ (REGNO (operands[2]) == 8)); ! 1474: xoperands[1] = operands[1]; ! 1475: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); ! 1476: } ! 1477: else ! 1478: { ! 1479: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", ! 1480: operands); ! 1481: } ! 1482: ! 1483: if (REGNO (operands[0]) == 8) ! 1484: return ""; ! 1485: return "mov %%o0,%0"; ! 1486: } ! 1487: ! 1488: /* Make floating point register f0 contain 0. ! 1489: SIZE is the number of registers (including f0) ! 1490: which should contain 0. */ ! 1491: ! 1492: void ! 1493: make_f0_contain_0 (size) ! 1494: int size; ! 1495: { ! 1496: if (size == 1) ! 1497: { ! 1498: if ((cc_status.flags & (CC_F0_IS_0)) == 0) ! 1499: output_asm_insn ("ld [%%fp-16],%%f0", 0); ! 1500: cc_status.flags |= CC_F0_IS_0; ! 1501: } ! 1502: else if (size == 2) ! 1503: { ! 1504: if ((cc_status.flags & CC_F0_IS_0) == 0) ! 1505: output_asm_insn ("ld [%%fp-16],%%f0", 0); ! 1506: if ((cc_status.flags & (CC_F1_IS_0)) == 0) ! 1507: output_asm_insn ("ld [%%fp-12],%%f1", 0); ! 1508: cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0; ! 1509: } ! 1510: } ! 1511: ! 1512: /* Since condition codes don't have logical links, we need to keep ! 1513: their setting and use together for set-cc insns. */ ! 1514: void ! 1515: gen_scc_insn (code, mode, operands) ! 1516: enum rtx_code code; ! 1517: enum machine_mode mode; ! 1518: rtx *operands; ! 1519: { ! 1520: extern rtx sequence_stack; ! 1521: rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0); ! 1522: rtx last_pat; ! 1523: ! 1524: /* Skip back over the CLOBBERs that may precede this insn. */ ! 1525: while (last_insn && GET_CODE (last_insn) == INSN ! 1526: && GET_CODE (PATTERN (last_insn)) == CLOBBER) ! 1527: last_insn = PREV_INSN (last_insn); ! 1528: /* We should have found the preceding compare. */ ! 1529: if (last_insn == 0 || GET_CODE (last_insn) != INSN) ! 1530: abort (); ! 1531: last_pat = PATTERN (last_insn); ! 1532: if (GET_CODE (last_pat) != SET ! 1533: || GET_CODE (SET_DEST (last_pat)) != CC0) ! 1534: abort (); ! 1535: ! 1536: /* Turn off that previous insn, now that we have got the data out of it. */ ! 1537: PUT_CODE (last_insn, NOTE); ! 1538: NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED; ! 1539: ! 1540: /* Emit one replacement insn to compare operands and store result. */ ! 1541: emit_insn (gen_rtx (SET, VOIDmode, operands[0], ! 1542: gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx))); ! 1543: } ! 1544: ! 1545: /* Output reasonable peephole for set-on-condition-code insns. ! 1546: Note that these insns assume a particular way of defining ! 1547: labels. Therefore, *both* tm-sparc.h and this function must ! 1548: be changed if a new syntax is needed. */ ! 1549: ! 1550: char * ! 1551: output_scc_insn (code, operand) ! 1552: enum rtx_code code; ! 1553: rtx operand; ! 1554: { ! 1555: rtx xoperands[2]; ! 1556: rtx label = gen_label_rtx (); ! 1557: int cc_in_fccr = cc_status.flags & CC_IN_FCCR; ! 1558: int antisymmetric = 0; ! 1559: ! 1560: xoperands[0] = operand; ! 1561: xoperands[1] = label; ! 1562: ! 1563: switch (code) ! 1564: { ! 1565: case NE: ! 1566: if (cc_in_fccr) ! 1567: output_asm_insn ("fbne,a %l0", &label); ! 1568: else ! 1569: output_asm_insn ("bne,a %l0", &label); ! 1570: break; ! 1571: case EQ: ! 1572: if (cc_in_fccr) ! 1573: output_asm_insn ("fbe,a %l0", &label); ! 1574: else ! 1575: output_asm_insn ("be,a %l0", &label); ! 1576: break; ! 1577: case GE: ! 1578: if (cc_in_fccr) ! 1579: output_asm_insn ("fbge,a %l0", &label); ! 1580: else ! 1581: output_asm_insn ("bge,a %l0", &label); ! 1582: antisymmetric = 1; ! 1583: break; ! 1584: case GT: ! 1585: if (cc_in_fccr) ! 1586: output_asm_insn ("fbg,a %l0", &label); ! 1587: else ! 1588: output_asm_insn ("bg,a %l0", &label); ! 1589: antisymmetric = 1; ! 1590: break; ! 1591: case LE: ! 1592: if (cc_in_fccr) ! 1593: output_asm_insn ("fble,a %l0", &label); ! 1594: else ! 1595: output_asm_insn ("ble,a %l0", &label); ! 1596: antisymmetric = 1; ! 1597: break; ! 1598: case LT: ! 1599: if (cc_in_fccr) ! 1600: output_asm_insn ("fbl,a %l0", &label); ! 1601: else ! 1602: output_asm_insn ("bl,a %l0", &label); ! 1603: antisymmetric = 1; ! 1604: break; ! 1605: case GEU: ! 1606: if (cc_in_fccr) ! 1607: abort (); ! 1608: else ! 1609: output_asm_insn ("bgeu,a %l0", &label); ! 1610: antisymmetric = 1; ! 1611: break; ! 1612: case GTU: ! 1613: if (cc_in_fccr) ! 1614: abort (); ! 1615: else ! 1616: output_asm_insn ("bgu,a %l0", &label); ! 1617: antisymmetric = 1; ! 1618: break; ! 1619: case LEU: ! 1620: if (cc_in_fccr) ! 1621: abort (); ! 1622: else ! 1623: output_asm_insn ("bleu,a %l0", &label); ! 1624: antisymmetric = 1; ! 1625: break; ! 1626: case LTU: ! 1627: if (cc_in_fccr) ! 1628: abort (); ! 1629: else ! 1630: output_asm_insn ("blu,a %l0", &label); ! 1631: antisymmetric = 1; ! 1632: break; ! 1633: default: ! 1634: abort (); ! 1635: } ! 1636: if (antisymmetric ! 1637: && (cc_status.flags & CC_REVERSED)) ! 1638: output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands); ! 1639: else ! 1640: output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands); ! 1641: return ""; ! 1642: } ! 1643: ! 1644: /* Output a delayed branch insn with the delay insn in its ! 1645: branch slot. The delayed branch insn template is in TEMPLATE, ! 1646: with operands OPERANDS. The insn in its delay slot is INSN. ! 1647: ! 1648: As a special case, since we know that all memory transfers are via ! 1649: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory ! 1650: reference around the branch as ! 1651: ! 1652: sethi %hi(x),%%g1 ! 1653: b ... ! 1654: ld/st [%g1+%lo(x)],... ! 1655: ! 1656: As another special case, we handle loading (SYMBOL_REF ...) and ! 1657: other large constants around branches as well: ! 1658: ! 1659: sethi %hi(x),%0 ! 1660: b ... ! 1661: or %0,%lo(x),%1 ! 1662: ! 1663: */ ! 1664: ! 1665: char * ! 1666: output_delayed_branch (template, operands, insn) ! 1667: char *template; ! 1668: rtx *operands; ! 1669: rtx insn; ! 1670: { ! 1671: extern rtx recog_operand[]; ! 1672: rtx src = XVECEXP (PATTERN (insn), 0, 1); ! 1673: rtx dest = XVECEXP (PATTERN (insn), 0, 0); ! 1674: ! 1675: if (GET_CODE (src) == SYMBOL_REF ! 1676: || (GET_CODE (src) == CONST_INT ! 1677: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0))) ! 1678: { ! 1679: rtx xoperands[2]; ! 1680: xoperands[0] = dest; ! 1681: xoperands[1] = src; ! 1682: ! 1683: /* Output the `sethi' insn. */ ! 1684: output_asm_insn ("sethi %%hi(%1),%0", xoperands); ! 1685: ! 1686: /* Output the branch instruction next. */ ! 1687: output_asm_insn (template, operands); ! 1688: ! 1689: /* Now output the `or' insn. */ ! 1690: output_asm_insn ("or %0,%%lo(%1),%0", xoperands); ! 1691: } ! 1692: else if ((GET_CODE (src) == MEM ! 1693: && CONSTANT_ADDRESS_P (XEXP (src, 0))) ! 1694: || (GET_CODE (dest) == MEM ! 1695: && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) ! 1696: { ! 1697: rtx xoperands[2]; ! 1698: char *split_template; ! 1699: xoperands[0] = dest; ! 1700: xoperands[1] = src; ! 1701: ! 1702: /* Output the `sethi' insn. */ ! 1703: if (GET_CODE (src) == MEM) ! 1704: { ! 1705: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 1706: && cc_prev_status.mdep == XEXP (operands[1], 0))) ! 1707: output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands); ! 1708: split_template = "ld [%%g1+%%lo(%m1)],%0"; ! 1709: } ! 1710: else ! 1711: { ! 1712: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) ! 1713: && cc_prev_status.mdep == XEXP (operands[0], 0))) ! 1714: output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands); ! 1715: split_template = "st %r1,[%%g1+%%lo(%m0)]"; ! 1716: } ! 1717: ! 1718: /* Output the branch instruction next. */ ! 1719: output_asm_insn (template, operands); ! 1720: ! 1721: /* Now output the load or store. ! 1722: No need to do a CC_STATUS_INIT, because we are branching anyway. */ ! 1723: output_asm_insn (split_template, xoperands); ! 1724: } ! 1725: else ! 1726: { ! 1727: extern char *insn_template[]; ! 1728: extern char *(*insn_outfun[])(); ! 1729: int insn_code_number; ! 1730: rtx pat = gen_rtx (SET, VOIDmode, dest, src); ! 1731: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); ! 1732: int i; ! 1733: extern rtx alter_subreg(); ! 1734: extern int insn_n_operands[]; ! 1735: ! 1736: /* Output the branch instruction first. */ ! 1737: output_asm_insn (template, operands); ! 1738: ! 1739: /* Now recognize the insn which we put in its delay slot. ! 1740: We must do this after outputing the branch insn, ! 1741: since operands may just be a pointer to `recog_operand'. */ ! 1742: insn_code_number = recog (pat, delay_insn); ! 1743: if (insn_code_number == -1) ! 1744: abort (); ! 1745: ! 1746: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 1747: { ! 1748: if (GET_CODE (recog_operand[i]) == SUBREG) ! 1749: recog_operand[i] = alter_subreg (recog_operand[i]); ! 1750: } ! 1751: ! 1752: /* Now get the template for what this insn would ! 1753: have been, without the branch. Its operands are ! 1754: exactly the same as they would be, so we don't ! 1755: need to do an insn_extract. */ ! 1756: template = insn_template[insn_code_number]; ! 1757: if (template == 0) ! 1758: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); ! 1759: output_asm_insn (template, recog_operand); ! 1760: } ! 1761: CC_STATUS_INIT; ! 1762: return ""; ! 1763: } ! 1764: ! 1765: /* Output a newly constructed insn DELAY_INSN. */ ! 1766: char * ! 1767: output_delay_insn (delay_insn) ! 1768: rtx delay_insn; ! 1769: { ! 1770: char *template; ! 1771: extern rtx recog_operand[]; ! 1772: extern char call_used_regs[]; ! 1773: extern char *insn_template[]; ! 1774: extern int insn_n_operands[]; ! 1775: extern char *(*insn_outfun[])(); ! 1776: extern rtx alter_subreg(); ! 1777: int insn_code_number; ! 1778: extern int insn_n_operands[]; ! 1779: int i; ! 1780: ! 1781: /* Now recognize the insn which we put in its delay slot. ! 1782: We must do this after outputing the branch insn, ! 1783: since operands may just be a pointer to `recog_operand'. */ ! 1784: insn_code_number = recog_memoized (delay_insn); ! 1785: if (insn_code_number == -1) ! 1786: abort (); ! 1787: ! 1788: /* Extract the operands of this delay insn. */ ! 1789: INSN_CODE (delay_insn) = insn_code_number; ! 1790: insn_extract (delay_insn); ! 1791: ! 1792: /* It is possible that this insn has not been properly scaned by final ! 1793: yet. If this insn's operands don't appear in the peephole's ! 1794: actual operands, then they won't be fixed up by final, so we ! 1795: make sure they get fixed up here. -- This is a kludge. */ ! 1796: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 1797: { ! 1798: if (GET_CODE (recog_operand[i]) == SUBREG) ! 1799: recog_operand[i] = alter_subreg (recog_operand[i]); ! 1800: } ! 1801: ! 1802: #ifdef REGISTER_CONSTRAINTS ! 1803: if (! constrain_operands (insn_code_number)) ! 1804: abort (); ! 1805: #endif ! 1806: ! 1807: cc_prev_status = cc_status; ! 1808: ! 1809: /* Update `cc_status' for this instruction. ! 1810: The instruction's output routine may change it further. ! 1811: If the output routine for a jump insn needs to depend ! 1812: on the cc status, it should look at cc_prev_status. */ ! 1813: ! 1814: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); ! 1815: ! 1816: /* Now get the template for what this insn would ! 1817: have been, without the branch. */ ! 1818: ! 1819: template = insn_template[insn_code_number]; ! 1820: if (template == 0) ! 1821: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); ! 1822: output_asm_insn (template, recog_operand); ! 1823: return ""; ! 1824: } ! 1825: ! 1826: /* Output the insn HEAD, keeping OPERANDS protected (wherever they are). ! 1827: HEAD comes from the target of some branch, so before we output it, ! 1828: we delete it from the target, lest we execute it twice. The caller ! 1829: of this function promises that such code motion is permissable. */ ! 1830: char * ! 1831: output_eager_then_insn (head, operands) ! 1832: rtx head; ! 1833: rtx *operands; ! 1834: { ! 1835: extern rtx alter_subreg (); ! 1836: extern int insn_n_operands[]; ! 1837: extern rtx recog_operand[]; ! 1838: rtx xoperands[MAX_RECOG_OPERANDS]; ! 1839: int insn_code_number, i, nbytes; ! 1840: rtx nhead; ! 1841: ! 1842: /* Micro-hack: run peephole on head if it looks like a good idea. ! 1843: Right now there's only one such case worth doing... ! 1844: ! 1845: This could be made smarter if the peephole for ``2-insn combine'' ! 1846: were also made smarter. */ ! 1847: if (GET_CODE (PATTERN (head)) == SET ! 1848: && REG_P (SET_SRC (PATTERN (head))) ! 1849: && REG_P (SET_DEST (PATTERN (head))) ! 1850: && (nhead = next_real_insn_no_labels (head)) ! 1851: && GET_CODE (nhead) == INSN ! 1852: && GET_CODE (PATTERN (nhead)) == SET ! 1853: && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0 ! 1854: && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head)) ! 1855: || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head)))) ! 1856: /* Something's wrong if this does not fly. */ ! 1857: if (! peephole (head)) ! 1858: abort (); ! 1859: ! 1860: /* Save our contents of `operands', since output_delay_insn sets them. */ ! 1861: insn_code_number = recog_memoized (head); ! 1862: nbytes = insn_n_operands[insn_code_number] * sizeof (rtx); ! 1863: bcopy (operands, xoperands, nbytes); ! 1864: ! 1865: /* Output the delay insn, and prevent duplication later. */ ! 1866: delete_insn (head); ! 1867: output_delay_insn (head); ! 1868: ! 1869: /* Restore this insn's operands. */ ! 1870: bcopy (xoperands, operands, nbytes); ! 1871: } ! 1872: ! 1873: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL; ! 1874: or 0, if there is none. Also return 0 if we cross a label. */ ! 1875: ! 1876: rtx ! 1877: next_real_insn_no_labels (label) ! 1878: rtx label; ! 1879: { ! 1880: register rtx insn = NEXT_INSN (label); ! 1881: register RTX_CODE code; ! 1882: ! 1883: while (insn) ! 1884: { ! 1885: code = GET_CODE (insn); ! 1886: if (code == INSN) ! 1887: { ! 1888: if (GET_CODE (PATTERN (insn)) != CLOBBER ! 1889: && GET_CODE (PATTERN (insn)) != USE) ! 1890: return insn; ! 1891: } ! 1892: if (code == CALL_INSN || code == JUMP_INSN) ! 1893: return insn; ! 1894: if (code == CODE_LABEL) ! 1895: return 0; ! 1896: insn = NEXT_INSN (insn); ! 1897: } ! 1898: ! 1899: return 0; ! 1900: } ! 1901: ! 1902: int ! 1903: operands_satisfy_eager_branch_peephole (operands, conditional) ! 1904: rtx *operands; ! 1905: int conditional; ! 1906: { ! 1907: rtx label; ! 1908: ! 1909: if (conditional) ! 1910: { ! 1911: if (GET_CODE (operands[0]) != IF_THEN_ELSE) ! 1912: return 0; ! 1913: ! 1914: if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF) ! 1915: label = XEXP (XEXP (operands[0], 1), 0); ! 1916: else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF) ! 1917: label = XEXP (XEXP (operands[0], 2), 0); ! 1918: else return 0; ! 1919: } ! 1920: else ! 1921: { ! 1922: label = operands[0]; ! 1923: } ! 1924: ! 1925: if (LABEL_NUSES (label) == 1) ! 1926: { ! 1927: rtx prev = PREV_INSN (label); ! 1928: while (prev && GET_CODE (prev) == NOTE) ! 1929: prev = PREV_INSN (prev); ! 1930: if (prev == 0 ! 1931: || GET_CODE (prev) == BARRIER) ! 1932: { ! 1933: rtx head = next_real_insn_no_labels (label); ! 1934: ! 1935: if (head ! 1936: && ! INSN_DELETED_P (head) ! 1937: && GET_CODE (head) == INSN ! 1938: && GET_CODE (PATTERN (head)) == SET ! 1939: && strict_single_insn_op_p (SET_SRC (PATTERN (head)), ! 1940: GET_MODE (SET_DEST (PATTERN (head)))) ! 1941: && strict_single_insn_op_p (SET_DEST (PATTERN (head)), ! 1942: GET_MODE (SET_DEST (PATTERN (head))))) ! 1943: { ! 1944: if (conditional == 2) ! 1945: return (GET_CODE (operands[1]) != PC ! 1946: && safe_insn_src_p (operands[2], VOIDmode) ! 1947: && strict_single_insn_op_p (operands[2], VOIDmode) ! 1948: && operand_clobbered_before_used_after (operands[1], label)); ! 1949: return 1; ! 1950: } ! 1951: } ! 1952: } ! 1953: ! 1954: if (conditional == 1 ! 1955: && GET_CODE (operands[1]) != PC ! 1956: && safe_insn_src_p (operands[2], VOIDmode) ! 1957: && strict_single_insn_op_p (operands[2], VOIDmode) ! 1958: && operand_clobbered_before_used_after (operands[1], label)) ! 1959: return 1; ! 1960: ! 1961: return 0; ! 1962: } ! 1963:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.