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