|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Sun SPARC. ! 2: Copyright (C) 1987, 1988, 1989, 1992, 1993 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 2, 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: #include <stdio.h> ! 22: #include "config.h" ! 23: #include "tree.h" ! 24: #include "rtl.h" ! 25: #include "regs.h" ! 26: #include "hard-reg-set.h" ! 27: #include "real.h" ! 28: #include "insn-config.h" ! 29: #include "conditions.h" ! 30: #include "insn-flags.h" ! 31: #include "output.h" ! 32: #include "insn-attr.h" ! 33: #include "flags.h" ! 34: #include "expr.h" ! 35: #include "recog.h" ! 36: ! 37: /* Global variables for machine-dependent things. */ ! 38: ! 39: /* Save the operands last given to a compare for use when we ! 40: generate a scc or bcc insn. */ ! 41: ! 42: rtx sparc_compare_op0, sparc_compare_op1; ! 43: ! 44: /* We may need an epilogue if we spill too many registers. ! 45: If this is non-zero, then we branch here for the epilogue. */ ! 46: static rtx leaf_label; ! 47: ! 48: #ifdef LEAF_REGISTERS ! 49: ! 50: /* Vector to say how input registers are mapped to output ! 51: registers. FRAME_POINTER_REGNUM cannot be remapped by ! 52: this function to eliminate it. You must use -fomit-frame-pointer ! 53: to get that. */ ! 54: char leaf_reg_remap[] = ! 55: { 0, 1, 2, 3, 4, 5, 6, 7, ! 56: -1, -1, -1, -1, -1, -1, 14, -1, ! 57: -1, -1, -1, -1, -1, -1, -1, -1, ! 58: 8, 9, 10, 11, 12, 13, -1, 15, ! 59: ! 60: 32, 33, 34, 35, 36, 37, 38, 39, ! 61: 40, 41, 42, 43, 44, 45, 46, 47, ! 62: 48, 49, 50, 51, 52, 53, 54, 55, ! 63: 56, 57, 58, 59, 60, 61, 62, 63}; ! 64: ! 65: #if 0 /* not used anymore */ ! 66: char leaf_reg_backmap[] = ! 67: { 0, 1, 2, 3, 4, 5, 6, 7, ! 68: 24, 25, 26, 27, 28, 29, 14, 31, ! 69: -1, -1, -1, -1, -1, -1, -1, -1, ! 70: -1, -1, -1, -1, -1, -1, -1, -1, ! 71: ! 72: 32, 33, 34, 35, 36, 37, 38, 39, ! 73: 40, 41, 42, 43, 44, 45, 46, 47, ! 74: 48, 49, 50, 51, 52, 53, 54, 55, ! 75: 56, 57, 58, 59, 60, 61, 62, 63}; ! 76: #endif ! 77: #endif ! 78: ! 79: /* Global variables set by FUNCTION_PROLOGUE. */ ! 80: /* Size of frame. Need to know this to emit return insns from ! 81: leaf procedures. */ ! 82: static int apparent_fsize; ! 83: static int actual_fsize; ! 84: ! 85: /* Name of where we pretend to think the frame pointer points. ! 86: Normally, this is "%fp", but if we are in a leaf procedure, ! 87: this is "%sp+something". */ ! 88: char *frame_base_name; ! 89: ! 90: static rtx find_addr_reg (); ! 91: ! 92: /* Return non-zero only if OP is a register of mode MODE, ! 93: or const0_rtx. */ ! 94: int ! 95: reg_or_0_operand (op, mode) ! 96: rtx op; ! 97: enum machine_mode mode; ! 98: { ! 99: if (op == const0_rtx || register_operand (op, mode)) ! 100: return 1; ! 101: if (GET_MODE (op) == DImode && GET_CODE (op) == CONST_DOUBLE ! 102: && CONST_DOUBLE_HIGH (op) == 0 ! 103: && CONST_DOUBLE_LOW (op) == 0) ! 104: return 1; ! 105: if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT ! 106: && GET_CODE (op) == CONST_DOUBLE ! 107: && fp_zero_operand (op)) ! 108: return 1; ! 109: return 0; ! 110: } ! 111: ! 112: /* Nonzero if OP is a floating point value with value 0.0. */ ! 113: int ! 114: fp_zero_operand (op) ! 115: rtx op; ! 116: { ! 117: REAL_VALUE_TYPE r; ! 118: ! 119: REAL_VALUE_FROM_CONST_DOUBLE (r, op); ! 120: return REAL_VALUES_EQUAL (r, dconst0); ! 121: } ! 122: ! 123: /* Nonzero if OP can appear as the dest of a RESTORE insn. */ ! 124: int ! 125: restore_operand (op, mode) ! 126: rtx op; ! 127: enum machine_mode mode; ! 128: { ! 129: return (GET_CODE (op) == REG && GET_MODE (op) == mode ! 130: && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32))); ! 131: } ! 132: ! 133: /* Call insn on SPARC can take a PC-relative constant address, or any regular ! 134: memory address. */ ! 135: ! 136: int ! 137: call_operand (op, mode) ! 138: rtx op; ! 139: enum machine_mode mode; ! 140: { ! 141: if (GET_CODE (op) != MEM) ! 142: abort (); ! 143: op = XEXP (op, 0); ! 144: return (CONSTANT_P (op) || memory_address_p (Pmode, op)); ! 145: } ! 146: ! 147: int ! 148: call_operand_address (op, mode) ! 149: rtx op; ! 150: enum machine_mode mode; ! 151: { ! 152: return (CONSTANT_P (op) || memory_address_p (Pmode, op)); ! 153: } ! 154: ! 155: /* Returns 1 if OP is either a symbol reference or a sum of a symbol ! 156: reference and a constant. */ ! 157: ! 158: int ! 159: symbolic_operand (op, mode) ! 160: register rtx op; ! 161: enum machine_mode mode; ! 162: { ! 163: switch (GET_CODE (op)) ! 164: { ! 165: case SYMBOL_REF: ! 166: case LABEL_REF: ! 167: return 1; ! 168: ! 169: case CONST: ! 170: op = XEXP (op, 0); ! 171: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF ! 172: || GET_CODE (XEXP (op, 0)) == LABEL_REF) ! 173: && GET_CODE (XEXP (op, 1)) == CONST_INT); ! 174: ! 175: /* ??? This clause seems to be irrelevant. */ ! 176: case CONST_DOUBLE: ! 177: return GET_MODE (op) == mode; ! 178: ! 179: default: ! 180: return 0; ! 181: } ! 182: } ! 183: ! 184: /* Return truth value of statement that OP is a symbolic memory ! 185: operand of mode MODE. */ ! 186: ! 187: int ! 188: symbolic_memory_operand (op, mode) ! 189: rtx op; ! 190: enum machine_mode mode; ! 191: { ! 192: if (GET_CODE (op) == SUBREG) ! 193: op = SUBREG_REG (op); ! 194: if (GET_CODE (op) != MEM) ! 195: return 0; ! 196: op = XEXP (op, 0); ! 197: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST ! 198: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF); ! 199: } ! 200: ! 201: /* Return 1 if the operand is either a register or a memory operand that is ! 202: not symbolic. */ ! 203: ! 204: int ! 205: reg_or_nonsymb_mem_operand (op, mode) ! 206: register rtx op; ! 207: enum machine_mode mode; ! 208: { ! 209: if (register_operand (op, mode)) ! 210: return 1; ! 211: ! 212: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) ! 213: return 1; ! 214: ! 215: return 0; ! 216: } ! 217: ! 218: int ! 219: sparc_operand (op, mode) ! 220: rtx op; ! 221: enum machine_mode mode; ! 222: { ! 223: if (register_operand (op, mode)) ! 224: return 1; ! 225: if (GET_CODE (op) == CONST_INT) ! 226: return SMALL_INT (op); ! 227: if (GET_MODE (op) != mode) ! 228: return 0; ! 229: if (GET_CODE (op) == SUBREG) ! 230: op = SUBREG_REG (op); ! 231: if (GET_CODE (op) != MEM) ! 232: return 0; ! 233: ! 234: op = XEXP (op, 0); ! 235: if (GET_CODE (op) == LO_SUM) ! 236: return (GET_CODE (XEXP (op, 0)) == REG ! 237: && symbolic_operand (XEXP (op, 1), Pmode)); ! 238: return memory_address_p (mode, op); ! 239: } ! 240: ! 241: int ! 242: move_operand (op, mode) ! 243: rtx op; ! 244: enum machine_mode mode; ! 245: { ! 246: if (mode == DImode && arith_double_operand (op, mode)) ! 247: return 1; ! 248: if (register_operand (op, mode)) ! 249: return 1; ! 250: if (GET_CODE (op) == CONST_INT) ! 251: return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0); ! 252: ! 253: if (GET_MODE (op) != mode) ! 254: return 0; ! 255: if (GET_CODE (op) == SUBREG) ! 256: op = SUBREG_REG (op); ! 257: if (GET_CODE (op) != MEM) ! 258: return 0; ! 259: op = XEXP (op, 0); ! 260: if (GET_CODE (op) == LO_SUM) ! 261: return (register_operand (XEXP (op, 0), Pmode) ! 262: && CONSTANT_P (XEXP (op, 1))); ! 263: return memory_address_p (mode, op); ! 264: } ! 265: ! 266: int ! 267: move_pic_label (op, mode) ! 268: rtx op; ! 269: enum machine_mode mode; ! 270: { ! 271: /* Special case for PIC. */ ! 272: if (flag_pic && GET_CODE (op) == LABEL_REF) ! 273: return 1; ! 274: return 0; ! 275: } ! 276: ! 277: int ! 278: memop (op, mode) ! 279: rtx op; ! 280: enum machine_mode mode; ! 281: { ! 282: if (GET_CODE (op) == MEM) ! 283: return (mode == VOIDmode || mode == GET_MODE (op)); ! 284: return 0; ! 285: } ! 286: ! 287: /* Return truth value of whether OP is EQ or NE. */ ! 288: ! 289: int ! 290: eq_or_neq (op, mode) ! 291: rtx op; ! 292: enum machine_mode mode; ! 293: { ! 294: return (GET_CODE (op) == EQ || GET_CODE (op) == NE); ! 295: } ! 296: ! 297: /* Return 1 if this is a comparison operator, but not an EQ, NE, GEU, ! 298: or LTU for non-floating-point. We handle those specially. */ ! 299: ! 300: int ! 301: normal_comp_operator (op, mode) ! 302: rtx op; ! 303: enum machine_mode mode; ! 304: { ! 305: enum rtx_code code = GET_CODE (op); ! 306: ! 307: if (GET_RTX_CLASS (code) != '<') ! 308: return 0; ! 309: ! 310: if (GET_MODE (XEXP (op, 0)) == CCFPmode ! 311: || GET_MODE (XEXP (op, 0)) == CCFPEmode) ! 312: return 1; ! 313: ! 314: return (code != NE && code != EQ && code != GEU && code != LTU); ! 315: } ! 316: ! 317: /* Return 1 if this is a comparison operator. This allows the use of ! 318: MATCH_OPERATOR to recognize all the branch insns. */ ! 319: ! 320: int ! 321: noov_compare_op (op, mode) ! 322: register rtx op; ! 323: enum machine_mode mode; ! 324: { ! 325: enum rtx_code code = GET_CODE (op); ! 326: ! 327: if (GET_RTX_CLASS (code) != '<') ! 328: return 0; ! 329: ! 330: if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode) ! 331: /* These are the only branches which work with CC_NOOVmode. */ ! 332: return (code == EQ || code == NE || code == GE || code == LT); ! 333: return 1; ! 334: } ! 335: ! 336: /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */ ! 337: ! 338: int ! 339: extend_op (op, mode) ! 340: rtx op; ! 341: enum machine_mode mode; ! 342: { ! 343: return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND; ! 344: } ! 345: ! 346: /* Return nonzero if OP is an operator of mode MODE which can set ! 347: the condition codes explicitly. We do not include PLUS and MINUS ! 348: because these require CC_NOOVmode, which we handle explicitly. */ ! 349: ! 350: int ! 351: cc_arithop (op, mode) ! 352: rtx op; ! 353: enum machine_mode mode; ! 354: { ! 355: if (GET_CODE (op) == AND ! 356: || GET_CODE (op) == IOR ! 357: || GET_CODE (op) == XOR) ! 358: return 1; ! 359: ! 360: return 0; ! 361: } ! 362: ! 363: /* Return nonzero if OP is an operator of mode MODE which can bitwise ! 364: complement its second operand and set the condition codes explicitly. */ ! 365: ! 366: int ! 367: cc_arithopn (op, mode) ! 368: rtx op; ! 369: enum machine_mode mode; ! 370: { ! 371: /* XOR is not here because combine canonicalizes (xor (not ...) ...) ! 372: and (xor ... (not ...)) to (not (xor ...)). */ ! 373: return (GET_CODE (op) == AND ! 374: || GET_CODE (op) == IOR); ! 375: } ! 376: ! 377: /* Return true if OP is a register, or is a CONST_INT that can fit in a 13 ! 378: bit immediate field. This is an acceptable SImode operand for most 3 ! 379: address instructions. */ ! 380: ! 381: int ! 382: arith_operand (op, mode) ! 383: rtx op; ! 384: enum machine_mode mode; ! 385: { ! 386: return (register_operand (op, mode) ! 387: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); ! 388: } ! 389: ! 390: /* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that ! 391: can fit in a 13 bit immediate field. This is an acceptable DImode operand ! 392: for most 3 address instructions. */ ! 393: ! 394: int ! 395: arith_double_operand (op, mode) ! 396: rtx op; ! 397: enum machine_mode mode; ! 398: { ! 399: return (register_operand (op, mode) ! 400: || (GET_CODE (op) == CONST_DOUBLE ! 401: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) ! 402: && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 ! 403: && ((CONST_DOUBLE_HIGH (op) == -1 ! 404: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000) ! 405: || (CONST_DOUBLE_HIGH (op) == 0 ! 406: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))) ! 407: || (GET_CODE (op) == CONST_INT ! 408: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) ! 409: && (unsigned) (INTVAL (op) + 0x1000) < 0x2000)); ! 410: } ! 411: ! 412: /* Return truth value of whether OP is a integer which fits the ! 413: range constraining immediate operands in most three-address insns, ! 414: which have a 13 bit immediate field. */ ! 415: ! 416: int ! 417: small_int (op, mode) ! 418: rtx op; ! 419: enum machine_mode mode; ! 420: { ! 421: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); ! 422: } ! 423: ! 424: /* Recognize operand values for the umul instruction. That instruction sign ! 425: extends immediate values just like all other sparc instructions, but ! 426: interprets the extended result as an unsigned number. */ ! 427: ! 428: int ! 429: uns_small_int (op, mode) ! 430: rtx op; ! 431: enum machine_mode mode; ! 432: { ! 433: #if HOST_BITS_PER_WIDE_INT > 32 ! 434: /* All allowed constants will fit a CONST_INT. */ ! 435: return (GET_CODE (op) == CONST_INT ! 436: && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000) ! 437: || (INTVAL (op) >= 0xFFFFF000 && INTVAL (op) < 0x100000000L))); ! 438: #else ! 439: return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000) ! 440: || (GET_CODE (op) == CONST_DOUBLE ! 441: && CONST_DOUBLE_HIGH (op) == 0 ! 442: && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000)); ! 443: #endif ! 444: } ! 445: ! 446: int ! 447: uns_arith_operand (op, mode) ! 448: rtx op; ! 449: enum machine_mode mode; ! 450: { ! 451: return register_operand (op, mode) || uns_small_int (op, mode); ! 452: } ! 453: ! 454: /* Return truth value of statement that OP is a call-clobbered register. */ ! 455: int ! 456: clobbered_register (op, mode) ! 457: rtx op; ! 458: enum machine_mode mode; ! 459: { ! 460: return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]); ! 461: } ! 462: ! 463: /* X and Y are two things to compare using CODE. Emit the compare insn and ! 464: return the rtx for register 0 in the proper mode. */ ! 465: ! 466: rtx ! 467: gen_compare_reg (code, x, y) ! 468: enum rtx_code code; ! 469: rtx x, y; ! 470: { ! 471: enum machine_mode mode = SELECT_CC_MODE (code, x, y); ! 472: rtx cc_reg = gen_rtx (REG, mode, 0); ! 473: ! 474: emit_insn (gen_rtx (SET, VOIDmode, cc_reg, ! 475: gen_rtx (COMPARE, mode, x, y))); ! 476: ! 477: return cc_reg; ! 478: } ! 479: ! 480: /* Return nonzero if a return peephole merging return with ! 481: setting of output register is ok. */ ! 482: int ! 483: leaf_return_peephole_ok () ! 484: { ! 485: return (actual_fsize == 0); ! 486: } ! 487: ! 488: /* Return nonzero if TRIAL can go into the function epilogue's ! 489: delay slot. SLOT is the slot we are trying to fill. */ ! 490: ! 491: int ! 492: eligible_for_epilogue_delay (trial, slot) ! 493: rtx trial; ! 494: int slot; ! 495: { ! 496: rtx pat, src; ! 497: ! 498: if (slot >= 1) ! 499: return 0; ! 500: if (GET_CODE (trial) != INSN ! 501: || GET_CODE (PATTERN (trial)) != SET) ! 502: return 0; ! 503: if (get_attr_length (trial) != 1) ! 504: return 0; ! 505: ! 506: /* In the case of a true leaf function, anything can go into the delay slot. ! 507: A delay slot only exists however if the frame size is zero, otherwise ! 508: we will put an insn to adjust the stack after the return. */ ! 509: if (leaf_function) ! 510: { ! 511: if (leaf_return_peephole_ok ()) ! 512: return (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE); ! 513: return 0; ! 514: } ! 515: ! 516: /* Otherwise, only operations which can be done in tandem with ! 517: a `restore' insn can go into the delay slot. */ ! 518: pat = PATTERN (trial); ! 519: if (GET_CODE (SET_DEST (pat)) != REG ! 520: || REGNO (SET_DEST (pat)) == 0 ! 521: || REGNO (SET_DEST (pat)) >= 32 ! 522: || REGNO (SET_DEST (pat)) < 24) ! 523: return 0; ! 524: ! 525: src = SET_SRC (pat); ! 526: if (arith_operand (src, GET_MODE (src))) ! 527: return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); ! 528: if (arith_double_operand (src, GET_MODE (src))) ! 529: return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); ! 530: if (GET_CODE (src) == PLUS) ! 531: { ! 532: if (register_operand (XEXP (src, 0), SImode) ! 533: && arith_operand (XEXP (src, 1), SImode)) ! 534: return 1; ! 535: if (register_operand (XEXP (src, 1), SImode) ! 536: && arith_operand (XEXP (src, 0), SImode)) ! 537: return 1; ! 538: if (register_operand (XEXP (src, 0), DImode) ! 539: && arith_double_operand (XEXP (src, 1), DImode)) ! 540: return 1; ! 541: if (register_operand (XEXP (src, 1), DImode) ! 542: && arith_double_operand (XEXP (src, 0), DImode)) ! 543: return 1; ! 544: } ! 545: if (GET_CODE (src) == MINUS ! 546: && register_operand (XEXP (src, 0), SImode) ! 547: && small_int (XEXP (src, 1), VOIDmode)) ! 548: return 1; ! 549: if (GET_CODE (src) == MINUS ! 550: && register_operand (XEXP (src, 0), DImode) ! 551: && !register_operand (XEXP (src, 1), DImode) ! 552: && arith_double_operand (XEXP (src, 1), DImode)) ! 553: return 1; ! 554: return 0; ! 555: } ! 556: ! 557: int ! 558: short_branch (uid1, uid2) ! 559: int uid1, uid2; ! 560: { ! 561: unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2]; ! 562: if (delta + 1024 < 2048) ! 563: return 1; ! 564: /* warning ("long branch, distance %d", delta); */ ! 565: return 0; ! 566: } ! 567: ! 568: /* Return non-zero if REG is not used after INSN. ! 569: We assume REG is a reload reg, and therefore does ! 570: not live past labels or calls or jumps. */ ! 571: int ! 572: reg_unused_after (reg, insn) ! 573: rtx reg; ! 574: rtx insn; ! 575: { ! 576: enum rtx_code code, prev_code = UNKNOWN; ! 577: ! 578: while (insn = NEXT_INSN (insn)) ! 579: { ! 580: if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)]) ! 581: return 1; ! 582: ! 583: code = GET_CODE (insn); ! 584: if (GET_CODE (insn) == CODE_LABEL) ! 585: return 1; ! 586: ! 587: if (GET_RTX_CLASS (code) == 'i') ! 588: { ! 589: rtx set = single_set (insn); ! 590: int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set)); ! 591: if (set && in_src) ! 592: return 0; ! 593: if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) ! 594: return 1; ! 595: if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn))) ! 596: return 0; ! 597: } ! 598: prev_code = code; ! 599: } ! 600: return 1; ! 601: } ! 602: ! 603: /* The rtx for the global offset table which is a special form ! 604: that *is* a position independent symbolic constant. */ ! 605: static rtx pic_pc_rtx; ! 606: ! 607: /* Ensure that we are not using patterns that are not OK with PIC. */ ! 608: ! 609: int ! 610: check_pic (i) ! 611: int i; ! 612: { ! 613: switch (flag_pic) ! 614: { ! 615: case 1: ! 616: if (GET_CODE (recog_operand[i]) == SYMBOL_REF ! 617: || (GET_CODE (recog_operand[i]) == CONST ! 618: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) ! 619: abort (); ! 620: case 2: ! 621: default: ! 622: return 1; ! 623: } ! 624: } ! 625: ! 626: /* Return true if X is an address which needs a temporary register when ! 627: reloaded while generating PIC code. */ ! 628: ! 629: int ! 630: pic_address_needs_scratch (x) ! 631: rtx x; ! 632: { ! 633: /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ ! 634: if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS ! 635: && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF ! 636: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT ! 637: && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) ! 638: return 1; ! 639: ! 640: return 0; ! 641: } ! 642: ! 643: /* Legitimize PIC addresses. If the address is already position-independent, ! 644: we return ORIG. Newly generated position-independent addresses go into a ! 645: reg. This is REG if non zero, otherwise we allocate register(s) as ! 646: necessary. */ ! 647: ! 648: rtx ! 649: legitimize_pic_address (orig, mode, reg) ! 650: rtx orig; ! 651: enum machine_mode mode; ! 652: rtx reg; ! 653: { ! 654: if (GET_CODE (orig) == SYMBOL_REF) ! 655: { ! 656: rtx pic_ref, address; ! 657: rtx insn; ! 658: ! 659: if (reg == 0) ! 660: { ! 661: if (reload_in_progress || reload_completed) ! 662: abort (); ! 663: else ! 664: reg = gen_reg_rtx (Pmode); ! 665: } ! 666: ! 667: if (flag_pic == 2) ! 668: { ! 669: /* If not during reload, allocate another temp reg here for loading ! 670: in the address, so that these instructions can be optimized ! 671: properly. */ ! 672: rtx temp_reg = ((reload_in_progress || reload_completed) ! 673: ? reg : gen_reg_rtx (Pmode)); ! 674: ! 675: /* Must put the SYMBOL_REF inside an UNSPEC here so that cse ! 676: won't get confused into thinking that these two instructions ! 677: are loading in the true address of the symbol. If in the ! 678: future a PIC rtx exists, that should be used instead. */ ! 679: emit_insn (gen_rtx (SET, VOIDmode, temp_reg, ! 680: gen_rtx (HIGH, Pmode, ! 681: gen_rtx (UNSPEC, Pmode, ! 682: gen_rtvec (1, orig), ! 683: 0)))); ! 684: emit_insn (gen_rtx (SET, VOIDmode, temp_reg, ! 685: gen_rtx (LO_SUM, Pmode, temp_reg, ! 686: gen_rtx (UNSPEC, Pmode, ! 687: gen_rtvec (1, orig), ! 688: 0)))); ! 689: address = temp_reg; ! 690: } ! 691: else ! 692: address = orig; ! 693: ! 694: pic_ref = gen_rtx (MEM, Pmode, ! 695: gen_rtx (PLUS, Pmode, ! 696: pic_offset_table_rtx, address)); ! 697: current_function_uses_pic_offset_table = 1; ! 698: RTX_UNCHANGING_P (pic_ref) = 1; ! 699: insn = emit_move_insn (reg, pic_ref); ! 700: /* Put a REG_EQUAL note on this insn, so that it can be optimized ! 701: by loop. */ ! 702: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, ! 703: REG_NOTES (insn)); ! 704: return reg; ! 705: } ! 706: else if (GET_CODE (orig) == CONST) ! 707: { ! 708: rtx base, offset; ! 709: ! 710: if (GET_CODE (XEXP (orig, 0)) == PLUS ! 711: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) ! 712: return orig; ! 713: ! 714: if (reg == 0) ! 715: { ! 716: if (reload_in_progress || reload_completed) ! 717: abort (); ! 718: else ! 719: reg = gen_reg_rtx (Pmode); ! 720: } ! 721: ! 722: if (GET_CODE (XEXP (orig, 0)) == PLUS) ! 723: { ! 724: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); ! 725: offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, ! 726: base == reg ? 0 : reg); ! 727: } ! 728: else ! 729: abort (); ! 730: ! 731: if (GET_CODE (offset) == CONST_INT) ! 732: { ! 733: if (SMALL_INT (offset)) ! 734: return plus_constant_for_output (base, INTVAL (offset)); ! 735: else if (! reload_in_progress && ! reload_completed) ! 736: offset = force_reg (Pmode, offset); ! 737: else ! 738: /* If we reach here, then something is seriously wrong. */ ! 739: abort (); ! 740: } ! 741: return gen_rtx (PLUS, Pmode, base, offset); ! 742: } ! 743: else if (GET_CODE (orig) == LABEL_REF) ! 744: current_function_uses_pic_offset_table = 1; ! 745: ! 746: return orig; ! 747: } ! 748: ! 749: /* Set up PIC-specific rtl. This should not cause any insns ! 750: to be emitted. */ ! 751: ! 752: void ! 753: initialize_pic () ! 754: { ! 755: } ! 756: ! 757: /* Emit special PIC prologues and epilogues. */ ! 758: ! 759: void ! 760: finalize_pic () ! 761: { ! 762: /* The table we use to reference PIC data. */ ! 763: rtx global_offset_table; ! 764: /* Labels to get the PC in the prologue of this function. */ ! 765: rtx l1, l2; ! 766: rtx seq; ! 767: int orig_flag_pic = flag_pic; ! 768: ! 769: if (current_function_uses_pic_offset_table == 0) ! 770: return; ! 771: ! 772: if (! flag_pic) ! 773: abort (); ! 774: ! 775: flag_pic = 0; ! 776: l1 = gen_label_rtx (); ! 777: l2 = gen_label_rtx (); ! 778: ! 779: start_sequence (); ! 780: ! 781: emit_label (l1); ! 782: /* Note that we pun calls and jumps here! */ ! 783: emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, ! 784: gen_rtvec (2, ! 785: gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)), ! 786: gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2))))); ! 787: emit_label (l2); ! 788: ! 789: /* Initialize every time through, since we can't easily ! 790: know this to be permanent. */ ! 791: global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); ! 792: pic_pc_rtx = gen_rtx (CONST, Pmode, ! 793: gen_rtx (MINUS, Pmode, ! 794: global_offset_table, ! 795: gen_rtx (CONST, Pmode, ! 796: gen_rtx (MINUS, Pmode, ! 797: gen_rtx (LABEL_REF, VOIDmode, l1), ! 798: pc_rtx)))); ! 799: ! 800: emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx, ! 801: gen_rtx (HIGH, Pmode, pic_pc_rtx))); ! 802: emit_insn (gen_rtx (SET, VOIDmode, ! 803: pic_offset_table_rtx, ! 804: gen_rtx (LO_SUM, Pmode, ! 805: pic_offset_table_rtx, pic_pc_rtx))); ! 806: emit_insn (gen_rtx (SET, VOIDmode, ! 807: pic_offset_table_rtx, ! 808: gen_rtx (PLUS, Pmode, ! 809: pic_offset_table_rtx, gen_rtx (REG, Pmode, 15)))); ! 810: /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */ ! 811: LABEL_PRESERVE_P (l1) = 1; ! 812: LABEL_PRESERVE_P (l2) = 1; ! 813: flag_pic = orig_flag_pic; ! 814: ! 815: seq = gen_sequence (); ! 816: end_sequence (); ! 817: emit_insn_after (seq, get_insns ()); ! 818: ! 819: /* Need to emit this whether or not we obey regdecls, ! 820: since setjmp/longjmp can cause life info to screw up. */ ! 821: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); ! 822: } ! 823: ! 824: /* For the SPARC, REG and REG+CONST is cost 0, REG+REG is cost 1, ! 825: and addresses involving symbolic constants are cost 2. ! 826: ! 827: We make REG+REG slightly more expensive because it might keep ! 828: a register live for longer than we might like. ! 829: ! 830: PIC addresses are very expensive. ! 831: ! 832: It is no coincidence that this has the same structure ! 833: as GO_IF_LEGITIMATE_ADDRESS. */ ! 834: int ! 835: sparc_address_cost (X) ! 836: rtx X; ! 837: { ! 838: #if 0 ! 839: /* Handled before calling here. */ ! 840: if (GET_CODE (X) == REG) ! 841: { return 1; } ! 842: #endif ! 843: if (GET_CODE (X) == PLUS) ! 844: { ! 845: if (GET_CODE (XEXP (X, 0)) == REG ! 846: && GET_CODE (XEXP (X, 1)) == REG) ! 847: return 2; ! 848: return 1; ! 849: } ! 850: else if (GET_CODE (X) == LO_SUM) ! 851: return 1; ! 852: else if (GET_CODE (X) == HIGH) ! 853: return 2; ! 854: return 4; ! 855: } ! 856: ! 857: /* Emit insns to move operands[1] into operands[0]. ! 858: ! 859: Return 1 if we have written out everything that needs to be done to ! 860: do the move. Otherwise, return 0 and the caller will emit the move ! 861: normally. */ ! 862: ! 863: int ! 864: emit_move_sequence (operands, mode) ! 865: rtx *operands; ! 866: enum machine_mode mode; ! 867: { ! 868: register rtx operand0 = operands[0]; ! 869: register rtx operand1 = operands[1]; ! 870: ! 871: if (CONSTANT_P (operand1) && flag_pic ! 872: && pic_address_needs_scratch (operand1)) ! 873: operands[1] = operand1 = legitimize_pic_address (operand1, mode, 0); ! 874: ! 875: /* Handle most common case first: storing into a register. */ ! 876: if (register_operand (operand0, mode)) ! 877: { ! 878: if (register_operand (operand1, mode) ! 879: || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1)) ! 880: || (GET_CODE (operand1) == CONST_DOUBLE ! 881: && arith_double_operand (operand1, DImode)) ! 882: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode) ! 883: /* Only `general_operands' can come here, so MEM is ok. */ ! 884: || GET_CODE (operand1) == MEM) ! 885: { ! 886: /* Run this case quickly. */ ! 887: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 888: return 1; ! 889: } ! 890: } ! 891: else if (GET_CODE (operand0) == MEM) ! 892: { ! 893: if (register_operand (operand1, mode) || operand1 == const0_rtx) ! 894: { ! 895: /* Run this case quickly. */ ! 896: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 897: return 1; ! 898: } ! 899: if (! reload_in_progress) ! 900: { ! 901: operands[0] = validize_mem (operand0); ! 902: operands[1] = operand1 = force_reg (mode, operand1); ! 903: } ! 904: } ! 905: ! 906: /* Simplify the source if we need to. Must handle DImode HIGH operators ! 907: here because such a move needs a clobber added. */ ! 908: if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode)) ! 909: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode)) ! 910: { ! 911: if (flag_pic && symbolic_operand (operand1, mode)) ! 912: { ! 913: rtx temp_reg = reload_in_progress ? operand0 : 0; ! 914: ! 915: operands[1] = legitimize_pic_address (operand1, mode, temp_reg); ! 916: } ! 917: else if (GET_CODE (operand1) == CONST_INT ! 918: ? (! SMALL_INT (operand1) ! 919: && (INTVAL (operand1) & 0x3ff) != 0) ! 920: : (GET_CODE (operand1) == CONST_DOUBLE ! 921: ? ! arith_double_operand (operand1, DImode) ! 922: : 1)) ! 923: { ! 924: /* For DImode values, temp must be operand0 because of the way ! 925: HI and LO_SUM work. The LO_SUM operator only copies half of ! 926: the LSW from the dest of the HI operator. If the LO_SUM dest is ! 927: not the same as the HI dest, then the MSW of the LO_SUM dest will ! 928: never be set. ! 929: ! 930: ??? The real problem here is that the ...(HI:DImode pattern emits ! 931: multiple instructions, and the ...(LO_SUM:DImode pattern emits ! 932: one instruction. This fails, because the compiler assumes that ! 933: LO_SUM copies all bits of the first operand to its dest. Better ! 934: would be to have the HI pattern emit one instruction and the ! 935: LO_SUM pattern multiple instructions. Even better would be ! 936: to use four rtl insns. */ ! 937: rtx temp = ((reload_in_progress || mode == DImode) ! 938: ? operand0 : gen_reg_rtx (mode)); ! 939: ! 940: emit_insn (gen_rtx (SET, VOIDmode, temp, ! 941: gen_rtx (HIGH, mode, operand1))); ! 942: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1); ! 943: } ! 944: } ! 945: ! 946: if (GET_CODE (operand1) == LABEL_REF && flag_pic) ! 947: { ! 948: /* The procedure for doing this involves using a call instruction to ! 949: get the pc into o7. We need to indicate this explicitly because ! 950: the tablejump pattern assumes that it can use this value also. */ ! 951: emit_insn (gen_rtx (PARALLEL, VOIDmode, ! 952: gen_rtvec (2, ! 953: gen_rtx (SET, VOIDmode, operand0, ! 954: operand1), ! 955: gen_rtx (SET, VOIDmode, ! 956: gen_rtx (REG, mode, 15), ! 957: pc_rtx)))); ! 958: return 1; ! 959: } ! 960: ! 961: /* Now have insn-emit do whatever it normally does. */ ! 962: return 0; ! 963: } ! 964: ! 965: /* Return the best assembler insn template ! 966: for moving operands[1] into operands[0] as a fullword. */ ! 967: ! 968: char * ! 969: singlemove_string (operands) ! 970: rtx *operands; ! 971: { ! 972: if (GET_CODE (operands[0]) == MEM) ! 973: { ! 974: if (GET_CODE (operands[1]) != MEM) ! 975: return "st %r1,%0"; ! 976: else ! 977: abort (); ! 978: } ! 979: else if (GET_CODE (operands[1]) == MEM) ! 980: return "ld %1,%0"; ! 981: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 982: { ! 983: REAL_VALUE_TYPE r; ! 984: long i; ! 985: ! 986: /* Must be SFmode, otherwise this doesn't make sense. */ ! 987: if (GET_MODE (operands[1]) != SFmode) ! 988: abort (); ! 989: ! 990: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); ! 991: REAL_VALUE_TO_TARGET_SINGLE (r, i); ! 992: operands[1] = gen_rtx (CONST_INT, VOIDmode, i); ! 993: ! 994: if (CONST_OK_FOR_LETTER_P (i, 'I')) ! 995: return "mov %1,%0"; ! 996: else if ((i & 0x000003FF) != 0) ! 997: return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; ! 998: else ! 999: return "sethi %%hi(%a1),%0"; ! 1000: } ! 1001: else if (GET_CODE (operands[1]) == CONST_INT ! 1002: && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) ! 1003: { ! 1004: int i = INTVAL (operands[1]); ! 1005: ! 1006: /* If all low order 10 bits are clear, then we only need a single ! 1007: sethi insn to load the constant. */ ! 1008: if ((i & 0x000003FF) != 0) ! 1009: return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; ! 1010: else ! 1011: return "sethi %%hi(%a1),%0"; ! 1012: } ! 1013: /* Operand 1 must be a register, or a 'I' type CONST_INT. */ ! 1014: return "mov %1,%0"; ! 1015: } ! 1016: ! 1017: /* Return non-zero if it is OK to assume that the given memory operand is ! 1018: aligned at least to a 8-byte boundary. This should only be called ! 1019: for memory accesses whose size is 8 bytes or larger. */ ! 1020: ! 1021: int ! 1022: mem_aligned_8 (mem) ! 1023: register rtx mem; ! 1024: { ! 1025: register rtx addr; ! 1026: register rtx base; ! 1027: register rtx offset; ! 1028: ! 1029: if (GET_CODE (mem) != MEM) ! 1030: return 0; /* It's gotta be a MEM! */ ! 1031: ! 1032: addr = XEXP (mem, 0); ! 1033: ! 1034: /* Now that all misaligned double parms are copied on function entry, ! 1035: we can assume any 64-bit object is 64-bit aligned except those which ! 1036: are at unaligned offsets from the stack or frame pointer. If the ! 1037: TARGET_UNALIGNED_DOUBLES switch is given, we do not make this ! 1038: assumption. */ ! 1039: ! 1040: /* See what register we use in the address. */ ! 1041: base = 0; ! 1042: if (GET_CODE (addr) == PLUS) ! 1043: { ! 1044: if (GET_CODE (XEXP (addr, 0)) == REG ! 1045: && GET_CODE (XEXP (addr, 1)) == CONST_INT) ! 1046: { ! 1047: base = XEXP (addr, 0); ! 1048: offset = XEXP (addr, 1); ! 1049: } ! 1050: } ! 1051: else if (GET_CODE (addr) == REG) ! 1052: { ! 1053: base = addr; ! 1054: offset = const0_rtx; ! 1055: } ! 1056: ! 1057: /* If it's the stack or frame pointer, check offset alignment. ! 1058: We can have improper alignment in the function entry code. */ ! 1059: if (base ! 1060: && (REGNO (base) == FRAME_POINTER_REGNUM ! 1061: || REGNO (base) == STACK_POINTER_REGNUM)) ! 1062: { ! 1063: if ((INTVAL (offset) & 0x7) == 0) ! 1064: return 1; ! 1065: } ! 1066: /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES ! 1067: is true, in which case we can only assume that an access is aligned if ! 1068: it is to an aggregate, it is to a constant address, or the address ! 1069: involves a LO_SUM. */ ! 1070: else if (! TARGET_UNALIGNED_DOUBLES || MEM_IN_STRUCT_P (mem) ! 1071: || CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM) ! 1072: return 1; ! 1073: ! 1074: /* An obviously unaligned address. */ ! 1075: return 0; ! 1076: } ! 1077: ! 1078: enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP }; ! 1079: ! 1080: /* Output assembler code to perform a doubleword move insn ! 1081: with operands OPERANDS. This is very similar to the following ! 1082: output_move_quad function. */ ! 1083: ! 1084: char * ! 1085: output_move_double (operands) ! 1086: rtx *operands; ! 1087: { ! 1088: register rtx op0 = operands[0]; ! 1089: register rtx op1 = operands[1]; ! 1090: register enum optype optype0; ! 1091: register enum optype optype1; ! 1092: rtx latehalf[2]; ! 1093: rtx addreg0 = 0; ! 1094: rtx addreg1 = 0; ! 1095: int highest_first = 0; ! 1096: int no_addreg1_decrement = 0; ! 1097: ! 1098: /* First classify both operands. */ ! 1099: ! 1100: if (REG_P (op0)) ! 1101: optype0 = REGOP; ! 1102: else if (offsettable_memref_p (op0)) ! 1103: optype0 = OFFSOP; ! 1104: else if (GET_CODE (op0) == MEM) ! 1105: optype0 = MEMOP; ! 1106: else ! 1107: optype0 = RNDOP; ! 1108: ! 1109: if (REG_P (op1)) ! 1110: optype1 = REGOP; ! 1111: else if (CONSTANT_P (op1)) ! 1112: optype1 = CNSTOP; ! 1113: else if (offsettable_memref_p (op1)) ! 1114: optype1 = OFFSOP; ! 1115: else if (GET_CODE (op1) == MEM) ! 1116: optype1 = MEMOP; ! 1117: else ! 1118: optype1 = RNDOP; ! 1119: ! 1120: /* Check for the cases that the operand constraints are not ! 1121: supposed to allow to happen. Abort if we get one, ! 1122: because generating code for these cases is painful. */ ! 1123: ! 1124: if (optype0 == RNDOP || optype1 == RNDOP ! 1125: || (optype0 == MEM && optype1 == MEM)) ! 1126: abort (); ! 1127: ! 1128: /* If an operand is an unoffsettable memory ref, find a register ! 1129: we can increment temporarily to make it refer to the second word. */ ! 1130: ! 1131: if (optype0 == MEMOP) ! 1132: addreg0 = find_addr_reg (XEXP (op0, 0)); ! 1133: ! 1134: if (optype1 == MEMOP) ! 1135: addreg1 = find_addr_reg (XEXP (op1, 0)); ! 1136: ! 1137: /* Ok, we can do one word at a time. ! 1138: Set up in LATEHALF the operands to use for the ! 1139: high-numbered (least significant) word and in some cases alter the ! 1140: operands in OPERANDS to be suitable for the low-numbered word. */ ! 1141: ! 1142: if (optype0 == REGOP) ! 1143: latehalf[0] = gen_rtx (REG, SImode, REGNO (op0) + 1); ! 1144: else if (optype0 == OFFSOP) ! 1145: latehalf[0] = adj_offsettable_operand (op0, 4); ! 1146: else ! 1147: latehalf[0] = op0; ! 1148: ! 1149: if (optype1 == REGOP) ! 1150: latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1); ! 1151: else if (optype1 == OFFSOP) ! 1152: latehalf[1] = adj_offsettable_operand (op1, 4); ! 1153: else if (optype1 == CNSTOP) ! 1154: split_double (op1, &operands[1], &latehalf[1]); ! 1155: else ! 1156: latehalf[1] = op1; ! 1157: ! 1158: /* Easy case: try moving both words at once. Check for moving between ! 1159: an even/odd register pair and a memory location. */ ! 1160: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP ! 1161: && (REGNO (op0) & 1) == 0) ! 1162: || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP ! 1163: && (REGNO (op1) & 1) == 0)) ! 1164: { ! 1165: register rtx mem; ! 1166: ! 1167: if (optype0 == REGOP) ! 1168: mem = op1; ! 1169: else ! 1170: mem = op0; ! 1171: ! 1172: if (mem_aligned_8 (mem)) ! 1173: return (mem == op1 ? "ldd %1,%0" : "std %1,%0"); ! 1174: } ! 1175: ! 1176: /* If the first move would clobber the source of the second one, ! 1177: do them in the other order. */ ! 1178: ! 1179: /* Overlapping registers. */ ! 1180: if (optype0 == REGOP && optype1 == REGOP ! 1181: && REGNO (op0) == REGNO (latehalf[1])) ! 1182: { ! 1183: /* Do that word. */ ! 1184: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1185: /* Do low-numbered word. */ ! 1186: return singlemove_string (operands); ! 1187: } ! 1188: /* Loading into a register which overlaps a register used in the address. */ ! 1189: else if (optype0 == REGOP && optype1 != REGOP ! 1190: && reg_overlap_mentioned_p (op0, op1)) ! 1191: { ! 1192: /* If both halves of dest are used in the src memory address, ! 1193: add the two regs and put them in the low reg (op0). ! 1194: Then it works to load latehalf first. */ ! 1195: if (reg_mentioned_p (op0, XEXP (op1, 0)) ! 1196: && reg_mentioned_p (latehalf[0], XEXP (op1, 0))) ! 1197: { ! 1198: rtx xops[2]; ! 1199: xops[0] = latehalf[0]; ! 1200: xops[1] = op0; ! 1201: output_asm_insn ("add %1,%0,%1", xops); ! 1202: operands[1] = gen_rtx (MEM, DImode, op0); ! 1203: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 1204: addreg1 = 0; ! 1205: highest_first = 1; ! 1206: } ! 1207: /* Only one register in the dest is used in the src memory address, ! 1208: and this is the first register of the dest, so we want to do ! 1209: the late half first here also. */ ! 1210: else if (! reg_mentioned_p (latehalf[0], XEXP (op1, 0))) ! 1211: highest_first = 1; ! 1212: /* Only one register in the dest is used in the src memory address, ! 1213: and this is the second register of the dest, so we want to do ! 1214: the late half last. If addreg1 is set, and addreg1 is the same ! 1215: register as latehalf, then we must suppress the trailing decrement, ! 1216: because it would clobber the value just loaded. */ ! 1217: else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0])) ! 1218: no_addreg1_decrement = 1; ! 1219: } ! 1220: ! 1221: /* Normal case: do the two words, low-numbered first. ! 1222: Overlap case (highest_first set): do high-numbered word first. */ ! 1223: ! 1224: if (! highest_first) ! 1225: output_asm_insn (singlemove_string (operands), operands); ! 1226: ! 1227: /* Make any unoffsettable addresses point at high-numbered word. */ ! 1228: if (addreg0) ! 1229: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1230: if (addreg1) ! 1231: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1232: ! 1233: /* Do that word. */ ! 1234: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1235: ! 1236: /* Undo the adds we just did. */ ! 1237: if (addreg0) ! 1238: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 1239: if (addreg1 && ! no_addreg1_decrement) ! 1240: output_asm_insn ("add %0,-0x4,%0", &addreg1); ! 1241: ! 1242: if (highest_first) ! 1243: output_asm_insn (singlemove_string (operands), operands); ! 1244: ! 1245: return ""; ! 1246: } ! 1247: ! 1248: /* Output assembler code to perform a quadword move insn ! 1249: with operands OPERANDS. This is very similar to the preceding ! 1250: output_move_double function. */ ! 1251: ! 1252: char * ! 1253: output_move_quad (operands) ! 1254: rtx *operands; ! 1255: { ! 1256: register rtx op0 = operands[0]; ! 1257: register rtx op1 = operands[1]; ! 1258: register enum optype optype0; ! 1259: register enum optype optype1; ! 1260: rtx wordpart[4][2]; ! 1261: rtx addreg0 = 0; ! 1262: rtx addreg1 = 0; ! 1263: ! 1264: /* First classify both operands. */ ! 1265: ! 1266: if (REG_P (op0)) ! 1267: optype0 = REGOP; ! 1268: else if (offsettable_memref_p (op0)) ! 1269: optype0 = OFFSOP; ! 1270: else if (GET_CODE (op0) == MEM) ! 1271: optype0 = MEMOP; ! 1272: else ! 1273: optype0 = RNDOP; ! 1274: ! 1275: if (REG_P (op1)) ! 1276: optype1 = REGOP; ! 1277: else if (CONSTANT_P (op1)) ! 1278: optype1 = CNSTOP; ! 1279: else if (offsettable_memref_p (op1)) ! 1280: optype1 = OFFSOP; ! 1281: else if (GET_CODE (op1) == MEM) ! 1282: optype1 = MEMOP; ! 1283: else ! 1284: optype1 = RNDOP; ! 1285: ! 1286: /* Check for the cases that the operand constraints are not ! 1287: supposed to allow to happen. Abort if we get one, ! 1288: because generating code for these cases is painful. */ ! 1289: ! 1290: if (optype0 == RNDOP || optype1 == RNDOP ! 1291: || (optype0 == MEM && optype1 == MEM)) ! 1292: abort (); ! 1293: ! 1294: /* If an operand is an unoffsettable memory ref, find a register ! 1295: we can increment temporarily to make it refer to the later words. */ ! 1296: ! 1297: if (optype0 == MEMOP) ! 1298: addreg0 = find_addr_reg (XEXP (op0, 0)); ! 1299: ! 1300: if (optype1 == MEMOP) ! 1301: addreg1 = find_addr_reg (XEXP (op1, 0)); ! 1302: ! 1303: /* Ok, we can do one word at a time. ! 1304: Set up in wordpart the operands to use for each word of the arguments. */ ! 1305: ! 1306: if (optype0 == REGOP) ! 1307: { ! 1308: wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0); ! 1309: wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1); ! 1310: wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2); ! 1311: wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3); ! 1312: } ! 1313: else if (optype0 == OFFSOP) ! 1314: { ! 1315: wordpart[0][0] = adj_offsettable_operand (op0, 0); ! 1316: wordpart[1][0] = adj_offsettable_operand (op0, 4); ! 1317: wordpart[2][0] = adj_offsettable_operand (op0, 8); ! 1318: wordpart[3][0] = adj_offsettable_operand (op0, 12); ! 1319: } ! 1320: else ! 1321: { ! 1322: wordpart[0][0] = op0; ! 1323: wordpart[1][0] = op0; ! 1324: wordpart[2][0] = op0; ! 1325: wordpart[3][0] = op0; ! 1326: } ! 1327: ! 1328: if (optype1 == REGOP) ! 1329: { ! 1330: wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0); ! 1331: wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1); ! 1332: wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2); ! 1333: wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3); ! 1334: } ! 1335: else if (optype1 == OFFSOP) ! 1336: { ! 1337: wordpart[0][1] = adj_offsettable_operand (op1, 0); ! 1338: wordpart[1][1] = adj_offsettable_operand (op1, 4); ! 1339: wordpart[2][1] = adj_offsettable_operand (op1, 8); ! 1340: wordpart[3][1] = adj_offsettable_operand (op1, 12); ! 1341: } ! 1342: else if (optype1 == CNSTOP) ! 1343: { ! 1344: REAL_VALUE_TYPE r; ! 1345: long l[4]; ! 1346: ! 1347: /* This only works for TFmode floating point constants. */ ! 1348: if (GET_CODE (op1) != CONST_DOUBLE || GET_MODE (op1) != TFmode) ! 1349: abort (); ! 1350: ! 1351: REAL_VALUE_FROM_CONST_DOUBLE (r, op1); ! 1352: REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); ! 1353: ! 1354: wordpart[0][1] = GEN_INT (l[0]); ! 1355: wordpart[1][1] = GEN_INT (l[1]); ! 1356: wordpart[2][1] = GEN_INT (l[2]); ! 1357: wordpart[3][1] = GEN_INT (l[3]); ! 1358: } ! 1359: else ! 1360: { ! 1361: wordpart[0][1] = op1; ! 1362: wordpart[1][1] = op1; ! 1363: wordpart[2][1] = op1; ! 1364: wordpart[3][1] = op1; ! 1365: } ! 1366: ! 1367: /* Easy case: try moving the quad as two pairs. Check for moving between ! 1368: an even/odd register pair and a memory location. */ ! 1369: /* ??? Should also handle the case of non-offsettable addresses here. ! 1370: We can at least do the first pair as a ldd/std, and then do the third ! 1371: and fourth words individually. */ ! 1372: if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0) ! 1373: || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0)) ! 1374: { ! 1375: rtx mem; ! 1376: ! 1377: if (optype0 == REGOP) ! 1378: mem = op1; ! 1379: else ! 1380: mem = op0; ! 1381: ! 1382: if (mem_aligned_8 (mem)) ! 1383: { ! 1384: operands[2] = adj_offsettable_operand (mem, 8); ! 1385: if (mem == op1) ! 1386: return "ldd %1,%0;ldd %2,%S0"; ! 1387: else ! 1388: return "std %1,%0;std %S1,%2"; ! 1389: } ! 1390: } ! 1391: ! 1392: /* If the first move would clobber the source of the second one, ! 1393: do them in the other order. */ ! 1394: ! 1395: /* Overlapping registers. */ ! 1396: if (optype0 == REGOP && optype1 == REGOP ! 1397: && (REGNO (op0) == REGNO (wordpart[1][3]) ! 1398: || REGNO (op0) == REGNO (wordpart[1][2]) ! 1399: || REGNO (op0) == REGNO (wordpart[1][1]))) ! 1400: { ! 1401: /* Do fourth word. */ ! 1402: output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]); ! 1403: /* Do the third word. */ ! 1404: output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]); ! 1405: /* Do the second word. */ ! 1406: output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]); ! 1407: /* Do lowest-numbered word. */ ! 1408: return singlemove_string (wordpart[0]); ! 1409: } ! 1410: /* Loading into a register which overlaps a register used in the address. */ ! 1411: if (optype0 == REGOP && optype1 != REGOP ! 1412: && reg_overlap_mentioned_p (op0, op1)) ! 1413: { ! 1414: /* ??? Not implemented yet. This is a bit complicated, because we ! 1415: must load which ever part overlaps the address last. If the address ! 1416: is a double-reg address, then there are two parts which need to ! 1417: be done last, which is impossible. We would need a scratch register ! 1418: in that case. */ ! 1419: abort (); ! 1420: } ! 1421: ! 1422: /* Normal case: move the four words in lowest to higest address order. */ ! 1423: ! 1424: output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]); ! 1425: ! 1426: /* Make any unoffsettable addresses point at the second word. */ ! 1427: if (addreg0) ! 1428: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1429: if (addreg1) ! 1430: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1431: ! 1432: /* Do the second word. */ ! 1433: output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]); ! 1434: ! 1435: /* Make any unoffsettable addresses point at the third word. */ ! 1436: if (addreg0) ! 1437: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1438: if (addreg1) ! 1439: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1440: ! 1441: /* Do the third word. */ ! 1442: output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]); ! 1443: ! 1444: /* Make any unoffsettable addresses point at the fourth word. */ ! 1445: if (addreg0) ! 1446: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1447: if (addreg1) ! 1448: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1449: ! 1450: /* Do the fourth word. */ ! 1451: output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]); ! 1452: ! 1453: /* Undo the adds we just did. */ ! 1454: if (addreg0) ! 1455: output_asm_insn ("add %0,-0xc,%0", &addreg0); ! 1456: if (addreg1) ! 1457: output_asm_insn ("add %0,-0xc,%0", &addreg1); ! 1458: ! 1459: return ""; ! 1460: } ! 1461: ! 1462: /* Output assembler code to perform a doubleword move insn with operands ! 1463: OPERANDS, one of which must be a floating point register. */ ! 1464: ! 1465: char * ! 1466: output_fp_move_double (operands) ! 1467: rtx *operands; ! 1468: { ! 1469: if (FP_REG_P (operands[0])) ! 1470: { ! 1471: if (FP_REG_P (operands[1])) ! 1472: return "fmovs %1,%0\n\tfmovs %R1,%R0"; ! 1473: else if (GET_CODE (operands[1]) == REG) ! 1474: abort (); ! 1475: else ! 1476: return output_move_double (operands); ! 1477: } ! 1478: else if (FP_REG_P (operands[1])) ! 1479: { ! 1480: if (GET_CODE (operands[0]) == REG) ! 1481: abort (); ! 1482: else ! 1483: return output_move_double (operands); ! 1484: } ! 1485: else abort (); ! 1486: } ! 1487: ! 1488: /* Output assembler code to perform a quadword move insn with operands ! 1489: OPERANDS, one of which must be a floating point register. */ ! 1490: ! 1491: char * ! 1492: output_fp_move_quad (operands) ! 1493: rtx *operands; ! 1494: { ! 1495: register rtx op0 = operands[0]; ! 1496: register rtx op1 = operands[1]; ! 1497: ! 1498: if (FP_REG_P (op0)) ! 1499: { ! 1500: if (FP_REG_P (op1)) ! 1501: return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0"; ! 1502: else if (GET_CODE (op1) == REG) ! 1503: abort (); ! 1504: else ! 1505: return output_move_quad (operands); ! 1506: } ! 1507: else if (FP_REG_P (op1)) ! 1508: { ! 1509: if (GET_CODE (op0) == REG) ! 1510: abort (); ! 1511: else ! 1512: return output_move_quad (operands); ! 1513: } ! 1514: else ! 1515: abort (); ! 1516: } ! 1517: ! 1518: /* Return a REG that occurs in ADDR with coefficient 1. ! 1519: ADDR can be effectively incremented by incrementing REG. */ ! 1520: ! 1521: static rtx ! 1522: find_addr_reg (addr) ! 1523: rtx addr; ! 1524: { ! 1525: while (GET_CODE (addr) == PLUS) ! 1526: { ! 1527: /* We absolutely can not fudge the frame pointer here, because the ! 1528: frame pointer must always be 8 byte aligned. It also confuses ! 1529: debuggers. */ ! 1530: if (GET_CODE (XEXP (addr, 0)) == REG ! 1531: && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM) ! 1532: addr = XEXP (addr, 0); ! 1533: else if (GET_CODE (XEXP (addr, 1)) == REG ! 1534: && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM) ! 1535: addr = XEXP (addr, 1); ! 1536: else if (CONSTANT_P (XEXP (addr, 0))) ! 1537: addr = XEXP (addr, 1); ! 1538: else if (CONSTANT_P (XEXP (addr, 1))) ! 1539: addr = XEXP (addr, 0); ! 1540: else ! 1541: abort (); ! 1542: } ! 1543: if (GET_CODE (addr) == REG) ! 1544: return addr; ! 1545: abort (); ! 1546: } ! 1547: ! 1548: #if 0 /* not currently used */ ! 1549: ! 1550: void ! 1551: output_sized_memop (opname, mode, signedp) ! 1552: char *opname; ! 1553: enum machine_mode mode; ! 1554: int signedp; ! 1555: { ! 1556: static char *ld_size_suffix_u[] = { "ub", "uh", "", "?", "d" }; ! 1557: static char *ld_size_suffix_s[] = { "sb", "sh", "", "?", "d" }; ! 1558: static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; ! 1559: char **opnametab, *modename; ! 1560: ! 1561: if (opname[0] == 'l') ! 1562: if (signedp) ! 1563: opnametab = ld_size_suffix_s; ! 1564: else ! 1565: opnametab = ld_size_suffix_u; ! 1566: else ! 1567: opnametab = st_size_suffix; ! 1568: modename = opnametab[GET_MODE_SIZE (mode) >> 1]; ! 1569: ! 1570: fprintf (asm_out_file, "\t%s%s", opname, modename); ! 1571: } ! 1572: ! 1573: void ! 1574: output_move_with_extension (operands) ! 1575: rtx *operands; ! 1576: { ! 1577: if (GET_MODE (operands[2]) == HImode) ! 1578: output_asm_insn ("sll %2,0x10,%0", operands); ! 1579: else if (GET_MODE (operands[2]) == QImode) ! 1580: output_asm_insn ("sll %2,0x18,%0", operands); ! 1581: else ! 1582: abort (); ! 1583: } ! 1584: #endif /* not currently used */ ! 1585: ! 1586: #if 0 ! 1587: /* ??? These are only used by the movstrsi pattern, but we get better code ! 1588: in general without that, because emit_block_move can do just as good a ! 1589: job as this function does when alignment and size are known. When they ! 1590: aren't known, a call to strcpy may be faster anyways, because it is ! 1591: likely to be carefully crafted assembly language code, and below we just ! 1592: do a byte-wise copy. ! 1593: ! 1594: Also, emit_block_move expands into multiple read/write RTL insns, which ! 1595: can then be optimized, whereas our movstrsi pattern can not be optimized ! 1596: at all. */ ! 1597: ! 1598: /* Load the address specified by OPERANDS[3] into the register ! 1599: specified by OPERANDS[0]. ! 1600: ! 1601: OPERANDS[3] may be the result of a sum, hence it could either be: ! 1602: ! 1603: (1) CONST ! 1604: (2) REG ! 1605: (2) REG + CONST_INT ! 1606: (3) REG + REG + CONST_INT ! 1607: (4) REG + REG (special case of 3). ! 1608: ! 1609: Note that (3) is not a legitimate address. ! 1610: All cases are handled here. */ ! 1611: ! 1612: void ! 1613: output_load_address (operands) ! 1614: rtx *operands; ! 1615: { ! 1616: rtx base, offset; ! 1617: ! 1618: if (CONSTANT_P (operands[3])) ! 1619: { ! 1620: output_asm_insn ("set %3,%0", operands); ! 1621: return; ! 1622: } ! 1623: ! 1624: if (REG_P (operands[3])) ! 1625: { ! 1626: if (REGNO (operands[0]) != REGNO (operands[3])) ! 1627: output_asm_insn ("mov %3,%0", operands); ! 1628: return; ! 1629: } ! 1630: ! 1631: if (GET_CODE (operands[3]) != PLUS) ! 1632: abort (); ! 1633: ! 1634: base = XEXP (operands[3], 0); ! 1635: offset = XEXP (operands[3], 1); ! 1636: ! 1637: if (GET_CODE (base) == CONST_INT) ! 1638: { ! 1639: rtx tmp = base; ! 1640: base = offset; ! 1641: offset = tmp; ! 1642: } ! 1643: ! 1644: if (GET_CODE (offset) != CONST_INT) ! 1645: { ! 1646: /* Operand is (PLUS (REG) (REG)). */ ! 1647: base = operands[3]; ! 1648: offset = const0_rtx; ! 1649: } ! 1650: ! 1651: if (REG_P (base)) ! 1652: { ! 1653: operands[6] = base; ! 1654: operands[7] = offset; ! 1655: if (SMALL_INT (offset)) ! 1656: output_asm_insn ("add %6,%7,%0", operands); ! 1657: else ! 1658: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); ! 1659: } ! 1660: else if (GET_CODE (base) == PLUS) ! 1661: { ! 1662: operands[6] = XEXP (base, 0); ! 1663: operands[7] = XEXP (base, 1); ! 1664: operands[8] = offset; ! 1665: ! 1666: if (SMALL_INT (offset)) ! 1667: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); ! 1668: else ! 1669: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); ! 1670: } ! 1671: else ! 1672: abort (); ! 1673: } ! 1674: ! 1675: /* Output code to place a size count SIZE in register REG. ! 1676: ALIGN is the size of the unit of transfer. ! 1677: ! 1678: Because block moves are pipelined, we don't include the ! 1679: first element in the transfer of SIZE to REG. */ ! 1680: ! 1681: static void ! 1682: output_size_for_block_move (size, reg, align) ! 1683: rtx size, reg; ! 1684: rtx align; ! 1685: { ! 1686: rtx xoperands[3]; ! 1687: ! 1688: xoperands[0] = reg; ! 1689: xoperands[1] = size; ! 1690: xoperands[2] = align; ! 1691: if (GET_CODE (size) == REG) ! 1692: output_asm_insn ("sub %1,%2,%0", xoperands); ! 1693: else ! 1694: { ! 1695: xoperands[1] ! 1696: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); ! 1697: output_asm_insn ("set %1,%0", xoperands); ! 1698: } ! 1699: } ! 1700: ! 1701: /* Emit code to perform a block move. ! 1702: ! 1703: OPERANDS[0] is the destination. ! 1704: OPERANDS[1] is the source. ! 1705: OPERANDS[2] is the size. ! 1706: OPERANDS[3] is the alignment safe to use. ! 1707: OPERANDS[4] is a register we can safely clobber as a temp. */ ! 1708: ! 1709: char * ! 1710: output_block_move (operands) ! 1711: rtx *operands; ! 1712: { ! 1713: /* A vector for our computed operands. Note that load_output_address ! 1714: makes use of (and can clobber) up to the 8th element of this vector. */ ! 1715: rtx xoperands[10]; ! 1716: rtx zoperands[10]; ! 1717: static int movstrsi_label = 0; ! 1718: int i; ! 1719: rtx temp1 = operands[4]; ! 1720: rtx sizertx = operands[2]; ! 1721: rtx alignrtx = operands[3]; ! 1722: int align = INTVAL (alignrtx); ! 1723: char label3[30], label5[30]; ! 1724: ! 1725: xoperands[0] = operands[0]; ! 1726: xoperands[1] = operands[1]; ! 1727: xoperands[2] = temp1; ! 1728: ! 1729: /* We can't move more than this many bytes at a time because we have only ! 1730: one register, %g1, to move them through. */ ! 1731: if (align > UNITS_PER_WORD) ! 1732: { ! 1733: align = UNITS_PER_WORD; ! 1734: alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD); ! 1735: } ! 1736: ! 1737: /* We consider 8 ld/st pairs, for a total of 16 inline insns to be ! 1738: reasonable here. (Actually will emit a maximum of 18 inline insns for ! 1739: the case of size == 31 and align == 4). */ ! 1740: ! 1741: if (GET_CODE (sizertx) == CONST_INT && (INTVAL (sizertx) / align) <= 8 ! 1742: && memory_address_p (QImode, plus_constant_for_output (xoperands[0], ! 1743: INTVAL (sizertx))) ! 1744: && memory_address_p (QImode, plus_constant_for_output (xoperands[1], ! 1745: INTVAL (sizertx)))) ! 1746: { ! 1747: int size = INTVAL (sizertx); ! 1748: int offset = 0; ! 1749: ! 1750: /* We will store different integers into this particular RTX. */ ! 1751: xoperands[2] = rtx_alloc (CONST_INT); ! 1752: PUT_MODE (xoperands[2], VOIDmode); ! 1753: ! 1754: /* This case is currently not handled. Abort instead of generating ! 1755: bad code. */ ! 1756: if (align > 4) ! 1757: abort (); ! 1758: ! 1759: if (align >= 4) ! 1760: { ! 1761: for (i = (size >> 2) - 1; i >= 0; i--) ! 1762: { ! 1763: INTVAL (xoperands[2]) = (i << 2) + offset; ! 1764: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", ! 1765: xoperands); ! 1766: } ! 1767: offset += (size & ~0x3); ! 1768: size = size & 0x3; ! 1769: if (size == 0) ! 1770: return ""; ! 1771: } ! 1772: ! 1773: if (align >= 2) ! 1774: { ! 1775: for (i = (size >> 1) - 1; i >= 0; i--) ! 1776: { ! 1777: INTVAL (xoperands[2]) = (i << 1) + offset; ! 1778: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", ! 1779: xoperands); ! 1780: } ! 1781: offset += (size & ~0x1); ! 1782: size = size & 0x1; ! 1783: if (size == 0) ! 1784: return ""; ! 1785: } ! 1786: ! 1787: if (align >= 1) ! 1788: { ! 1789: for (i = size - 1; i >= 0; i--) ! 1790: { ! 1791: INTVAL (xoperands[2]) = i + offset; ! 1792: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", ! 1793: xoperands); ! 1794: } ! 1795: return ""; ! 1796: } ! 1797: ! 1798: /* We should never reach here. */ ! 1799: abort (); ! 1800: } ! 1801: ! 1802: /* If the size isn't known to be a multiple of the alignment, ! 1803: we have to do it in smaller pieces. If we could determine that ! 1804: the size was a multiple of 2 (or whatever), we could be smarter ! 1805: about this. */ ! 1806: if (GET_CODE (sizertx) != CONST_INT) ! 1807: align = 1; ! 1808: else ! 1809: { ! 1810: int size = INTVAL (sizertx); ! 1811: while (size % align) ! 1812: align >>= 1; ! 1813: } ! 1814: ! 1815: if (align != INTVAL (alignrtx)) ! 1816: alignrtx = gen_rtx (CONST_INT, VOIDmode, align); ! 1817: ! 1818: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1819: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); ! 1820: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1821: ! 1822: ASM_GENERATE_INTERNAL_LABEL (label3, "Lm", INTVAL (xoperands[3])); ! 1823: ASM_GENERATE_INTERNAL_LABEL (label5, "Lm", INTVAL (xoperands[5])); ! 1824: ! 1825: /* This is the size of the transfer. Emit code to decrement the size ! 1826: value by ALIGN, and store the result in the temp1 register. */ ! 1827: output_size_for_block_move (sizertx, temp1, alignrtx); ! 1828: ! 1829: /* Must handle the case when the size is zero or negative, so the first thing ! 1830: we do is compare the size against zero, and only copy bytes if it is ! 1831: zero or greater. Note that we have already subtracted off the alignment ! 1832: once, so we must copy 1 alignment worth of bytes if the size is zero ! 1833: here. ! 1834: ! 1835: The SUN assembler complains about labels in branch delay slots, so we ! 1836: do this before outputting the load address, so that there will always ! 1837: be a harmless insn between the branch here and the next label emitted ! 1838: below. */ ! 1839: ! 1840: { ! 1841: char pattern[100]; ! 1842: ! 1843: sprintf (pattern, "cmp %%2,0\n\tbl %s", &label5[1]); ! 1844: output_asm_insn (pattern, xoperands); ! 1845: } ! 1846: ! 1847: zoperands[0] = operands[0]; ! 1848: zoperands[3] = plus_constant_for_output (operands[0], align); ! 1849: output_load_address (zoperands); ! 1850: ! 1851: /* ??? This might be much faster if the loops below were preconditioned ! 1852: and unrolled. ! 1853: ! 1854: That is, at run time, copy enough bytes one at a time to ensure that the ! 1855: target and source addresses are aligned to the the largest possible ! 1856: alignment. Then use a preconditioned unrolled loop to copy say 16 ! 1857: bytes at a time. Then copy bytes one at a time until finish the rest. */ ! 1858: ! 1859: /* Output the first label separately, so that it is spaced properly. */ ! 1860: ! 1861: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "Lm", INTVAL (xoperands[3])); ! 1862: ! 1863: { ! 1864: char pattern[200]; ! 1865: register char *ld_suffix = (align == 1) ? "ub" : (align == 2) ? "uh" : ""; ! 1866: register char *st_suffix = (align == 1) ? "b" : (align == 2) ? "h" : ""; ! 1867: ! 1868: sprintf (pattern, "ld%s [%%1+%%2],%%%%g1\n\tsubcc %%2,%%4,%%2\n\tbge %s\n\tst%s %%%%g1,[%%0+%%2]\n%s:", ld_suffix, &label3[1], st_suffix, &label5[1]); ! 1869: output_asm_insn (pattern, xoperands); ! 1870: } ! 1871: ! 1872: return ""; ! 1873: } ! 1874: #endif ! 1875: ! 1876: /* Output reasonable peephole for set-on-condition-code insns. ! 1877: Note that these insns assume a particular way of defining ! 1878: labels. Therefore, *both* sparc.h and this function must ! 1879: be changed if a new syntax is needed. */ ! 1880: ! 1881: char * ! 1882: output_scc_insn (operands, insn) ! 1883: rtx operands[]; ! 1884: rtx insn; ! 1885: { ! 1886: static char string[100]; ! 1887: rtx label = 0, next = insn; ! 1888: int need_label = 0; ! 1889: ! 1890: /* Try doing a jump optimization which jump.c can't do for us ! 1891: because we did not expose that setcc works by using branches. ! 1892: ! 1893: If this scc insn is followed by an unconditional branch, then have ! 1894: the jump insn emitted here jump to that location, instead of to ! 1895: the end of the scc sequence as usual. */ ! 1896: ! 1897: do ! 1898: { ! 1899: if (GET_CODE (next) == CODE_LABEL) ! 1900: label = next; ! 1901: next = NEXT_INSN (next); ! 1902: if (next == 0) ! 1903: break; ! 1904: } ! 1905: while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL); ! 1906: ! 1907: /* If we are in a sequence, and the following insn is a sequence also, ! 1908: then just following the current insn's next field will take us to the ! 1909: first insn of the next sequence, which is the wrong place. We don't ! 1910: want to optimize with a branch that has had its delay slot filled. ! 1911: Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next ! 1912: which fails only if NEXT is such a branch. */ ! 1913: ! 1914: if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next) ! 1915: && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next)) ! 1916: label = JUMP_LABEL (next); ! 1917: /* If not optimizing, jump label fields are not set. To be safe, always ! 1918: check here to whether label is still zero. */ ! 1919: if (label == 0) ! 1920: { ! 1921: label = gen_label_rtx (); ! 1922: need_label = 1; ! 1923: } ! 1924: ! 1925: LABEL_NUSES (label) += 1; ! 1926: ! 1927: operands[2] = label; ! 1928: ! 1929: /* If we are in a delay slot, assume it is the delay slot of an fpcc ! 1930: insn since our type isn't allowed anywhere else. */ ! 1931: ! 1932: /* ??? Fpcc instructions no longer have delay slots, so this code is ! 1933: probably obsolete. */ ! 1934: ! 1935: /* The fastest way to emit code for this is an annulled branch followed ! 1936: by two move insns. This will take two cycles if the branch is taken, ! 1937: and three cycles if the branch is not taken. ! 1938: ! 1939: However, if we are in the delay slot of another branch, this won't work, ! 1940: because we can't put a branch in the delay slot of another branch. ! 1941: The above sequence would effectively take 3 or 4 cycles respectively ! 1942: since a no op would have be inserted between the two branches. ! 1943: In this case, we want to emit a move, annulled branch, and then the ! 1944: second move. This sequence always takes 3 cycles, and hence is faster ! 1945: when we are in a branch delay slot. */ ! 1946: ! 1947: if (final_sequence) ! 1948: { ! 1949: strcpy (string, "mov 0,%0\n\t"); ! 1950: strcat (string, output_cbranch (operands[1], 2, 0, 1, 0)); ! 1951: strcat (string, "\n\tmov 1,%0"); ! 1952: } ! 1953: else ! 1954: { ! 1955: strcpy (string, output_cbranch (operands[1], 2, 0, 1, 0)); ! 1956: strcat (string, "\n\tmov 1,%0\n\tmov 0,%0"); ! 1957: } ! 1958: ! 1959: if (need_label) ! 1960: strcat (string, "\n%l2:"); ! 1961: ! 1962: return string; ! 1963: } ! 1964: ! 1965: /* Vectors to keep interesting information about registers where ! 1966: it can easily be got. */ ! 1967: ! 1968: /* Modes for condition codes. */ ! 1969: #define C_MODES \ ! 1970: ((1 << (int) CCmode) | (1 << (int) CC_NOOVmode) \ ! 1971: | (1 << (int) CCFPmode) | (1 << (int) CCFPEmode)) ! 1972: ! 1973: /* Modes for single-word (and smaller) quantities. */ ! 1974: #define S_MODES \ ! 1975: ((1 << (int) QImode) | (1 << (int) HImode) | (1 << (int) SImode) \ ! 1976: | (1 << (int) QFmode) | (1 << (int) HFmode) | (1 << (int) SFmode) \ ! 1977: | (1 << (int) CQImode) | (1 << (int) CHImode)) ! 1978: ! 1979: /* Modes for double-word (and smaller) quantities. */ ! 1980: #define D_MODES \ ! 1981: (S_MODES | (1 << (int) DImode) | (1 << (int) DFmode) \ ! 1982: | (1 << (int) CSImode) | (1 << (int) SCmode)) ! 1983: ! 1984: /* Modes for quad-word quantities. */ ! 1985: #define T_MODES \ ! 1986: (D_MODES | (1 << (int) TImode) | (1 << (int) TFmode) \ ! 1987: | (1 << (int) DCmode) | (1 << (int) CDImode)) ! 1988: ! 1989: /* Modes for single-float quantities. We must allow any single word or ! 1990: smaller quantity. This is because the fix/float conversion instructions ! 1991: take integer inputs/outputs from the float registers. */ ! 1992: #define SF_MODES (S_MODES) ! 1993: ! 1994: /* Modes for double-float quantities. */ ! 1995: #define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode)) ! 1996: ! 1997: /* Modes for quad-float quantities. */ ! 1998: #define TF_MODES (DF_MODES | (1 << (int) TFmode) | (1 << (int) DCmode)) ! 1999: ! 2000: /* Value is 1 if register/mode pair is acceptable on sparc. ! 2001: The funny mixture of D and T modes is because integer operations ! 2002: do not specially operate on tetra quantities, so non-quad-aligned ! 2003: registers can hold quadword quantities (except %o4 and %i4 because ! 2004: they cross fixed registers. */ ! 2005: ! 2006: int hard_regno_mode_ok[] = { ! 2007: C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, ! 2008: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, ! 2009: T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, ! 2010: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, ! 2011: ! 2012: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 2013: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 2014: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 2015: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES}; ! 2016: ! 2017: #ifdef __GNUC__ ! 2018: inline ! 2019: #endif ! 2020: static int ! 2021: save_regs (file, low, high, base, offset, n_fregs) ! 2022: FILE *file; ! 2023: int low, high; ! 2024: char *base; ! 2025: int offset; ! 2026: int n_fregs; ! 2027: { ! 2028: int i; ! 2029: ! 2030: for (i = low; i < high; i += 2) ! 2031: { ! 2032: if (regs_ever_live[i] && ! call_used_regs[i]) ! 2033: if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 2034: fprintf (file, "\tstd %s,[%s+%d]\n", ! 2035: reg_names[i], base, offset + 4 * n_fregs), ! 2036: n_fregs += 2; ! 2037: else ! 2038: fprintf (file, "\tst %s,[%s+%d]\n", ! 2039: reg_names[i], base, offset + 4 * n_fregs), ! 2040: n_fregs += 2; ! 2041: else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 2042: fprintf (file, "\tst %s,[%s+%d]\n", ! 2043: reg_names[i+1], base, offset + 4 * n_fregs), ! 2044: n_fregs += 2; ! 2045: } ! 2046: return n_fregs; ! 2047: } ! 2048: ! 2049: #ifdef __GNUC__ ! 2050: inline ! 2051: #endif ! 2052: static int ! 2053: restore_regs (file, low, high, base, offset, n_fregs) ! 2054: FILE *file; ! 2055: int low, high; ! 2056: char *base; ! 2057: int offset; ! 2058: { ! 2059: int i; ! 2060: ! 2061: for (i = low; i < high; i += 2) ! 2062: { ! 2063: if (regs_ever_live[i] && ! call_used_regs[i]) ! 2064: if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 2065: fprintf (file, "\tldd [%s+%d], %s\n", ! 2066: base, offset + 4 * n_fregs, reg_names[i]), ! 2067: n_fregs += 2; ! 2068: else ! 2069: fprintf (file, "\tld [%s+%d],%s\n", ! 2070: base, offset + 4 * n_fregs, reg_names[i]), ! 2071: n_fregs += 2; ! 2072: else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 2073: fprintf (file, "\tld [%s+%d],%s\n", ! 2074: base, offset + 4 * n_fregs, reg_names[i+1]), ! 2075: n_fregs += 2; ! 2076: } ! 2077: return n_fregs; ! 2078: } ! 2079: ! 2080: /* Static variables we want to share between prologue and epilogue. */ ! 2081: ! 2082: /* Number of live floating point registers needed to be saved. */ ! 2083: static int num_fregs; ! 2084: ! 2085: int ! 2086: compute_frame_size (size, leaf_function) ! 2087: int size; ! 2088: int leaf_function; ! 2089: { ! 2090: int fregs_ever_live = 0; ! 2091: int n_fregs = 0, i; ! 2092: int outgoing_args_size = (current_function_outgoing_args_size ! 2093: + REG_PARM_STACK_SPACE (current_function_decl)); ! 2094: ! 2095: apparent_fsize = ((size) + 7 - STARTING_FRAME_OFFSET) & -8; ! 2096: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2) ! 2097: fregs_ever_live |= regs_ever_live[i]|regs_ever_live[i+1]; ! 2098: ! 2099: if (TARGET_EPILOGUE && fregs_ever_live) ! 2100: { ! 2101: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2) ! 2102: if ((regs_ever_live[i] && ! call_used_regs[i]) ! 2103: || (regs_ever_live[i+1] && ! call_used_regs[i+1])) ! 2104: n_fregs += 2; ! 2105: } ! 2106: ! 2107: /* Set up values for use in `function_epilogue'. */ ! 2108: num_fregs = n_fregs; ! 2109: ! 2110: apparent_fsize += (outgoing_args_size+7) & -8; ! 2111: if (leaf_function && n_fregs == 0 ! 2112: && apparent_fsize == (REG_PARM_STACK_SPACE (current_function_decl) ! 2113: - STARTING_FRAME_OFFSET)) ! 2114: apparent_fsize = 0; ! 2115: ! 2116: actual_fsize = apparent_fsize + n_fregs*4; ! 2117: ! 2118: /* Make sure nothing can clobber our register windows. ! 2119: If a SAVE must be done, or there is a stack-local variable, ! 2120: the register window area must be allocated. */ ! 2121: if (leaf_function == 0 || size > 0) ! 2122: actual_fsize += (16 * UNITS_PER_WORD)+8; ! 2123: ! 2124: return actual_fsize; ! 2125: } ! 2126: ! 2127: /* Output code for the function prologue. */ ! 2128: ! 2129: void ! 2130: output_function_prologue (file, size, leaf_function) ! 2131: FILE *file; ! 2132: int size; ! 2133: int leaf_function; ! 2134: { ! 2135: /* ??? This should be %sp+actual_fsize for a leaf function. I think it ! 2136: works only because it is never used. */ ! 2137: if (leaf_function) ! 2138: frame_base_name = "%sp+80"; ! 2139: else ! 2140: frame_base_name = "%fp"; ! 2141: ! 2142: /* Need to use actual_fsize, since we are also allocating ! 2143: space for our callee (and our own register save area). */ ! 2144: actual_fsize = compute_frame_size (size, leaf_function); ! 2145: ! 2146: fprintf (file, "\t!#PROLOGUE# 0\n"); ! 2147: if (actual_fsize == 0) ! 2148: /* do nothing. */ ; ! 2149: else if (actual_fsize <= 4096) ! 2150: { ! 2151: if (! leaf_function) ! 2152: fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize); ! 2153: else ! 2154: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize); ! 2155: } ! 2156: else if (actual_fsize <= 8192) ! 2157: { ! 2158: /* For frames in the range 4097..8192, we can use just two insns. */ ! 2159: if (! leaf_function) ! 2160: { ! 2161: fprintf (file, "\tsave %%sp,-4096,%%sp\n"); ! 2162: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096); ! 2163: } ! 2164: else ! 2165: { ! 2166: fprintf (file, "\tadd %%sp,-4096,%%sp\n"); ! 2167: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096); ! 2168: } ! 2169: } ! 2170: else ! 2171: { ! 2172: if (! leaf_function) ! 2173: { ! 2174: fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize); ! 2175: if ((actual_fsize & 0x3ff) != 0) ! 2176: fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize); ! 2177: fprintf (file, "\tsave %%sp,%%g1,%%sp\n"); ! 2178: } ! 2179: else ! 2180: { ! 2181: fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize); ! 2182: if ((actual_fsize & 0x3ff) != 0) ! 2183: fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize); ! 2184: fprintf (file, "\tadd %%sp,%%g1,%%sp\n"); ! 2185: } ! 2186: } ! 2187: ! 2188: /* If doing anything with PIC, do it now. */ ! 2189: if (! flag_pic) ! 2190: fprintf (file, "\t!#PROLOGUE# 1\n"); ! 2191: ! 2192: /* Figure out where to save any special registers. */ ! 2193: if (num_fregs) ! 2194: { ! 2195: int offset, n_fregs = num_fregs; ! 2196: ! 2197: /* ??? This should always be -apparent_fsize. */ ! 2198: if (! leaf_function) ! 2199: offset = -apparent_fsize; ! 2200: else ! 2201: offset = 0; ! 2202: ! 2203: if (TARGET_EPILOGUE && ! leaf_function) ! 2204: n_fregs = save_regs (file, 0, 16, frame_base_name, offset, 0); ! 2205: else if (leaf_function) ! 2206: n_fregs = save_regs (file, 0, 32, frame_base_name, offset, 0); ! 2207: if (TARGET_EPILOGUE) ! 2208: save_regs (file, 32, FIRST_PSEUDO_REGISTER, ! 2209: frame_base_name, offset, n_fregs); ! 2210: } ! 2211: ! 2212: leaf_label = 0; ! 2213: if (leaf_function && actual_fsize != 0) ! 2214: { ! 2215: /* warning ("leaf procedure with frame size %d", actual_fsize); */ ! 2216: if (! TARGET_EPILOGUE) ! 2217: leaf_label = gen_label_rtx (); ! 2218: } ! 2219: } ! 2220: ! 2221: /* Output code for the function epilogue. */ ! 2222: ! 2223: void ! 2224: output_function_epilogue (file, size, leaf_function) ! 2225: FILE *file; ! 2226: int size; ! 2227: int leaf_function; ! 2228: { ! 2229: char *ret; ! 2230: ! 2231: if (leaf_label) ! 2232: { ! 2233: emit_label_after (leaf_label, get_last_insn ()); ! 2234: final_scan_insn (get_last_insn (), file, 0, 0, 1); ! 2235: } ! 2236: ! 2237: if (num_fregs) ! 2238: { ! 2239: int offset, n_fregs = num_fregs; ! 2240: ! 2241: /* ??? This should always be -apparent_fsize. */ ! 2242: if (! leaf_function) ! 2243: offset = -apparent_fsize; ! 2244: else ! 2245: offset = 0; ! 2246: ! 2247: if (TARGET_EPILOGUE && ! leaf_function) ! 2248: n_fregs = restore_regs (file, 0, 16, frame_base_name, offset, 0); ! 2249: else if (leaf_function) ! 2250: n_fregs = restore_regs (file, 0, 32, frame_base_name, offset, 0); ! 2251: if (TARGET_EPILOGUE) ! 2252: restore_regs (file, 32, FIRST_PSEUDO_REGISTER, ! 2253: frame_base_name, offset, n_fregs); ! 2254: } ! 2255: ! 2256: /* Work out how to skip the caller's unimp instruction if required. */ ! 2257: if (leaf_function) ! 2258: ret = (current_function_returns_struct ? "jmp %o7+12" : "retl"); ! 2259: else ! 2260: ret = (current_function_returns_struct ? "jmp %i7+12" : "ret"); ! 2261: ! 2262: if (TARGET_EPILOGUE || leaf_label) ! 2263: { ! 2264: int old_target_epilogue = TARGET_EPILOGUE; ! 2265: target_flags &= ~old_target_epilogue; ! 2266: ! 2267: if (! leaf_function) ! 2268: { ! 2269: /* If we wound up with things in our delay slot, flush them here. */ ! 2270: if (current_function_epilogue_delay_list) ! 2271: { ! 2272: rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode), ! 2273: get_last_insn ()); ! 2274: PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode, ! 2275: gen_rtvec (2, ! 2276: PATTERN (XEXP (current_function_epilogue_delay_list, 0)), ! 2277: PATTERN (insn))); ! 2278: final_scan_insn (insn, file, 1, 0, 1); ! 2279: } ! 2280: else ! 2281: fprintf (file, "\t%s\n\trestore\n", ret); ! 2282: } ! 2283: /* All of the following cases are for leaf functions. */ ! 2284: else if (current_function_epilogue_delay_list) ! 2285: { ! 2286: /* eligible_for_epilogue_delay_slot ensures that if this is a ! 2287: leaf function, then we will only have insn in the delay slot ! 2288: if the frame size is zero, thus no adjust for the stack is ! 2289: needed here. */ ! 2290: if (actual_fsize != 0) ! 2291: abort (); ! 2292: fprintf (file, "\t%s\n", ret); ! 2293: final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), ! 2294: file, 1, 0, 1); ! 2295: } ! 2296: /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to ! 2297: avoid generating confusing assembly language output. */ ! 2298: else if (actual_fsize == 0) ! 2299: fprintf (file, "\t%s\n\tnop\n", ret); ! 2300: else if (actual_fsize <= 4096) ! 2301: fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize); ! 2302: else if (actual_fsize <= 8192) ! 2303: fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n", ! 2304: ret, actual_fsize - 4096); ! 2305: else if ((actual_fsize & 0x3ff) == 0) ! 2306: fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n", ! 2307: actual_fsize, ret); ! 2308: else ! 2309: fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n", ! 2310: actual_fsize, actual_fsize, ret); ! 2311: target_flags |= old_target_epilogue; ! 2312: } ! 2313: } ! 2314: ! 2315: /* Do what is necessary for `va_start'. The argument is ignored; ! 2316: We look at the current function to determine if stdarg or varargs ! 2317: is used and return the address of the first unnamed parameter. */ ! 2318: ! 2319: rtx ! 2320: sparc_builtin_saveregs (arglist) ! 2321: tree arglist; ! 2322: { ! 2323: tree fntype = TREE_TYPE (current_function_decl); ! 2324: int stdarg = (TYPE_ARG_TYPES (fntype) != 0 ! 2325: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ! 2326: != void_type_node)); ! 2327: int first_reg = current_function_args_info; ! 2328: rtx address; ! 2329: int regno; ! 2330: ! 2331: #if 0 /* This code seemed to have no effect except to make ! 2332: varargs not work right when va_list wasn't the first arg. */ ! 2333: if (! stdarg) ! 2334: first_reg = 0; ! 2335: #endif ! 2336: ! 2337: for (regno = first_reg; regno < NPARM_REGS; regno++) ! 2338: emit_move_insn (gen_rtx (MEM, word_mode, ! 2339: gen_rtx (PLUS, Pmode, ! 2340: frame_pointer_rtx, ! 2341: GEN_INT (STACK_POINTER_OFFSET ! 2342: + UNITS_PER_WORD * regno))), ! 2343: gen_rtx (REG, word_mode, BASE_INCOMING_ARG_REG (word_mode) ! 2344: + regno)); ! 2345: ! 2346: address = gen_rtx (PLUS, Pmode, ! 2347: frame_pointer_rtx, ! 2348: GEN_INT (STACK_POINTER_OFFSET ! 2349: + UNITS_PER_WORD * first_reg)); ! 2350: ! 2351: return address; ! 2352: } ! 2353: ! 2354: /* Return the string to output a conditional branch to LABEL, which is ! 2355: the operand number of the label. OP is the conditional expression. The ! 2356: mode of register 0 says what kind of comparison we made. ! 2357: ! 2358: REVERSED is non-zero if we should reverse the sense of the comparison. ! 2359: ! 2360: ANNUL is non-zero if we should generate an annulling branch. ! 2361: ! 2362: NOOP is non-zero if we have to follow this branch by a noop. */ ! 2363: ! 2364: char * ! 2365: output_cbranch (op, label, reversed, annul, noop) ! 2366: rtx op; ! 2367: int label; ! 2368: int reversed, annul, noop; ! 2369: { ! 2370: static char string[20]; ! 2371: enum rtx_code code = GET_CODE (op); ! 2372: enum machine_mode mode = GET_MODE (XEXP (op, 0)); ! 2373: static char labelno[] = " %lX"; ! 2374: ! 2375: /* ??? FP branches can not be preceded by another floating point insn. ! 2376: Because there is currently no concept of pre-delay slots, we can fix ! 2377: this only by always emitting a nop before a floating point branch. */ ! 2378: ! 2379: if (mode == CCFPmode || mode == CCFPEmode) ! 2380: strcpy (string, "nop\n\t"); ! 2381: ! 2382: /* If not floating-point or if EQ or NE, we can just reverse the code. */ ! 2383: if (reversed ! 2384: && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE)) ! 2385: code = reverse_condition (code), reversed = 0; ! 2386: ! 2387: /* Start by writing the branch condition. */ ! 2388: switch (code) ! 2389: { ! 2390: case NE: ! 2391: if (mode == CCFPmode || mode == CCFPEmode) ! 2392: strcat (string, "fbne"); ! 2393: else ! 2394: strcpy (string, "bne"); ! 2395: break; ! 2396: ! 2397: case EQ: ! 2398: if (mode == CCFPmode || mode == CCFPEmode) ! 2399: strcat (string, "fbe"); ! 2400: else ! 2401: strcpy (string, "be"); ! 2402: break; ! 2403: ! 2404: case GE: ! 2405: if (mode == CCFPmode || mode == CCFPEmode) ! 2406: { ! 2407: if (reversed) ! 2408: strcat (string, "fbul"); ! 2409: else ! 2410: strcat (string, "fbge"); ! 2411: } ! 2412: else if (mode == CC_NOOVmode) ! 2413: strcpy (string, "bpos"); ! 2414: else ! 2415: strcpy (string, "bge"); ! 2416: break; ! 2417: ! 2418: case GT: ! 2419: if (mode == CCFPmode || mode == CCFPEmode) ! 2420: { ! 2421: if (reversed) ! 2422: strcat (string, "fbule"); ! 2423: else ! 2424: strcat (string, "fbg"); ! 2425: } ! 2426: else ! 2427: strcpy (string, "bg"); ! 2428: break; ! 2429: ! 2430: case LE: ! 2431: if (mode == CCFPmode || mode == CCFPEmode) ! 2432: { ! 2433: if (reversed) ! 2434: strcat (string, "fbug"); ! 2435: else ! 2436: strcat (string, "fble"); ! 2437: } ! 2438: else ! 2439: strcpy (string, "ble"); ! 2440: break; ! 2441: ! 2442: case LT: ! 2443: if (mode == CCFPmode || mode == CCFPEmode) ! 2444: { ! 2445: if (reversed) ! 2446: strcat (string, "fbuge"); ! 2447: else ! 2448: strcat (string, "fbl"); ! 2449: } ! 2450: else if (mode == CC_NOOVmode) ! 2451: strcpy (string, "bneg"); ! 2452: else ! 2453: strcpy (string, "bl"); ! 2454: break; ! 2455: ! 2456: case GEU: ! 2457: strcpy (string, "bgeu"); ! 2458: break; ! 2459: ! 2460: case GTU: ! 2461: strcpy (string, "bgu"); ! 2462: break; ! 2463: ! 2464: case LEU: ! 2465: strcpy (string, "bleu"); ! 2466: break; ! 2467: ! 2468: case LTU: ! 2469: strcpy (string, "blu"); ! 2470: break; ! 2471: } ! 2472: ! 2473: /* Now add the annulling, the label, and a possible noop. */ ! 2474: if (annul) ! 2475: strcat (string, ",a"); ! 2476: ! 2477: labelno[3] = label + '0'; ! 2478: strcat (string, labelno); ! 2479: ! 2480: if (noop) ! 2481: strcat (string, "\n\tnop"); ! 2482: ! 2483: return string; ! 2484: } ! 2485: ! 2486: /* Output assembler code to return from a function. */ ! 2487: ! 2488: char * ! 2489: output_return (operands) ! 2490: rtx *operands; ! 2491: { ! 2492: if (leaf_label) ! 2493: { ! 2494: operands[0] = leaf_label; ! 2495: return "b,a %l0"; ! 2496: } ! 2497: else if (leaf_function) ! 2498: { ! 2499: /* If we didn't allocate a frame pointer for the current function, ! 2500: the stack pointer might have been adjusted. Output code to ! 2501: restore it now. */ ! 2502: ! 2503: operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize); ! 2504: ! 2505: /* Use sub of negated value in first two cases instead of add to ! 2506: allow actual_fsize == 4096. */ ! 2507: ! 2508: if (actual_fsize <= 4096) ! 2509: { ! 2510: if (current_function_returns_struct) ! 2511: return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp"; ! 2512: else ! 2513: return "retl\n\tsub %%sp,-%0,%%sp"; ! 2514: } ! 2515: else if (actual_fsize <= 8192) ! 2516: { ! 2517: operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize - 4096); ! 2518: if (current_function_returns_struct) ! 2519: return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp"; ! 2520: else ! 2521: return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp"; ! 2522: } ! 2523: else if (current_function_returns_struct) ! 2524: { ! 2525: if ((actual_fsize & 0x3ff) != 0) ! 2526: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp"; ! 2527: else ! 2528: return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp"; ! 2529: } ! 2530: else ! 2531: { ! 2532: if ((actual_fsize & 0x3ff) != 0) ! 2533: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp"; ! 2534: else ! 2535: return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp"; ! 2536: } ! 2537: } ! 2538: else ! 2539: { ! 2540: if (current_function_returns_struct) ! 2541: return "jmp %%i7+12\n\trestore"; ! 2542: else ! 2543: return "ret\n\trestore"; ! 2544: } ! 2545: } ! 2546: ! 2547: /* Leaf functions and non-leaf functions have different needs. */ ! 2548: ! 2549: static int ! 2550: reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER; ! 2551: ! 2552: static int ! 2553: reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER; ! 2554: ! 2555: static int *reg_alloc_orders[] = { ! 2556: reg_leaf_alloc_order, ! 2557: reg_nonleaf_alloc_order}; ! 2558: ! 2559: void ! 2560: order_regs_for_local_alloc () ! 2561: { ! 2562: static int last_order_nonleaf = 1; ! 2563: ! 2564: if (regs_ever_live[15] != last_order_nonleaf) ! 2565: { ! 2566: last_order_nonleaf = !last_order_nonleaf; ! 2567: bcopy (reg_alloc_orders[last_order_nonleaf], reg_alloc_order, ! 2568: FIRST_PSEUDO_REGISTER * sizeof (int)); ! 2569: } ! 2570: } ! 2571: ! 2572: /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1. ! 2573: This makes them candidates for using ldd and std insns. ! 2574: ! 2575: Note reg1 and reg2 *must* be hard registers. To be sure we will ! 2576: abort if we are passed pseudo registers. */ ! 2577: ! 2578: int ! 2579: registers_ok_for_ldd_peep (reg1, reg2) ! 2580: rtx reg1, reg2; ! 2581: { ! 2582: ! 2583: /* We might have been passed a SUBREG. */ ! 2584: if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) ! 2585: return 0; ! 2586: ! 2587: if (REGNO (reg1) % 2 != 0) ! 2588: return 0; ! 2589: ! 2590: return (REGNO (reg1) == REGNO (reg2) - 1); ! 2591: ! 2592: } ! 2593: ! 2594: /* Return 1 if addr1 and addr2 are suitable for use in an ldd or ! 2595: std insn. ! 2596: ! 2597: This can only happen when addr1 and addr2 are consecutive memory ! 2598: locations (addr1 + 4 == addr2). addr1 must also be aligned on a ! 2599: 64 bit boundary (addr1 % 8 == 0). ! 2600: ! 2601: We know %sp and %fp are kept aligned on a 64 bit boundary. Other ! 2602: registers are assumed to *never* be properly aligned and are ! 2603: rejected. ! 2604: ! 2605: Knowing %sp and %fp are kept aligned on a 64 bit boundary, we ! 2606: need only check that the offset for addr1 % 8 == 0. */ ! 2607: ! 2608: int ! 2609: addrs_ok_for_ldd_peep (addr1, addr2) ! 2610: rtx addr1, addr2; ! 2611: { ! 2612: int reg1, offset1; ! 2613: ! 2614: /* Extract a register number and offset (if used) from the first addr. */ ! 2615: if (GET_CODE (addr1) == PLUS) ! 2616: { ! 2617: /* If not a REG, return zero. */ ! 2618: if (GET_CODE (XEXP (addr1, 0)) != REG) ! 2619: return 0; ! 2620: else ! 2621: { ! 2622: reg1 = REGNO (XEXP (addr1, 0)); ! 2623: /* The offset must be constant! */ ! 2624: if (GET_CODE (XEXP (addr1, 1)) != CONST_INT) ! 2625: return 0; ! 2626: offset1 = INTVAL (XEXP (addr1, 1)); ! 2627: } ! 2628: } ! 2629: else if (GET_CODE (addr1) != REG) ! 2630: return 0; ! 2631: else ! 2632: { ! 2633: reg1 = REGNO (addr1); ! 2634: /* This was a simple (mem (reg)) expression. Offset is 0. */ ! 2635: offset1 = 0; ! 2636: } ! 2637: ! 2638: /* Make sure the second address is a (mem (plus (reg) (const_int). */ ! 2639: if (GET_CODE (addr2) != PLUS) ! 2640: return 0; ! 2641: ! 2642: if (GET_CODE (XEXP (addr2, 0)) != REG ! 2643: || GET_CODE (XEXP (addr2, 1)) != CONST_INT) ! 2644: return 0; ! 2645: ! 2646: /* Only %fp and %sp are allowed. Additionally both addresses must ! 2647: use the same register. */ ! 2648: if (reg1 != FRAME_POINTER_REGNUM && reg1 != STACK_POINTER_REGNUM) ! 2649: return 0; ! 2650: ! 2651: if (reg1 != REGNO (XEXP (addr2, 0))) ! 2652: return 0; ! 2653: ! 2654: /* The first offset must be evenly divisible by 8 to ensure the ! 2655: address is 64 bit aligned. */ ! 2656: if (offset1 % 8 != 0) ! 2657: return 0; ! 2658: ! 2659: /* The offset for the second addr must be 4 more than the first addr. */ ! 2660: if (INTVAL (XEXP (addr2, 1)) != offset1 + 4) ! 2661: return 0; ! 2662: ! 2663: /* All the tests passed. addr1 and addr2 are valid for ldd and std ! 2664: instructions. */ ! 2665: return 1; ! 2666: } ! 2667: ! 2668: /* Return 1 if reg is a pseudo, or is the first register in ! 2669: a hard register pair. This makes it a candidate for use in ! 2670: ldd and std insns. */ ! 2671: ! 2672: int ! 2673: register_ok_for_ldd (reg) ! 2674: rtx reg; ! 2675: { ! 2676: ! 2677: /* We might have been passed a SUBREG. */ ! 2678: if (GET_CODE (reg) != REG) ! 2679: return 0; ! 2680: ! 2681: if (REGNO (reg) < FIRST_PSEUDO_REGISTER) ! 2682: return (REGNO (reg) % 2 == 0); ! 2683: else ! 2684: return 1; ! 2685: ! 2686: } ! 2687: ! 2688: /* Print operand X (an rtx) in assembler syntax to file FILE. ! 2689: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. ! 2690: For `%' followed by punctuation, CODE is the punctuation and X is null. */ ! 2691: ! 2692: void ! 2693: print_operand (file, x, code) ! 2694: FILE *file; ! 2695: rtx x; ! 2696: int code; ! 2697: { ! 2698: switch (code) ! 2699: { ! 2700: case '#': ! 2701: /* Output a 'nop' if there's nothing for the delay slot. */ ! 2702: if (dbr_sequence_length () == 0) ! 2703: fputs ("\n\tnop", file); ! 2704: return; ! 2705: case '*': ! 2706: /* Output an annul flag if there's nothing for the delay slot and we ! 2707: are optimizing. This is always used with '(' below. */ ! 2708: /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch; ! 2709: this is a dbx bug. So, we only do this when optimizing. */ ! 2710: if (dbr_sequence_length () == 0 && optimize) ! 2711: fputs (",a", file); ! 2712: return; ! 2713: case '(': ! 2714: /* Output a 'nop' if there's nothing for the delay slot and we are ! 2715: not optimizing. This is always used with '*' above. */ ! 2716: if (dbr_sequence_length () == 0 && ! optimize) ! 2717: fputs ("\n\tnop", file); ! 2718: return; ! 2719: case 'Y': ! 2720: /* Adjust the operand to take into account a RESTORE operation. */ ! 2721: if (GET_CODE (x) != REG) ! 2722: output_operand_lossage ("Invalid %%Y operand"); ! 2723: else if (REGNO (x) < 8) ! 2724: fputs (reg_names[REGNO (x)], file); ! 2725: else if (REGNO (x) >= 24 && REGNO (x) < 32) ! 2726: fputs (reg_names[REGNO (x)-16], file); ! 2727: else ! 2728: output_operand_lossage ("Invalid %%Y operand"); ! 2729: return; ! 2730: case 'R': ! 2731: /* Print out the second register name of a register pair or quad. ! 2732: I.e., R (%o0) => %o1. */ ! 2733: fputs (reg_names[REGNO (x)+1], file); ! 2734: return; ! 2735: case 'S': ! 2736: /* Print out the third register name of a register quad. ! 2737: I.e., S (%o0) => %o2. */ ! 2738: fputs (reg_names[REGNO (x)+2], file); ! 2739: return; ! 2740: case 'T': ! 2741: /* Print out the fourth register name of a register quad. ! 2742: I.e., T (%o0) => %o3. */ ! 2743: fputs (reg_names[REGNO (x)+3], file); ! 2744: return; ! 2745: case 'm': ! 2746: /* Print the operand's address only. */ ! 2747: output_address (XEXP (x, 0)); ! 2748: return; ! 2749: case 'r': ! 2750: /* In this case we need a register. Use %g0 if the ! 2751: operand is const0_rtx. */ ! 2752: if (x == const0_rtx ! 2753: || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) ! 2754: { ! 2755: fputs ("%g0", file); ! 2756: return; ! 2757: } ! 2758: else ! 2759: break; ! 2760: ! 2761: case 'A': ! 2762: switch (GET_CODE (x)) ! 2763: { ! 2764: case IOR: fputs ("or", file); break; ! 2765: case AND: fputs ("and", file); break; ! 2766: case XOR: fputs ("xor", file); break; ! 2767: default: output_operand_lossage ("Invalid %%A operand"); ! 2768: } ! 2769: return; ! 2770: ! 2771: case 'B': ! 2772: switch (GET_CODE (x)) ! 2773: { ! 2774: case IOR: fputs ("orn", file); break; ! 2775: case AND: fputs ("andn", file); break; ! 2776: case XOR: fputs ("xnor", file); break; ! 2777: default: output_operand_lossage ("Invalid %%B operand"); ! 2778: } ! 2779: return; ! 2780: ! 2781: case 'b': ! 2782: { ! 2783: /* Print a sign-extended character. */ ! 2784: int i = INTVAL (x) & 0xff; ! 2785: if (i & 0x80) ! 2786: i |= 0xffffff00; ! 2787: fprintf (file, "%d", i); ! 2788: return; ! 2789: } ! 2790: ! 2791: case 0: ! 2792: /* Do nothing special. */ ! 2793: break; ! 2794: ! 2795: default: ! 2796: /* Undocumented flag. */ ! 2797: output_operand_lossage ("invalid operand output code"); ! 2798: } ! 2799: ! 2800: if (GET_CODE (x) == REG) ! 2801: fputs (reg_names[REGNO (x)], file); ! 2802: else if (GET_CODE (x) == MEM) ! 2803: { ! 2804: fputc ('[', file); ! 2805: if (CONSTANT_P (XEXP (x, 0))) ! 2806: /* Poor Sun assembler doesn't understand absolute addressing. */ ! 2807: fputs ("%g0+", file); ! 2808: output_address (XEXP (x, 0)); ! 2809: fputc (']', file); ! 2810: } ! 2811: else if (GET_CODE (x) == HIGH) ! 2812: { ! 2813: fputs ("%hi(", file); ! 2814: output_addr_const (file, XEXP (x, 0)); ! 2815: fputc (')', file); ! 2816: } ! 2817: else if (GET_CODE (x) == LO_SUM) ! 2818: { ! 2819: print_operand (file, XEXP (x, 0), 0); ! 2820: fputs ("+%lo(", file); ! 2821: output_addr_const (file, XEXP (x, 1)); ! 2822: fputc (')', file); ! 2823: } ! 2824: else if (GET_CODE (x) == CONST_DOUBLE ! 2825: && (GET_MODE (x) == VOIDmode ! 2826: || GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)) ! 2827: { ! 2828: if (CONST_DOUBLE_HIGH (x) == 0) ! 2829: fprintf (file, "%u", CONST_DOUBLE_LOW (x)); ! 2830: else if (CONST_DOUBLE_HIGH (x) == -1 ! 2831: && CONST_DOUBLE_LOW (x) < 0) ! 2832: fprintf (file, "%d", CONST_DOUBLE_LOW (x)); ! 2833: else ! 2834: output_operand_lossage ("long long constant not a valid immediate operand"); ! 2835: } ! 2836: else if (GET_CODE (x) == CONST_DOUBLE) ! 2837: output_operand_lossage ("floating point constant not a valid immediate operand"); ! 2838: else { output_addr_const (file, x); } ! 2839: } ! 2840: ! 2841: /* This function outputs assembler code for VALUE to FILE, where VALUE is ! 2842: a 64 bit (DImode) value. */ ! 2843: ! 2844: /* ??? If there is a 64 bit counterpart to .word that the assembler ! 2845: understands, then using that would simply this code greatly. */ ! 2846: ! 2847: void ! 2848: output_double_int (file, value) ! 2849: FILE *file; ! 2850: rtx value; ! 2851: { ! 2852: if (GET_CODE (value) == CONST_INT) ! 2853: { ! 2854: if (INTVAL (value) < 0) ! 2855: ASM_OUTPUT_INT (file, constm1_rtx); ! 2856: else ! 2857: ASM_OUTPUT_INT (file, const0_rtx); ! 2858: ASM_OUTPUT_INT (file, value); ! 2859: } ! 2860: else if (GET_CODE (value) == CONST_DOUBLE) ! 2861: { ! 2862: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode, ! 2863: CONST_DOUBLE_HIGH (value))); ! 2864: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode, ! 2865: CONST_DOUBLE_LOW (value))); ! 2866: } ! 2867: else if (GET_CODE (value) == SYMBOL_REF ! 2868: || GET_CODE (value) == CONST ! 2869: || GET_CODE (value) == PLUS) ! 2870: { ! 2871: /* Addresses are only 32 bits. */ ! 2872: ASM_OUTPUT_INT (file, const0_rtx); ! 2873: ASM_OUTPUT_INT (file, value); ! 2874: } ! 2875: else ! 2876: abort (); ! 2877: } ! 2878: ! 2879: #ifndef CHAR_TYPE_SIZE ! 2880: #define CHAR_TYPE_SIZE BITS_PER_UNIT ! 2881: #endif ! 2882: ! 2883: #ifndef SHORT_TYPE_SIZE ! 2884: #define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2) ! 2885: #endif ! 2886: ! 2887: #ifndef INT_TYPE_SIZE ! 2888: #define INT_TYPE_SIZE BITS_PER_WORD ! 2889: #endif ! 2890: ! 2891: #ifndef LONG_TYPE_SIZE ! 2892: #define LONG_TYPE_SIZE BITS_PER_WORD ! 2893: #endif ! 2894: ! 2895: #ifndef LONG_LONG_TYPE_SIZE ! 2896: #define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) ! 2897: #endif ! 2898: ! 2899: #ifndef FLOAT_TYPE_SIZE ! 2900: #define FLOAT_TYPE_SIZE BITS_PER_WORD ! 2901: #endif ! 2902: ! 2903: #ifndef DOUBLE_TYPE_SIZE ! 2904: #define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) ! 2905: #endif ! 2906: ! 2907: #ifndef LONG_DOUBLE_TYPE_SIZE ! 2908: #define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) ! 2909: #endif ! 2910: ! 2911: unsigned long ! 2912: sparc_type_code (type) ! 2913: register tree type; ! 2914: { ! 2915: register unsigned long qualifiers = 0; ! 2916: register unsigned shift = 6; ! 2917: ! 2918: for (;;) ! 2919: { ! 2920: switch (TREE_CODE (type)) ! 2921: { ! 2922: case ERROR_MARK: ! 2923: return qualifiers; ! 2924: ! 2925: case ARRAY_TYPE: ! 2926: qualifiers |= (3 << shift); ! 2927: shift += 2; ! 2928: type = TREE_TYPE (type); ! 2929: break; ! 2930: ! 2931: case FUNCTION_TYPE: ! 2932: case METHOD_TYPE: ! 2933: qualifiers |= (2 << shift); ! 2934: shift += 2; ! 2935: type = TREE_TYPE (type); ! 2936: break; ! 2937: ! 2938: case POINTER_TYPE: ! 2939: case REFERENCE_TYPE: ! 2940: case OFFSET_TYPE: ! 2941: qualifiers |= (1 << shift); ! 2942: shift += 2; ! 2943: type = TREE_TYPE (type); ! 2944: break; ! 2945: ! 2946: case RECORD_TYPE: ! 2947: return (qualifiers | 8); ! 2948: ! 2949: case UNION_TYPE: ! 2950: return (qualifiers | 9); ! 2951: ! 2952: case ENUMERAL_TYPE: ! 2953: return (qualifiers | 10); ! 2954: ! 2955: case VOID_TYPE: ! 2956: return (qualifiers | 16); ! 2957: ! 2958: case INTEGER_TYPE: ! 2959: /* If this is a range type, consider it to be the underlying ! 2960: type. */ ! 2961: if (TREE_TYPE (type) != 0) ! 2962: { ! 2963: type = TREE_TYPE (type); ! 2964: break; ! 2965: } ! 2966: ! 2967: /* Carefully distinguish all the standard types of C, ! 2968: without messing up if the language is not C. ! 2969: Note that we check only for the names that contain spaces; ! 2970: other names might occur by coincidence in other languages. */ ! 2971: if (TYPE_NAME (type) != 0 ! 2972: && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL ! 2973: && DECL_NAME (TYPE_NAME (type)) != 0 ! 2974: && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) ! 2975: { ! 2976: char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); ! 2977: ! 2978: if (!strcmp (name, "unsigned char")) ! 2979: return (qualifiers | 12); ! 2980: if (!strcmp (name, "signed char")) ! 2981: return (qualifiers | 2); ! 2982: if (!strcmp (name, "unsigned int")) ! 2983: return (qualifiers | 14); ! 2984: if (!strcmp (name, "short int")) ! 2985: return (qualifiers | 3); ! 2986: if (!strcmp (name, "short unsigned int")) ! 2987: return (qualifiers | 13); ! 2988: if (!strcmp (name, "long int")) ! 2989: return (qualifiers | 5); ! 2990: if (!strcmp (name, "long unsigned int")) ! 2991: return (qualifiers | 15); ! 2992: if (!strcmp (name, "long long int")) ! 2993: return (qualifiers | 5); /* Who knows? */ ! 2994: if (!strcmp (name, "long long unsigned int")) ! 2995: return (qualifiers | 15); /* Who knows? */ ! 2996: } ! 2997: ! 2998: /* Most integer types will be sorted out above, however, for the ! 2999: sake of special `array index' integer types, the following code ! 3000: is also provided. */ ! 3001: ! 3002: if (TYPE_PRECISION (type) == INT_TYPE_SIZE) ! 3003: return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4)); ! 3004: ! 3005: if (TYPE_PRECISION (type) == LONG_TYPE_SIZE) ! 3006: return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5)); ! 3007: ! 3008: if (TYPE_PRECISION (type) == LONG_LONG_TYPE_SIZE) ! 3009: return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5)); ! 3010: ! 3011: if (TYPE_PRECISION (type) == SHORT_TYPE_SIZE) ! 3012: return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3)); ! 3013: ! 3014: if (TYPE_PRECISION (type) == CHAR_TYPE_SIZE) ! 3015: return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2)); ! 3016: ! 3017: abort (); ! 3018: ! 3019: case REAL_TYPE: ! 3020: /* Carefully distinguish all the standard types of C, ! 3021: without messing up if the language is not C. */ ! 3022: if (TYPE_NAME (type) != 0 ! 3023: && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL ! 3024: && DECL_NAME (TYPE_NAME (type)) != 0 ! 3025: && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) ! 3026: { ! 3027: char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); ! 3028: ! 3029: if (!strcmp (name, "long double")) ! 3030: return (qualifiers | 7); /* Who knows? */ ! 3031: } ! 3032: ! 3033: if (TYPE_PRECISION (type) == DOUBLE_TYPE_SIZE) ! 3034: return (qualifiers | 7); ! 3035: if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE) ! 3036: return (qualifiers | 6); ! 3037: if (TYPE_PRECISION (type) == LONG_DOUBLE_TYPE_SIZE) ! 3038: return (qualifiers | 7); /* Who knows? */ ! 3039: abort (); ! 3040: ! 3041: case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */ ! 3042: /* ??? We need to distinguish between double and float complex types, ! 3043: but I don't know how yet because I can't reach this code from ! 3044: existing front-ends. */ ! 3045: return (qualifiers | 7); /* Who knows? */ ! 3046: ! 3047: case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */ ! 3048: case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */ ! 3049: case FILE_TYPE: /* GNU Pascal FILE type. */ ! 3050: case STRING_TYPE: /* GNU Fortran STRING type. */ ! 3051: case SET_TYPE: /* GNU Pascal SET type. */ ! 3052: case LANG_TYPE: /* ? */ ! 3053: return qualifiers; ! 3054: ! 3055: default: ! 3056: abort (); /* Not a type! */ ! 3057: } ! 3058: } ! 3059: } ! 3060: ! 3061: /* Subroutines to support a flat (single) register window calling ! 3062: convention. */ ! 3063: ! 3064: /* Single-register window sparc stack frames look like: ! 3065: ! 3066: Before call After call ! 3067: +-----------------------+ +-----------------------+ ! 3068: high | | | | ! 3069: mem. | | | | ! 3070: | caller's temps. | | caller's temps. | ! 3071: | | | | ! 3072: +-----------------------+ +-----------------------+ ! 3073: | | | | ! 3074: | arguments on stack. | | arguments on stack. | ! 3075: | |FP+92->| | ! 3076: +-----------------------+ +-----------------------+ ! 3077: | 6 words to save | | 6 words to save | ! 3078: | arguments passed | | arguments passed | ! 3079: | in registers, even | | in registers, even | ! 3080: SP+68->| if not passed. |FP+68->| if not passed. | ! 3081: +-----------------------+ +-----------------------+ ! 3082: | 1 word struct addr |FP+64->| 1 word struct addr | ! 3083: +-----------------------+ +-----------------------+ ! 3084: | | | | ! 3085: | 16 word reg save area | | 16 word reg save area | ! 3086: SP->| | FP->| | ! 3087: +-----------------------+ +-----------------------+ ! 3088: | 4 word area for | ! 3089: FP-16->| fp/alu reg moves | ! 3090: +-----------------------+ ! 3091: | | ! 3092: | local variables | ! 3093: | | ! 3094: +-----------------------+ ! 3095: | | ! 3096: | fp register save | ! 3097: | | ! 3098: +-----------------------+ ! 3099: | | ! 3100: | gp register save | ! 3101: | | ! 3102: +-----------------------+ ! 3103: | | ! 3104: | alloca allocations | ! 3105: | | ! 3106: +-----------------------+ ! 3107: | | ! 3108: | arguments on stack | ! 3109: SP+92->| | ! 3110: +-----------------------+ ! 3111: | 6 words to save | ! 3112: | arguments passed | ! 3113: | in registers, even | ! 3114: low SP+68->| if not passed. | ! 3115: memory +-----------------------+ ! 3116: SP+64->| 1 word struct addr | ! 3117: +-----------------------+ ! 3118: | | ! 3119: I 16 word reg save area | ! 3120: SP->| | ! 3121: +-----------------------+ */ ! 3122: ! 3123: /* Structure to be filled in by sparc_frw_compute_frame_size with register ! 3124: save masks, and offsets for the current function. */ ! 3125: ! 3126: struct sparc_frame_info ! 3127: { ! 3128: unsigned long total_size; /* # bytes that the entire frame takes up. */ ! 3129: unsigned long var_size; /* # bytes that variables take up. */ ! 3130: unsigned long args_size; /* # bytes that outgoing arguments take up. */ ! 3131: unsigned long extra_size; /* # bytes of extra gunk. */ ! 3132: unsigned int gp_reg_size; /* # bytes needed to store gp regs. */ ! 3133: unsigned int fp_reg_size; /* # bytes needed to store fp regs. */ ! 3134: unsigned long mask; /* Mask of saved gp registers. */ ! 3135: unsigned long fmask; /* Mask of saved fp registers. */ ! 3136: unsigned long gp_sp_offset; /* Offset from new sp to store gp regs. */ ! 3137: unsigned long fp_sp_offset; /* Offset from new sp to store fp regs. */ ! 3138: int initialized; /* Nonzero if frame size already calculated. */ ! 3139: }; ! 3140: ! 3141: /* Current frame information calculated by sparc_frw_compute_frame_size. */ ! 3142: struct sparc_frame_info current_frame_info; ! 3143: ! 3144: /* Zero structure to initialize current_frame_info. */ ! 3145: struct sparc_frame_info zero_frame_info; ! 3146: ! 3147: /* Tell prologue and epilogue if register REGNO should be saved / restored. */ ! 3148: ! 3149: #define MUST_SAVE_REGISTER(regno) \ ! 3150: ((regs_ever_live[regno] && !call_used_regs[regno]) \ ! 3151: || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) \ ! 3152: || (regno == 15 && regs_ever_live[15])) ! 3153: ! 3154: /* Return the bytes needed to compute the frame pointer from the current ! 3155: stack pointer. */ ! 3156: ! 3157: unsigned long ! 3158: sparc_frw_compute_frame_size (size) ! 3159: int size; /* # of var. bytes allocated. */ ! 3160: { ! 3161: int regno; ! 3162: unsigned long total_size; /* # bytes that the entire frame takes up. */ ! 3163: unsigned long var_size; /* # bytes that variables take up. */ ! 3164: unsigned long args_size; /* # bytes that outgoing arguments take up. */ ! 3165: unsigned long extra_size; /* # extra bytes. */ ! 3166: unsigned int gp_reg_size; /* # bytes needed to store gp regs. */ ! 3167: unsigned int fp_reg_size; /* # bytes needed to store fp regs. */ ! 3168: unsigned long mask; /* Mask of saved gp registers. */ ! 3169: unsigned long fmask; /* Mask of saved fp registers. */ ! 3170: ! 3171: /* This is the size of the 16 word reg save area, 1 word struct addr ! 3172: area, and 4 word fp/alu register copy area. */ ! 3173: extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0); ! 3174: var_size = size; ! 3175: /* Also include the size needed for the 6 parameter registers. */ ! 3176: args_size = current_function_outgoing_args_size + 24; ! 3177: total_size = var_size + args_size + extra_size; ! 3178: gp_reg_size = 0; ! 3179: fp_reg_size = 0; ! 3180: mask = 0; ! 3181: fmask = 0; ! 3182: ! 3183: /* Calculate space needed for gp registers. */ ! 3184: for (regno = 1; regno <= 31; regno++) ! 3185: { ! 3186: if (MUST_SAVE_REGISTER (regno)) ! 3187: { ! 3188: if ((regno & 0x1) == 0 && MUST_SAVE_REGISTER (regno+1)) ! 3189: { ! 3190: if (gp_reg_size % 8 != 0) ! 3191: gp_reg_size += UNITS_PER_WORD; ! 3192: gp_reg_size += 2 * UNITS_PER_WORD; ! 3193: mask |= 3 << regno; ! 3194: regno++; ! 3195: } ! 3196: else ! 3197: { ! 3198: gp_reg_size += UNITS_PER_WORD; ! 3199: mask |= 1 << regno; ! 3200: } ! 3201: } ! 3202: } ! 3203: /* Add extra word in case we have to align the space to a double word ! 3204: boundary. */ ! 3205: if (gp_reg_size != 0) ! 3206: gp_reg_size += UNITS_PER_WORD; ! 3207: ! 3208: /* Calculate space needed for fp registers. */ ! 3209: for (regno = 32; regno <= 63; regno++) ! 3210: { ! 3211: if (regs_ever_live[regno] && !call_used_regs[regno]) ! 3212: { ! 3213: fp_reg_size += UNITS_PER_WORD; ! 3214: fmask |= 1 << (regno - 32); ! 3215: } ! 3216: } ! 3217: ! 3218: total_size += gp_reg_size + fp_reg_size; ! 3219: ! 3220: if (total_size == extra_size) ! 3221: total_size = extra_size = 0; ! 3222: ! 3223: total_size = SPARC_STACK_ALIGN (total_size); ! 3224: ! 3225: /* Save other computed information. */ ! 3226: current_frame_info.total_size = total_size; ! 3227: current_frame_info.var_size = var_size; ! 3228: current_frame_info.args_size = args_size; ! 3229: current_frame_info.extra_size = extra_size; ! 3230: current_frame_info.gp_reg_size = gp_reg_size; ! 3231: current_frame_info.fp_reg_size = fp_reg_size; ! 3232: current_frame_info.mask = mask; ! 3233: current_frame_info.fmask = fmask; ! 3234: current_frame_info.initialized = reload_completed; ! 3235: ! 3236: if (mask) ! 3237: { ! 3238: unsigned long offset = args_size; ! 3239: if (extra_size) ! 3240: offset += FIRST_PARM_OFFSET(0); ! 3241: current_frame_info.gp_sp_offset = offset; ! 3242: } ! 3243: ! 3244: if (fmask) ! 3245: { ! 3246: unsigned long offset = args_size + gp_reg_size; ! 3247: if (extra_size) ! 3248: offset += FIRST_PARM_OFFSET(0); ! 3249: current_frame_info.fp_sp_offset = offset; ! 3250: } ! 3251: ! 3252: /* Ok, we're done. */ ! 3253: return total_size; ! 3254: } ! 3255: ! 3256: /* Common code to save/restore registers. */ ! 3257: ! 3258: void ! 3259: sparc_frw_save_restore (file, word_op, doubleword_op) ! 3260: FILE *file; /* Stream to write to. */ ! 3261: char *word_op; /* Operation to do for one word. */ ! 3262: char *doubleword_op; /* Operation to do for doubleword. */ ! 3263: { ! 3264: int regno; ! 3265: unsigned long mask = current_frame_info.mask; ! 3266: unsigned long fmask = current_frame_info.fmask; ! 3267: unsigned long gp_offset; ! 3268: unsigned long fp_offset; ! 3269: unsigned long max_offset; ! 3270: char *base_reg; ! 3271: ! 3272: if (mask == 0 && fmask == 0) ! 3273: return; ! 3274: ! 3275: base_reg = reg_names[STACK_POINTER_REGNUM]; ! 3276: gp_offset = current_frame_info.gp_sp_offset; ! 3277: fp_offset = current_frame_info.fp_sp_offset; ! 3278: max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset; ! 3279: ! 3280: /* Deal with calling functions with a large structure. */ ! 3281: if (max_offset >= 4096) ! 3282: { ! 3283: char *temp = "%g2"; ! 3284: fprintf (file, "\tset %ld,%s\n", max_offset, temp); ! 3285: fprintf (file, "\tadd %s,%s,%s\n", temp, base_reg, temp); ! 3286: base_reg = temp; ! 3287: gp_offset = max_offset - gp_offset; ! 3288: fp_offset = max_offset - fp_offset; ! 3289: } ! 3290: ! 3291: /* Save registers starting from high to low. The debuggers prefer ! 3292: at least the return register be stored at func+4, and also it ! 3293: allows us not to need a nop in the epilog if at least one ! 3294: register is reloaded in addition to return address. */ ! 3295: ! 3296: if (mask || frame_pointer_needed) ! 3297: { ! 3298: for (regno = 1; regno <= 31; regno++) ! 3299: { ! 3300: if ((mask & (1L << regno)) != 0 ! 3301: || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)) ! 3302: { ! 3303: if ((regno & 0x1) == 0 && ((mask & (1L << (regno+1))) != 0)) ! 3304: { ! 3305: if (gp_offset % 8 != 0) ! 3306: gp_offset += UNITS_PER_WORD; ! 3307: ! 3308: if (word_op[0] == 's') ! 3309: fprintf (file, "\t%s %s,[%s+%d]\n", ! 3310: doubleword_op, reg_names[regno], ! 3311: base_reg, gp_offset); ! 3312: else ! 3313: fprintf (file, "\t%s [%s+%d],%s\n", ! 3314: doubleword_op, base_reg, gp_offset, ! 3315: reg_names[regno]); ! 3316: ! 3317: gp_offset += 2 * UNITS_PER_WORD; ! 3318: regno++; ! 3319: } ! 3320: else ! 3321: { ! 3322: if (word_op[0] == 's') ! 3323: fprintf (file, "\t%s %s,[%s+%d]\n", ! 3324: word_op, reg_names[regno], ! 3325: base_reg, gp_offset); ! 3326: else ! 3327: fprintf (file, "\t%s [%s+%d],%s\n", ! 3328: word_op, base_reg, gp_offset, reg_names[regno]); ! 3329: ! 3330: gp_offset += UNITS_PER_WORD; ! 3331: } ! 3332: } ! 3333: } ! 3334: } ! 3335: ! 3336: if (fmask) ! 3337: { ! 3338: for (regno = 32; regno <= 63; regno++) ! 3339: { ! 3340: if ((fmask & (1L << (regno - 32))) != 0) ! 3341: { ! 3342: if (word_op[0] == 's') ! 3343: fprintf (file, "\t%s %s,[%s+%d]\n", ! 3344: word_op, reg_names[regno], ! 3345: base_reg, gp_offset); ! 3346: else ! 3347: fprintf (file, "\t%s [%s+%d],%s\n", ! 3348: word_op, base_reg, gp_offset, reg_names[regno]); ! 3349: ! 3350: fp_offset += UNITS_PER_WORD; ! 3351: } ! 3352: } ! 3353: } ! 3354: } ! 3355: ! 3356: /* Set up the stack and frame (if desired) for the function. */ ! 3357: ! 3358: void ! 3359: sparc_frw_output_function_prologue (file, size, ignored) ! 3360: FILE *file; ! 3361: int size; ! 3362: { ! 3363: extern char call_used_regs[]; ! 3364: int tsize; ! 3365: char *sp_str = reg_names[STACK_POINTER_REGNUM]; ! 3366: ! 3367: /* ??? This should be %sp+actual_fsize for a leaf function. I think it ! 3368: works only because it is never used. */ ! 3369: frame_base_name ! 3370: = (!frame_pointer_needed) ? "%sp+80" : reg_names[FRAME_POINTER_REGNUM]; ! 3371: ! 3372: fprintf (file, "\t!#PROLOGUE# 0\n"); ! 3373: ! 3374: size = SPARC_STACK_ALIGN (size); ! 3375: tsize = (! current_frame_info.initialized ! 3376: ? sparc_frw_compute_frame_size (size) ! 3377: : current_frame_info.total_size); ! 3378: ! 3379: if (tsize > 0) ! 3380: { ! 3381: if (tsize <= 4095) ! 3382: fprintf (file, ! 3383: "\tsub %s,%d,%s\t\t!# vars= %d, regs= %d/%d, args = %d, extra= %d\n", ! 3384: sp_str, tsize, sp_str, current_frame_info.var_size, ! 3385: current_frame_info.gp_reg_size / 4, ! 3386: current_frame_info.fp_reg_size / 8, ! 3387: current_function_outgoing_args_size, ! 3388: current_frame_info.extra_size); ! 3389: else ! 3390: fprintf (file, ! 3391: "\tset %d,%s\n\tsub\t%s,%s,%s\t\t!# vars= %d, regs= %d/%d, args = %d, sfo= %d\n", ! 3392: tsize, "%g1", sp_str, "%g1", ! 3393: sp_str, current_frame_info.var_size, ! 3394: current_frame_info.gp_reg_size / 4, ! 3395: current_frame_info.fp_reg_size / 8, ! 3396: current_function_outgoing_args_size, ! 3397: current_frame_info.extra_size); ! 3398: } ! 3399: ! 3400: sparc_frw_save_restore (file, "st", "std"); ! 3401: ! 3402: if (frame_pointer_needed) ! 3403: { ! 3404: if (tsize <= 4095) ! 3405: fprintf (file, "\tadd %s,%d,%s\t!# set up frame pointer\n", sp_str, ! 3406: tsize, frame_base_name); ! 3407: else ! 3408: fprintf (file, "\tadd %s,%s,%s\t!# set up frame pointer\n", sp_str, ! 3409: "%g1", frame_base_name); ! 3410: } ! 3411: } ! 3412: ! 3413: /* Do any necessary cleanup after a function to restore stack, frame, ! 3414: and regs. */ ! 3415: ! 3416: void ! 3417: sparc_frw_output_function_epilogue (file, size, ignored1, ignored2) ! 3418: FILE *file; ! 3419: int size; ! 3420: { ! 3421: extern FILE *asm_out_data_file, *asm_out_file; ! 3422: extern char call_used_regs[]; ! 3423: extern int frame_pointer_needed; ! 3424: int tsize; ! 3425: char *sp_str = reg_names[STACK_POINTER_REGNUM]; ! 3426: char *t1_str = "%g1"; ! 3427: rtx epilogue_delay = current_function_epilogue_delay_list; ! 3428: int noepilogue = FALSE; ! 3429: ! 3430: /* The epilogue does not depend on any registers, but the stack ! 3431: registers, so we assume that if we have 1 pending nop, it can be ! 3432: ignored, and 2 it must be filled (2 nops occur for integer ! 3433: multiply and divide). */ ! 3434: ! 3435: size = SPARC_STACK_ALIGN (size); ! 3436: tsize = (!current_frame_info.initialized ! 3437: ? sparc_frw_compute_frame_size (size) ! 3438: : current_frame_info.total_size); ! 3439: ! 3440: if (tsize == 0 && epilogue_delay == 0) ! 3441: { ! 3442: rtx insn = get_last_insn (); ! 3443: ! 3444: /* If the last insn was a BARRIER, we don't have to write any code ! 3445: because a jump (aka return) was put there. */ ! 3446: if (GET_CODE (insn) == NOTE) ! 3447: insn = prev_nonnote_insn (insn); ! 3448: if (insn && GET_CODE (insn) == BARRIER) ! 3449: noepilogue = TRUE; ! 3450: } ! 3451: ! 3452: if (!noepilogue) ! 3453: { ! 3454: /* In the reload sequence, we don't need to fill the load delay ! 3455: slots for most of the loads, also see if we can fill the final ! 3456: delay slot if not otherwise filled by the reload sequence. */ ! 3457: ! 3458: if (tsize > 4095) ! 3459: fprintf (file, "\tset %d,%s\n", tsize, t1_str); ! 3460: ! 3461: if (frame_pointer_needed) ! 3462: { ! 3463: char *fp_str = reg_names[FRAME_POINTER_REGNUM]; ! 3464: if (tsize > 4095) ! 3465: fprintf (file,"\tsub %s,%s,%s\t\t!# sp not trusted here\n", ! 3466: fp_str, t1_str, sp_str); ! 3467: else ! 3468: fprintf (file,"\tsub %s,%d,%s\t\t!# sp not trusted here\n", ! 3469: fp_str, tsize, sp_str); ! 3470: } ! 3471: ! 3472: sparc_frw_save_restore (file, "ld", "ldd"); ! 3473: ! 3474: if (current_function_returns_struct) ! 3475: fprintf (file, "\tjmp %%o7+12\n"); ! 3476: else ! 3477: fprintf (file, "\tretl\n"); ! 3478: ! 3479: /* If the only register saved is the return address, we need a ! 3480: nop, unless we have an instruction to put into it. Otherwise ! 3481: we don't since reloading multiple registers doesn't reference ! 3482: the register being loaded. */ ! 3483: ! 3484: if (epilogue_delay) ! 3485: { ! 3486: if (tsize) ! 3487: abort (); ! 3488: final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1); ! 3489: } ! 3490: ! 3491: else if (tsize > 4095) ! 3492: fprintf (file, "\tadd %s,%s,%s\n", sp_str, t1_str, sp_str); ! 3493: ! 3494: else if (tsize > 0) ! 3495: fprintf (file, "\tadd %s,%d,%s\n", sp_str, tsize, sp_str); ! 3496: ! 3497: else ! 3498: fprintf (file, "\tnop\n"); ! 3499: } ! 3500: ! 3501: /* Reset state info for each function. */ ! 3502: current_frame_info = zero_frame_info; ! 3503: } ! 3504: ! 3505: /* Define the number of delay slots needed for the function epilogue. ! 3506: ! 3507: On the sparc, we need a slot if either no stack has been allocated, ! 3508: or the only register saved is the return register. */ ! 3509: ! 3510: int ! 3511: sparc_frw_epilogue_delay_slots () ! 3512: { ! 3513: if (!current_frame_info.initialized) ! 3514: (void) sparc_frw_compute_frame_size (get_frame_size ()); ! 3515: ! 3516: if (current_frame_info.total_size == 0) ! 3517: return 1; ! 3518: ! 3519: return 0; ! 3520: } ! 3521: ! 3522: /* Return true is TRIAL is a valid insn for the epilogue delay slot. ! 3523: Any single length instruction which doesn't reference the stack or frame ! 3524: pointer is OK. */ ! 3525: ! 3526: int ! 3527: sparc_frw_eligible_for_epilogue_delay (trial, slot) ! 3528: rtx trial; ! 3529: int slot; ! 3530: { ! 3531: if (get_attr_length (trial) == 1 ! 3532: && ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial)) ! 3533: && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial))) ! 3534: return 1; ! 3535: return 0; ! 3536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.