|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Sun SPARC. ! 2: Copyright (C) 1987, 1988, 1989, 1992 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 "rtl.h" ! 24: #include "regs.h" ! 25: #include "hard-reg-set.h" ! 26: #include "real.h" ! 27: #include "insn-config.h" ! 28: #include "conditions.h" ! 29: #include "insn-flags.h" ! 30: #include "output.h" ! 31: #include "insn-attr.h" ! 32: #include "flags.h" ! 33: #include "expr.h" ! 34: #include "recog.h" ! 35: ! 36: /* Global variables for machine-dependent things. */ ! 37: ! 38: /* Save the operands last given to a compare for use when we ! 39: generate a scc or bcc insn. */ ! 40: ! 41: rtx sparc_compare_op0, sparc_compare_op1; ! 42: ! 43: /* We may need an epilogue if we spill too many registers. ! 44: If this is non-zero, then we branch here for the epilogue. */ ! 45: static rtx leaf_label; ! 46: ! 47: #ifdef LEAF_REGISTERS ! 48: ! 49: /* Vector to say how input registers are mapped to output ! 50: registers. FRAME_POINTER_REGNUM cannot be remapped by ! 51: this function to eliminate it. You must use -fomit-frame-pointer ! 52: to get that. */ ! 53: char leaf_reg_remap[] = ! 54: { 0, 1, 2, 3, 4, 5, 6, 7, ! 55: -1, -1, -1, -1, -1, -1, 14, -1, ! 56: -1, -1, -1, -1, -1, -1, -1, -1, ! 57: 8, 9, 10, 11, 12, 13, -1, 15, ! 58: ! 59: 32, 33, 34, 35, 36, 37, 38, 39, ! 60: 40, 41, 42, 43, 44, 45, 46, 47, ! 61: 48, 49, 50, 51, 52, 53, 54, 55, ! 62: 56, 57, 58, 59, 60, 61, 62, 63}; ! 63: ! 64: char leaf_reg_backmap[] = ! 65: { 0, 1, 2, 3, 4, 5, 6, 7, ! 66: 24, 25, 26, 27, 28, 29, 14, 31, ! 67: -1, -1, -1, -1, -1, -1, -1, -1, ! 68: -1, -1, -1, -1, -1, -1, -1, -1, ! 69: ! 70: 32, 33, 34, 35, 36, 37, 38, 39, ! 71: 40, 41, 42, 43, 44, 45, 46, 47, ! 72: 48, 49, 50, 51, 52, 53, 54, 55, ! 73: 56, 57, 58, 59, 60, 61, 62, 63}; ! 74: #endif ! 75: ! 76: /* Global variables set by FUNCTION_PROLOGUE. */ ! 77: /* Size of frame. Need to know this to emit return insns from ! 78: leaf procedures. */ ! 79: int apparent_fsize; ! 80: int actual_fsize; ! 81: ! 82: /* Name of where we pretend to think the frame pointer points. ! 83: Normally, this is "%fp", but if we are in a leaf procedure, ! 84: this is "%sp+something". */ ! 85: char *frame_base_name; ! 86: ! 87: static rtx find_addr_reg (); ! 88: ! 89: /* Return non-zero only if OP is a register of mode MODE, ! 90: or const0_rtx. */ ! 91: int ! 92: reg_or_0_operand (op, mode) ! 93: rtx op; ! 94: enum machine_mode mode; ! 95: { ! 96: if (op == const0_rtx || register_operand (op, mode)) ! 97: return 1; ! 98: if (GET_CODE (op) == CONST_DOUBLE ! 99: && CONST_DOUBLE_HIGH (op) == 0 ! 100: && CONST_DOUBLE_LOW (op) == 0) ! 101: return 1; ! 102: return 0; ! 103: } ! 104: ! 105: /* Nonzero if OP can appear as the dest of a RESTORE insn. */ ! 106: int ! 107: restore_operand (op, mode) ! 108: rtx op; ! 109: enum machine_mode mode; ! 110: { ! 111: return (GET_CODE (op) == REG && GET_MODE (op) == mode ! 112: && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32))); ! 113: } ! 114: ! 115: /* PC-relative call insn on SPARC is independent of `memory_operand'. */ ! 116: ! 117: int ! 118: call_operand (op, mode) ! 119: rtx op; ! 120: enum machine_mode mode; ! 121: { ! 122: if (GET_CODE (op) != MEM) ! 123: abort (); ! 124: op = XEXP (op, 0); ! 125: return (REG_P (op) || CONSTANT_P (op)); ! 126: } ! 127: ! 128: int ! 129: call_operand_address (op, mode) ! 130: rtx op; ! 131: enum machine_mode mode; ! 132: { ! 133: return (REG_P (op) || CONSTANT_P (op)); ! 134: } ! 135: ! 136: /* Returns 1 if OP is either a symbol reference or a sum of a symbol ! 137: reference and a constant. */ ! 138: ! 139: int ! 140: symbolic_operand (op, mode) ! 141: register rtx op; ! 142: enum machine_mode mode; ! 143: { ! 144: switch (GET_CODE (op)) ! 145: { ! 146: case SYMBOL_REF: ! 147: case LABEL_REF: ! 148: return 1; ! 149: ! 150: case CONST: ! 151: op = XEXP (op, 0); ! 152: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF ! 153: || GET_CODE (XEXP (op, 0)) == LABEL_REF) ! 154: && GET_CODE (XEXP (op, 1)) == CONST_INT); ! 155: ! 156: /* This clause seems to be irrelevant. */ ! 157: case CONST_DOUBLE: ! 158: return GET_MODE (op) == mode; ! 159: ! 160: default: ! 161: return 0; ! 162: } ! 163: } ! 164: ! 165: /* Return truth value of statement that OP is a symbolic memory ! 166: operand of mode MODE. */ ! 167: ! 168: int ! 169: symbolic_memory_operand (op, mode) ! 170: rtx op; ! 171: enum machine_mode mode; ! 172: { ! 173: if (GET_CODE (op) == SUBREG) ! 174: op = SUBREG_REG (op); ! 175: if (GET_CODE (op) != MEM) ! 176: return 0; ! 177: op = XEXP (op, 0); ! 178: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST ! 179: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF); ! 180: } ! 181: ! 182: /* Return 1 if the operand is either a register or a memory operand that is ! 183: not symbolic. */ ! 184: ! 185: int ! 186: reg_or_nonsymb_mem_operand (op, mode) ! 187: register rtx op; ! 188: enum machine_mode mode; ! 189: { ! 190: if (register_operand (op, mode)) ! 191: return 1; ! 192: ! 193: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) ! 194: return 1; ! 195: ! 196: return 0; ! 197: } ! 198: ! 199: int ! 200: sparc_operand (op, mode) ! 201: rtx op; ! 202: enum machine_mode mode; ! 203: { ! 204: if (register_operand (op, mode)) ! 205: return 1; ! 206: if (GET_CODE (op) == CONST_INT) ! 207: return SMALL_INT (op); ! 208: if (GET_MODE (op) != mode) ! 209: return 0; ! 210: if (GET_CODE (op) == SUBREG) ! 211: op = SUBREG_REG (op); ! 212: if (GET_CODE (op) != MEM) ! 213: return 0; ! 214: ! 215: op = XEXP (op, 0); ! 216: if (GET_CODE (op) == LO_SUM) ! 217: return (GET_CODE (XEXP (op, 0)) == REG ! 218: && symbolic_operand (XEXP (op, 1), Pmode)); ! 219: return memory_address_p (mode, op); ! 220: } ! 221: ! 222: int ! 223: move_operand (op, mode) ! 224: rtx op; ! 225: enum machine_mode mode; ! 226: { ! 227: if (mode == DImode && arith_double_operand (op, mode)) ! 228: return 1; ! 229: if (register_operand (op, mode)) ! 230: return 1; ! 231: if (GET_CODE (op) == CONST_INT) ! 232: return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0); ! 233: ! 234: if (GET_MODE (op) != mode) ! 235: return 0; ! 236: if (GET_CODE (op) == SUBREG) ! 237: op = SUBREG_REG (op); ! 238: if (GET_CODE (op) != MEM) ! 239: return 0; ! 240: op = XEXP (op, 0); ! 241: if (GET_CODE (op) == LO_SUM) ! 242: return (register_operand (XEXP (op, 0), Pmode) ! 243: && CONSTANT_P (XEXP (op, 1))); ! 244: return memory_address_p (mode, op); ! 245: } ! 246: ! 247: int ! 248: move_pic_label (op, mode) ! 249: rtx op; ! 250: enum machine_mode mode; ! 251: { ! 252: /* Special case for PIC. */ ! 253: if (flag_pic && GET_CODE (op) == LABEL_REF) ! 254: return 1; ! 255: return 0; ! 256: } ! 257: ! 258: /* The rtx for the global offset table which is a special form ! 259: that *is* a position independent symbolic constant. */ ! 260: rtx pic_pc_rtx; ! 261: ! 262: /* Ensure that we are not using patterns that are not OK with PIC. */ ! 263: ! 264: int ! 265: check_pic (i) ! 266: int i; ! 267: { ! 268: switch (flag_pic) ! 269: { ! 270: case 1: ! 271: if (GET_CODE (recog_operand[i]) == SYMBOL_REF ! 272: || (GET_CODE (recog_operand[i]) == CONST ! 273: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) ! 274: abort (); ! 275: case 2: ! 276: default: ! 277: return 1; ! 278: } ! 279: } ! 280: ! 281: /* Return true if X is an address which needs a temporary register when ! 282: reloaded while generating PIC code. */ ! 283: ! 284: int ! 285: pic_address_needs_scratch (x) ! 286: rtx x; ! 287: { ! 288: /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ ! 289: if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS ! 290: && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF ! 291: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT ! 292: && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) ! 293: return 1; ! 294: ! 295: return 0; ! 296: } ! 297: ! 298: int ! 299: memop (op, mode) ! 300: rtx op; ! 301: enum machine_mode mode; ! 302: { ! 303: if (GET_CODE (op) == MEM) ! 304: return (mode == VOIDmode || mode == GET_MODE (op)); ! 305: return 0; ! 306: } ! 307: ! 308: /* Return truth value of whether OP is EQ or NE. */ ! 309: ! 310: int ! 311: eq_or_neq (op, mode) ! 312: rtx op; ! 313: enum machine_mode mode; ! 314: { ! 315: return (GET_CODE (op) == EQ || GET_CODE (op) == NE); ! 316: } ! 317: ! 318: /* Return 1 if this is a comparison operator, but not an EQ, NE, GEU, ! 319: or LTU for non-floating-point. We handle those specially. */ ! 320: ! 321: int ! 322: normal_comp_operator (op, mode) ! 323: rtx op; ! 324: enum machine_mode mode; ! 325: { ! 326: enum rtx_code code = GET_CODE (op); ! 327: ! 328: if (GET_RTX_CLASS (code) != '<') ! 329: return 0; ! 330: ! 331: if (GET_MODE (XEXP (op, 0)) == CCFPmode) ! 332: return 1; ! 333: ! 334: return (code != NE && code != EQ && code != GEU && code != LTU); ! 335: } ! 336: ! 337: /* Return 1 if this is a comparison operator. This allows the use of ! 338: MATCH_OPERATOR to recognize all the branch insns. */ ! 339: ! 340: int ! 341: noov_compare_op (op, mode) ! 342: register rtx op; ! 343: enum machine_mode mode; ! 344: { ! 345: enum rtx_code code = GET_CODE (op); ! 346: ! 347: if (GET_RTX_CLASS (code) != '<') ! 348: return 0; ! 349: ! 350: if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode) ! 351: /* These are the only branches which work with CC_NOOVmode. */ ! 352: return (code == EQ || code == NE || code == GE || code == LT); ! 353: return 1; ! 354: } ! 355: ! 356: /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */ ! 357: ! 358: int ! 359: extend_op (op, mode) ! 360: rtx op; ! 361: enum machine_mode mode; ! 362: { ! 363: return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND; ! 364: } ! 365: ! 366: /* Return nonzero if OP is an operator of mode MODE which can set ! 367: the condition codes explicitly. We do not include PLUS and MINUS ! 368: because these require CC_NOOVmode, which we handle explicitly. */ ! 369: ! 370: int ! 371: cc_arithop (op, mode) ! 372: rtx op; ! 373: enum machine_mode mode; ! 374: { ! 375: if (GET_CODE (op) == AND ! 376: || GET_CODE (op) == IOR ! 377: || GET_CODE (op) == XOR) ! 378: return 1; ! 379: ! 380: return 0; ! 381: } ! 382: ! 383: /* Return nonzero if OP is an operator of mode MODE which can bitwise ! 384: complement its second operand and set the condition codes explicitly. */ ! 385: ! 386: int ! 387: cc_arithopn (op, mode) ! 388: rtx op; ! 389: enum machine_mode mode; ! 390: { ! 391: /* XOR is not here because combine canonicalizes (xor (not ...) ...) ! 392: and (xor ... (not ...)) to (not (xor ...)). */ ! 393: return (GET_CODE (op) == AND ! 394: || GET_CODE (op) == IOR); ! 395: } ! 396: ! 397: /* Return truth value of whether OP can be used as an operands in a three ! 398: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */ ! 399: ! 400: int ! 401: arith_operand (op, mode) ! 402: rtx op; ! 403: enum machine_mode mode; ! 404: { ! 405: return (register_operand (op, mode) ! 406: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); ! 407: } ! 408: ! 409: /* Return truth value of whether OP can be used as an operand in a two ! 410: address arithmetic insn (such as set 123456,%o4) of mode MODE. */ ! 411: ! 412: int ! 413: arith32_operand (op, mode) ! 414: rtx op; ! 415: enum machine_mode mode; ! 416: { ! 417: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); ! 418: } ! 419: ! 420: /* Return truth value of whether OP is a register or a CONST_DOUBLE. */ ! 421: ! 422: int ! 423: arith_double_operand (op, mode) ! 424: rtx op; ! 425: enum machine_mode mode; ! 426: { ! 427: return (register_operand (op, mode) ! 428: || (GET_CODE (op) == CONST_DOUBLE ! 429: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) ! 430: && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 ! 431: && ((CONST_DOUBLE_HIGH (op) == -1 ! 432: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000) ! 433: || (CONST_DOUBLE_HIGH (op) == 0 ! 434: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))) ! 435: || (GET_CODE (op) == CONST_INT ! 436: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) ! 437: && (unsigned) (INTVAL (op) + 0x1000) < 0x2000)); ! 438: } ! 439: ! 440: /* Return truth value of whether OP is a integer which fits the ! 441: range constraining immediate operands in three-address insns. */ ! 442: ! 443: int ! 444: small_int (op, mode) ! 445: rtx op; ! 446: enum machine_mode mode; ! 447: { ! 448: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); ! 449: } ! 450: ! 451: /* Return truth value of statement that OP is a call-clobbered register. */ ! 452: int ! 453: clobbered_register (op, mode) ! 454: rtx op; ! 455: enum machine_mode mode; ! 456: { ! 457: return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]); ! 458: } ! 459: ! 460: /* X and Y are two things to compare using CODE. Emit the compare insn and ! 461: return the rtx for register 0 in the proper mode. */ ! 462: ! 463: rtx ! 464: gen_compare_reg (code, x, y) ! 465: enum rtx_code code; ! 466: rtx x, y; ! 467: { ! 468: enum machine_mode mode = SELECT_CC_MODE (code, x); ! 469: rtx cc_reg = gen_rtx (REG, mode, 0); ! 470: ! 471: emit_insn (gen_rtx (SET, VOIDmode, cc_reg, ! 472: gen_rtx (COMPARE, mode, x, y))); ! 473: ! 474: return cc_reg; ! 475: } ! 476: ! 477: /* Return nonzero if a return peephole merging return with ! 478: setting of output register is ok. */ ! 479: int ! 480: leaf_return_peephole_ok () ! 481: { ! 482: return (actual_fsize == 0); ! 483: } ! 484: ! 485: /* Return nonzero if TRIAL can go into the function epilogue's ! 486: delay slot. SLOT is the slot we are trying to fill. */ ! 487: ! 488: int ! 489: eligible_for_epilogue_delay (trial, slot) ! 490: rtx trial; ! 491: int slot; ! 492: { ! 493: static char *this_function_name; ! 494: rtx pat, src; ! 495: ! 496: if (slot >= 1) ! 497: return 0; ! 498: if (GET_CODE (trial) != INSN ! 499: || GET_CODE (PATTERN (trial)) != SET) ! 500: return 0; ! 501: if (get_attr_length (trial) != 1) ! 502: return 0; ! 503: ! 504: /* In the case of a true leaf function, anything can ! 505: go into the delay slot. */ ! 506: if (leaf_function) ! 507: { ! 508: if (leaf_return_peephole_ok ()) ! 509: return (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE); ! 510: return 0; ! 511: } ! 512: ! 513: /* Otherwise, only operations which can be done in tandem with ! 514: a `restore' insn can go into the delay slot. */ ! 515: pat = PATTERN (trial); ! 516: if (GET_CODE (SET_DEST (pat)) != REG ! 517: || REGNO (SET_DEST (pat)) == 0 ! 518: || (leaf_function ! 519: && REGNO (SET_DEST (pat)) < 32 ! 520: && REGNO (SET_DEST (pat)) >= 16) ! 521: || (! leaf_function ! 522: && (REGNO (SET_DEST (pat)) >= 32 ! 523: || REGNO (SET_DEST (pat)) < 24))) ! 524: return 0; ! 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: /* Legitimize PIC addresses. If the address is already position-independent, ! 604: we return ORIG. Newly generated position-independent addresses go into a ! 605: reg. This is REG if non zero, otherwise we allocate register(s) as ! 606: necessary. If this is called during reload, and we need a second temp ! 607: register, then we use SCRATCH, which is provided via the ! 608: SECONDARY_INPUT_RELOAD_CLASS mechanism. */ ! 609: ! 610: rtx ! 611: legitimize_pic_address (orig, mode, reg, scratch) ! 612: rtx orig; ! 613: enum machine_mode mode; ! 614: rtx reg, scratch; ! 615: { ! 616: if (GET_CODE (orig) == SYMBOL_REF) ! 617: { ! 618: rtx pic_ref, address; ! 619: rtx insn; ! 620: ! 621: if (reg == 0) ! 622: { ! 623: if (reload_in_progress) ! 624: abort (); ! 625: else ! 626: reg = gen_reg_rtx (Pmode); ! 627: } ! 628: ! 629: if (flag_pic == 2) ! 630: { ! 631: /* If not during reload, allocate another temp reg here for loading ! 632: in the address, so that these instructions can be optimized ! 633: properly. */ ! 634: rtx temp_reg = (reload_in_progress ? reg : gen_reg_rtx (Pmode)); ! 635: ! 636: emit_insn (gen_rtx (SET, VOIDmode, temp_reg, ! 637: gen_rtx (HIGH, Pmode, orig))); ! 638: emit_insn (gen_rtx (SET, VOIDmode, temp_reg, ! 639: gen_rtx (LO_SUM, Pmode, temp_reg, orig))); ! 640: address = temp_reg; ! 641: } ! 642: else ! 643: address = orig; ! 644: ! 645: pic_ref = gen_rtx (MEM, Pmode, ! 646: gen_rtx (PLUS, Pmode, ! 647: pic_offset_table_rtx, address)); ! 648: current_function_uses_pic_offset_table = 1; ! 649: RTX_UNCHANGING_P (pic_ref) = 1; ! 650: insn = emit_move_insn (reg, pic_ref); ! 651: /* Put a REG_EQUAL note on this insn, so that it can be optimized ! 652: by loop. */ ! 653: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, ! 654: REG_NOTES (insn)); ! 655: return reg; ! 656: } ! 657: else if (GET_CODE (orig) == CONST) ! 658: { ! 659: rtx base, offset; ! 660: ! 661: if (GET_CODE (XEXP (orig, 0)) == PLUS ! 662: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) ! 663: return orig; ! 664: ! 665: if (reg == 0) ! 666: { ! 667: if (reload_in_progress) ! 668: abort (); ! 669: else ! 670: reg = gen_reg_rtx (Pmode); ! 671: } ! 672: ! 673: if (GET_CODE (XEXP (orig, 0)) == PLUS) ! 674: { ! 675: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, ! 676: reg, 0); ! 677: offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, ! 678: base == reg ? 0 : reg, 0); ! 679: } ! 680: else ! 681: abort (); ! 682: ! 683: if (GET_CODE (offset) == CONST_INT) ! 684: { ! 685: if (SMALL_INT (offset)) ! 686: return plus_constant_for_output (base, INTVAL (offset)); ! 687: else if (! reload_in_progress) ! 688: offset = force_reg (Pmode, offset); ! 689: /* We can't create any new registers during reload, so use the ! 690: SCRATCH reg provided by the reload_insi pattern. */ ! 691: else if (scratch) ! 692: { ! 693: emit_move_insn (scratch, offset); ! 694: offset = scratch; ! 695: } ! 696: else ! 697: /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS ! 698: macro needs to be adjusted so that a scratch reg is provided ! 699: for this address. */ ! 700: abort (); ! 701: } ! 702: return gen_rtx (PLUS, Pmode, base, offset); ! 703: } ! 704: else if (GET_CODE (orig) == LABEL_REF) ! 705: current_function_uses_pic_offset_table = 1; ! 706: ! 707: return orig; ! 708: } ! 709: ! 710: /* Set up PIC-specific rtl. This should not cause any insns ! 711: to be emitted. */ ! 712: ! 713: void ! 714: initialize_pic () ! 715: { ! 716: } ! 717: ! 718: /* Emit special PIC prologues and epilogues. */ ! 719: ! 720: void ! 721: finalize_pic () ! 722: { ! 723: /* The table we use to reference PIC data. */ ! 724: rtx global_offset_table; ! 725: /* Labels to get the PC in the prologue of this function. */ ! 726: rtx l1, l2; ! 727: rtx seq; ! 728: int orig_flag_pic = flag_pic; ! 729: ! 730: if (current_function_uses_pic_offset_table == 0) ! 731: return; ! 732: ! 733: if (! flag_pic) ! 734: abort (); ! 735: ! 736: flag_pic = 0; ! 737: l1 = gen_label_rtx (); ! 738: l2 = gen_label_rtx (); ! 739: ! 740: start_sequence (); ! 741: ! 742: emit_label (l1); ! 743: /* Note that we pun calls and jumps here! */ ! 744: emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, ! 745: gen_rtvec (2, ! 746: gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)), ! 747: gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2))))); ! 748: emit_label (l2); ! 749: ! 750: /* Initialize every time through, since we can't easily ! 751: know this to be permanent. */ ! 752: global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "*__GLOBAL_OFFSET_TABLE_"); ! 753: pic_pc_rtx = gen_rtx (CONST, Pmode, ! 754: gen_rtx (MINUS, Pmode, ! 755: global_offset_table, ! 756: gen_rtx (CONST, Pmode, ! 757: gen_rtx (MINUS, Pmode, ! 758: gen_rtx (LABEL_REF, VOIDmode, l1), ! 759: pc_rtx)))); ! 760: ! 761: emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx, ! 762: gen_rtx (HIGH, Pmode, pic_pc_rtx))); ! 763: emit_insn (gen_rtx (SET, VOIDmode, ! 764: pic_offset_table_rtx, ! 765: gen_rtx (LO_SUM, Pmode, ! 766: pic_offset_table_rtx, pic_pc_rtx))); ! 767: emit_insn (gen_rtx (SET, VOIDmode, ! 768: pic_offset_table_rtx, ! 769: gen_rtx (PLUS, Pmode, ! 770: pic_offset_table_rtx, gen_rtx (REG, Pmode, 15)))); ! 771: /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */ ! 772: LABEL_PRESERVE_P (l1) = 1; ! 773: LABEL_PRESERVE_P (l2) = 1; ! 774: flag_pic = orig_flag_pic; ! 775: ! 776: seq = gen_sequence (); ! 777: end_sequence (); ! 778: emit_insn_after (seq, get_insns ()); ! 779: ! 780: /* Need to emit this whether or not we obey regdecls, ! 781: since setjmp/longjmp can cause life info to screw up. */ ! 782: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); ! 783: } ! 784: ! 785: /* For the SPARC, REG and REG+CONST is cost 0, REG+REG is cost 1, ! 786: and addresses involving symbolic constants are cost 2. ! 787: ! 788: We make REG+REG slightly more expensive because it might keep ! 789: a register live for longer than we might like. ! 790: ! 791: PIC addresses are very expensive. ! 792: ! 793: It is no coincidence that this has the same structure ! 794: as GO_IF_LEGITIMATE_ADDRESS. */ ! 795: int ! 796: sparc_address_cost (X) ! 797: rtx X; ! 798: { ! 799: #if 0 ! 800: /* Handled before calling here. */ ! 801: if (GET_CODE (X) == REG) ! 802: { return 1; } ! 803: #endif ! 804: if (GET_CODE (X) == PLUS) ! 805: { ! 806: if (GET_CODE (XEXP (X, 0)) == REG ! 807: && GET_CODE (XEXP (X, 1)) == REG) ! 808: return 2; ! 809: return 1; ! 810: } ! 811: else if (GET_CODE (X) == LO_SUM) ! 812: return 1; ! 813: else if (GET_CODE (X) == HIGH) ! 814: return 2; ! 815: return 4; ! 816: } ! 817: ! 818: /* Emit insns to move operands[1] into operands[0]. ! 819: ! 820: Return 1 if we have written out everything that needs to be done to ! 821: do the move. Otherwise, return 0 and the caller will emit the move ! 822: normally. ! 823: ! 824: SCRATCH_REG if non zero can be used as a scratch register for the move ! 825: operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */ ! 826: ! 827: int ! 828: emit_move_sequence (operands, mode, scratch_reg) ! 829: rtx *operands; ! 830: enum machine_mode mode; ! 831: rtx scratch_reg; ! 832: { ! 833: register rtx operand0 = operands[0]; ! 834: register rtx operand1 = operands[1]; ! 835: ! 836: /* Handle most common case first: storing into a register. */ ! 837: if (register_operand (operand0, mode)) ! 838: { ! 839: if (register_operand (operand1, mode) ! 840: || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1)) ! 841: || (GET_CODE (operand1) == CONST_DOUBLE ! 842: && arith_double_operand (operand1, DImode)) ! 843: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode) ! 844: /* Only `general_operands' can come here, so MEM is ok. */ ! 845: || GET_CODE (operand1) == MEM) ! 846: { ! 847: /* Run this case quickly. */ ! 848: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 849: return 1; ! 850: } ! 851: } ! 852: else if (GET_CODE (operand0) == MEM) ! 853: { ! 854: if (register_operand (operand1, mode) || operand1 == const0_rtx) ! 855: { ! 856: /* Run this case quickly. */ ! 857: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 858: return 1; ! 859: } ! 860: if (! reload_in_progress) ! 861: { ! 862: operands[0] = validize_mem (operand0); ! 863: operands[1] = operand1 = force_reg (mode, operand1); ! 864: } ! 865: } ! 866: ! 867: /* Simplify the source if we need to. Must handle DImode HIGH operators ! 868: here because such a move needs a clobber added. */ ! 869: if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode)) ! 870: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode)) ! 871: { ! 872: if (flag_pic && symbolic_operand (operand1, mode)) ! 873: { ! 874: rtx temp_reg = reload_in_progress ? operand0 : 0; ! 875: ! 876: operands[1] = legitimize_pic_address (operand1, mode, temp_reg, ! 877: scratch_reg); ! 878: } ! 879: else if (GET_CODE (operand1) == CONST_INT ! 880: ? (! SMALL_INT (operand1) ! 881: && (INTVAL (operand1) & 0x3ff) != 0) ! 882: : (GET_CODE (operand1) == CONST_DOUBLE ! 883: ? ! arith_double_operand (operand1, DImode) ! 884: : 1)) ! 885: { ! 886: /* For DImode values, temp must be operand0 because of the way ! 887: HI and LO_SUM work. The LO_SUM operator only copies half of ! 888: the LSW from the dest of the HI operator. If the LO_SUM dest is ! 889: not the same as the HI dest, then the MSW of the LO_SUM dest will ! 890: never be set. ! 891: ! 892: ??? The real problem here is that the ...(HI:DImode pattern emits ! 893: multiple instructions, and the ...(LO_SUM:DImode pattern emits ! 894: one instruction. This fails, because the compiler assumes that ! 895: LO_SUM copies all bits of the first operand to its dest. Better ! 896: would be to have the HI pattern emit one instruction and the ! 897: LO_SUM pattern multiple instructions. Even better would be ! 898: to use four rtl insns. */ ! 899: rtx temp = ((reload_in_progress || mode == DImode) ! 900: ? operand0 : gen_reg_rtx (mode)); ! 901: ! 902: emit_insn (gen_rtx (SET, VOIDmode, temp, ! 903: gen_rtx (HIGH, mode, operand1))); ! 904: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1); ! 905: } ! 906: } ! 907: ! 908: if (GET_CODE (operand1) == LABEL_REF && flag_pic) ! 909: { ! 910: /* The procedure for doing this involves using a call instruction to ! 911: get the pc into o7. We need to indicate this explicitly because ! 912: the tablejump pattern assumes that it can use this value also. */ ! 913: emit_insn (gen_rtx (PARALLEL, VOIDmode, ! 914: gen_rtvec (2, ! 915: gen_rtx (SET, VOIDmode, operand0, ! 916: operand1), ! 917: gen_rtx (SET, VOIDmode, ! 918: gen_rtx (REG, mode, 15), ! 919: pc_rtx)))); ! 920: return 1; ! 921: } ! 922: ! 923: /* Now have insn-emit do whatever it normally does. */ ! 924: return 0; ! 925: } ! 926: ! 927: /* Return the best assembler insn template ! 928: for moving operands[1] into operands[0] as a fullword. */ ! 929: ! 930: char * ! 931: singlemove_string (operands) ! 932: rtx *operands; ! 933: { ! 934: if (GET_CODE (operands[0]) == MEM) ! 935: { ! 936: if (GET_CODE (operands[1]) != MEM) ! 937: return "st %r1,%0"; ! 938: else ! 939: abort (); ! 940: } ! 941: if (GET_CODE (operands[1]) == MEM) ! 942: return "ld %1,%0"; ! 943: if (GET_CODE (operands[1]) == CONST_INT ! 944: && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) ! 945: { ! 946: int i = INTVAL (operands[1]); ! 947: ! 948: /* If all low order 12 bits are clear, then we only need a single ! 949: sethi insn to load the constant. */ ! 950: if (i & 0x00000FFF) ! 951: return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; ! 952: else ! 953: return "sethi %%hi(%a1),%0"; ! 954: } ! 955: /* ??? Wrong if target is DImode? */ ! 956: return "mov %1,%0"; ! 957: } ! 958: ! 959: /* Output assembler code to perform a doubleword move insn ! 960: with operands OPERANDS. */ ! 961: ! 962: char * ! 963: output_move_double (operands) ! 964: rtx *operands; ! 965: { ! 966: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 967: rtx latehalf[2]; ! 968: rtx addreg0 = 0, addreg1 = 0; ! 969: ! 970: /* First classify both operands. */ ! 971: ! 972: if (REG_P (operands[0])) ! 973: optype0 = REGOP; ! 974: else if (offsettable_memref_p (operands[0])) ! 975: optype0 = OFFSOP; ! 976: else if (GET_CODE (operands[0]) == MEM) ! 977: optype0 = MEMOP; ! 978: else ! 979: optype0 = RNDOP; ! 980: ! 981: if (REG_P (operands[1])) ! 982: optype1 = REGOP; ! 983: else if (CONSTANT_P (operands[1])) ! 984: optype1 = CNSTOP; ! 985: else if (offsettable_memref_p (operands[1])) ! 986: optype1 = OFFSOP; ! 987: else if (GET_CODE (operands[1]) == MEM) ! 988: optype1 = MEMOP; ! 989: else ! 990: optype1 = RNDOP; ! 991: ! 992: /* Check for the cases that the operand constraints are not ! 993: supposed to allow to happen. Abort if we get one, ! 994: because generating code for these cases is painful. */ ! 995: ! 996: if (optype0 == RNDOP || optype1 == RNDOP) ! 997: abort (); ! 998: ! 999: /* If an operand is an unoffsettable memory ref, find a register ! 1000: we can increment temporarily to make it refer to the second word. */ ! 1001: ! 1002: if (optype0 == MEMOP) ! 1003: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 1004: ! 1005: if (optype1 == MEMOP) ! 1006: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 1007: ! 1008: /* Ok, we can do one word at a time. ! 1009: Normally we do the low-numbered word first, ! 1010: but if either operand is autodecrementing then we ! 1011: do the high-numbered word first. ! 1012: ! 1013: In either case, set up in LATEHALF the operands to use for the ! 1014: high-numbered (least significant) word and in some cases alter the ! 1015: operands in OPERANDS to be suitable for the low-numbered word. */ ! 1016: ! 1017: if (optype0 == REGOP) ! 1018: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 1019: else if (optype0 == OFFSOP) ! 1020: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 1021: else ! 1022: latehalf[0] = operands[0]; ! 1023: ! 1024: if (optype1 == REGOP) ! 1025: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 1026: else if (optype1 == OFFSOP) ! 1027: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 1028: else if (optype1 == CNSTOP) ! 1029: split_double (operands[1], &operands[1], &latehalf[1]); ! 1030: else ! 1031: latehalf[1] = operands[1]; ! 1032: ! 1033: /* If the first move would clobber the source of the second one, ! 1034: do them in the other order. ! 1035: ! 1036: RMS says "This happens only for registers; ! 1037: such overlap can't happen in memory unless the user explicitly ! 1038: sets it up, and that is an undefined circumstance." ! 1039: ! 1040: but it happens on the sparc when loading parameter registers, ! 1041: so I am going to define that circumstance, and make it work ! 1042: as expected. */ ! 1043: ! 1044: /* Easy case: try moving both words at once. */ ! 1045: /* First check for moving between an even/odd register pair ! 1046: and a memory location. */ ! 1047: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP ! 1048: && (REGNO (operands[0]) & 1) == 0) ! 1049: || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP ! 1050: && (REGNO (operands[1]) & 1) == 0)) ! 1051: { ! 1052: rtx op1, op2; ! 1053: rtx base = 0, offset = const0_rtx; ! 1054: ! 1055: /* OP1 gets the register pair, and OP2 gets the memory address. */ ! 1056: if (optype0 == REGOP) ! 1057: op1 = operands[0], op2 = operands[1]; ! 1058: else ! 1059: op1 = operands[1], op2 = operands[0]; ! 1060: ! 1061: /* Now see if we can trust the address to be 8-byte aligned. */ ! 1062: /* Trust global variables. */ ! 1063: ! 1064: if (GET_CODE (op2) == LO_SUM) ! 1065: { ! 1066: operands[0] = op1; ! 1067: operands[1] = op2; ! 1068: ! 1069: if (final_sequence) ! 1070: abort (); ! 1071: return "ldd %1,%0"; ! 1072: } ! 1073: ! 1074: if (GET_CODE (XEXP (op2, 0)) == PLUS) ! 1075: { ! 1076: rtx temp = XEXP (op2, 0); ! 1077: if (GET_CODE (XEXP (temp, 0)) == REG) ! 1078: base = XEXP (temp, 0), offset = XEXP (temp, 1); ! 1079: else if (GET_CODE (XEXP (temp, 1)) == REG) ! 1080: base = XEXP (temp, 1), offset = XEXP (temp, 0); ! 1081: } ! 1082: ! 1083: /* Trust round enough offsets from the stack or frame pointer. */ ! 1084: if (base ! 1085: && (REGNO (base) == FRAME_POINTER_REGNUM ! 1086: || REGNO (base) == STACK_POINTER_REGNUM)) ! 1087: { ! 1088: if (GET_CODE (offset) == CONST_INT ! 1089: && (INTVAL (offset) & 0x7) == 0) ! 1090: { ! 1091: if (op1 == operands[0]) ! 1092: return "ldd %1,%0"; ! 1093: else ! 1094: return "std %1,%0"; ! 1095: } ! 1096: } ! 1097: /* We know structs not on the stack are properly aligned. Since a ! 1098: double asks for 8-byte alignment, we know it must have got that ! 1099: if it is in a struct. But a DImode need not be 8-byte aligned, ! 1100: because it could be a struct containing two ints or pointers. */ ! 1101: else if (GET_CODE (operands[1]) == MEM ! 1102: && GET_MODE (operands[1]) == DFmode ! 1103: && (CONSTANT_P (XEXP (operands[1], 0)) ! 1104: /* Let user ask for it anyway. */ ! 1105: || TARGET_ALIGN)) ! 1106: return "ldd %1,%0"; ! 1107: else if (GET_CODE (operands[0]) == MEM ! 1108: && GET_MODE (operands[0]) == DFmode ! 1109: && (CONSTANT_P (XEXP (operands[0], 0)) ! 1110: || TARGET_ALIGN)) ! 1111: return "std %1,%0"; ! 1112: } ! 1113: ! 1114: if (optype0 == REGOP && optype1 == REGOP ! 1115: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 1116: { ! 1117: /* Make any unoffsettable addresses point at high-numbered word. */ ! 1118: if (addreg0) ! 1119: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1120: if (addreg1) ! 1121: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1122: ! 1123: /* Do that word. */ ! 1124: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1125: ! 1126: /* Undo the adds we just did. */ ! 1127: if (addreg0) ! 1128: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 1129: if (addreg1) ! 1130: output_asm_insn ("add %0,-0x4,%0", &addreg1); ! 1131: ! 1132: /* Do low-numbered word. */ ! 1133: return singlemove_string (operands); ! 1134: } ! 1135: else if (optype0 == REGOP && optype1 != REGOP ! 1136: && reg_overlap_mentioned_p (operands[0], operands[1])) ! 1137: { ! 1138: /* Do the late half first. */ ! 1139: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1140: /* Then clobber. */ ! 1141: return singlemove_string (operands); ! 1142: } ! 1143: ! 1144: /* Normal case: do the two words, low-numbered first. */ ! 1145: ! 1146: output_asm_insn (singlemove_string (operands), operands); ! 1147: ! 1148: /* Make any unoffsettable addresses point at high-numbered word. */ ! 1149: if (addreg0) ! 1150: output_asm_insn ("add %0,0x4,%0", &addreg0); ! 1151: if (addreg1) ! 1152: output_asm_insn ("add %0,0x4,%0", &addreg1); ! 1153: ! 1154: /* Do that word. */ ! 1155: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1156: ! 1157: /* Undo the adds we just did. */ ! 1158: if (addreg0) ! 1159: output_asm_insn ("add %0,-0x4,%0", &addreg0); ! 1160: if (addreg1) ! 1161: output_asm_insn ("add %0,-0x4,%0", &addreg1); ! 1162: ! 1163: return ""; ! 1164: } ! 1165: ! 1166: char * ! 1167: output_fp_move_double (operands) ! 1168: rtx *operands; ! 1169: { ! 1170: rtx addr; ! 1171: ! 1172: if (FP_REG_P (operands[0])) ! 1173: { ! 1174: if (FP_REG_P (operands[1])) ! 1175: return "fmovs %1,%0\n\tfmovs %R1,%R0"; ! 1176: if (GET_CODE (operands[1]) == REG) ! 1177: { ! 1178: if ((REGNO (operands[1]) & 1) == 0) ! 1179: return "std %1,[%@-8]\n\tldd [%@-8],%0"; ! 1180: else ! 1181: return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0"; ! 1182: } ! 1183: addr = XEXP (operands[1], 0); ! 1184: ! 1185: /* Use ldd if known to be aligned. */ ! 1186: if (TARGET_ALIGN ! 1187: || (GET_CODE (addr) == PLUS ! 1188: && (((XEXP (addr, 0) == frame_pointer_rtx ! 1189: || XEXP (addr, 0) == stack_pointer_rtx) ! 1190: && GET_CODE (XEXP (addr, 1)) == CONST_INT ! 1191: && (INTVAL (XEXP (addr, 1)) & 0x7) == 0) ! 1192: /* Arrays are known to be aligned, ! 1193: and reg+reg addresses are used (on this machine) ! 1194: only for array accesses. */ ! 1195: || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))))) ! 1196: || (GET_MODE (operands[0]) == DFmode ! 1197: && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr)))) ! 1198: return "ldd %1,%0"; ! 1199: ! 1200: /* Otherwise use two ld insns. */ ! 1201: operands[2] ! 1202: = gen_rtx (MEM, GET_MODE (operands[1]), ! 1203: plus_constant_for_output (addr, 4)); ! 1204: return "ld %1,%0\n\tld %2,%R0"; ! 1205: } ! 1206: else if (FP_REG_P (operands[1])) ! 1207: { ! 1208: if (GET_CODE (operands[0]) == REG) ! 1209: { ! 1210: if ((REGNO (operands[0]) & 1) == 0) ! 1211: return "std %1,[%@-8]\n\tldd [%@-8],%0"; ! 1212: else ! 1213: return "std %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0"; ! 1214: } ! 1215: addr = XEXP (operands[0], 0); ! 1216: ! 1217: /* Use std if we can be sure it is well-aligned. */ ! 1218: if (TARGET_ALIGN ! 1219: || (GET_CODE (addr) == PLUS ! 1220: && (((XEXP (addr, 0) == frame_pointer_rtx ! 1221: || XEXP (addr, 0) == stack_pointer_rtx) ! 1222: && GET_CODE (XEXP (addr, 1)) == CONST_INT ! 1223: && (INTVAL (XEXP (addr, 1)) & 0x7) == 0) ! 1224: /* Arrays are known to be aligned, ! 1225: and reg+reg addresses are used (on this machine) ! 1226: only for array accesses. */ ! 1227: || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))))) ! 1228: || (GET_MODE (operands[1]) == DFmode ! 1229: && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr)))) ! 1230: return "std %1,%0"; ! 1231: ! 1232: /* Otherwise use two st insns. */ ! 1233: operands[2] ! 1234: = gen_rtx (MEM, GET_MODE (operands[0]), ! 1235: plus_constant_for_output (addr, 4)); ! 1236: return "st %r1,%0\n\tst %R1,%2"; ! 1237: } ! 1238: else abort (); ! 1239: } ! 1240: ! 1241: /* Return a REG that occurs in ADDR with coefficient 1. ! 1242: ADDR can be effectively incremented by incrementing REG. */ ! 1243: ! 1244: static rtx ! 1245: find_addr_reg (addr) ! 1246: rtx addr; ! 1247: { ! 1248: while (GET_CODE (addr) == PLUS) ! 1249: { ! 1250: /* We absolutely can not fudge the frame pointer here, because the ! 1251: frame pointer must always be 8 byte aligned. It also confuses ! 1252: debuggers. */ ! 1253: if (GET_CODE (XEXP (addr, 0)) == REG ! 1254: && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM) ! 1255: addr = XEXP (addr, 0); ! 1256: else if (GET_CODE (XEXP (addr, 1)) == REG ! 1257: && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM) ! 1258: addr = XEXP (addr, 1); ! 1259: else if (CONSTANT_P (XEXP (addr, 0))) ! 1260: addr = XEXP (addr, 1); ! 1261: else if (CONSTANT_P (XEXP (addr, 1))) ! 1262: addr = XEXP (addr, 0); ! 1263: else ! 1264: abort (); ! 1265: } ! 1266: if (GET_CODE (addr) == REG) ! 1267: return addr; ! 1268: abort (); ! 1269: } ! 1270: ! 1271: void ! 1272: output_sized_memop (opname, mode, signedp) ! 1273: char *opname; ! 1274: enum machine_mode mode; ! 1275: int signedp; ! 1276: { ! 1277: static char *ld_size_suffix_u[] = { "ub", "uh", "", "?", "d" }; ! 1278: static char *ld_size_suffix_s[] = { "sb", "sh", "", "?", "d" }; ! 1279: static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; ! 1280: char **opnametab, *modename; ! 1281: ! 1282: if (opname[0] == 'l') ! 1283: if (signedp) ! 1284: opnametab = ld_size_suffix_s; ! 1285: else ! 1286: opnametab = ld_size_suffix_u; ! 1287: else ! 1288: opnametab = st_size_suffix; ! 1289: modename = opnametab[GET_MODE_SIZE (mode) >> 1]; ! 1290: ! 1291: fprintf (asm_out_file, "\t%s%s", opname, modename); ! 1292: } ! 1293: ! 1294: void ! 1295: output_move_with_extension (operands) ! 1296: rtx *operands; ! 1297: { ! 1298: if (GET_MODE (operands[2]) == HImode) ! 1299: output_asm_insn ("sll %2,0x10,%0", operands); ! 1300: else if (GET_MODE (operands[2]) == QImode) ! 1301: output_asm_insn ("sll %2,0x18,%0", operands); ! 1302: else ! 1303: abort (); ! 1304: } ! 1305: ! 1306: /* Load the address specified by OPERANDS[3] into the register ! 1307: specified by OPERANDS[0]. ! 1308: ! 1309: OPERANDS[3] may be the result of a sum, hence it could either be: ! 1310: ! 1311: (1) CONST ! 1312: (2) REG ! 1313: (2) REG + CONST_INT ! 1314: (3) REG + REG + CONST_INT ! 1315: (4) REG + REG (special case of 3). ! 1316: ! 1317: Note that (3) is not a legitimate address. ! 1318: All cases are handled here. */ ! 1319: ! 1320: void ! 1321: output_load_address (operands) ! 1322: rtx *operands; ! 1323: { ! 1324: rtx base, offset; ! 1325: ! 1326: if (CONSTANT_P (operands[3])) ! 1327: { ! 1328: output_asm_insn ("set %3,%0", operands); ! 1329: return; ! 1330: } ! 1331: ! 1332: if (REG_P (operands[3])) ! 1333: { ! 1334: if (REGNO (operands[0]) != REGNO (operands[3])) ! 1335: output_asm_insn ("mov %3,%0", operands); ! 1336: return; ! 1337: } ! 1338: ! 1339: if (GET_CODE (operands[3]) != PLUS) ! 1340: abort (); ! 1341: ! 1342: base = XEXP (operands[3], 0); ! 1343: offset = XEXP (operands[3], 1); ! 1344: ! 1345: if (GET_CODE (base) == CONST_INT) ! 1346: { ! 1347: rtx tmp = base; ! 1348: base = offset; ! 1349: offset = tmp; ! 1350: } ! 1351: ! 1352: if (GET_CODE (offset) != CONST_INT) ! 1353: { ! 1354: /* Operand is (PLUS (REG) (REG)). */ ! 1355: base = operands[3]; ! 1356: offset = const0_rtx; ! 1357: } ! 1358: ! 1359: if (REG_P (base)) ! 1360: { ! 1361: operands[6] = base; ! 1362: operands[7] = offset; ! 1363: if (SMALL_INT (offset)) ! 1364: output_asm_insn ("add %6,%7,%0", operands); ! 1365: else ! 1366: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); ! 1367: } ! 1368: else if (GET_CODE (base) == PLUS) ! 1369: { ! 1370: operands[6] = XEXP (base, 0); ! 1371: operands[7] = XEXP (base, 1); ! 1372: operands[8] = offset; ! 1373: ! 1374: if (SMALL_INT (offset)) ! 1375: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); ! 1376: else ! 1377: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); ! 1378: } ! 1379: else ! 1380: abort (); ! 1381: } ! 1382: ! 1383: /* Output code to place a size count SIZE in register REG. ! 1384: ALIGN is the size of the unit of transfer. ! 1385: ! 1386: Because block moves are pipelined, we don't include the ! 1387: first element in the transfer of SIZE to REG. */ ! 1388: ! 1389: static void ! 1390: output_size_for_block_move (size, reg, align) ! 1391: rtx size, reg; ! 1392: rtx align; ! 1393: { ! 1394: rtx xoperands[3]; ! 1395: ! 1396: xoperands[0] = reg; ! 1397: xoperands[1] = size; ! 1398: xoperands[2] = align; ! 1399: if (GET_CODE (size) == REG) ! 1400: output_asm_insn ("sub %1,%2,%0", xoperands); ! 1401: else ! 1402: { ! 1403: xoperands[1] ! 1404: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); ! 1405: output_asm_insn ("set %1,%0", xoperands); ! 1406: } ! 1407: } ! 1408: ! 1409: /* Emit code to perform a block move. ! 1410: ! 1411: OPERANDS[0] is the destination. ! 1412: OPERANDS[1] is the source. ! 1413: OPERANDS[2] is the size. ! 1414: OPERANDS[3] is the alignment safe to use. ! 1415: OPERANDS[4] is a register we can safely clobber as a temp. */ ! 1416: ! 1417: char * ! 1418: output_block_move (operands) ! 1419: rtx *operands; ! 1420: { ! 1421: /* A vector for our computed operands. Note that load_output_address ! 1422: makes use of (and can clobber) up to the 8th element of this vector. */ ! 1423: rtx xoperands[10]; ! 1424: rtx zoperands[10]; ! 1425: static int movstrsi_label = 0; ! 1426: int i; ! 1427: rtx temp1 = operands[4]; ! 1428: rtx sizertx = operands[2]; ! 1429: rtx alignrtx = operands[3]; ! 1430: int align = INTVAL (alignrtx); ! 1431: ! 1432: xoperands[0] = operands[0]; ! 1433: xoperands[1] = operands[1]; ! 1434: xoperands[2] = temp1; ! 1435: ! 1436: /* We can't move more than this many bytes at a time ! 1437: because we have only one register to move them through. */ ! 1438: if (align > GET_MODE_SIZE (GET_MODE (temp1))) ! 1439: { ! 1440: align = GET_MODE_SIZE (GET_MODE (temp1)); ! 1441: alignrtx = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (temp1))); ! 1442: } ! 1443: ! 1444: /* If the size isn't known to be a multiple of the alignment, ! 1445: we have to do it in smaller pieces. If we could determine that ! 1446: the size was a multiple of 2 (or whatever), we could be smarter ! 1447: about this. */ ! 1448: if (GET_CODE (sizertx) != CONST_INT) ! 1449: align = 1; ! 1450: else ! 1451: { ! 1452: int size = INTVAL (sizertx); ! 1453: while (size % align) ! 1454: align >>= 1; ! 1455: } ! 1456: ! 1457: if (align != INTVAL (alignrtx)) ! 1458: alignrtx = gen_rtx (CONST_INT, VOIDmode, align); ! 1459: ! 1460: /* Recognize special cases of block moves. These occur ! 1461: when GNU C++ is forced to treat something as BLKmode ! 1462: to keep it in memory, when its mode could be represented ! 1463: with something smaller. ! 1464: ! 1465: We cannot do this for global variables, since we don't know ! 1466: what pages they don't cross. Sigh. */ ! 1467: if (GET_CODE (sizertx) == CONST_INT && INTVAL (sizertx) <= 16) ! 1468: { ! 1469: int size = INTVAL (sizertx); ! 1470: ! 1471: if (align == 1) ! 1472: { ! 1473: if (memory_address_p (QImode, ! 1474: plus_constant_for_output (xoperands[0], size)) ! 1475: && memory_address_p (QImode, ! 1476: plus_constant_for_output (xoperands[1], ! 1477: size))) ! 1478: { ! 1479: /* We will store different integers into this particular RTX. */ ! 1480: xoperands[2] = rtx_alloc (CONST_INT); ! 1481: PUT_MODE (xoperands[2], VOIDmode); ! 1482: for (i = size-1; i >= 0; i--) ! 1483: { ! 1484: INTVAL (xoperands[2]) = i; ! 1485: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", ! 1486: xoperands); ! 1487: } ! 1488: return ""; ! 1489: } ! 1490: } ! 1491: else if (align == 2) ! 1492: { ! 1493: if (memory_address_p (HImode, ! 1494: plus_constant_for_output (xoperands[0], size)) ! 1495: && memory_address_p (HImode, ! 1496: plus_constant_for_output (xoperands[1], ! 1497: size))) ! 1498: { ! 1499: /* We will store different integers into this particular RTX. */ ! 1500: xoperands[2] = rtx_alloc (CONST_INT); ! 1501: PUT_MODE (xoperands[2], VOIDmode); ! 1502: for (i = (size>>1)-1; i >= 0; i--) ! 1503: { ! 1504: INTVAL (xoperands[2]) = i<<1; ! 1505: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", ! 1506: xoperands); ! 1507: } ! 1508: return ""; ! 1509: } ! 1510: } ! 1511: else ! 1512: { ! 1513: if (memory_address_p (SImode, ! 1514: plus_constant_for_output (xoperands[0], size)) ! 1515: && memory_address_p (SImode, ! 1516: plus_constant_for_output (xoperands[1], ! 1517: size))) ! 1518: { ! 1519: /* We will store different integers into this particular RTX. */ ! 1520: xoperands[2] = rtx_alloc (CONST_INT); ! 1521: PUT_MODE (xoperands[2], VOIDmode); ! 1522: for (i = (size>>2)-1; i >= 0; i--) ! 1523: { ! 1524: INTVAL (xoperands[2]) = i<<2; ! 1525: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", ! 1526: xoperands); ! 1527: } ! 1528: return ""; ! 1529: } ! 1530: } ! 1531: } ! 1532: ! 1533: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1534: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); ! 1535: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); ! 1536: ! 1537: /* This is the size of the transfer. ! 1538: Either use the register which already contains the size, ! 1539: or use a free register (used by no operands). ! 1540: Also emit code to decrement the size value by ALIGN. */ ! 1541: output_size_for_block_move (sizertx, temp1, alignrtx); ! 1542: ! 1543: /* Must handle the case when the size is zero or negative, so the first thing ! 1544: we do is compare the size against zero, and only copy bytes if it is ! 1545: zero or greater. Note that we have already subtracted off the alignment ! 1546: once, so we must copy 1 alignment worth of bytes if the size is zero ! 1547: here. ! 1548: ! 1549: The SUN assembler complains about labels in branch delay slots, so we ! 1550: do this before outputing the load address, so that there will always ! 1551: be a harmless insn between the branch here and the next label emitted ! 1552: below. */ ! 1553: ! 1554: #ifdef NO_UNDERSCORES ! 1555: output_asm_insn ("cmp %2,0\n\tbl .Lm%5", xoperands); ! 1556: #else ! 1557: output_asm_insn ("cmp %2,0\n\tbl Lm%5", xoperands); ! 1558: #endif ! 1559: ! 1560: zoperands[0] = operands[0]; ! 1561: zoperands[3] = plus_constant_for_output (operands[0], align); ! 1562: output_load_address (zoperands); ! 1563: ! 1564: /* ??? This might be much faster if the loops below were preconditioned ! 1565: and unrolled. ! 1566: ! 1567: That is, at run time, copy enough bytes one at a time to ensure that the ! 1568: target and source addresses are aligned to the the largest possible ! 1569: alignment. Then use a preconditioned unrolled loop to copy say 16 ! 1570: bytes at a time. Then copy bytes one at a time until finish the rest. */ ! 1571: ! 1572: /* Output the first label separately, so that it is spaced properly. */ ! 1573: ! 1574: #ifdef NO_UNDERSCORES ! 1575: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, ".Lm", INTVAL (xoperands[3])); ! 1576: #else ! 1577: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "Lm", INTVAL (xoperands[3])); ! 1578: #endif ! 1579: ! 1580: #ifdef NO_UNDERSCORES ! 1581: if (align == 1) ! 1582: output_asm_insn ("ldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]\n.Lm%5:", xoperands); ! 1583: else if (align == 2) ! 1584: output_asm_insn ("lduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]\n.Lm%5:", xoperands); ! 1585: else ! 1586: output_asm_insn ("ld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]\n.Lm%5:", xoperands); ! 1587: return ""; ! 1588: #else ! 1589: if (align == 1) ! 1590: output_asm_insn ("ldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]\nLm%5:", xoperands); ! 1591: else if (align == 2) ! 1592: output_asm_insn ("lduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]\nLm%5:", xoperands); ! 1593: else ! 1594: output_asm_insn ("ld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]\nLm%5:", xoperands); ! 1595: return ""; ! 1596: #endif ! 1597: } ! 1598: ! 1599: /* Output reasonable peephole for set-on-condition-code insns. ! 1600: Note that these insns assume a particular way of defining ! 1601: labels. Therefore, *both* sparc.h and this function must ! 1602: be changed if a new syntax is needed. */ ! 1603: ! 1604: char * ! 1605: output_scc_insn (operands, insn) ! 1606: rtx operands[]; ! 1607: rtx insn; ! 1608: { ! 1609: static char string[100]; ! 1610: rtx label = 0, next = insn; ! 1611: int need_label = 0; ! 1612: ! 1613: /* Try doing a jump optimization which jump.c can't do for us ! 1614: because we did not expose that setcc works by using branches. ! 1615: ! 1616: If this scc insn is followed by an unconditional branch, then have ! 1617: the jump insn emitted here jump to that location, instead of to ! 1618: the end of the scc sequence as usual. */ ! 1619: ! 1620: do ! 1621: { ! 1622: if (GET_CODE (next) == CODE_LABEL) ! 1623: label = next; ! 1624: next = NEXT_INSN (next); ! 1625: if (next == 0) ! 1626: break; ! 1627: } ! 1628: while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL); ! 1629: ! 1630: /* If we are in a sequence, and the following insn is a sequence also, ! 1631: then just following the current insn's next field will take us to the ! 1632: first insn of the next sequence, which is the wrong place. We don't ! 1633: want to optimize with a branch that has had its delay slot filled. ! 1634: Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next ! 1635: which fails only if NEXT is such a branch. */ ! 1636: ! 1637: if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next) ! 1638: && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next)) ! 1639: label = JUMP_LABEL (next); ! 1640: /* If not optimizing, jump label fields are not set. To be safe, always ! 1641: check here to whether label is still zero. */ ! 1642: if (label == 0) ! 1643: { ! 1644: label = gen_label_rtx (); ! 1645: need_label = 1; ! 1646: } ! 1647: ! 1648: LABEL_NUSES (label) += 1; ! 1649: ! 1650: operands[2] = label; ! 1651: ! 1652: /* If we are in a delay slot, assume it is the delay slot of an fpcc ! 1653: insn since our type isn't allowed anywhere else. */ ! 1654: ! 1655: /* ??? Fpcc instructions no longer have delay slots, so this code is ! 1656: probably obsolete. */ ! 1657: ! 1658: /* The fastest way to emit code for this is an annulled branch followed ! 1659: by two move insns. This will take two cycles if the branch is taken, ! 1660: and three cycles if the branch is not taken. ! 1661: ! 1662: However, if we are in the delay slot of another branch, this won't work, ! 1663: because we can't put a branch in the delay slot of another branch. ! 1664: The above sequence would effectively take 3 or 4 cycles respectively ! 1665: since a no op would have be inserted between the two branches. ! 1666: In this case, we want to emit a move, annulled branch, and then the ! 1667: second move. This sequence always takes 3 cycles, and hence is faster ! 1668: when we are in a branch delay slot. */ ! 1669: ! 1670: if (final_sequence) ! 1671: { ! 1672: strcpy (string, "mov 0,%0\n\t"); ! 1673: strcat (string, output_cbranch (operands[1], 2, 0, 1, 0)); ! 1674: strcat (string, "\n\tmov 1,%0"); ! 1675: } ! 1676: else ! 1677: { ! 1678: strcpy (string, output_cbranch (operands[1], 2, 0, 1, 0)); ! 1679: strcat (string, "\n\tmov 1,%0\n\tmov 0,%0"); ! 1680: } ! 1681: ! 1682: if (need_label) ! 1683: strcat (string, "\n%l2:"); ! 1684: ! 1685: return string; ! 1686: } ! 1687: ! 1688: /* Vectors to keep interesting information about registers where ! 1689: it can easily be got. */ ! 1690: ! 1691: /* Modes for condition codes. */ ! 1692: #define C_MODES \ ! 1693: ((1 << (int) CCmode) | (1 << (int) CC_NOOVmode) | (1 << (int) CCFPmode)) ! 1694: ! 1695: /* Modes for single-word (and smaller) quantities. */ ! 1696: #define S_MODES \ ! 1697: (~C_MODES \ ! 1698: & ~ ((1 << (int) DImode) | (1 << (int) TImode) \ ! 1699: | (1 << (int) DFmode) | (1 << (int) TFmode))) ! 1700: ! 1701: /* Modes for double-word (and smaller) quantities. */ ! 1702: #define D_MODES \ ! 1703: (~C_MODES \ ! 1704: & ~ ((1 << (int) TImode) | (1 << (int) TFmode))) ! 1705: ! 1706: /* Modes for quad-word quantities. */ ! 1707: #define T_MODES (~C_MODES) ! 1708: ! 1709: /* Modes for single-float quantities. */ ! 1710: #define SF_MODES ((1 << (int) SFmode)) ! 1711: ! 1712: /* Modes for double-float quantities. */ ! 1713: #define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode)) ! 1714: ! 1715: /* Modes for quad-float quantities. */ ! 1716: #define TF_MODES (DF_MODES | (1 << (int) TFmode) | (1 << (int) DCmode)) ! 1717: ! 1718: /* Value is 1 if register/mode pair is acceptable on sparc. ! 1719: The funny mixture of D and T modes is because integer operations ! 1720: do not specially operate on tetra quantities, so non-quad-aligned ! 1721: registers can hold quadword quantities (except %o4 and %i4 because ! 1722: they cross fixed registers. */ ! 1723: ! 1724: int hard_regno_mode_ok[] = { ! 1725: C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, ! 1726: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, ! 1727: T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, ! 1728: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, ! 1729: ! 1730: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 1731: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 1732: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, ! 1733: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES}; ! 1734: ! 1735: #ifdef __GNUC__ ! 1736: inline ! 1737: #endif ! 1738: static int ! 1739: save_regs (file, low, high, base, offset, n_fregs) ! 1740: FILE *file; ! 1741: int low, high; ! 1742: char *base; ! 1743: int offset; ! 1744: int n_fregs; ! 1745: { ! 1746: int i; ! 1747: ! 1748: for (i = low; i < high; i += 2) ! 1749: { ! 1750: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1751: if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 1752: fprintf (file, "\tstd %s,[%s+%d]\n", ! 1753: reg_names[i], base, offset + 4 * n_fregs), ! 1754: n_fregs += 2; ! 1755: else ! 1756: fprintf (file, "\tst %s,[%s+%d]\n", ! 1757: reg_names[i], base, offset + 4 * n_fregs), ! 1758: n_fregs += 2; ! 1759: else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 1760: fprintf (file, "\tst %s,[%s+%d]\n", ! 1761: reg_names[i+1], base, offset + 4 * n_fregs), ! 1762: n_fregs += 2; ! 1763: } ! 1764: return n_fregs; ! 1765: } ! 1766: ! 1767: #ifdef __GNUC__ ! 1768: inline ! 1769: #endif ! 1770: static int ! 1771: restore_regs (file, low, high, base, offset, n_fregs) ! 1772: FILE *file; ! 1773: int low, high; ! 1774: char *base; ! 1775: int offset; ! 1776: { ! 1777: int i; ! 1778: ! 1779: for (i = low; i < high; i += 2) ! 1780: { ! 1781: if (regs_ever_live[i] && ! call_used_regs[i]) ! 1782: if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 1783: fprintf (file, "\tldd [%s+%d], %s\n", ! 1784: base, offset + 4 * n_fregs, reg_names[i]), ! 1785: n_fregs += 2; ! 1786: else ! 1787: fprintf (file, "\tld [%s+%d],%s\n", ! 1788: base, offset + 4 * n_fregs, reg_names[i]), ! 1789: n_fregs += 2; ! 1790: else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) ! 1791: fprintf (file, "\tld [%s+%d],%s\n", ! 1792: base, offset + 4 * n_fregs, reg_names[i+1]), ! 1793: n_fregs += 2; ! 1794: } ! 1795: return n_fregs; ! 1796: } ! 1797: ! 1798: /* Static variables we want to share between prologue and epilogue. */ ! 1799: ! 1800: /* Number of live floating point registers needed to be saved. */ ! 1801: static int num_fregs; ! 1802: ! 1803: /* Nonzero if any floating point register was ever used. */ ! 1804: static int fregs_ever_live; ! 1805: ! 1806: int ! 1807: compute_frame_size (size, leaf_function) ! 1808: int size; ! 1809: int leaf_function; ! 1810: { ! 1811: int fregs_ever_live = 0; ! 1812: int n_fregs = 0, i; ! 1813: int outgoing_args_size = (current_function_outgoing_args_size ! 1814: + REG_PARM_STACK_SPACE (current_function_decl)); ! 1815: ! 1816: apparent_fsize = ((size) + 7 - STARTING_FRAME_OFFSET) & -8; ! 1817: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2) ! 1818: fregs_ever_live |= regs_ever_live[i]|regs_ever_live[i+1]; ! 1819: ! 1820: if (TARGET_EPILOGUE && fregs_ever_live) ! 1821: { ! 1822: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2) ! 1823: if ((regs_ever_live[i] && ! call_used_regs[i]) ! 1824: || (regs_ever_live[i+1] && ! call_used_regs[i+1])) ! 1825: n_fregs += 2; ! 1826: } ! 1827: ! 1828: /* Set up values for use in `function_epilogue'. */ ! 1829: num_fregs = n_fregs; ! 1830: ! 1831: apparent_fsize += (outgoing_args_size+7) & -8; ! 1832: if (leaf_function && n_fregs == 0 ! 1833: && apparent_fsize == (REG_PARM_STACK_SPACE (current_function_decl) ! 1834: - STARTING_FRAME_OFFSET)) ! 1835: apparent_fsize = 0; ! 1836: ! 1837: actual_fsize = apparent_fsize + n_fregs*4; ! 1838: ! 1839: /* Make sure nothing can clobber our register windows. ! 1840: If a SAVE must be done, or there is a stack-local variable, ! 1841: the register window area must be allocated. */ ! 1842: if (leaf_function == 0 || size > 0) ! 1843: actual_fsize += (16 * UNITS_PER_WORD)+8; ! 1844: ! 1845: return actual_fsize; ! 1846: } ! 1847: ! 1848: void ! 1849: output_function_prologue (file, size, leaf_function) ! 1850: FILE *file; ! 1851: int size; ! 1852: { ! 1853: if (leaf_function) ! 1854: frame_base_name = "%sp+80"; ! 1855: else ! 1856: frame_base_name = "%fp"; ! 1857: ! 1858: actual_fsize = compute_frame_size (size, leaf_function); ! 1859: ! 1860: fprintf (file, "\t!#PROLOGUE# 0\n"); ! 1861: if (actual_fsize == 0) /* do nothing. */ ; ! 1862: else if (actual_fsize < 4096) ! 1863: { ! 1864: if (! leaf_function) ! 1865: fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize); ! 1866: else ! 1867: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize); ! 1868: } ! 1869: else if (! leaf_function) ! 1870: { ! 1871: /* Need to use actual_fsize, since we are also allocating space for ! 1872: our callee (and our own register save area). */ ! 1873: fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n", ! 1874: -actual_fsize, -actual_fsize); ! 1875: fprintf (file, "\tsave %%sp,%%g1,%%sp\n"); ! 1876: } ! 1877: else ! 1878: { ! 1879: /* Put pointer to parameters into %g4, and allocate ! 1880: frame space using result computed into %g1. actual_fsize ! 1881: used instead of apparent_fsize for reasons stated above. */ ! 1882: abort (); ! 1883: ! 1884: fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n", ! 1885: -actual_fsize, -actual_fsize); ! 1886: fprintf (file, "\tadd %%sp,64,%%g4\n\tadd %%sp,%%g1,%%sp\n"); ! 1887: } ! 1888: ! 1889: /* If doing anything with PIC, do it now. */ ! 1890: if (! flag_pic) ! 1891: fprintf (file, "\t!#PROLOGUE# 1\n"); ! 1892: ! 1893: /* Figure out where to save any special registers. */ ! 1894: if (num_fregs) ! 1895: { ! 1896: int offset, n_fregs = num_fregs; ! 1897: ! 1898: if (! leaf_function) ! 1899: offset = -apparent_fsize; ! 1900: else ! 1901: offset = 0; ! 1902: ! 1903: if (TARGET_EPILOGUE && ! leaf_function) ! 1904: n_fregs = save_regs (file, 0, 16, frame_base_name, offset, 0); ! 1905: else if (leaf_function) ! 1906: n_fregs = save_regs (file, 0, 32, frame_base_name, offset, 0); ! 1907: if (TARGET_EPILOGUE) ! 1908: save_regs (file, 32, FIRST_PSEUDO_REGISTER, ! 1909: frame_base_name, offset, n_fregs); ! 1910: } ! 1911: ! 1912: if (regs_ever_live[62]) ! 1913: fprintf (file, "\tst %s,[%s-16]\n\tst %s,[%s-12]\n", ! 1914: reg_names[0], frame_base_name, ! 1915: reg_names[0], frame_base_name); ! 1916: ! 1917: leaf_label = 0; ! 1918: if (leaf_function && actual_fsize != 0) ! 1919: { ! 1920: /* warning ("leaf procedure with frame size %d", actual_fsize); */ ! 1921: if (! TARGET_EPILOGUE) ! 1922: leaf_label = gen_label_rtx (); ! 1923: } ! 1924: } ! 1925: ! 1926: void ! 1927: output_function_epilogue (file, size, leaf_function, true_epilogue) ! 1928: FILE *file; ! 1929: int size; ! 1930: { ! 1931: int n_fregs, i; ! 1932: char *ret; ! 1933: ! 1934: if (leaf_label) ! 1935: { ! 1936: if (leaf_function < 0) ! 1937: abort (); ! 1938: emit_label_after (leaf_label, get_last_insn ()); ! 1939: final_scan_insn (get_last_insn (), file, 0, 0, 1); ! 1940: } ! 1941: ! 1942: if (num_fregs) ! 1943: { ! 1944: int offset, n_fregs = num_fregs; ! 1945: ! 1946: if (! leaf_function) ! 1947: offset = -apparent_fsize; ! 1948: else ! 1949: offset = 0; ! 1950: ! 1951: if (TARGET_EPILOGUE && ! leaf_function) ! 1952: n_fregs = restore_regs (file, 0, 16, frame_base_name, offset, 0); ! 1953: else if (leaf_function) ! 1954: n_fregs = restore_regs (file, 0, 32, frame_base_name, offset, 0); ! 1955: if (TARGET_EPILOGUE) ! 1956: restore_regs (file, 32, FIRST_PSEUDO_REGISTER, ! 1957: frame_base_name, offset, n_fregs); ! 1958: } ! 1959: ! 1960: /* Work out how to skip the caller's unimp instruction if required. */ ! 1961: if (leaf_function) ! 1962: ret = (current_function_returns_struct ? "jmp %o7+12" : "retl"); ! 1963: else ! 1964: ret = (current_function_returns_struct ? "jmp %i7+12" : "ret"); ! 1965: ! 1966: /* Tail calls have to do this work themselves. */ ! 1967: if (leaf_function >= 0) ! 1968: { ! 1969: if (TARGET_EPILOGUE || leaf_label) ! 1970: { ! 1971: int old_target_epilogue = TARGET_EPILOGUE; ! 1972: target_flags &= ~old_target_epilogue; ! 1973: ! 1974: if (! leaf_function) ! 1975: { ! 1976: /* If we wound up with things in our delay slot, ! 1977: flush them here. */ ! 1978: if (current_function_epilogue_delay_list) ! 1979: { ! 1980: rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode), ! 1981: get_last_insn ()); ! 1982: PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode, ! 1983: gen_rtvec (2, ! 1984: PATTERN (XEXP (current_function_epilogue_delay_list, 0)), ! 1985: PATTERN (insn))); ! 1986: final_scan_insn (insn, file, 1, 0, 1); ! 1987: } ! 1988: else ! 1989: fprintf (file, "\t%s\n\trestore\n", ret); ! 1990: } ! 1991: else if (actual_fsize < 4096) ! 1992: { ! 1993: if (current_function_epilogue_delay_list) ! 1994: { ! 1995: fprintf (file, "\t%s\n", ret); ! 1996: final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), ! 1997: file, 1, 0, 1); ! 1998: } ! 1999: else ! 2000: fprintf (file, "\t%s\n\tadd %%sp,%d,%%sp\n", ! 2001: ret, actual_fsize); ! 2002: } ! 2003: else ! 2004: { ! 2005: if (current_function_epilogue_delay_list) ! 2006: abort (); ! 2007: fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n", ! 2008: actual_fsize, actual_fsize, ret); ! 2009: } ! 2010: target_flags |= old_target_epilogue; ! 2011: } ! 2012: } ! 2013: else if (true_epilogue) ! 2014: { ! 2015: /* We may still need a return insn! Somebody could jump around ! 2016: the tail-calls that this function makes. */ ! 2017: if (TARGET_EPILOGUE) ! 2018: { ! 2019: rtx last = get_last_insn (); ! 2020: ! 2021: last = prev_nonnote_insn (last); ! 2022: if (last == 0 ! 2023: || (GET_CODE (last) != JUMP_INSN && GET_CODE (last) != BARRIER)) ! 2024: fprintf (file, "\t%s\n\tnop\n", ret); ! 2025: } ! 2026: } ! 2027: } ! 2028: ! 2029: /* Return the string to output a conditional branch to LABEL, which is ! 2030: the operand number of the label. OP is the conditional expression. The ! 2031: mode of register 0 says what kind of comparison we made. ! 2032: ! 2033: REVERSED is non-zero if we should reverse the sense of the comparison. ! 2034: ! 2035: ANNUL is non-zero if we should generate an annulling branch. ! 2036: ! 2037: NOOP is non-zero if we have to follow this branch by a noop. */ ! 2038: ! 2039: char * ! 2040: output_cbranch (op, label, reversed, annul, noop) ! 2041: rtx op; ! 2042: int label; ! 2043: int reversed, annul, noop; ! 2044: { ! 2045: static char string[20]; ! 2046: enum rtx_code code = GET_CODE (op); ! 2047: enum machine_mode mode = GET_MODE (XEXP (op, 0)); ! 2048: static char labelno[] = " %lX"; ! 2049: ! 2050: /* ??? FP branches can not be preceeded by another floating point insn. ! 2051: Because there is currently no concept of pre-delay slots, we can fix ! 2052: this only by always emitting a nop before a floating point branch. */ ! 2053: ! 2054: if (mode == CCFPmode) ! 2055: strcpy (string, "nop\n\t"); ! 2056: ! 2057: /* If not floating-point or if EQ or NE, we can just reverse the code. */ ! 2058: if (reversed && (mode != CCFPmode || code == EQ || code == NE)) ! 2059: code = reverse_condition (code), reversed = 0; ! 2060: ! 2061: /* Start by writing the branch condition. */ ! 2062: switch (code) ! 2063: { ! 2064: case NE: ! 2065: if (mode == CCFPmode) ! 2066: strcat (string, "fbne"); ! 2067: else ! 2068: strcpy (string, "bne"); ! 2069: break; ! 2070: ! 2071: case EQ: ! 2072: if (mode == CCFPmode) ! 2073: strcat (string, "fbe"); ! 2074: else ! 2075: strcpy (string, "be"); ! 2076: break; ! 2077: ! 2078: case GE: ! 2079: if (mode == CCFPmode) ! 2080: { ! 2081: if (reversed) ! 2082: strcat (string, "fbul"); ! 2083: else ! 2084: strcat (string, "fbge"); ! 2085: } ! 2086: else if (mode == CC_NOOVmode) ! 2087: strcpy (string, "bpos"); ! 2088: else ! 2089: strcpy (string, "bge"); ! 2090: break; ! 2091: ! 2092: case GT: ! 2093: if (mode == CCFPmode) ! 2094: { ! 2095: if (reversed) ! 2096: strcat (string, "fbule"); ! 2097: else ! 2098: strcat (string, "fbg"); ! 2099: } ! 2100: else ! 2101: strcpy (string, "bg"); ! 2102: break; ! 2103: ! 2104: case LE: ! 2105: if (mode == CCFPmode) ! 2106: { ! 2107: if (reversed) ! 2108: strcat (string, "fbug"); ! 2109: else ! 2110: strcat (string, "fble"); ! 2111: } ! 2112: else ! 2113: strcpy (string, "ble"); ! 2114: break; ! 2115: ! 2116: case LT: ! 2117: if (mode == CCFPmode) ! 2118: { ! 2119: if (reversed) ! 2120: strcat (string, "fbuge"); ! 2121: else ! 2122: strcat (string, "fbl"); ! 2123: } ! 2124: else if (mode == CC_NOOVmode) ! 2125: strcpy (string, "bneg"); ! 2126: else ! 2127: strcpy (string, "bl"); ! 2128: break; ! 2129: ! 2130: case GEU: ! 2131: strcpy (string, "bgeu"); ! 2132: break; ! 2133: ! 2134: case GTU: ! 2135: strcpy (string, "bgu"); ! 2136: break; ! 2137: ! 2138: case LEU: ! 2139: strcpy (string, "bleu"); ! 2140: break; ! 2141: ! 2142: case LTU: ! 2143: strcpy (string, "blu"); ! 2144: break; ! 2145: } ! 2146: ! 2147: /* Now add the annulling, the label, and a possible noop. */ ! 2148: if (annul) ! 2149: strcat (string, ",a"); ! 2150: ! 2151: labelno[3] = label + '0'; ! 2152: strcat (string, labelno); ! 2153: ! 2154: if (noop) ! 2155: strcat (string, "\n\tnop"); ! 2156: ! 2157: return string; ! 2158: } ! 2159: ! 2160: char * ! 2161: output_return (operands) ! 2162: rtx *operands; ! 2163: { ! 2164: if (leaf_label) ! 2165: { ! 2166: operands[0] = leaf_label; ! 2167: return "b,a %l0"; ! 2168: } ! 2169: else if (leaf_function) ! 2170: { ! 2171: operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize); ! 2172: if (actual_fsize < 4096) ! 2173: { ! 2174: if (current_function_returns_struct) ! 2175: return "jmp %%o7+12\n\tadd %%sp,%0,%%sp"; ! 2176: else ! 2177: return "retl\n\tadd %%sp,%0,%%sp"; ! 2178: } ! 2179: else ! 2180: { ! 2181: if (current_function_returns_struct) ! 2182: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp"; ! 2183: else ! 2184: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp"; ! 2185: } ! 2186: } ! 2187: else ! 2188: { ! 2189: if (current_function_returns_struct) ! 2190: return "jmp %%i7+12\n\trestore"; ! 2191: else ! 2192: return "ret\n\trestore"; ! 2193: } ! 2194: } ! 2195: ! 2196: char * ! 2197: output_floatsisf2 (operands) ! 2198: rtx *operands; ! 2199: { ! 2200: if (GET_CODE (operands[1]) == MEM) ! 2201: return "ld %1,%0\n\tfitos %0,%0"; ! 2202: else if (FP_REG_P (operands[1])) ! 2203: return "fitos %1,%0"; ! 2204: return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitos %0,%0"; ! 2205: } ! 2206: ! 2207: char * ! 2208: output_floatsidf2 (operands) ! 2209: rtx *operands; ! 2210: { ! 2211: if (GET_CODE (operands[1]) == MEM) ! 2212: return "ld %1,%0\n\tfitod %0,%0"; ! 2213: else if (FP_REG_P (operands[1])) ! 2214: return "fitod %1,%0"; ! 2215: return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitod %0,%0"; ! 2216: } ! 2217: ! 2218: int ! 2219: tail_call_valid_p () ! 2220: { ! 2221: static int checked = 0; ! 2222: static int valid_p = 0; ! 2223: ! 2224: if (! checked) ! 2225: { ! 2226: register int i; ! 2227: ! 2228: checked = 1; ! 2229: for (i = 32; i < FIRST_PSEUDO_REGISTER; i++) ! 2230: if (! fixed_regs[i] && ! call_used_regs[i]) ! 2231: return 0; ! 2232: valid_p = 1; ! 2233: } ! 2234: return valid_p; ! 2235: } ! 2236: ! 2237: /* Leaf functions and non-leaf functions have different needs. */ ! 2238: ! 2239: static int ! 2240: reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER; ! 2241: ! 2242: static int ! 2243: reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER; ! 2244: ! 2245: static int *reg_alloc_orders[] = { ! 2246: reg_leaf_alloc_order, ! 2247: reg_nonleaf_alloc_order}; ! 2248: ! 2249: void ! 2250: order_regs_for_local_alloc () ! 2251: { ! 2252: static int last_order_nonleaf = 1; ! 2253: ! 2254: if (regs_ever_live[15] != last_order_nonleaf) ! 2255: { ! 2256: last_order_nonleaf = !last_order_nonleaf; ! 2257: bcopy (reg_alloc_orders[last_order_nonleaf], reg_alloc_order, ! 2258: FIRST_PSEUDO_REGISTER * sizeof (int)); ! 2259: } ! 2260: } ! 2261: ! 2262: /* Machine dependent routines for the branch probability, arc profiling ! 2263: code. */ ! 2264: ! 2265: /* The label used by the arc profiling code. */ ! 2266: ! 2267: static rtx profiler_label; ! 2268: ! 2269: void ! 2270: init_arc_profiler () ! 2271: { ! 2272: /* Generate and save a copy of this so it can be shared. */ ! 2273: profiler_label = gen_rtx (SYMBOL_REF, Pmode, "*LPBX2"); ! 2274: } ! 2275: ! 2276: void ! 2277: output_arc_profiler (arcno, insert_after) ! 2278: int arcno; ! 2279: rtx insert_after; ! 2280: { ! 2281: rtx profiler_target_addr ! 2282: = gen_rtx (CONST, Pmode, ! 2283: gen_rtx (PLUS, Pmode, profiler_label, ! 2284: gen_rtx (CONST_INT, VOIDmode, 4 * arcno))); ! 2285: register rtx profiler_reg = gen_reg_rtx (SImode); ! 2286: register rtx temp = gen_reg_rtx (Pmode); ! 2287: register rtx profiler_target = gen_rtx (MEM, SImode, ! 2288: gen_rtx (LO_SUM, Pmode, temp, ! 2289: profiler_target_addr)); ! 2290: /* The insns are emitted from last to first after the insn insert_after. ! 2291: Emit_insn_after is used because sometimes we want to put the ! 2292: instrumentation code after the last insn of the function. */ ! 2293: emit_insn_after (gen_rtx (SET, VOIDmode, profiler_target, profiler_reg), ! 2294: insert_after); ! 2295: emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, ! 2296: gen_rtx (PLUS, SImode, profiler_reg, const1_rtx)), ! 2297: insert_after); ! 2298: emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, profiler_target), ! 2299: insert_after); ! 2300: emit_insn_after (gen_rtx (SET, VOIDmode, temp, ! 2301: gen_rtx (HIGH, Pmode, profiler_target_addr)), ! 2302: insert_after); ! 2303: } ! 2304: ! 2305: /* All the remaining routines in this file have been turned off. */ ! 2306: #if 0 ! 2307: char * ! 2308: output_tail_call (operands, insn) ! 2309: rtx *operands; ! 2310: rtx insn; ! 2311: { ! 2312: int this_fsize = actual_fsize; ! 2313: rtx next; ! 2314: int need_nop_at_end = 0; ! 2315: ! 2316: next = next_real_insn (insn); ! 2317: while (next && GET_CODE (next) == CODE_LABEL) ! 2318: next = next_real_insn (insn); ! 2319: ! 2320: if (final_sequence && this_fsize > 0) ! 2321: { ! 2322: rtx xoperands[1]; ! 2323: ! 2324: /* If we have to restore any registers, don't take any chances ! 2325: restoring a register before we discharge it into ! 2326: its home. If the frame size is only 88, we are guaranteed ! 2327: that the epilogue will fit in the delay slot. */ ! 2328: rtx delay_insn = XVECEXP (final_sequence, 0, 1); ! 2329: if (GET_CODE (PATTERN (delay_insn)) == SET) ! 2330: { ! 2331: rtx dest = SET_DEST (PATTERN (delay_insn)); ! 2332: if (GET_CODE (dest) == REG ! 2333: && reg_mentioned_p (dest, insn)) ! 2334: abort (); ! 2335: } ! 2336: else if (GET_CODE (PATTERN (delay_insn)) == PARALLEL) ! 2337: abort (); ! 2338: xoperands[0] = operands[0]; ! 2339: final_scan_insn (delay_insn, asm_out_file, 0, 0, 1); ! 2340: operands[0] = xoperands[0]; ! 2341: final_sequence = 0; ! 2342: } ! 2343: ! 2344: /* Make sure we are clear to return. */ ! 2345: output_function_epilogue (asm_out_file, get_frame_size (), -1, 0); ! 2346: ! 2347: /* Strip the MEM. */ ! 2348: operands[0] = XEXP (operands[0], 0); ! 2349: ! 2350: if (final_sequence == 0 ! 2351: && (next == 0 ! 2352: || GET_CODE (next) == CALL_INSN ! 2353: || GET_CODE (next) == JUMP_INSN)) ! 2354: need_nop_at_end = 1; ! 2355: ! 2356: if (flag_pic) ! 2357: return output_pic_sequence_2 (2, 3, 0, "jmpl %%g1+%3", operands, need_nop_at_end); ! 2358: ! 2359: if (GET_CODE (operands[0]) == REG) ! 2360: output_asm_insn ("jmpl %a0,%%g0", operands); ! 2361: else if (TARGET_TAIL_CALL) ! 2362: { ! 2363: /* We assume all labels will be within 16 MB of our call. */ ! 2364: if (need_nop_at_end || final_sequence) ! 2365: output_asm_insn ("b %a0", operands); ! 2366: else ! 2367: output_asm_insn ("b,a %a0", operands); ! 2368: } ! 2369: else if (! final_sequence) ! 2370: { ! 2371: output_asm_insn ("sethi %%hi(%a0),%%g1\n\tjmpl %%g1+%%lo(%a0),%%g1", ! 2372: operands); ! 2373: } ! 2374: else ! 2375: { ! 2376: int i; ! 2377: rtx x = PATTERN (XVECEXP (final_sequence, 0, 1)); ! 2378: for (i = 1; i < 32; i++) ! 2379: if ((i == 1 || ! fixed_regs[i]) ! 2380: && call_used_regs[i] ! 2381: && ! refers_to_regno_p (i, i+1, x, 0)) ! 2382: break; ! 2383: if (i == 32) ! 2384: abort (); ! 2385: operands[1] = gen_rtx (REG, SImode, i); ! 2386: output_asm_insn ("sethi %%hi(%a0),%1\n\tjmpl %1+%%lo(%a0),%1", operands); ! 2387: } ! 2388: return (need_nop_at_end ? "nop" : ""); ! 2389: } ! 2390: #endif ! 2391: ! 2392: /* Print operand X (an rtx) in assembler syntax to file FILE. ! 2393: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. ! 2394: For `%' followed by punctuation, CODE is the punctuation and X is null. */ ! 2395: ! 2396: void ! 2397: print_operand (file, x, code) ! 2398: FILE *file; ! 2399: rtx x; ! 2400: int code; ! 2401: { ! 2402: switch (code) ! 2403: { ! 2404: case '#': ! 2405: /* Output a 'nop' if there's nothing for the delay slot. */ ! 2406: if (dbr_sequence_length () == 0) ! 2407: fputs ("\n\tnop", file); ! 2408: return; ! 2409: case '*': ! 2410: /* Output an annul flag if there's nothing for the delay slot. */ ! 2411: if (dbr_sequence_length () == 0) ! 2412: fputs (",a", file); ! 2413: return; ! 2414: case 'Y': ! 2415: /* Adjust the operand to take into account a RESTORE operation. */ ! 2416: if (GET_CODE (x) != REG) ! 2417: abort (); ! 2418: if (REGNO (x) < 8) ! 2419: fputs (reg_names[REGNO (x)], file); ! 2420: else if (REGNO (x) >= 24 && REGNO (x) < 32) ! 2421: fputs (reg_names[REGNO (x)-16], file); ! 2422: else ! 2423: abort (); ! 2424: return; ! 2425: case '@': ! 2426: /* Print out what we are using as the frame pointer. This might ! 2427: be %fp, or might be %sp+offset. */ ! 2428: fputs (frame_base_name, file); ! 2429: return; ! 2430: case 'R': ! 2431: /* Print out the second register name of a register pair. ! 2432: I.e., R (%o0) => %o1. */ ! 2433: fputs (reg_names[REGNO (x)+1], file); ! 2434: return; ! 2435: case 'm': ! 2436: /* Print the operand's address only. */ ! 2437: output_address (XEXP (x, 0)); ! 2438: return; ! 2439: case 'r': ! 2440: /* In this case we need a register. Use %g0 if the ! 2441: operand in const0_rtx. */ ! 2442: if (x == const0_rtx) ! 2443: { ! 2444: fputs ("%g0", file); ! 2445: return; ! 2446: } ! 2447: else ! 2448: break; ! 2449: ! 2450: case 'A': ! 2451: switch (GET_CODE (x)) ! 2452: { ! 2453: case IOR: fputs ("or", file); break; ! 2454: case AND: fputs ("and", file); break; ! 2455: case XOR: fputs ("xor", file); break; ! 2456: default: abort (); ! 2457: } ! 2458: return; ! 2459: ! 2460: case 'B': ! 2461: switch (GET_CODE (x)) ! 2462: { ! 2463: case IOR: fputs ("orn", file); break; ! 2464: case AND: fputs ("andn", file); break; ! 2465: case XOR: fputs ("xnor", file); break; ! 2466: default: abort (); ! 2467: } ! 2468: return; ! 2469: ! 2470: case 'b': ! 2471: { ! 2472: /* Print a sign-extended character. */ ! 2473: int i = INTVAL (x) & 0xff; ! 2474: if (i & 0x80) ! 2475: i |= 0xffffff00; ! 2476: fprintf (file, "%d", i); ! 2477: return; ! 2478: } ! 2479: ! 2480: case 0: ! 2481: /* Do nothing special. */ ! 2482: break; ! 2483: ! 2484: default: ! 2485: /* Undocumented flag. */ ! 2486: abort (); ! 2487: } ! 2488: ! 2489: if (GET_CODE (x) == REG) ! 2490: fputs (reg_names[REGNO (x)], file); ! 2491: else if (GET_CODE (x) == MEM) ! 2492: { ! 2493: fputc ('[', file); ! 2494: if (CONSTANT_P (XEXP (x, 0))) ! 2495: /* Poor Sun assembler doesn't understand absolute addressing. */ ! 2496: fputs ("%g0+", file); ! 2497: output_address (XEXP (x, 0)); ! 2498: fputc (']', file); ! 2499: } ! 2500: else if (GET_CODE (x) == HIGH) ! 2501: { ! 2502: fputs ("%hi(", file); ! 2503: output_addr_const (file, XEXP (x, 0)); ! 2504: fputc (')', file); ! 2505: } ! 2506: else if (GET_CODE (x) == LO_SUM) ! 2507: { ! 2508: print_operand (file, XEXP (x, 0), 0); ! 2509: fputs ("+%lo(", file); ! 2510: output_addr_const (file, XEXP (x, 1)); ! 2511: fputc (')', file); ! 2512: } ! 2513: else if (GET_CODE (x) == CONST_DOUBLE) ! 2514: { ! 2515: if (CONST_DOUBLE_HIGH (x) == 0) ! 2516: fprintf (file, "%u", CONST_DOUBLE_LOW (x)); ! 2517: else if (CONST_DOUBLE_HIGH (x) == -1 ! 2518: && CONST_DOUBLE_LOW (x) < 0) ! 2519: fprintf (file, "%d", CONST_DOUBLE_LOW (x)); ! 2520: else ! 2521: abort (); ! 2522: } ! 2523: else { output_addr_const (file, x); } ! 2524: } ! 2525: ! 2526: /* This function outputs assembler code for VALUE to FILE, where VALUE is ! 2527: a 64 bit (DImode) value. */ ! 2528: ! 2529: /* ??? If there is a 64 bit counterpart to .word that the assembler ! 2530: understands, then using that would simply this code greatly. */ ! 2531: ! 2532: void ! 2533: output_double_int (file, value) ! 2534: FILE *file; ! 2535: rtx value; ! 2536: { ! 2537: if (GET_CODE (value) == CONST_INT) ! 2538: { ! 2539: if (INTVAL (value) < 0) ! 2540: ASM_OUTPUT_INT (file, constm1_rtx); ! 2541: else ! 2542: ASM_OUTPUT_INT (file, const0_rtx); ! 2543: ASM_OUTPUT_INT (file, value); ! 2544: } ! 2545: else if (GET_CODE (value) == CONST_DOUBLE) ! 2546: { ! 2547: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode, ! 2548: CONST_DOUBLE_HIGH (value))); ! 2549: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode, ! 2550: CONST_DOUBLE_LOW (value))); ! 2551: } ! 2552: else if (GET_CODE (value) == SYMBOL_REF ! 2553: || GET_CODE (value) == CONST ! 2554: || GET_CODE (value) == PLUS) ! 2555: { ! 2556: /* Addresses are only 32 bits. */ ! 2557: ASM_OUTPUT_INT (file, const0_rtx); ! 2558: ASM_OUTPUT_INT (file, value); ! 2559: } ! 2560: else ! 2561: abort (); ! 2562: } ! 2563:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.