|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Intel 860 ! 2: Copyright (C) 1989, 1991 Free Software Foundation, Inc. ! 3: Derived from sparc.c. ! 4: ! 5: Written by Richard Stallman ([email protected]). ! 6: ! 7: Hacked substantially by Ron Guilmette ([email protected]) to cater ! 8: to the whims of the System V Release 4 assembler. ! 9: ! 10: This file is part of GNU CC. ! 11: ! 12: GNU CC is free software; you can redistribute it and/or modify ! 13: it under the terms of the GNU General Public License as published by ! 14: the Free Software Foundation; either version 2, or (at your option) ! 15: any later version. ! 16: ! 17: GNU CC is distributed in the hope that it will be useful, ! 18: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 19: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 20: GNU General Public License for more details. ! 21: ! 22: You should have received a copy of the GNU General Public License ! 23: along with GNU CC; see the file COPYING. If not, write to ! 24: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 25: ! 26: ! 27: #include "config.h" ! 28: #include "flags.h" ! 29: #include "rtl.h" ! 30: #include "regs.h" ! 31: #include "hard-reg-set.h" ! 32: #include "real.h" ! 33: #include "insn-config.h" ! 34: #include "conditions.h" ! 35: #include "insn-flags.h" ! 36: #include "output.h" ! 37: #include "recog.h" ! 38: #include "insn-attr.h" ! 39: ! 40: #include <stdio.h> ! 41: ! 42: static rtx find_addr_reg (); ! 43: ! 44: #ifndef I860_REG_PREFIX ! 45: #define I860_REG_PREFIX "" ! 46: #endif ! 47: ! 48: char *i860_reg_prefix = I860_REG_PREFIX; ! 49: ! 50: /* Save information from a "cmpxx" operation until the branch is emitted. */ ! 51: ! 52: rtx i860_compare_op0, i860_compare_op1; ! 53: ! 54: /* Return non-zero if this pattern, can be evaluated safely, even if it ! 55: was not asked for. */ ! 56: int ! 57: safe_insn_src_p (op, mode) ! 58: rtx op; ! 59: enum machine_mode mode; ! 60: { ! 61: /* Just experimenting. */ ! 62: ! 63: /* No floating point src is safe if it contains an arithmetic ! 64: operation, since that operation may trap. */ ! 65: switch (GET_CODE (op)) ! 66: { ! 67: case CONST_INT: ! 68: case LABEL_REF: ! 69: case SYMBOL_REF: ! 70: case CONST: ! 71: return 1; ! 72: ! 73: case REG: ! 74: return 1; ! 75: ! 76: case MEM: ! 77: return CONSTANT_ADDRESS_P (XEXP (op, 0)); ! 78: ! 79: /* We never need to negate or complement constants. */ ! 80: case NEG: ! 81: return (mode != SFmode && mode != DFmode); ! 82: case NOT: ! 83: case ZERO_EXTEND: ! 84: return 1; ! 85: ! 86: case EQ: ! 87: case NE: ! 88: case LT: ! 89: case GT: ! 90: case LE: ! 91: case GE: ! 92: case LTU: ! 93: case GTU: ! 94: case LEU: ! 95: case GEU: ! 96: case MINUS: ! 97: case PLUS: ! 98: return (mode != SFmode && mode != DFmode); ! 99: case AND: ! 100: case IOR: ! 101: case XOR: ! 102: case LSHIFT: ! 103: case ASHIFT: ! 104: case ASHIFTRT: ! 105: case LSHIFTRT: ! 106: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) ! 107: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) ! 108: return 0; ! 109: return 1; ! 110: ! 111: default: ! 112: return 0; ! 113: } ! 114: } ! 115: ! 116: /* Return 1 if REG is clobbered in IN. ! 117: Return 2 if REG is used in IN. ! 118: Return 3 if REG is both used and clobbered in IN. ! 119: Return 0 if neither. */ ! 120: ! 121: static int ! 122: reg_clobbered_p (reg, in) ! 123: rtx reg; ! 124: rtx in; ! 125: { ! 126: register enum rtx_code code; ! 127: ! 128: if (in == 0) ! 129: return 0; ! 130: ! 131: code = GET_CODE (in); ! 132: ! 133: if (code == SET || code == CLOBBER) ! 134: { ! 135: rtx dest = SET_DEST (in); ! 136: int set = 0; ! 137: int used = 0; ! 138: ! 139: while (GET_CODE (dest) == STRICT_LOW_PART ! 140: || GET_CODE (dest) == SUBREG ! 141: || GET_CODE (dest) == SIGN_EXTRACT ! 142: || GET_CODE (dest) == ZERO_EXTRACT) ! 143: dest = XEXP (dest, 0); ! 144: ! 145: if (dest == reg) ! 146: set = 1; ! 147: else if (GET_CODE (dest) == REG ! 148: && refers_to_regno_p (REGNO (reg), ! 149: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), ! 150: SET_DEST (in), 0)) ! 151: { ! 152: set = 1; ! 153: /* Anything that sets just part of the register ! 154: is considered using as well as setting it. ! 155: But note that a straight SUBREG of a single-word value ! 156: clobbers the entire value. */ ! 157: if (dest != SET_DEST (in) ! 158: && ! (GET_CODE (SET_DEST (in)) == SUBREG ! 159: || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest)))) ! 160: used = 1; ! 161: } ! 162: ! 163: if (code == SET) ! 164: { ! 165: if (set) ! 166: used = refers_to_regno_p (REGNO (reg), ! 167: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), ! 168: SET_SRC (in), 0); ! 169: else ! 170: used = refers_to_regno_p (REGNO (reg), ! 171: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), ! 172: in, 0); ! 173: } ! 174: ! 175: return set + used * 2; ! 176: } ! 177: ! 178: if (refers_to_regno_p (REGNO (reg), ! 179: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), ! 180: in, 0)) ! 181: return 2; ! 182: return 0; ! 183: } ! 184: ! 185: /* Return non-zero if OP can be written to without screwing up ! 186: GCC's model of what's going on. It is assumed that this operand ! 187: appears in the dest position of a SET insn in a conditional ! 188: branch's delay slot. AFTER is the label to start looking from. */ ! 189: int ! 190: operand_clobbered_before_used_after (op, after) ! 191: rtx op; ! 192: rtx after; ! 193: { ! 194: /* Just experimenting. */ ! 195: if (GET_CODE (op) == CC0) ! 196: return 1; ! 197: if (GET_CODE (op) == REG) ! 198: { ! 199: rtx insn; ! 200: ! 201: if (op == stack_pointer_rtx) ! 202: return 0; ! 203: ! 204: /* Scan forward from the label, to see if the value of OP ! 205: is clobbered before the first use. */ ! 206: ! 207: for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) ! 208: { ! 209: if (GET_CODE (insn) == NOTE) ! 210: continue; ! 211: if (GET_CODE (insn) == INSN ! 212: || GET_CODE (insn) == JUMP_INSN ! 213: || GET_CODE (insn) == CALL_INSN) ! 214: { ! 215: switch (reg_clobbered_p (op, PATTERN (insn))) ! 216: { ! 217: default: ! 218: return 0; ! 219: case 1: ! 220: return 1; ! 221: case 0: ! 222: break; ! 223: } ! 224: } ! 225: /* If we reach another label without clobbering OP, ! 226: then we cannot safely write it here. */ ! 227: else if (GET_CODE (insn) == CODE_LABEL) ! 228: return 0; ! 229: if (GET_CODE (insn) == JUMP_INSN) ! 230: { ! 231: if (condjump_p (insn)) ! 232: return 0; ! 233: /* This is a jump insn which has already ! 234: been mangled. We can't tell what it does. */ ! 235: if (GET_CODE (PATTERN (insn)) == PARALLEL) ! 236: return 0; ! 237: if (! JUMP_LABEL (insn)) ! 238: return 0; ! 239: /* Keep following jumps. */ ! 240: insn = JUMP_LABEL (insn); ! 241: } ! 242: } ! 243: return 1; ! 244: } ! 245: ! 246: /* In both of these cases, the first insn executed ! 247: for this op will be a orh whatever%h,%?r0,%?r31, ! 248: which is tolerable. */ ! 249: if (GET_CODE (op) == MEM) ! 250: return (CONSTANT_ADDRESS_P (XEXP (op, 0))); ! 251: ! 252: return 0; ! 253: } ! 254: ! 255: /* Return non-zero if this pattern, as a source to a "SET", ! 256: is known to yield an instruction of unit size. */ ! 257: int ! 258: single_insn_src_p (op, mode) ! 259: rtx op; ! 260: enum machine_mode mode; ! 261: { ! 262: switch (GET_CODE (op)) ! 263: { ! 264: case CONST_INT: ! 265: /* This is not always a single insn src, technically, ! 266: but output_delayed_branch knows how to deal with it. */ ! 267: return 1; ! 268: ! 269: case SYMBOL_REF: ! 270: case CONST: ! 271: /* This is not a single insn src, technically, ! 272: but output_delayed_branch knows how to deal with it. */ ! 273: return 1; ! 274: ! 275: case REG: ! 276: return 1; ! 277: ! 278: case MEM: ! 279: return 1; ! 280: ! 281: /* We never need to negate or complement constants. */ ! 282: case NEG: ! 283: return (mode != DFmode); ! 284: case NOT: ! 285: case ZERO_EXTEND: ! 286: return 1; ! 287: ! 288: case PLUS: ! 289: case MINUS: ! 290: /* Detect cases that require multiple instructions. */ ! 291: if (CONSTANT_P (XEXP (op, 1)) ! 292: && !(GET_CODE (XEXP (op, 1)) == CONST_INT ! 293: && SMALL_INT (XEXP (op, 1)))) ! 294: return 0; ! 295: case EQ: ! 296: case NE: ! 297: case LT: ! 298: case GT: ! 299: case LE: ! 300: case GE: ! 301: case LTU: ! 302: case GTU: ! 303: case LEU: ! 304: case GEU: ! 305: /* Not doing floating point, since they probably ! 306: take longer than the branch slot they might fill. */ ! 307: return (mode != SFmode && mode != DFmode); ! 308: ! 309: case AND: ! 310: if (GET_CODE (XEXP (op, 1)) == NOT) ! 311: { ! 312: rtx arg = XEXP (XEXP (op, 1), 0); ! 313: if (CONSTANT_P (arg) ! 314: && !(GET_CODE (arg) == CONST_INT ! 315: && (SMALL_INT (arg) ! 316: || INTVAL (arg) & 0xffff == 0))) ! 317: return 0; ! 318: } ! 319: case IOR: ! 320: case XOR: ! 321: /* Both small and round numbers take one instruction; ! 322: others take two. */ ! 323: if (CONSTANT_P (XEXP (op, 1)) ! 324: && !(GET_CODE (XEXP (op, 1)) == CONST_INT ! 325: && (SMALL_INT (XEXP (op, 1)) ! 326: || INTVAL (XEXP (op, 1)) & 0xffff == 0))) ! 327: return 0; ! 328: ! 329: case LSHIFT: ! 330: case ASHIFT: ! 331: case ASHIFTRT: ! 332: case LSHIFTRT: ! 333: return 1; ! 334: ! 335: case SUBREG: ! 336: if (SUBREG_WORD (op) != 0) ! 337: return 0; ! 338: return single_insn_src_p (SUBREG_REG (op), mode); ! 339: ! 340: /* Not doing floating point, since they probably ! 341: take longer than the branch slot they might fill. */ ! 342: case FLOAT_EXTEND: ! 343: case FLOAT_TRUNCATE: ! 344: case FLOAT: ! 345: case FIX: ! 346: case UNSIGNED_FLOAT: ! 347: case UNSIGNED_FIX: ! 348: return 0; ! 349: ! 350: default: ! 351: return 0; ! 352: } ! 353: } ! 354: ! 355: /* Return non-zero only if OP is a register of mode MODE, ! 356: or const0_rtx. */ ! 357: int ! 358: reg_or_0_operand (op, mode) ! 359: rtx op; ! 360: enum machine_mode mode; ! 361: { ! 362: return (op == const0_rtx || register_operand (op, mode) ! 363: || op == CONST0_RTX (mode)); ! 364: } ! 365: ! 366: /* Return truth value of whether OP can be used as an operands in a three ! 367: address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */ ! 368: ! 369: int ! 370: arith_operand (op, mode) ! 371: rtx op; ! 372: enum machine_mode mode; ! 373: { ! 374: return (register_operand (op, mode) ! 375: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); ! 376: } ! 377: ! 378: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */ ! 379: ! 380: int ! 381: logic_operand (op, mode) ! 382: rtx op; ! 383: enum machine_mode mode; ! 384: { ! 385: return (register_operand (op, mode) ! 386: || (GET_CODE (op) == CONST_INT && LOGIC_INT (op))); ! 387: } ! 388: ! 389: /* Return 1 if OP is a valid first operand for a shift insn of mode MODE. */ ! 390: ! 391: int ! 392: shift_operand (op, mode) ! 393: rtx op; ! 394: enum machine_mode mode; ! 395: { ! 396: return (register_operand (op, mode) ! 397: || (GET_CODE (op) == CONST_INT)); ! 398: } ! 399: ! 400: /* Return 1 if OP is a valid first operand for either a logical insn ! 401: or an add insn of mode MODE. */ ! 402: ! 403: int ! 404: compare_operand (op, mode) ! 405: rtx op; ! 406: enum machine_mode mode; ! 407: { ! 408: return (register_operand (op, mode) ! 409: || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op))); ! 410: } ! 411: ! 412: /* Return truth value of whether OP can be used as the 5-bit immediate ! 413: operand of a bte or btne insn. */ ! 414: ! 415: int ! 416: bte_operand (op, mode) ! 417: rtx op; ! 418: enum machine_mode mode; ! 419: { ! 420: return (register_operand (op, mode) ! 421: || (GET_CODE (op) == CONST_INT ! 422: && (unsigned) INTVAL (op) < 0x20)); ! 423: } ! 424: ! 425: /* Return 1 if OP is an indexed memory reference of mode MODE. */ ! 426: ! 427: int ! 428: indexed_operand (op, mode) ! 429: rtx op; ! 430: enum machine_mode mode; ! 431: { ! 432: return (GET_CODE (op) == MEM && GET_MODE (op) == mode ! 433: && GET_CODE (XEXP (op, 0)) == PLUS ! 434: && GET_MODE (XEXP (op, 0)) == SImode ! 435: && register_operand (XEXP (XEXP (op, 0), 0), SImode) ! 436: && register_operand (XEXP (XEXP (op, 0), 1), SImode)); ! 437: } ! 438: ! 439: /* Return 1 if OP is a suitable source operand for a load insn ! 440: with mode MODE. */ ! 441: ! 442: int ! 443: load_operand (op, mode) ! 444: rtx op; ! 445: enum machine_mode mode; ! 446: { ! 447: return (memory_operand (op, mode) || indexed_operand (op, mode)); ! 448: } ! 449: ! 450: /* Return truth value of whether OP is a integer which fits the ! 451: range constraining immediate operands in add/subtract insns. */ ! 452: ! 453: int ! 454: small_int (op, mode) ! 455: rtx op; ! 456: enum machine_mode mode; ! 457: { ! 458: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); ! 459: } ! 460: ! 461: /* Return truth value of whether OP is a integer which fits the ! 462: range constraining immediate operands in logic insns. */ ! 463: ! 464: int ! 465: logic_int (op, mode) ! 466: rtx op; ! 467: enum machine_mode mode; ! 468: { ! 469: return (GET_CODE (op) == CONST_INT && LOGIC_INT (op)); ! 470: } ! 471: ! 472: /* Test for a valid operand for a call instruction. ! 473: Don't allow the arg pointer register or virtual regs ! 474: since they may change into reg + const, which the patterns ! 475: can't handle yet. */ ! 476: ! 477: int ! 478: call_insn_operand (op, mode) ! 479: rtx op; ! 480: enum machine_mode mode; ! 481: { ! 482: if (GET_CODE (op) == MEM ! 483: && (CONSTANT_ADDRESS_P (XEXP (op, 0)) ! 484: || (GET_CODE (XEXP (op, 0)) == REG ! 485: && XEXP (op, 0) != arg_pointer_rtx ! 486: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER ! 487: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) ! 488: return 1; ! 489: return 0; ! 490: } ! 491: ! 492: /* Return the best assembler insn template ! 493: for moving operands[1] into operands[0] as a fullword. */ ! 494: ! 495: static char * ! 496: singlemove_string (operands) ! 497: rtx *operands; ! 498: { ! 499: if (GET_CODE (operands[0]) == MEM) ! 500: { ! 501: if (GET_CODE (operands[1]) != MEM) ! 502: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) ! 503: { ! 504: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 505: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 506: && cc_prev_status.mdep == XEXP (operands[0], 0))) ! 507: { ! 508: CC_STATUS_INIT; ! 509: output_asm_insn ("orh %h0,%?r0,%?r31", operands); ! 510: } ! 511: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 512: cc_status.mdep = XEXP (operands[0], 0); ! 513: return "st.l %r1,%L0(%?r31)"; ! 514: } ! 515: else ! 516: return "st.l %r1,%0"; ! 517: else ! 518: abort (); ! 519: #if 0 ! 520: { ! 521: rtx xoperands[2]; ! 522: ! 523: cc_status.flags &= ~CC_F0_IS_0; ! 524: xoperands[0] = gen_rtx (REG, SFmode, 32); ! 525: xoperands[1] = operands[1]; ! 526: output_asm_insn (singlemove_string (xoperands), xoperands); ! 527: xoperands[1] = xoperands[0]; ! 528: xoperands[0] = operands[0]; ! 529: output_asm_insn (singlemove_string (xoperands), xoperands); ! 530: return ""; ! 531: } ! 532: #endif ! 533: } ! 534: if (GET_CODE (operands[1]) == MEM) ! 535: { ! 536: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) ! 537: { ! 538: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 539: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 540: && cc_prev_status.mdep == XEXP (operands[1], 0))) ! 541: { ! 542: CC_STATUS_INIT; ! 543: output_asm_insn ("orh %h1,%?r0,%?r31", operands); ! 544: } ! 545: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 546: cc_status.mdep = XEXP (operands[1], 0); ! 547: return "ld.l %L1(%?r31),%0"; ! 548: } ! 549: return "ld.l %m1,%0"; ! 550: } ! 551: if (GET_CODE (operands[1]) == CONST_INT) ! 552: { ! 553: if (operands[1] == const0_rtx) ! 554: return "mov %?r0,%0"; ! 555: if((INTVAL (operands[1]) & 0xffff0000) == 0) ! 556: return "or %L1,%?r0,%0"; ! 557: if((INTVAL (operands[1]) & 0xffff8000) == 0xffff8000) ! 558: return "adds %1,%?r0,%0"; ! 559: if((INTVAL (operands[1]) & 0x0000ffff) == 0) ! 560: return "orh %H1,%?r0,%0"; ! 561: } ! 562: return "mov %1,%0"; ! 563: } ! 564: ! 565: /* Output assembler code to perform a doubleword move insn ! 566: with operands OPERANDS. */ ! 567: ! 568: char * ! 569: output_move_double (operands) ! 570: rtx *operands; ! 571: { ! 572: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 573: rtx latehalf[2]; ! 574: rtx addreg0 = 0, addreg1 = 0; ! 575: int highest_first = 0; ! 576: int no_addreg1_decrement = 0; ! 577: ! 578: /* First classify both operands. */ ! 579: ! 580: if (REG_P (operands[0])) ! 581: optype0 = REGOP; ! 582: else if (offsettable_memref_p (operands[0])) ! 583: optype0 = OFFSOP; ! 584: else if (GET_CODE (operands[0]) == MEM) ! 585: optype0 = MEMOP; ! 586: else ! 587: optype0 = RNDOP; ! 588: ! 589: if (REG_P (operands[1])) ! 590: optype1 = REGOP; ! 591: else if (CONSTANT_P (operands[1])) ! 592: optype1 = CNSTOP; ! 593: else if (offsettable_memref_p (operands[1])) ! 594: optype1 = OFFSOP; ! 595: else if (GET_CODE (operands[1]) == MEM) ! 596: optype1 = MEMOP; ! 597: else ! 598: optype1 = RNDOP; ! 599: ! 600: /* Check for the cases that the operand constraints are not ! 601: supposed to allow to happen. Abort if we get one, ! 602: because generating code for these cases is painful. */ ! 603: ! 604: if (optype0 == RNDOP || optype1 == RNDOP) ! 605: abort (); ! 606: ! 607: /* If an operand is an unoffsettable memory ref, find a register ! 608: we can increment temporarily to make it refer to the second word. */ ! 609: ! 610: if (optype0 == MEMOP) ! 611: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 612: ! 613: if (optype1 == MEMOP) ! 614: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 615: ! 616: /* ??? Perhaps in some cases move double words ! 617: if there is a spare pair of floating regs. */ ! 618: ! 619: /* Ok, we can do one word at a time. ! 620: Normally we do the low-numbered word first, ! 621: but if either operand is autodecrementing then we ! 622: do the high-numbered word first. ! 623: ! 624: In either case, set up in LATEHALF the operands to use ! 625: for the high-numbered word and in some cases alter the ! 626: operands in OPERANDS to be suitable for the low-numbered word. */ ! 627: ! 628: if (optype0 == REGOP) ! 629: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 630: else if (optype0 == OFFSOP) ! 631: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 632: else ! 633: latehalf[0] = operands[0]; ! 634: ! 635: if (optype1 == REGOP) ! 636: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 637: else if (optype1 == OFFSOP) ! 638: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 639: else if (optype1 == CNSTOP) ! 640: { ! 641: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 642: split_double (operands[1], &operands[1], &latehalf[1]); ! 643: else if (CONSTANT_P (operands[1])) ! 644: latehalf[1] = const0_rtx; ! 645: } ! 646: else ! 647: latehalf[1] = operands[1]; ! 648: ! 649: /* If the first move would clobber the source of the second one, ! 650: do them in the other order. ! 651: ! 652: RMS says "This happens only for registers; ! 653: such overlap can't happen in memory unless the user explicitly ! 654: sets it up, and that is an undefined circumstance." ! 655: ! 656: but it happens on the sparc when loading parameter registers, ! 657: so I am going to define that circumstance, and make it work ! 658: as expected. */ ! 659: ! 660: if (optype0 == REGOP && optype1 == REGOP ! 661: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 662: { ! 663: CC_STATUS_PARTIAL_INIT; ! 664: /* Make any unoffsettable addresses point at high-numbered word. */ ! 665: if (addreg0) ! 666: output_asm_insn ("adds 0x4,%0,%0", &addreg0); ! 667: if (addreg1) ! 668: output_asm_insn ("adds 0x4,%0,%0", &addreg1); ! 669: ! 670: /* Do that word. */ ! 671: output_asm_insn (singlemove_string (latehalf), latehalf); ! 672: ! 673: /* Undo the adds we just did. */ ! 674: if (addreg0) ! 675: output_asm_insn ("adds -0x4,%0,%0", &addreg0); ! 676: if (addreg1) ! 677: output_asm_insn ("adds -0x4,%0,%0", &addreg1); ! 678: ! 679: /* Do low-numbered word. */ ! 680: return singlemove_string (operands); ! 681: } ! 682: else if (optype0 == REGOP && optype1 != REGOP ! 683: && reg_overlap_mentioned_p (operands[0], operands[1])) ! 684: { ! 685: /* If both halves of dest are used in the src memory address, ! 686: add the two regs and put them in the low reg (operands[0]). ! 687: Then it works to load latehalf first. */ ! 688: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) ! 689: && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) ! 690: { ! 691: rtx xops[2]; ! 692: xops[0] = latehalf[0]; ! 693: xops[1] = operands[0]; ! 694: output_asm_insn ("adds %1,%0,%1", xops); ! 695: operands[1] = gen_rtx (MEM, DImode, operands[0]); ! 696: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 697: addreg1 = 0; ! 698: highest_first = 1; ! 699: } ! 700: /* Only one register in the dest is used in the src memory address, ! 701: and this is the first register of the dest, so we want to do ! 702: the late half first here also. */ ! 703: else if (! reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) ! 704: highest_first = 1; ! 705: /* Only one register in the dest is used in the src memory address, ! 706: and this is the second register of the dest, so we want to do ! 707: the late half last. If addreg1 is set, and addreg1 is the same ! 708: register as latehalf, then we must suppress the trailing decrement, ! 709: because it would clobber the value just loaded. */ ! 710: else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0])) ! 711: no_addreg1_decrement = 1; ! 712: } ! 713: ! 714: /* Normal case: do the two words, low-numbered first. ! 715: Overlap case (highest_first set): do high-numbered word first. */ ! 716: ! 717: if (! highest_first) ! 718: output_asm_insn (singlemove_string (operands), operands); ! 719: ! 720: CC_STATUS_PARTIAL_INIT; ! 721: /* Make any unoffsettable addresses point at high-numbered word. */ ! 722: if (addreg0) ! 723: output_asm_insn ("adds 0x4,%0,%0", &addreg0); ! 724: if (addreg1) ! 725: output_asm_insn ("adds 0x4,%0,%0", &addreg1); ! 726: ! 727: /* Do that word. */ ! 728: output_asm_insn (singlemove_string (latehalf), latehalf); ! 729: ! 730: /* Undo the adds we just did. */ ! 731: if (addreg0) ! 732: output_asm_insn ("adds -0x4,%0,%0", &addreg0); ! 733: if (addreg1 && !no_addreg1_decrement) ! 734: output_asm_insn ("adds -0x4,%0,%0", &addreg1); ! 735: ! 736: if (highest_first) ! 737: output_asm_insn (singlemove_string (operands), operands); ! 738: ! 739: return ""; ! 740: } ! 741: ! 742: char * ! 743: output_fp_move_double (operands) ! 744: rtx *operands; ! 745: { ! 746: /* If the source operand is any sort of zero, use f0 instead. */ ! 747: ! 748: if (operands[1] == CONST0_RTX (GET_MODE (operands[1]))) ! 749: operands[1] = gen_rtx (REG, DFmode, F0_REGNUM); ! 750: ! 751: if (FP_REG_P (operands[0])) ! 752: { ! 753: if (FP_REG_P (operands[1])) ! 754: return "fmov.dd %1,%0"; ! 755: if (GET_CODE (operands[1]) == REG) ! 756: { ! 757: output_asm_insn ("ixfr %1,%0", operands); ! 758: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); ! 759: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); ! 760: return "ixfr %1,%0"; ! 761: } ! 762: if (operands[1] == CONST0_RTX (DFmode)) ! 763: return "fmov.dd f0,%0"; ! 764: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) ! 765: { ! 766: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 767: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 768: && cc_prev_status.mdep == XEXP (operands[1], 0))) ! 769: { ! 770: CC_STATUS_INIT; ! 771: output_asm_insn ("orh %h1,%?r0,%?r31", operands); ! 772: } ! 773: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 774: cc_status.mdep = XEXP (operands[1], 0); ! 775: return "fld.d %L1(%?r31),%0"; ! 776: } ! 777: return "fld.d %1,%0"; ! 778: } ! 779: else if (FP_REG_P (operands[1])) ! 780: { ! 781: if (GET_CODE (operands[0]) == REG) ! 782: { ! 783: output_asm_insn ("fxfr %1,%0", operands); ! 784: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); ! 785: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); ! 786: return "fxfr %1,%0"; ! 787: } ! 788: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) ! 789: { ! 790: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 791: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 792: && cc_prev_status.mdep == XEXP (operands[0], 0))) ! 793: { ! 794: CC_STATUS_INIT; ! 795: output_asm_insn ("orh %h0,%?r0,%?r31", operands); ! 796: } ! 797: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 798: cc_status.mdep = XEXP (operands[0], 0); ! 799: return "fst.d %1,%L0(%?r31)"; ! 800: } ! 801: return "fst.d %1,%0"; ! 802: } ! 803: else ! 804: abort (); ! 805: /* NOTREACHED */ ! 806: return NULL; ! 807: } ! 808: ! 809: /* Return a REG that occurs in ADDR with coefficient 1. ! 810: ADDR can be effectively incremented by incrementing REG. */ ! 811: ! 812: static rtx ! 813: find_addr_reg (addr) ! 814: rtx addr; ! 815: { ! 816: while (GET_CODE (addr) == PLUS) ! 817: { ! 818: if (GET_CODE (XEXP (addr, 0)) == REG) ! 819: addr = XEXP (addr, 0); ! 820: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 821: addr = XEXP (addr, 1); ! 822: else if (CONSTANT_P (XEXP (addr, 0))) ! 823: addr = XEXP (addr, 1); ! 824: else if (CONSTANT_P (XEXP (addr, 1))) ! 825: addr = XEXP (addr, 0); ! 826: else ! 827: abort (); ! 828: } ! 829: if (GET_CODE (addr) == REG) ! 830: return addr; ! 831: abort (); ! 832: /* NOTREACHED */ ! 833: return NULL; ! 834: } ! 835: ! 836: /* Return a template for a load instruction with mode MODE and ! 837: arguments from the string ARGS. ! 838: ! 839: This string is in static storage. */ ! 840: ! 841: static char * ! 842: load_opcode (mode, args, reg) ! 843: enum machine_mode mode; ! 844: char *args; ! 845: rtx reg; ! 846: { ! 847: static char buf[30]; ! 848: char *opcode; ! 849: ! 850: switch (mode) ! 851: { ! 852: case QImode: ! 853: opcode = "ld.b"; ! 854: break; ! 855: ! 856: case HImode: ! 857: opcode = "ld.s"; ! 858: break; ! 859: ! 860: case SImode: ! 861: case SFmode: ! 862: if (FP_REG_P (reg)) ! 863: opcode = "fld.l"; ! 864: else ! 865: opcode = "ld.l"; ! 866: break; ! 867: ! 868: case DImode: ! 869: if (!FP_REG_P (reg)) ! 870: abort (); ! 871: case DFmode: ! 872: opcode = "fld.d"; ! 873: break; ! 874: ! 875: default: ! 876: abort (); ! 877: } ! 878: ! 879: sprintf (buf, "%s %s", opcode, args); ! 880: return buf; ! 881: } ! 882: ! 883: /* Return a template for a store instruction with mode MODE and ! 884: arguments from the string ARGS. ! 885: ! 886: This string is in static storage. */ ! 887: ! 888: static char * ! 889: store_opcode (mode, args, reg) ! 890: enum machine_mode mode; ! 891: char *args; ! 892: rtx reg; ! 893: { ! 894: static char buf[30]; ! 895: char *opcode; ! 896: ! 897: switch (mode) ! 898: { ! 899: case QImode: ! 900: opcode = "st.b"; ! 901: break; ! 902: ! 903: case HImode: ! 904: opcode = "st.s"; ! 905: break; ! 906: ! 907: case SImode: ! 908: case SFmode: ! 909: if (FP_REG_P (reg)) ! 910: opcode = "fst.l"; ! 911: else ! 912: opcode = "st.l"; ! 913: break; ! 914: ! 915: case DImode: ! 916: if (!FP_REG_P (reg)) ! 917: abort (); ! 918: case DFmode: ! 919: opcode = "fst.d"; ! 920: break; ! 921: ! 922: default: ! 923: abort (); ! 924: } ! 925: ! 926: sprintf (buf, "%s %s", opcode, args); ! 927: return buf; ! 928: } ! 929: ! 930: /* Output a store-in-memory whose operands are OPERANDS[0,1]. ! 931: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. ! 932: ! 933: This function returns a template for an insn. ! 934: This is in static storage. ! 935: ! 936: It may also output some insns directly. ! 937: It may alter the values of operands[0] and operands[1]. */ ! 938: ! 939: char * ! 940: output_store (operands) ! 941: rtx *operands; ! 942: { ! 943: enum machine_mode mode = GET_MODE (operands[0]); ! 944: rtx address = XEXP (operands[0], 0); ! 945: char *string; ! 946: ! 947: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 948: cc_status.mdep = address; ! 949: ! 950: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 951: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 952: && address == cc_prev_status.mdep)) ! 953: { ! 954: CC_STATUS_INIT; ! 955: output_asm_insn ("orh %h0,%?r0,%?r31", operands); ! 956: cc_prev_status.mdep = address; ! 957: } ! 958: ! 959: /* Store zero in two parts when appropriate. */ ! 960: if (mode == DFmode && operands[1] == CONST0_RTX (DFmode)) ! 961: return store_opcode (DFmode, "%r1,%L0(%?r31)", operands[1]); ! 962: ! 963: /* Code below isn't smart enough to move a doubleword in two parts, ! 964: so use output_move_double to do that in the cases that require it. */ ! 965: if ((mode == DImode || mode == DFmode) ! 966: && ! FP_REG_P (operands[1])) ! 967: return output_move_double (operands); ! 968: ! 969: return store_opcode (mode, "%r1,%L0(%?r31)", operands[1]); ! 970: } ! 971: ! 972: /* Output a load-from-memory whose operands are OPERANDS[0,1]. ! 973: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. ! 974: ! 975: This function returns a template for an insn. ! 976: This is in static storage. ! 977: ! 978: It may also output some insns directly. ! 979: It may alter the values of operands[0] and operands[1]. */ ! 980: ! 981: char * ! 982: output_load (operands) ! 983: rtx *operands; ! 984: { ! 985: enum machine_mode mode = GET_MODE (operands[0]); ! 986: rtx address = XEXP (operands[1], 0); ! 987: ! 988: /* We don't bother trying to see if we know %hi(address). ! 989: This is because we are doing a load, and if we know the ! 990: %hi value, we probably also know that value in memory. */ ! 991: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; ! 992: cc_status.mdep = address; ! 993: ! 994: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 995: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 996: && address == cc_prev_status.mdep ! 997: && cc_prev_status.mdep == cc_status.mdep)) ! 998: { ! 999: CC_STATUS_INIT; ! 1000: output_asm_insn ("orh %h1,%?r0,%?r31", operands); ! 1001: cc_prev_status.mdep = address; ! 1002: } ! 1003: ! 1004: /* Code below isn't smart enough to move a doubleword in two parts, ! 1005: so use output_move_double to do that in the cases that require it. */ ! 1006: if ((mode == DImode || mode == DFmode) ! 1007: && ! FP_REG_P (operands[0])) ! 1008: return output_move_double (operands); ! 1009: ! 1010: return load_opcode (mode, "%L1(%?r31),%0", operands[0]); ! 1011: } ! 1012: ! 1013: #if 0 ! 1014: /* Load the address specified by OPERANDS[3] into the register ! 1015: specified by OPERANDS[0]. ! 1016: ! 1017: OPERANDS[3] may be the result of a sum, hence it could either be: ! 1018: ! 1019: (1) CONST ! 1020: (2) REG ! 1021: (2) REG + CONST_INT ! 1022: (3) REG + REG + CONST_INT ! 1023: (4) REG + REG (special case of 3). ! 1024: ! 1025: Note that (3) is not a legitimate address. ! 1026: All cases are handled here. */ ! 1027: ! 1028: void ! 1029: output_load_address (operands) ! 1030: rtx *operands; ! 1031: { ! 1032: rtx base, offset; ! 1033: ! 1034: if (CONSTANT_P (operands[3])) ! 1035: { ! 1036: output_asm_insn ("mov %3,%0", operands); ! 1037: return; ! 1038: } ! 1039: ! 1040: if (REG_P (operands[3])) ! 1041: { ! 1042: if (REGNO (operands[0]) != REGNO (operands[3])) ! 1043: output_asm_insn ("shl %?r0,%3,%0", operands); ! 1044: return; ! 1045: } ! 1046: ! 1047: if (GET_CODE (operands[3]) != PLUS) ! 1048: abort (); ! 1049: ! 1050: base = XEXP (operands[3], 0); ! 1051: offset = XEXP (operands[3], 1); ! 1052: ! 1053: if (GET_CODE (base) == CONST_INT) ! 1054: { ! 1055: rtx tmp = base; ! 1056: base = offset; ! 1057: offset = tmp; ! 1058: } ! 1059: ! 1060: if (GET_CODE (offset) != CONST_INT) ! 1061: { ! 1062: /* Operand is (PLUS (REG) (REG)). */ ! 1063: base = operands[3]; ! 1064: offset = const0_rtx; ! 1065: } ! 1066: ! 1067: if (REG_P (base)) ! 1068: { ! 1069: operands[6] = base; ! 1070: operands[7] = offset; ! 1071: CC_STATUS_PARTIAL_INIT; ! 1072: if (SMALL_INT (offset)) ! 1073: output_asm_insn ("adds %7,%6,%0", operands); ! 1074: else ! 1075: output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands); ! 1076: } ! 1077: else if (GET_CODE (base) == PLUS) ! 1078: { ! 1079: operands[6] = XEXP (base, 0); ! 1080: operands[7] = XEXP (base, 1); ! 1081: operands[8] = offset; ! 1082: ! 1083: CC_STATUS_PARTIAL_INIT; ! 1084: if (SMALL_INT (offset)) ! 1085: output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands); ! 1086: else ! 1087: output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands); ! 1088: } ! 1089: else ! 1090: abort (); ! 1091: } ! 1092: #endif ! 1093: ! 1094: /* Output code to place a size count SIZE in register REG. ! 1095: Because block moves are pipelined, we don't include the ! 1096: first element in the transfer of SIZE to REG. ! 1097: For this, we subtract ALIGN. (Actually, I think it is not ! 1098: right to subtract on this machine, so right now we don't.) */ ! 1099: ! 1100: static void ! 1101: output_size_for_block_move (size, reg, align) ! 1102: rtx size, reg, align; ! 1103: { ! 1104: rtx xoperands[3]; ! 1105: ! 1106: xoperands[0] = reg; ! 1107: xoperands[1] = size; ! 1108: xoperands[2] = align; ! 1109: ! 1110: #if 1 ! 1111: cc_status.flags &= ~ CC_KNOW_HI_R31; ! 1112: output_asm_insn (singlemove_string (xoperands), xoperands); ! 1113: #else ! 1114: if (GET_CODE (size) == REG) ! 1115: output_asm_insn ("sub %2,%1,%0", xoperands); ! 1116: else ! 1117: { ! 1118: xoperands[1] ! 1119: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); ! 1120: cc_status.flags &= ~ CC_KNOW_HI_R31; ! 1121: output_asm_insn ("mov %1,%0", xoperands); ! 1122: } ! 1123: #endif ! 1124: } ! 1125: ! 1126: /* Emit code to perform a block move. ! 1127: ! 1128: OPERANDS[0] is the destination. ! 1129: OPERANDS[1] is the source. ! 1130: OPERANDS[2] is the size. ! 1131: OPERANDS[3] is the known safe alignment. ! 1132: OPERANDS[4..6] are pseudos we can safely clobber as temps. */ ! 1133: ! 1134: char * ! 1135: output_block_move (operands) ! 1136: rtx *operands; ! 1137: { ! 1138: /* A vector for our computed operands. Note that load_output_address ! 1139: makes use of (and can clobber) up to the 8th element of this vector. */ ! 1140: rtx xoperands[10]; ! 1141: rtx zoperands[10]; ! 1142: static int movstrsi_label = 0; ! 1143: int i, j; ! 1144: rtx temp1 = operands[4]; ! 1145: rtx alignrtx = operands[3]; ! 1146: int align = INTVAL (alignrtx); ! 1147: int chunk_size; ! 1148: ! 1149: xoperands[0] = operands[0]; ! 1150: xoperands[1] = operands[1]; ! 1151: xoperands[2] = temp1; ! 1152: ! 1153: /* We can't move more than four bytes at a time ! 1154: because we have only one register to move them through. */ ! 1155: if (align > 4) ! 1156: { ! 1157: align = 4; ! 1158: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); ! 1159: } ! 1160: ! 1161: /* Recognize special cases of block moves. These occur ! 1162: when GNU C++ is forced to treat something as BLKmode ! 1163: to keep it in memory, when its mode could be represented ! 1164: with something smaller. ! 1165: ! 1166: We cannot do this for global variables, since we don't know ! 1167: what pages they don't cross. Sigh. */ ! 1168: if (GET_CODE (operands[2]) == CONST_INT ! 1169: && ! CONSTANT_ADDRESS_P (operands[0]) ! 1170: && ! CONSTANT_ADDRESS_P (operands[1])) ! 1171: { ! 1172: int size = INTVAL (operands[2]); ! 1173: rtx op0 = xoperands[0]; ! 1174: rtx op1 = xoperands[1]; ! 1175: ! 1176: if ((align & 3) == 0 && (size & 3) == 0 && (size >> 2) <= 16) ! 1177: { ! 1178: if (memory_address_p (SImode, plus_constant (op0, size)) ! 1179: && memory_address_p (SImode, plus_constant (op1, size))) ! 1180: { ! 1181: cc_status.flags &= ~CC_KNOW_HI_R31; ! 1182: for (i = (size>>2)-1; i >= 0; i--) ! 1183: { ! 1184: xoperands[0] = plus_constant (op0, i * 4); ! 1185: xoperands[1] = plus_constant (op1, i * 4); ! 1186: output_asm_insn ("ld.l %a1,%?r31\n\tst.l %?r31,%a0", ! 1187: xoperands); ! 1188: } ! 1189: return ""; ! 1190: } ! 1191: } ! 1192: else if ((align & 1) == 0 && (size & 1) == 0 && (size >> 1) <= 16) ! 1193: { ! 1194: if (memory_address_p (HImode, plus_constant (op0, size)) ! 1195: && memory_address_p (HImode, plus_constant (op1, size))) ! 1196: { ! 1197: cc_status.flags &= ~CC_KNOW_HI_R31; ! 1198: for (i = (size>>1)-1; i >= 0; i--) ! 1199: { ! 1200: xoperands[0] = plus_constant (op0, i * 2); ! 1201: xoperands[1] = plus_constant (op1, i * 2); ! 1202: output_asm_insn ("ld.s %a1,%?r31\n\tst.s %?r31,%a0", ! 1203: xoperands); ! 1204: } ! 1205: return ""; ! 1206: } ! 1207: } ! 1208: else if (size <= 16) ! 1209: { ! 1210: if (memory_address_p (QImode, plus_constant (op0, size)) ! 1211: && memory_address_p (QImode, plus_constant (op1, size))) ! 1212: { ! 1213: cc_status.flags &= ~CC_KNOW_HI_R31; ! 1214: for (i = size-1; i >= 0; i--) ! 1215: { ! 1216: xoperands[0] = plus_constant (op0, i); ! 1217: xoperands[1] = plus_constant (op1, i); ! 1218: output_asm_insn ("ld.b %a1,%?r31\n\tst.b %?r31,%a0", ! 1219: xoperands); ! 1220: } ! 1221: return ""; ! 1222: } ! 1223: } ! 1224: } ! 1225: ! 1226: /* Since we clobber untold things, nix the condition codes. */ ! 1227: CC_STATUS_INIT; ! 1228: ! 1229: /* This is the size of the transfer. ! 1230: Either use the register which already contains the size, ! 1231: or use a free register (used by no operands). */ ! 1232: output_size_for_block_move (operands[2], operands[4], alignrtx); ! 1233: ! 1234: #if 0 ! 1235: /* Also emit code to decrement the size value by ALIGN. */ ! 1236: zoperands[0] = operands[0]; ! 1237: zoperands[3] = plus_constant (operands[0], align); ! 1238: output_load_address (zoperands); ! 1239: #endif ! 1240: ! 1241: /* Generate number for unique label. */ ! 1242: ! 1243: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1244: ! 1245: /* Calculate the size of the chunks we will be trying to move first. */ ! 1246: ! 1247: #if 0 ! 1248: if ((align & 3) == 0) ! 1249: chunk_size = 4; ! 1250: else if ((align & 1) == 0) ! 1251: chunk_size = 2; ! 1252: else ! 1253: #endif ! 1254: chunk_size = 1; ! 1255: ! 1256: /* Copy the increment (negative) to a register for bla insn. */ ! 1257: ! 1258: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - chunk_size); ! 1259: xoperands[5] = operands[5]; ! 1260: output_asm_insn ("adds %4,%?r0,%5", xoperands); ! 1261: ! 1262: /* Predecrement the loop counter. This happens again also in the `bla' ! 1263: instruction which precedes the loop, but we need to have it done ! 1264: two times before we enter the loop because of the bizarre semantics ! 1265: of the bla instruction. */ ! 1266: ! 1267: output_asm_insn ("adds %5,%2,%2", xoperands); ! 1268: ! 1269: /* Check for the case where the original count was less than or equal to ! 1270: zero. Avoid going through the loop at all if the original count was ! 1271: indeed less than or equal to zero. Note that we treat the count as ! 1272: if it were a signed 32-bit quantity here, rather than an unsigned one, ! 1273: even though we really shouldn't. We have to do this because of the ! 1274: semantics of the `ble' instruction, which assume that the count is ! 1275: a signed 32-bit value. Anyway, in practice it won't matter because ! 1276: nobody is going to try to do a memcpy() of more than half of the ! 1277: entire address space (i.e. 2 gigabytes) anyway. */ ! 1278: ! 1279: output_asm_insn ("bc .Le%3", xoperands); ! 1280: ! 1281: /* Make available a register which is a temporary. */ ! 1282: ! 1283: xoperands[6] = operands[6]; ! 1284: ! 1285: /* Now the actual loop. ! 1286: In xoperands, elements 1 and 0 are the input and output vectors. ! 1287: Element 2 is the loop index. Element 5 is the increment. */ ! 1288: ! 1289: output_asm_insn ("subs %1,%5,%1", xoperands); ! 1290: output_asm_insn ("bla %5,%2,.Lm%3", xoperands); ! 1291: output_asm_insn ("adds %0,%2,%6", xoperands); ! 1292: output_asm_insn ("\n.Lm%3:", xoperands); /* Label for bla above. */ ! 1293: output_asm_insn ("\n.Ls%3:", xoperands); /* Loop start label. */ ! 1294: output_asm_insn ("adds %5,%6,%6", xoperands); ! 1295: ! 1296: /* NOTE: The code here which is supposed to handle the cases where the ! 1297: sources and destinations are known to start on a 4 or 2 byte boundary ! 1298: are currently broken. They fail to do anything about the overflow ! 1299: bytes which might still need to be copied even after we have copied ! 1300: some number of words or halfwords. Thus, for now we use the lowest ! 1301: common denominator, i.e. the code which just copies some number of ! 1302: totally unaligned individual bytes. (See the calculation of ! 1303: chunk_size above. */ ! 1304: ! 1305: if (chunk_size == 4) ! 1306: { ! 1307: output_asm_insn ("ld.l %2(%1),%?r31", xoperands); ! 1308: output_asm_insn ("bla %5,%2,.Ls%3", xoperands); ! 1309: output_asm_insn ("st.l %?r31,8(%6)", xoperands); ! 1310: } ! 1311: else if (chunk_size == 2) ! 1312: { ! 1313: output_asm_insn ("ld.s %2(%1),%?r31", xoperands); ! 1314: output_asm_insn ("bla %5,%2,.Ls%3", xoperands); ! 1315: output_asm_insn ("st.s %?r31,4(%6)", xoperands); ! 1316: } ! 1317: else /* chunk_size == 1 */ ! 1318: { ! 1319: output_asm_insn ("ld.b %2(%1),%?r31", xoperands); ! 1320: output_asm_insn ("bla %5,%2,.Ls%3", xoperands); ! 1321: output_asm_insn ("st.b %?r31,2(%6)", xoperands); ! 1322: } ! 1323: output_asm_insn ("\n.Le%3:", xoperands); /* Here if count <= 0. */ ! 1324: ! 1325: return ""; ! 1326: } ! 1327: ! 1328: /* Output a delayed branch insn with the delay insn in its ! 1329: branch slot. The delayed branch insn template is in TEMPLATE, ! 1330: with operands OPERANDS. The insn in its delay slot is INSN. ! 1331: ! 1332: As a special case, since we know that all memory transfers are via ! 1333: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory ! 1334: reference around the branch as ! 1335: ! 1336: orh ha%x,%?r0,%?r31 ! 1337: b ... ! 1338: ld/st l%x(%?r31),... ! 1339: ! 1340: As another special case, we handle loading (SYMBOL_REF ...) and ! 1341: other large constants around branches as well: ! 1342: ! 1343: orh h%x,%?r0,%0 ! 1344: b ... ! 1345: or l%x,%0,%1 ! 1346: ! 1347: */ ! 1348: ! 1349: char * ! 1350: output_delayed_branch (template, operands, insn) ! 1351: char *template; ! 1352: rtx *operands; ! 1353: rtx insn; ! 1354: { ! 1355: rtx src = XVECEXP (PATTERN (insn), 0, 1); ! 1356: rtx dest = XVECEXP (PATTERN (insn), 0, 0); ! 1357: ! 1358: /* See if we are doing some branch together with setting some register ! 1359: to some 32-bit value which does (or may) have some of the high-order ! 1360: 16 bits set. If so, we need to set the register in two stages. One ! 1361: stage must be done before the branch, and the other one can be done ! 1362: in the delay slot. */ ! 1363: ! 1364: if ( (GET_CODE (src) == CONST_INT ! 1365: && ((unsigned) INTVAL (src) & (unsigned) 0xffff0000) != (unsigned) 0) ! 1366: || (GET_CODE (src) == SYMBOL_REF) ! 1367: || (GET_CODE (src) == LABEL_REF) ! 1368: || (GET_CODE (src) == CONST)) ! 1369: { ! 1370: rtx xoperands[2]; ! 1371: xoperands[0] = dest; ! 1372: xoperands[1] = src; ! 1373: ! 1374: CC_STATUS_PARTIAL_INIT; ! 1375: /* Output the `orh' insn. */ ! 1376: output_asm_insn ("orh %H1,%?r0,%0", xoperands); ! 1377: ! 1378: /* Output the branch instruction next. */ ! 1379: output_asm_insn (template, operands); ! 1380: ! 1381: /* Now output the `or' insn. */ ! 1382: output_asm_insn ("or %L1,%0,%0", xoperands); ! 1383: } ! 1384: else if ((GET_CODE (src) == MEM ! 1385: && CONSTANT_ADDRESS_P (XEXP (src, 0))) ! 1386: || (GET_CODE (dest) == MEM ! 1387: && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) ! 1388: { ! 1389: rtx xoperands[2]; ! 1390: char *split_template; ! 1391: xoperands[0] = dest; ! 1392: xoperands[1] = src; ! 1393: ! 1394: /* Output the `orh' insn. */ ! 1395: if (GET_CODE (src) == MEM) ! 1396: { ! 1397: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 1398: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 1399: && cc_prev_status.mdep == XEXP (operands[1], 0))) ! 1400: { ! 1401: CC_STATUS_INIT; ! 1402: output_asm_insn ("orh %h1,%?r0,%?r31", xoperands); ! 1403: } ! 1404: split_template = load_opcode (GET_MODE (dest), ! 1405: "%L1(%?r31),%0", dest); ! 1406: } ! 1407: else ! 1408: { ! 1409: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) ! 1410: && (cc_prev_status.flags & CC_HI_R31_ADJ) ! 1411: && cc_prev_status.mdep == XEXP (operands[0], 0))) ! 1412: { ! 1413: CC_STATUS_INIT; ! 1414: output_asm_insn ("orh %h0,%?r0,%?r31", xoperands); ! 1415: } ! 1416: split_template = store_opcode (GET_MODE (dest), ! 1417: "%r1,%L0(%?r31)", src); ! 1418: } ! 1419: ! 1420: /* Output the branch instruction next. */ ! 1421: output_asm_insn (template, operands); ! 1422: ! 1423: /* Now output the load or store. ! 1424: No need to do a CC_STATUS_INIT, because we are branching anyway. */ ! 1425: output_asm_insn (split_template, xoperands); ! 1426: } ! 1427: else ! 1428: { ! 1429: int insn_code_number; ! 1430: rtx pat = gen_rtx (SET, VOIDmode, dest, src); ! 1431: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); ! 1432: int i; ! 1433: ! 1434: /* Output the branch instruction first. */ ! 1435: output_asm_insn (template, operands); ! 1436: ! 1437: /* Now recognize the insn which we put in its delay slot. ! 1438: We must do this after outputting the branch insn, ! 1439: since operands may just be a pointer to `recog_operand'. */ ! 1440: INSN_CODE (delay_insn) = insn_code_number = recog (pat, delay_insn); ! 1441: if (insn_code_number == -1) ! 1442: abort (); ! 1443: ! 1444: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 1445: { ! 1446: if (GET_CODE (recog_operand[i]) == SUBREG) ! 1447: recog_operand[i] = alter_subreg (recog_operand[i]); ! 1448: } ! 1449: ! 1450: insn_extract (delay_insn); ! 1451: if (! constrain_operands (insn_code_number, 1)) ! 1452: fatal_insn_not_found (delay_insn); ! 1453: ! 1454: template = insn_template[insn_code_number]; ! 1455: if (template == 0) ! 1456: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); ! 1457: output_asm_insn (template, recog_operand); ! 1458: } ! 1459: CC_STATUS_INIT; ! 1460: return ""; ! 1461: } ! 1462: ! 1463: /* Output a newly constructed insn DELAY_INSN. */ ! 1464: char * ! 1465: output_delay_insn (delay_insn) ! 1466: rtx delay_insn; ! 1467: { ! 1468: char *template; ! 1469: int insn_code_number; ! 1470: int i; ! 1471: ! 1472: /* Now recognize the insn which we put in its delay slot. ! 1473: We must do this after outputting the branch insn, ! 1474: since operands may just be a pointer to `recog_operand'. */ ! 1475: insn_code_number = recog_memoized (delay_insn); ! 1476: if (insn_code_number == -1) ! 1477: abort (); ! 1478: ! 1479: /* Extract the operands of this delay insn. */ ! 1480: INSN_CODE (delay_insn) = insn_code_number; ! 1481: insn_extract (delay_insn); ! 1482: ! 1483: /* It is possible that this insn has not been properly scanned by final ! 1484: yet. If this insn's operands don't appear in the peephole's ! 1485: actual operands, then they won't be fixed up by final, so we ! 1486: make sure they get fixed up here. -- This is a kludge. */ ! 1487: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 1488: { ! 1489: if (GET_CODE (recog_operand[i]) == SUBREG) ! 1490: recog_operand[i] = alter_subreg (recog_operand[i]); ! 1491: } ! 1492: ! 1493: #ifdef REGISTER_CONSTRAINTS ! 1494: if (! constrain_operands (insn_code_number)) ! 1495: abort (); ! 1496: #endif ! 1497: ! 1498: cc_prev_status = cc_status; ! 1499: ! 1500: /* Update `cc_status' for this instruction. ! 1501: The instruction's output routine may change it further. ! 1502: If the output routine for a jump insn needs to depend ! 1503: on the cc status, it should look at cc_prev_status. */ ! 1504: ! 1505: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); ! 1506: ! 1507: /* Now get the template for what this insn would ! 1508: have been, without the branch. */ ! 1509: ! 1510: template = insn_template[insn_code_number]; ! 1511: if (template == 0) ! 1512: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); ! 1513: output_asm_insn (template, recog_operand); ! 1514: return ""; ! 1515: } ! 1516: ! 1517: /* Special routine to convert an SFmode value represented as a ! 1518: CONST_DOUBLE into its equivalent unsigned long bit pattern. ! 1519: We convert the value from a double precision floating-point ! 1520: value to single precision first, and thence to a bit-wise ! 1521: equivalent unsigned long value. This routine is used when ! 1522: generating an immediate move of an SFmode value directly ! 1523: into a general register because the svr4 assembler doesn't ! 1524: grok floating literals in instruction operand contexts. */ ! 1525: ! 1526: unsigned long ! 1527: sfmode_constant_to_ulong (x) ! 1528: rtx x; ! 1529: { ! 1530: REAL_VALUE_TYPE d; ! 1531: union { float f; unsigned long i; } u2; ! 1532: ! 1533: if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != SFmode) ! 1534: abort (); ! 1535: ! 1536: #if TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT ! 1537: error IEEE emulation needed ! 1538: #endif ! 1539: REAL_VALUE_FROM_CONST_DOUBLE (d, x); ! 1540: u2.f = d; ! 1541: return u2.i; ! 1542: } ! 1543: ! 1544: /* This function generates the assembly code for function entry. ! 1545: The macro FUNCTION_PROLOGUE in i860.h is defined to call this function. ! 1546: ! 1547: ASM_FILE is a stdio stream to output the code to. ! 1548: SIZE is an int: how many units of temporary storage to allocate. ! 1549: ! 1550: Refer to the array `regs_ever_live' to determine which registers ! 1551: to save; `regs_ever_live[I]' is nonzero if register number I ! 1552: is ever used in the function. This macro is responsible for ! 1553: knowing which registers should not be saved even if used. ! 1554: ! 1555: NOTE: `frame_lower_bytes' is the count of bytes which will lie ! 1556: between the new `fp' value and the new `sp' value after the ! 1557: prologue is done. `frame_upper_bytes' is the count of bytes ! 1558: that will lie between the new `fp' and the *old* `sp' value ! 1559: after the new `fp' is setup (in the prologue). The upper ! 1560: part of each frame always includes at least 2 words (8 bytes) ! 1561: to hold the saved frame pointer and the saved return address. ! 1562: ! 1563: The svr4 ABI for the i860 now requires that the values of the ! 1564: stack pointer and frame pointer registers be kept aligned to ! 1565: 16-byte boundaries at all times. We obey that restriction here. ! 1566: ! 1567: The svr4 ABI for the i860 is entirely vague when it comes to specifying ! 1568: exactly where the "preserved" registers should be saved. The native ! 1569: svr4 C compiler I now have doesn't help to clarify the requirements ! 1570: very much because it is plainly out-of-date and non-ABI-compliant ! 1571: (in at least one important way, i.e. how it generates function ! 1572: epilogues). ! 1573: ! 1574: The native svr4 C compiler saves the "preserved" registers (i.e. ! 1575: r4-r15 and f2-f7) in the lower part of a frame (i.e. at negative ! 1576: offsets from the frame pointer). ! 1577: ! 1578: Previous versions of GCC also saved the "preserved" registers in the ! 1579: "negative" part of the frame, but they saved them using positive ! 1580: offsets from the (adjusted) stack pointer (after it had been adjusted ! 1581: to allocate space for the new frame). That's just plain wrong ! 1582: because if the current function calls alloca(), the stack pointer ! 1583: will get moved, and it will be impossible to restore the registers ! 1584: properly again after that. ! 1585: ! 1586: Both compilers handled parameter registers (i.e. r16-r27 and f8-f15) ! 1587: by copying their values either into various "preserved" registers or ! 1588: into stack slots in the lower part of the current frame (as seemed ! 1589: appropriate, depending upon subsequent usage of these values). ! 1590: ! 1591: Here we want to save the preserved registers at some offset from the ! 1592: frame pointer register so as to avoid any possible problems arising ! 1593: from calls to alloca(). We can either save them at small positive ! 1594: offsets from the frame pointer, or at small negative offsets from ! 1595: the frame pointer. If we save them at small negative offsets from ! 1596: the frame pointer (i.e. in the lower part of the frame) then we ! 1597: must tell the rest of GCC (via STARTING_FRAME_OFFSET) exactly how ! 1598: many bytes of space we plan to use in the lower part of the frame ! 1599: for this purpose. Since other parts of the compiler reference the ! 1600: value of STARTING_FRAME_OFFSET long before final() calls this function, ! 1601: we would have to go ahead and assume the worst-case storage requirements ! 1602: for saving all of the "preserved" registers (and use that number, i.e. ! 1603: `80', to define STARTING_FRAME_OFFSET) if we wanted to save them in ! 1604: the lower part of the frame. That could potentially be very wasteful, ! 1605: and that wastefulness could really hamper people compiling for embedded ! 1606: i860 targets with very tight limits on stack space. Thus, we choose ! 1607: here to save the preserved registers in the upper part of the ! 1608: frame, so that we can decide at the very last minute how much (or how ! 1609: little) space we must allocate for this purpose. ! 1610: ! 1611: To satisfy the needs of the svr4 ABI "tdesc" scheme, preserved ! 1612: registers must always be saved so that the saved values of registers ! 1613: with higher numbers are at higher addresses. We obey that restriction ! 1614: here. ! 1615: ! 1616: There are two somewhat different ways that you can generate prologues ! 1617: here... i.e. pedantically ABI-compliant, and the "other" way. The ! 1618: "other" way is more consistent with what is currently generated by the ! 1619: "native" svr4 C compiler for the i860. That's important if you want ! 1620: to use the current (as of 8/91) incarnation of svr4 SDB for the i860. ! 1621: The SVR4 SDB for the i860 insists on having function prologues be ! 1622: non-ABI-compliant! ! 1623: ! 1624: To get fully ABI-compliant prologues, define I860_STRICT_ABI_PROLOGUES ! 1625: in the i860svr4.h file. (By default this is *not* defined). ! 1626: ! 1627: The differences between the ABI-compliant and non-ABI-compliant prologues ! 1628: are that (a) the ABI version seems to require the use of *signed* ! 1629: (rather than unsigned) adds and subtracts, and (b) the ordering of ! 1630: the various steps (e.g. saving preserved registers, saving the ! 1631: return address, setting up the new frame pointer value) is different. ! 1632: ! 1633: For strict ABI compliance, it seems to be the case that the very last ! 1634: thing that is supposed to happen in the prologue is getting the frame ! 1635: pointer set to its new value (but only after everything else has ! 1636: already been properly setup). We do that here, but only if the symbol ! 1637: I860_STRICT_ABI_PROLOGUES is defined. ! 1638: */ ! 1639: ! 1640: #ifndef STACK_ALIGNMENT ! 1641: #define STACK_ALIGNMENT 16 ! 1642: #endif ! 1643: ! 1644: extern char call_used_regs[]; ! 1645: extern int leaf_function_p (); ! 1646: ! 1647: char *current_function_original_name; ! 1648: ! 1649: static int must_preserve_r1; ! 1650: static unsigned must_preserve_bytes; ! 1651: ! 1652: void ! 1653: function_prologue (asm_file, local_bytes) ! 1654: register FILE *asm_file; ! 1655: register unsigned local_bytes; ! 1656: { ! 1657: register unsigned frame_lower_bytes; ! 1658: register unsigned frame_upper_bytes; ! 1659: register unsigned total_fsize; ! 1660: register unsigned preserved_reg_bytes = 0; ! 1661: register unsigned i; ! 1662: register unsigned preserved_so_far = 0; ! 1663: ! 1664: must_preserve_r1 = (optimize < 2 || ! leaf_function_p ()); ! 1665: must_preserve_bytes = 4 + (must_preserve_r1 ? 4 : 0); ! 1666: ! 1667: /* Count registers that need preserving. Ignore r0. It never needs ! 1668: preserving. */ ! 1669: ! 1670: for (i = 1; i < FIRST_PSEUDO_REGISTER; i++) ! 1671: { ! 1672: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1673: preserved_reg_bytes += 4; ! 1674: } ! 1675: ! 1676: /* Round-up the frame_lower_bytes so that it's a multiple of 16. */ ! 1677: ! 1678: frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; ! 1679: ! 1680: /* The upper part of each frame will contain the saved fp, ! 1681: the saved r1, and stack slots for all of the other "preserved" ! 1682: registers that we find we will need to save & restore. */ ! 1683: ! 1684: frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes; ! 1685: ! 1686: /* Round-up the frame_upper_bytes so that it's a multiple of 16. */ ! 1687: ! 1688: frame_upper_bytes ! 1689: = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; ! 1690: ! 1691: total_fsize = frame_upper_bytes + frame_lower_bytes; ! 1692: ! 1693: #ifndef I860_STRICT_ABI_PROLOGUES ! 1694: ! 1695: /* There are two kinds of function prologues. ! 1696: You use the "small" version if the total frame size is ! 1697: small enough so that it can fit into an immediate 16-bit ! 1698: value in one instruction. Otherwise, you use the "large" ! 1699: version of the function prologue. */ ! 1700: ! 1701: if (total_fsize > 0x7fff) ! 1702: { ! 1703: /* Adjust the stack pointer. The ABI sez to do this using `adds', ! 1704: but the native C compiler on svr4 uses `addu'. */ ! 1705: ! 1706: fprintf (asm_file, "\taddu -%d,%ssp,%ssp\n", ! 1707: frame_upper_bytes, i860_reg_prefix, i860_reg_prefix); ! 1708: ! 1709: /* Save the old frame pointer. */ ! 1710: ! 1711: fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n", ! 1712: i860_reg_prefix, i860_reg_prefix); ! 1713: ! 1714: /* Setup the new frame pointer. The ABI sez to do this after ! 1715: preserving registers (using adds), but that's not what the ! 1716: native C compiler on svr4 does. */ ! 1717: ! 1718: fprintf (asm_file, "\taddu 0,%ssp,%sfp\n", ! 1719: i860_reg_prefix, i860_reg_prefix); ! 1720: ! 1721: /* Get the value of frame_lower_bytes into r31. */ ! 1722: ! 1723: fprintf (asm_file, "\torh %d,%sr0,%sr31\n", ! 1724: frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix); ! 1725: fprintf (asm_file, "\tor %d,%sr31,%sr31\n", ! 1726: frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix); ! 1727: ! 1728: /* Now re-adjust the stack pointer using the value in r31. ! 1729: The ABI sez to do this with `subs' but SDB may prefer `subu'. */ ! 1730: ! 1731: fprintf (asm_file, "\tsubu %ssp,%sr31,%ssp\n", ! 1732: i860_reg_prefix, i860_reg_prefix, i860_reg_prefix); ! 1733: ! 1734: /* Preserve registers. The ABI sez to do this before setting ! 1735: up the new frame pointer, but that's not what the native ! 1736: C compiler on svr4 does. */ ! 1737: ! 1738: for (i = 1; i < 32; i++) ! 1739: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1740: fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n", ! 1741: i860_reg_prefix, reg_names[i], ! 1742: must_preserve_bytes + (4 * preserved_so_far++), ! 1743: i860_reg_prefix); ! 1744: ! 1745: for (i = 32; i < 64; i++) ! 1746: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1747: fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n", ! 1748: i860_reg_prefix, reg_names[i], ! 1749: must_preserve_bytes + (4 * preserved_so_far++), ! 1750: i860_reg_prefix); ! 1751: ! 1752: /* Save the return address. */ ! 1753: ! 1754: if (must_preserve_r1) ! 1755: fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n", ! 1756: i860_reg_prefix, i860_reg_prefix); ! 1757: } ! 1758: else ! 1759: { ! 1760: /* Adjust the stack pointer. The ABI sez to do this using `adds', ! 1761: but the native C compiler on svr4 uses `addu'. */ ! 1762: ! 1763: fprintf (asm_file, "\taddu -%d,%ssp,%ssp\n", ! 1764: total_fsize, i860_reg_prefix, i860_reg_prefix); ! 1765: ! 1766: /* Save the old frame pointer. */ ! 1767: ! 1768: fprintf (asm_file, "\tst.l %sfp,%d(%ssp)\n", ! 1769: i860_reg_prefix, frame_lower_bytes, i860_reg_prefix); ! 1770: ! 1771: /* Setup the new frame pointer. The ABI sez to do this after ! 1772: preserving registers and after saving the return address, ! 1773: (and its saz to do this using adds), but that's not what the ! 1774: native C compiler on svr4 does. */ ! 1775: ! 1776: fprintf (asm_file, "\taddu %d,%ssp,%sfp\n", ! 1777: frame_lower_bytes, i860_reg_prefix, i860_reg_prefix); ! 1778: ! 1779: /* Preserve registers. The ABI sez to do this before setting ! 1780: up the new frame pointer, but that's not what the native ! 1781: compiler on svr4 does. */ ! 1782: ! 1783: for (i = 1; i < 32; i++) ! 1784: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1785: fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n", ! 1786: i860_reg_prefix, reg_names[i], ! 1787: must_preserve_bytes + (4 * preserved_so_far++), ! 1788: i860_reg_prefix); ! 1789: ! 1790: for (i = 32; i < 64; i++) ! 1791: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1792: fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n", ! 1793: i860_reg_prefix, reg_names[i], ! 1794: must_preserve_bytes + (4 * preserved_so_far++), ! 1795: i860_reg_prefix); ! 1796: ! 1797: /* Save the return address. The ABI sez to do this earlier, ! 1798: and also via an offset from %sp, but the native C compiler ! 1799: on svr4 does it later (i.e. now) and uses an offset from ! 1800: %fp. */ ! 1801: ! 1802: if (must_preserve_r1) ! 1803: fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n", ! 1804: i860_reg_prefix, i860_reg_prefix); ! 1805: } ! 1806: ! 1807: #else /* defined(I860_STRICT_ABI_PROLOGUES) */ ! 1808: ! 1809: /* There are two kinds of function prologues. ! 1810: You use the "small" version if the total frame size is ! 1811: small enough so that it can fit into an immediate 16-bit ! 1812: value in one instruction. Otherwise, you use the "large" ! 1813: version of the function prologue. */ ! 1814: ! 1815: if (total_fsize > 0x7fff) ! 1816: { ! 1817: /* Adjust the stack pointer (thereby allocating a new frame). */ ! 1818: ! 1819: fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n", ! 1820: frame_upper_bytes, i860_reg_prefix, i860_reg_prefix); ! 1821: ! 1822: /* Save the caller's frame pointer. */ ! 1823: ! 1824: fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n", ! 1825: i860_reg_prefix, i860_reg_prefix); ! 1826: ! 1827: /* Save return address. */ ! 1828: ! 1829: if (must_preserve_r1) ! 1830: fprintf (asm_file, "\tst.l %sr1,4(%ssp)\n", ! 1831: i860_reg_prefix, i860_reg_prefix); ! 1832: ! 1833: /* Get the value of frame_lower_bytes into r31 for later use. */ ! 1834: ! 1835: fprintf (asm_file, "\torh %d,%sr0,%sr31\n", ! 1836: frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix); ! 1837: fprintf (asm_file, "\tor %d,%sr31,%sr31\n", ! 1838: frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix); ! 1839: ! 1840: /* Now re-adjust the stack pointer using the value in r31. */ ! 1841: ! 1842: fprintf (asm_file, "\tsubs %ssp,%sr31,%ssp\n", ! 1843: i860_reg_prefix, i860_reg_prefix, i860_reg_prefix); ! 1844: ! 1845: /* Pre-compute value to be used as the new frame pointer. */ ! 1846: ! 1847: fprintf (asm_file, "\tadds %ssp,%sr31,%sr31\n", ! 1848: i860_reg_prefix, i860_reg_prefix, i860_reg_prefix); ! 1849: ! 1850: /* Preserve registers. */ ! 1851: ! 1852: for (i = 1; i < 32; i++) ! 1853: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1854: fprintf (asm_file, "\tst.l %s%s,%d(%sr31)\n", ! 1855: i860_reg_prefix, reg_names[i], ! 1856: must_preserve_bytes + (4 * preserved_so_far++), ! 1857: i860_reg_prefix); ! 1858: ! 1859: for (i = 32; i < 64; i++) ! 1860: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1861: fprintf (asm_file, "\tfst.l %s%s,%d(%sr31)\n", ! 1862: i860_reg_prefix, reg_names[i], ! 1863: must_preserve_bytes + (4 * preserved_so_far++), ! 1864: i860_reg_prefix); ! 1865: ! 1866: /* Actually set the new value of the frame pointer. */ ! 1867: ! 1868: fprintf (asm_file, "\tmov %sr31,%sfp\n", ! 1869: i860_reg_prefix, i860_reg_prefix); ! 1870: } ! 1871: else ! 1872: { ! 1873: /* Adjust the stack pointer. */ ! 1874: ! 1875: fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n", ! 1876: total_fsize, i860_reg_prefix, i860_reg_prefix); ! 1877: ! 1878: /* Save the caller's frame pointer. */ ! 1879: ! 1880: fprintf (asm_file, "\tst.l %sfp,%d(%ssp)\n", ! 1881: i860_reg_prefix, frame_lower_bytes, i860_reg_prefix); ! 1882: ! 1883: /* Save the return address. */ ! 1884: ! 1885: if (must_preserve_r1) ! 1886: fprintf (asm_file, "\tst.l %sr1,%d(%ssp)\n", ! 1887: i860_reg_prefix, frame_lower_bytes + 4, i860_reg_prefix); ! 1888: ! 1889: /* Preserve registers. */ ! 1890: ! 1891: for (i = 1; i < 32; i++) ! 1892: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1893: fprintf (asm_file, "\tst.l %s%s,%d(%ssp)\n", ! 1894: i860_reg_prefix, reg_names[i], ! 1895: frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++), ! 1896: i860_reg_prefix); ! 1897: ! 1898: for (i = 32; i < 64; i++) ! 1899: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1900: fprintf (asm_file, "\tfst.l %s%s,%d(%ssp)\n", ! 1901: i860_reg_prefix, reg_names[i], ! 1902: frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++), ! 1903: i860_reg_prefix); ! 1904: ! 1905: /* Setup the new frame pointer. */ ! 1906: ! 1907: fprintf (asm_file, "\tadds %d,%ssp,%sfp\n", ! 1908: frame_lower_bytes, i860_reg_prefix, i860_reg_prefix); ! 1909: } ! 1910: #endif /* defined(I860_STRICT_ABI_PROLOGUES) */ ! 1911: ! 1912: #ifdef ASM_OUTPUT_PROLOGUE_SUFFIX ! 1913: ASM_OUTPUT_PROLOGUE_SUFFIX (asm_file); ! 1914: #endif /* defined(ASM_OUTPUT_PROLOGUE_SUFFIX) */ ! 1915: } ! 1916: ! 1917: /* This function generates the assembly code for function exit. ! 1918: The macro FUNCTION_EPILOGUE in i860.h is defined to call this function. ! 1919: ! 1920: ASM_FILE is a stdio stream to output the code to. ! 1921: SIZE is an int: how many units of temporary storage to allocate. ! 1922: ! 1923: The function epilogue should not depend on the current stack pointer! ! 1924: It should use the frame pointer only. This is mandatory because ! 1925: of alloca; we also take advantage of it to omit stack adjustments ! 1926: before returning. ! 1927: ! 1928: Note that when we go to restore the preserved register values we must ! 1929: not try to address their slots by using offsets from the stack pointer. ! 1930: That's because the stack pointer may have been moved during the function ! 1931: execution due to a call to alloca(). Rather, we must restore all ! 1932: preserved registers via offsets from the frame pointer value. ! 1933: ! 1934: Note also that when the current frame is being "popped" (by adjusting ! 1935: the value of the stack pointer) on function exit, we must (for the ! 1936: sake of alloca) set the new value of the stack pointer based upon ! 1937: the current value of the frame pointer. We can't just add what we ! 1938: believe to be the (static) frame size to the stack pointer because ! 1939: if we did that, and alloca() had been called during this function, ! 1940: we would end up returning *without* having fully deallocated all of ! 1941: the space grabbed by alloca. If that happened, and a function ! 1942: containing one or more alloca() calls was called over and over again, ! 1943: then the stack would grow without limit! ! 1944: ! 1945: Finally note that the epilogues generated here are completely ABI ! 1946: compliant. They go out of their way to insure that the value in ! 1947: the frame pointer register is never less than the value in the stack ! 1948: pointer register. It's not clear why this relationship needs to be ! 1949: maintained at all times, but maintaining it only costs one extra ! 1950: instruction, so what the hell. ! 1951: */ ! 1952: ! 1953: /* This corresponds to a version 4 TDESC structure. Lower numbered ! 1954: versions successively omit the last word of the structure. We ! 1955: don't try to handle version 5 here. */ ! 1956: ! 1957: typedef struct TDESC_flags { ! 1958: int version:4; ! 1959: int reg_packing:1; ! 1960: int callable_block:1; ! 1961: int reserved:4; ! 1962: int fregs:6; /* fp regs 2-7 */ ! 1963: int iregs:16; /* regs 0-15 */ ! 1964: } TDESC_flags; ! 1965: ! 1966: typedef struct TDESC { ! 1967: TDESC_flags flags; ! 1968: int integer_reg_offset; /* same as must_preserve_bytes */ ! 1969: int floating_point_reg_offset; ! 1970: unsigned int positive_frame_size; /* same as frame_upper_bytes */ ! 1971: unsigned int negative_frame_size; /* same as frame_lower_bytes */ ! 1972: } TDESC; ! 1973: ! 1974: void ! 1975: function_epilogue (asm_file, local_bytes) ! 1976: register FILE *asm_file; ! 1977: register unsigned local_bytes; ! 1978: { ! 1979: register unsigned frame_upper_bytes; ! 1980: register unsigned frame_lower_bytes; ! 1981: register unsigned preserved_reg_bytes = 0; ! 1982: register unsigned i; ! 1983: register unsigned restored_so_far = 0; ! 1984: register unsigned int_restored; ! 1985: register unsigned mask; ! 1986: unsigned intflags=0; ! 1987: register TDESC_flags *flags = (TDESC_flags *) &intflags; ! 1988: ! 1989: flags->version = 4; ! 1990: flags->reg_packing = 1; ! 1991: flags->iregs = 8; /* old fp always gets saved */ ! 1992: ! 1993: /* Round-up the frame_lower_bytes so that it's a multiple of 16. */ ! 1994: ! 1995: frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; ! 1996: ! 1997: /* Count the number of registers that were preserved in the prologue. ! 1998: Ignore r0. It is never preserved. */ ! 1999: ! 2000: for (i = 1; i < FIRST_PSEUDO_REGISTER; i++) ! 2001: { ! 2002: if (regs_ever_live[i] && ! call_used_regs[i]) ! 2003: preserved_reg_bytes += 4; ! 2004: } ! 2005: ! 2006: /* The upper part of each frame will contain only saved fp, ! 2007: the saved r1, and stack slots for all of the other "preserved" ! 2008: registers that we find we will need to save & restore. */ ! 2009: ! 2010: frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes; ! 2011: ! 2012: /* Round-up frame_upper_bytes so that t is a multiple of 16. */ ! 2013: ! 2014: frame_upper_bytes ! 2015: = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; ! 2016: ! 2017: /* Restore all of the "preserved" registers that need restoring. */ ! 2018: ! 2019: mask = 2; ! 2020: ! 2021: for (i = 1; i < 32; i++, mask<<=1) ! 2022: if (regs_ever_live[i] && ! call_used_regs[i]) { ! 2023: fprintf (asm_file, "\tld.l %d(%sfp),%s%s\n", ! 2024: must_preserve_bytes + (4 * restored_so_far++), ! 2025: i860_reg_prefix, i860_reg_prefix, reg_names[i]); ! 2026: if (i > 3 && i < 16) ! 2027: flags->iregs |= mask; ! 2028: } ! 2029: ! 2030: int_restored = restored_so_far; ! 2031: mask = 1; ! 2032: ! 2033: for (i = 32; i < 64; i++) { ! 2034: if (regs_ever_live[i] && ! call_used_regs[i]) { ! 2035: fprintf (asm_file, "\tfld.l %d(%sfp),%s%s\n", ! 2036: must_preserve_bytes + (4 * restored_so_far++), ! 2037: i860_reg_prefix, i860_reg_prefix, reg_names[i]); ! 2038: if (i > 33 & i < 40) ! 2039: flags->fregs |= mask; ! 2040: } ! 2041: if (i > 33 && i < 40) ! 2042: mask<<=1; ! 2043: } ! 2044: ! 2045: /* Get the value we plan to use to restore the stack pointer into r31. */ ! 2046: ! 2047: fprintf (asm_file, "\tadds %d,%sfp,%sr31\n", ! 2048: frame_upper_bytes, i860_reg_prefix, i860_reg_prefix); ! 2049: ! 2050: /* Restore the return address and the old frame pointer. */ ! 2051: ! 2052: if (must_preserve_r1) { ! 2053: fprintf (asm_file, "\tld.l 4(%sfp),%sr1\n", ! 2054: i860_reg_prefix, i860_reg_prefix); ! 2055: flags->iregs |= 2; ! 2056: } ! 2057: ! 2058: fprintf (asm_file, "\tld.l 0(%sfp),%sfp\n", ! 2059: i860_reg_prefix, i860_reg_prefix); ! 2060: ! 2061: /* Return and restore the old stack pointer value. */ ! 2062: ! 2063: fprintf (asm_file, "\tbri %sr1\n\tmov %sr31,%ssp\n", ! 2064: i860_reg_prefix, i860_reg_prefix, i860_reg_prefix); ! 2065: ! 2066: #ifdef OUTPUT_TDESC /* Output an ABI-compliant TDESC entry */ ! 2067: if (! frame_lower_bytes) { ! 2068: flags->version--; ! 2069: if (! frame_upper_bytes) { ! 2070: flags->version--; ! 2071: if (restored_so_far == int_restored) /* No FP saves */ ! 2072: flags->version--; ! 2073: } ! 2074: } ! 2075: assemble_name(asm_file,current_function_original_name); ! 2076: fputs(".TDESC:\n", asm_file); ! 2077: fprintf(asm_file, "%s 0x%0x\n", ASM_LONG, intflags); ! 2078: fprintf(asm_file, "%s %d\n", ASM_LONG, ! 2079: int_restored ? must_preserve_bytes : 0); ! 2080: if (flags->version > 1) { ! 2081: fprintf(asm_file, "%s %d\n", ASM_LONG, ! 2082: (restored_so_far == int_restored) ? 0 : must_preserve_bytes + ! 2083: (4 * int_restored)); ! 2084: if (flags->version > 2) { ! 2085: fprintf(asm_file, "%s %d\n", ASM_LONG, frame_upper_bytes); ! 2086: if (flags->version > 3) ! 2087: fprintf(asm_file, "%s %d\n", ASM_LONG, frame_lower_bytes); ! 2088: } ! 2089: } ! 2090: tdesc_section(); ! 2091: fprintf(asm_file, "%s ", ASM_LONG); ! 2092: assemble_name(asm_file, current_function_original_name); ! 2093: fprintf(asm_file, "\n%s ", ASM_LONG); ! 2094: assemble_name(asm_file, current_function_original_name); ! 2095: fputs(".TDESC\n", asm_file); ! 2096: text_section(); ! 2097: #endif ! 2098: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.