|
|
1.1 ! root 1: /* Subroutines used for code generation on the DEC Alpha. ! 2: Copyright (C) 1992 Free Software Foundation, Inc. ! 3: Contributed by Richard Kenner ([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: ! 22: #include <stdio.h> ! 23: #include "config.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 "recog.h" ! 35: #include "reload.h" ! 36: #include "expr.h" ! 37: #include "obstack.h" ! 38: #include "tree.h" ! 39: ! 40: /* Save information from a "cmpxx" operation until the branch or scc is ! 41: emitted. */ ! 42: ! 43: rtx alpha_compare_op0, alpha_compare_op1; ! 44: int alpha_compare_fp_p; ! 45: ! 46: /* Save the name of the current function as used by the assembler. This ! 47: is used by the epilogue. */ ! 48: ! 49: char *alpha_function_name; ! 50: ! 51: /* Nonzero if the current function needs gp. */ ! 52: ! 53: int alpha_function_needs_gp; ! 54: ! 55: /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ ! 56: ! 57: int ! 58: zap_mask (value) ! 59: HOST_WIDE_INT value; ! 60: { ! 61: int i; ! 62: ! 63: for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; ! 64: i++, value >>= 8) ! 65: if ((value & 0xff) != 0 && (value & 0xff) != 0xff) ! 66: return 0; ! 67: ! 68: return 1; ! 69: } ! 70: ! 71: /* Returns 1 if OP is either the constant zero or a register. If a ! 72: register, it must be in the proper mode unless MODE is VOIDmode. */ ! 73: ! 74: int ! 75: reg_or_0_operand (op, mode) ! 76: register rtx op; ! 77: enum machine_mode mode; ! 78: { ! 79: return op == const0_rtx || register_operand (op, mode); ! 80: } ! 81: ! 82: /* Return 1 if OP is an 8-bit constant or any register. */ ! 83: ! 84: int ! 85: reg_or_8bit_operand (op, mode) ! 86: register rtx op; ! 87: enum machine_mode mode; ! 88: { ! 89: return ((GET_CODE (op) == CONST_INT ! 90: && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100) ! 91: || register_operand (op, mode)); ! 92: } ! 93: ! 94: /* Return 1 if the operand is a valid second operand to an add insn. */ ! 95: ! 96: int ! 97: add_operand (op, mode) ! 98: register rtx op; ! 99: enum machine_mode mode; ! 100: { ! 101: if (GET_CODE (op) == CONST_INT) ! 102: return ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000 ! 103: || ((INTVAL (op) & 0xffff) == 0 ! 104: && (INTVAL (op) >> 31 == -1 ! 105: || INTVAL (op) >> 31 == 0))); ! 106: ! 107: return register_operand (op, mode); ! 108: } ! 109: ! 110: /* Return 1 if the operand is a valid second operand to a sign-extending ! 111: add insn. */ ! 112: ! 113: int ! 114: sext_add_operand (op, mode) ! 115: register rtx op; ! 116: enum machine_mode mode; ! 117: { ! 118: if (GET_CODE (op) == CONST_INT) ! 119: return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255 ! 120: || (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255); ! 121: ! 122: return register_operand (op, mode); ! 123: } ! 124: ! 125: /* Return 1 if OP is the constant 4 or 8. */ ! 126: ! 127: int ! 128: const48_operand (op, mode) ! 129: register rtx op; ! 130: enum machine_mode mode; ! 131: { ! 132: return (GET_CODE (op) == CONST_INT ! 133: && (INTVAL (op) == 4 || INTVAL (op) == 8)); ! 134: } ! 135: ! 136: /* Return 1 if OP is a valid first operand to an AND insn. */ ! 137: ! 138: int ! 139: and_operand (op, mode) ! 140: register rtx op; ! 141: enum machine_mode mode; ! 142: { ! 143: if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) ! 144: return (zap_mask (CONST_DOUBLE_LOW (op)) ! 145: && zap_mask (CONST_DOUBLE_HIGH (op))); ! 146: ! 147: if (GET_CODE (op) == CONST_INT) ! 148: return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 ! 149: || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100 ! 150: || zap_mask (INTVAL (op))); ! 151: ! 152: return register_operand (op, mode); ! 153: } ! 154: ! 155: /* Return 1 if OP is a constant that is the width, in bits, of an integral ! 156: mode smaller than DImode. */ ! 157: ! 158: int ! 159: mode_width_operand (op, mode) ! 160: register rtx op; ! 161: enum machine_mode mode; ! 162: { ! 163: return (GET_CODE (op) == CONST_INT ! 164: && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32)); ! 165: } ! 166: ! 167: /* Return 1 if OP is a constant that is the width of an integral machine mode ! 168: smaller than an integer. */ ! 169: ! 170: int ! 171: mode_mask_operand (op, mode) ! 172: register rtx op; ! 173: enum machine_mode mode; ! 174: { ! 175: #if HOST_BITS_PER_WIDE_INT == 32 ! 176: if (GET_CODE (op) == CONST_DOUBLE) ! 177: return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1; ! 178: #endif ! 179: ! 180: if (GET_CODE (op) == CONST_INT) ! 181: return (INTVAL (op) == 0xff ! 182: || INTVAL (op) == 0xffff ! 183: #if HOST_BITS_PER_WIDE_INT == 64 ! 184: || INTVAL (op) == 0xffffffff ! 185: #endif ! 186: ); ! 187: } ! 188: ! 189: /* Return 1 if OP is a multiple of 8 less than 64. */ ! 190: ! 191: int ! 192: mul8_operand (op, mode) ! 193: register rtx op; ! 194: enum machine_mode mode; ! 195: { ! 196: return (GET_CODE (op) == CONST_INT ! 197: && (unsigned HOST_WIDE_INT) INTVAL (op) < 64 ! 198: && (INTVAL (op) & 7) == 0); ! 199: } ! 200: ! 201: /* Return 1 if OP is the constant zero in floating-point. */ ! 202: ! 203: int ! 204: fp0_operand (op, mode) ! 205: register rtx op; ! 206: enum machine_mode mode; ! 207: { ! 208: return (GET_MODE (op) == mode ! 209: && GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode)); ! 210: } ! 211: ! 212: /* Return 1 if OP is the floating-point constant zero or a register. */ ! 213: ! 214: int ! 215: reg_or_fp0_operand (op, mode) ! 216: register rtx op; ! 217: enum machine_mode mode; ! 218: { ! 219: return fp0_operand (op, mode) || register_operand (op, mode); ! 220: } ! 221: ! 222: /* Return 1 if OP is a register or a constant integer. */ ! 223: ! 224: ! 225: int ! 226: reg_or_cint_operand (op, mode) ! 227: register rtx op; ! 228: enum machine_mode mode; ! 229: { ! 230: return GET_CODE (op) == CONST_INT || register_operand (op, mode); ! 231: } ! 232: ! 233: /* Return 1 if OP is a valid operand for the source of a move insn. */ ! 234: ! 235: int ! 236: input_operand (op, mode) ! 237: register rtx op; ! 238: enum machine_mode mode; ! 239: { ! 240: if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) ! 241: return 0; ! 242: ! 243: if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode) ! 244: return 0; ! 245: ! 246: switch (GET_CODE (op)) ! 247: { ! 248: case LABEL_REF: ! 249: case SYMBOL_REF: ! 250: case CONST: ! 251: return mode == DImode; ! 252: ! 253: case REG: ! 254: return 1; ! 255: ! 256: case SUBREG: ! 257: if (register_operand (op, mode)) ! 258: return 1; ! 259: /* ... fall through ... */ ! 260: case MEM: ! 261: return mode != HImode && mode != QImode && general_operand (op, mode); ! 262: ! 263: case CONST_DOUBLE: ! 264: return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode); ! 265: ! 266: case CONST_INT: ! 267: return mode == QImode || mode == HImode || add_operand (op, mode); ! 268: } ! 269: ! 270: return 0; ! 271: } ! 272: ! 273: /* Return 1 if OP is a SYMBOL_REF for the current function. */ ! 274: ! 275: int ! 276: current_function_operand (op, mode) ! 277: rtx op; ! 278: enum machine_mode mode; ! 279: { ! 280: return (GET_CODE (op) == SYMBOL_REF ! 281: && ! strcmp (XSTR (op, 0), current_function_name)); ! 282: } ! 283: ! 284: /* Return 1 if OP is a valid Alpha comparison operator. Here we know which ! 285: comparisons are valid in which insn. */ ! 286: ! 287: int ! 288: alpha_comparison_operator (op, mode) ! 289: register rtx op; ! 290: enum machine_mode mode; ! 291: { ! 292: enum rtx_code code = GET_CODE (op); ! 293: ! 294: if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<') ! 295: return 0; ! 296: ! 297: return (code == EQ || code == LE || code == LT ! 298: || (mode == DImode && (code == LEU || code == LTU))); ! 299: } ! 300: ! 301: /* Return 1 if OP is a signed comparison operation. */ ! 302: ! 303: int ! 304: signed_comparison_operator (op, mode) ! 305: register rtx op; ! 306: enum machine_mode mode; ! 307: { ! 308: switch (GET_CODE (op)) ! 309: { ! 310: case EQ: case NE: case LE: case LT: case GE: case GT: ! 311: return 1; ! 312: } ! 313: ! 314: return 0; ! 315: } ! 316: ! 317: /* Return 1 if this is a divide or modulus operator. */ ! 318: ! 319: int ! 320: divmod_operator (op, mode) ! 321: register rtx op; ! 322: enum machine_mode mode; ! 323: { ! 324: switch (GET_CODE (op)) ! 325: { ! 326: case DIV: case MOD: case UDIV: case UMOD: ! 327: return 1; ! 328: } ! 329: ! 330: return 0; ! 331: } ! 332: ! 333: /* Return 1 if this memory address is a known aligned register plus ! 334: a constant. It must be a valid address. This means that we can do ! 335: this as an aligned reference plus some offset. ! 336: ! 337: Take into account what reload will do. ! 338: ! 339: We could say that out-of-range stack slots are alignable, but that would ! 340: complicate get_aligned_mem and it isn't worth the trouble since few ! 341: functions have large stack space. */ ! 342: ! 343: int ! 344: aligned_memory_operand (op, mode) ! 345: register rtx op; ! 346: enum machine_mode mode; ! 347: { ! 348: if (GET_CODE (op) == SUBREG) ! 349: { ! 350: if (GET_MODE (op) != mode) ! 351: return 0; ! 352: op = SUBREG_REG (op); ! 353: mode = GET_MODE (op); ! 354: } ! 355: ! 356: if (reload_in_progress && GET_CODE (op) == REG ! 357: && REGNO (op) >= FIRST_PSEUDO_REGISTER) ! 358: op = reg_equiv_mem[REGNO (op)]; ! 359: ! 360: if (GET_CODE (op) != MEM || GET_MODE (op) != mode ! 361: || ! memory_address_p (mode, XEXP (op, 0))) ! 362: return 0; ! 363: ! 364: op = XEXP (op, 0); ! 365: ! 366: if (GET_CODE (op) == PLUS) ! 367: op = XEXP (op, 0); ! 368: ! 369: return (GET_CODE (op) == REG ! 370: && (REGNO (op) == STACK_POINTER_REGNUM || op == frame_pointer_rtx ! 371: || (REGNO (op) >= FIRST_VIRTUAL_REGISTER ! 372: && REGNO (op) <= LAST_VIRTUAL_REGISTER))); ! 373: } ! 374: ! 375: /* Similar, but return 1 if OP is a MEM which is not alignable. */ ! 376: ! 377: int ! 378: unaligned_memory_operand (op, mode) ! 379: register rtx op; ! 380: enum machine_mode mode; ! 381: { ! 382: if (GET_CODE (op) == SUBREG) ! 383: { ! 384: if (GET_MODE (op) != mode) ! 385: return 0; ! 386: op = SUBREG_REG (op); ! 387: mode = GET_MODE (op); ! 388: } ! 389: ! 390: if (reload_in_progress && GET_CODE (op) == REG ! 391: && REGNO (op) >= FIRST_PSEUDO_REGISTER) ! 392: op = reg_equiv_mem[REGNO (op)]; ! 393: ! 394: if (GET_CODE (op) != MEM || GET_MODE (op) != mode) ! 395: return 0; ! 396: ! 397: op = XEXP (op, 0); ! 398: ! 399: if (! memory_address_p (mode, op)) ! 400: return 1; ! 401: ! 402: if (GET_CODE (op) == PLUS) ! 403: op = XEXP (op, 0); ! 404: ! 405: return (GET_CODE (op) != REG ! 406: || (REGNO (op) != STACK_POINTER_REGNUM && op != frame_pointer_rtx ! 407: && (REGNO (op) < FIRST_VIRTUAL_REGISTER ! 408: || REGNO (op) > LAST_VIRTUAL_REGISTER))); ! 409: } ! 410: ! 411: /* Return 1 if OP is any memory location. During reload a pseudo matches. */ ! 412: ! 413: int ! 414: any_memory_operand (op, mode) ! 415: register rtx op; ! 416: enum machine_mode mode; ! 417: { ! 418: return (GET_CODE (op) == MEM ! 419: || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) ! 420: || (reload_in_progress && GET_CODE (op) == REG ! 421: && REGNO (op) >= FIRST_PSEUDO_REGISTER) ! 422: || (reload_in_progress && GET_CODE (op) == SUBREG ! 423: && GET_CODE (SUBREG_REG (op)) == REG ! 424: && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)); ! 425: } ! 426: ! 427: /* REF is an alignable memory location. Place an aligned SImode ! 428: reference into *PALIGNED_MEM and the number of bits to shift into ! 429: *PBITNUM. */ ! 430: ! 431: void ! 432: get_aligned_mem (ref, paligned_mem, pbitnum) ! 433: rtx ref; ! 434: rtx *paligned_mem, *pbitnum; ! 435: { ! 436: rtx base; ! 437: HOST_WIDE_INT offset = 0; ! 438: ! 439: if (GET_CODE (ref) == SUBREG) ! 440: { ! 441: offset = SUBREG_WORD (ref) * UNITS_PER_WORD; ! 442: if (BYTES_BIG_ENDIAN) ! 443: offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) ! 444: - MIN (UNITS_PER_WORD, ! 445: GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); ! 446: ref = SUBREG_REG (ref); ! 447: } ! 448: ! 449: if (GET_CODE (ref) == REG) ! 450: ref = reg_equiv_mem[REGNO (ref)]; ! 451: ! 452: if (reload_in_progress) ! 453: base = find_replacement (&XEXP (ref, 0)); ! 454: else ! 455: base = XEXP (ref, 0); ! 456: ! 457: if (GET_CODE (base) == PLUS) ! 458: offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); ! 459: ! 460: *paligned_mem = gen_rtx (MEM, SImode, ! 461: plus_constant (base, offset & ~3)); ! 462: MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref); ! 463: MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref); ! 464: RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref); ! 465: ! 466: *pbitnum = GEN_INT ((offset & 3) * 8); ! 467: } ! 468: ! 469: /* Similar, but just get the address. Handle the two reload cases. */ ! 470: ! 471: rtx ! 472: get_unaligned_address (ref) ! 473: rtx ref; ! 474: { ! 475: rtx base; ! 476: HOST_WIDE_INT offset = 0; ! 477: ! 478: if (GET_CODE (ref) == SUBREG) ! 479: { ! 480: offset = SUBREG_WORD (ref) * UNITS_PER_WORD; ! 481: if (BYTES_BIG_ENDIAN) ! 482: offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) ! 483: - MIN (UNITS_PER_WORD, ! 484: GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); ! 485: ref = SUBREG_REG (ref); ! 486: } ! 487: ! 488: if (GET_CODE (ref) == REG) ! 489: ref = reg_equiv_mem[REGNO (ref)]; ! 490: ! 491: if (reload_in_progress) ! 492: base = find_replacement (&XEXP (ref, 0)); ! 493: else ! 494: base = XEXP (ref, 0); ! 495: ! 496: if (GET_CODE (base) == PLUS) ! 497: offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); ! 498: ! 499: return plus_constant (base, offset); ! 500: } ! 501: ! 502: /* Subfunction of the following function. Update the flags of any MEM ! 503: found in part of X. */ ! 504: ! 505: static void ! 506: alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p) ! 507: rtx x; ! 508: int in_struct_p, volatile_p, unchanging_p; ! 509: { ! 510: int i; ! 511: ! 512: switch (GET_CODE (x)) ! 513: { ! 514: case SEQUENCE: ! 515: case PARALLEL: ! 516: for (i = XVECLEN (x, 0) - 1; i >= 0; i--) ! 517: alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p, ! 518: unchanging_p); ! 519: break; ! 520: ! 521: case INSN: ! 522: alpha_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p, ! 523: unchanging_p); ! 524: break; ! 525: ! 526: case SET: ! 527: alpha_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p, ! 528: unchanging_p); ! 529: alpha_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, ! 530: unchanging_p); ! 531: break; ! 532: ! 533: case MEM: ! 534: MEM_IN_STRUCT_P (x) = in_struct_p; ! 535: MEM_VOLATILE_P (x) = volatile_p; ! 536: RTX_UNCHANGING_P (x) = unchanging_p; ! 537: break; ! 538: } ! 539: } ! 540: ! 541: /* Given INSN, which is either an INSN or a SEQUENCE generated to ! 542: perform a memory operation, look for any MEMs in either a SET_DEST or ! 543: a SET_SRC and copy the in-struct, unchanging, and volatile flags from ! 544: REF into each of the MEMs found. If REF is not a MEM, don't do ! 545: anything. */ ! 546: ! 547: void ! 548: alpha_set_memflags (insn, ref) ! 549: rtx insn; ! 550: rtx ref; ! 551: { ! 552: /* Note that it is always safe to get these flags, though they won't ! 553: be what we think if REF is not a MEM. */ ! 554: int in_struct_p = MEM_IN_STRUCT_P (ref); ! 555: int volatile_p = MEM_VOLATILE_P (ref); ! 556: int unchanging_p = RTX_UNCHANGING_P (ref); ! 557: ! 558: if (GET_CODE (ref) != MEM ! 559: || (! in_struct_p && ! volatile_p && ! unchanging_p)) ! 560: return; ! 561: ! 562: alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p); ! 563: } ! 564: ! 565: /* Try to output insns to set TARGET equal to the constant C if it can be ! 566: done in less than N insns. Returns 1 if it can be done and the ! 567: insns have been emitted. If it would take more than N insns, zero is ! 568: returned and no insns and emitted. */ ! 569: ! 570: int ! 571: alpha_emit_set_const (target, c, n) ! 572: rtx target; ! 573: HOST_WIDE_INT c; ! 574: int n; ! 575: { ! 576: HOST_WIDE_INT new = c; ! 577: int i, bits; ! 578: ! 579: #if HOST_BITS_PER_WIDE_INT == 64 ! 580: /* We are only called for SImode and DImode. If this is SImode, ensure that ! 581: we are sign extended to a full word. This does not make any sense when ! 582: cross-compiling on a narrow machine. */ ! 583: ! 584: if (GET_MODE (target) == SImode) ! 585: c = (c & 0xffffffff) - 2 * (c & 0x80000000); ! 586: #endif ! 587: ! 588: /* If this is a sign-extended 32-bit constant, we can do this in at most ! 589: three insns, so do it if we have enough insns left. We always have ! 590: a sign-extended 32-bit constant when compiling on a narrow machine. */ ! 591: ! 592: if (HOST_BITS_PER_WIDE_INT != 64 ! 593: || c >> 31 == -1 || c >> 31 == 0) ! 594: { ! 595: HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000); ! 596: HOST_WIDE_INT tmp1 = c - low; ! 597: HOST_WIDE_INT high ! 598: = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 599: HOST_WIDE_INT tmp2 = c - (high << 16) - low; ! 600: HOST_WIDE_INT extra = 0; ! 601: ! 602: if (tmp2) ! 603: { ! 604: extra = 0x4000; ! 605: tmp1 -= 0x40000000; ! 606: high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 607: } ! 608: ! 609: if (c == low || (low == 0 && extra == 0)) ! 610: { ! 611: emit_move_insn (target, GEN_INT (c)); ! 612: return 1; ! 613: } ! 614: else if (n >= 2 + (extra != 0)) ! 615: { ! 616: emit_move_insn (target, GEN_INT (low)); ! 617: if (extra != 0) ! 618: emit_insn (gen_add2_insn (target, GEN_INT (extra << 16))); ! 619: ! 620: emit_insn (gen_add2_insn (target, GEN_INT (high << 16))); ! 621: return 1; ! 622: } ! 623: } ! 624: ! 625: /* If we couldn't do it that way, try some other methods (that depend on ! 626: being able to compute in the target's word size). But if we have no ! 627: instructions left, don't bother. Also, don't even try if this is ! 628: SImode (in which case we should have already done something, but ! 629: do a sanity check here). */ ! 630: ! 631: if (n == 1 || HOST_BITS_PER_WIDE_INT < 64 || GET_MODE (target) != DImode) ! 632: return 0; ! 633: ! 634: /* First, see if can load a value into the target that is the same as the ! 635: constant except that all bytes that are 0 are changed to be 0xff. If we ! 636: can, then we can do a ZAPNOT to obtain the desired constant. */ ! 637: ! 638: for (i = 0; i < 64; i += 8) ! 639: if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0) ! 640: new |= (HOST_WIDE_INT) 0xff << i; ! 641: ! 642: if (alpha_emit_set_const (target, new, n - 1)) ! 643: { ! 644: emit_insn (gen_anddi3 (target, target, GEN_INT (c | ~ new))); ! 645: return 1; ! 646: } ! 647: ! 648: /* Find, see if we can load a related constant and then shift and possibly ! 649: negate it to get the constant we want. Try this once each increasing ! 650: numbers of insns. */ ! 651: ! 652: for (i = 1; i < n; i++) ! 653: { ! 654: /* First try complementing. */ ! 655: if (alpha_emit_set_const (target, ~ c, i)) ! 656: { ! 657: emit_insn (gen_one_cmpldi2 (target, target)); ! 658: return 1; ! 659: } ! 660: ! 661: /* First try to form a constant and do a left shift. We can do this ! 662: if some low-order bits are zero; the exact_log2 call below tells ! 663: us that information. The bits we are shifting out could be any ! 664: value, but here we'll just try the 0- and sign-extended forms of ! 665: the constant. To try to increase the chance of having the same ! 666: constant in more than one insn, start at the highest number of ! 667: bits to shift, but try all possibilities in case a ZAPNOT will ! 668: be useful. */ ! 669: ! 670: if ((bits = exact_log2 (c & - c)) > 0) ! 671: for (; bits > 0; bits--) ! 672: if (alpha_emit_set_const (target, c >> bits, i) ! 673: || alpha_emit_set_const (target, ! 674: ((unsigned HOST_WIDE_INT) c) >> bits, ! 675: i)) ! 676: { ! 677: emit_insn (gen_ashldi3 (target, target, GEN_INT (bits))); ! 678: return 1; ! 679: } ! 680: ! 681: /* Now try high-order zero bits. Here we try the shifted-in bits as ! 682: all zero and all ones. */ ! 683: ! 684: if ((bits = HOST_BITS_PER_WIDE_INT - floor_log2 (c) - 1) > 0) ! 685: for (; bits > 0; bits--) ! 686: if (alpha_emit_set_const (target, c << bits, i) ! 687: || alpha_emit_set_const (target, ! 688: ((c << bits) ! 689: | (((HOST_WIDE_INT) 1 << bits) - 1)), ! 690: i)) ! 691: { ! 692: emit_insn (gen_lshrdi3 (target, target, GEN_INT (bits))); ! 693: return 1; ! 694: } ! 695: ! 696: /* Now try high-order 1 bits. We get that with a sign-extension. ! 697: But one bit isn't enough here. */ ! 698: ! 699: if ((bits = HOST_BITS_PER_WIDE_INT - floor_log2 (~ c) - 2) > 0) ! 700: for (; bits > 0; bits--) ! 701: if (alpha_emit_set_const (target, c << bits, i) ! 702: || alpha_emit_set_const (target, ! 703: ((c << bits) ! 704: | (((HOST_WIDE_INT) 1 << bits) - 1)), ! 705: i)) ! 706: { ! 707: emit_insn (gen_ashrdi3 (target, target, GEN_INT (bits))); ! 708: return 1; ! 709: } ! 710: } ! 711: ! 712: return 0; ! 713: } ! 714: ! 715: /* Adjust the cost of a scheduling dependency. Return the new cost of ! 716: a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ ! 717: ! 718: int ! 719: alpha_adjust_cost (insn, link, dep_insn, cost) ! 720: rtx insn; ! 721: rtx link; ! 722: rtx dep_insn; ! 723: int cost; ! 724: { ! 725: rtx set; ! 726: ! 727: /* If the dependence is an anti-dependence, there is no cost. For an ! 728: output dependence, there is sometimes a cost, but it doesn't seem ! 729: worth handling those few cases. */ ! 730: ! 731: if (REG_NOTE_KIND (link) != 0) ! 732: return 0; ! 733: ! 734: /* If INSN is a store insn and DEP_INSN is setting the data being stored, ! 735: we can sometimes lower the cost. */ ! 736: ! 737: if (recog_memoized (insn) >= 0 && get_attr_type (insn) == TYPE_ST ! 738: && (set = single_set (dep_insn)) != 0 ! 739: && GET_CODE (PATTERN (insn)) == SET ! 740: && rtx_equal_p (SET_DEST (set), SET_SRC (PATTERN (insn)))) ! 741: switch (get_attr_type (dep_insn)) ! 742: { ! 743: case TYPE_LD: ! 744: /* No savings here. */ ! 745: return cost; ! 746: ! 747: case TYPE_IMULL: ! 748: case TYPE_IMULQ: ! 749: /* In these cases, we save one cycle. */ ! 750: return cost - 2; ! 751: ! 752: default: ! 753: /* In all other cases, we save two cycles. */ ! 754: return MAX (0, cost - 4); ! 755: } ! 756: ! 757: /* Another case that needs adjustment is an arithmetic or logical ! 758: operation. It's cost is usually one cycle, but we default it to ! 759: two in the MD file. The only case that it is actually two is ! 760: for the address in loads and stores. */ ! 761: ! 762: if (recog_memoized (dep_insn) >= 0 ! 763: && get_attr_type (dep_insn) == TYPE_IADDLOG) ! 764: switch (get_attr_type (insn)) ! 765: { ! 766: case TYPE_LD: ! 767: case TYPE_ST: ! 768: return cost; ! 769: ! 770: default: ! 771: return 2; ! 772: } ! 773: ! 774: /* The final case is when a compare feeds into an integer branch. The cost ! 775: is only one cycle in that case. */ ! 776: ! 777: if (recog_memoized (dep_insn) >= 0 ! 778: && get_attr_type (dep_insn) == TYPE_ICMP ! 779: && recog_memoized (insn) >= 0 ! 780: && get_attr_type (insn) == TYPE_IBR) ! 781: return 2; ! 782: ! 783: /* Otherwise, return the default cost. */ ! 784: ! 785: return cost; ! 786: } ! 787: ! 788: /* Print an operand. Recognize special options, documented below. */ ! 789: ! 790: void ! 791: print_operand (file, x, code) ! 792: FILE *file; ! 793: rtx x; ! 794: char code; ! 795: { ! 796: int i; ! 797: ! 798: switch (code) ! 799: { ! 800: case 'r': ! 801: /* If this operand is the constant zero, write it as "$31". */ ! 802: if (GET_CODE (x) == REG) ! 803: fprintf (file, "%s", reg_names[REGNO (x)]); ! 804: else if (x == CONST0_RTX (GET_MODE (x))) ! 805: fprintf (file, "$31"); ! 806: else ! 807: output_operand_lossage ("invalid %%r value"); ! 808: ! 809: break; ! 810: ! 811: case 'R': ! 812: /* Similar, but for floating-point. */ ! 813: if (GET_CODE (x) == REG) ! 814: fprintf (file, "%s", reg_names[REGNO (x)]); ! 815: else if (x == CONST0_RTX (GET_MODE (x))) ! 816: fprintf (file, "$f31"); ! 817: else ! 818: output_operand_lossage ("invalid %%R value"); ! 819: ! 820: break; ! 821: ! 822: case 'N': ! 823: /* Write the 1's complement of a constant. */ ! 824: if (GET_CODE (x) != CONST_INT) ! 825: output_operand_lossage ("invalid %%N value"); ! 826: ! 827: fprintf (file, "%ld", ~ INTVAL (x)); ! 828: break; ! 829: ! 830: case 'P': ! 831: /* Write 1 << C, for a constant C. */ ! 832: if (GET_CODE (x) != CONST_INT) ! 833: output_operand_lossage ("invalid %%P value"); ! 834: ! 835: fprintf (file, "%ld", (HOST_WIDE_INT) 1 << INTVAL (x)); ! 836: break; ! 837: ! 838: case 'h': ! 839: /* Write the high-order 16 bits of a constant, sign-extended. */ ! 840: if (GET_CODE (x) != CONST_INT) ! 841: output_operand_lossage ("invalid %%h value"); ! 842: ! 843: fprintf (file, "%ld", INTVAL (x) >> 16); ! 844: break; ! 845: ! 846: case 'L': ! 847: /* Write the low-order 16 bits of a constant, sign-extended. */ ! 848: if (GET_CODE (x) != CONST_INT) ! 849: output_operand_lossage ("invalid %%L value"); ! 850: ! 851: fprintf (file, "%ld", (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000)); ! 852: break; ! 853: ! 854: case 'm': ! 855: /* Write mask for ZAP insn. */ ! 856: if (GET_CODE (x) == CONST_DOUBLE) ! 857: { ! 858: HOST_WIDE_INT mask = 0; ! 859: HOST_WIDE_INT value; ! 860: ! 861: value = CONST_DOUBLE_LOW (x); ! 862: for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; ! 863: i++, value >>= 8) ! 864: if (value & 0xff) ! 865: mask |= (1 << i); ! 866: ! 867: value = CONST_DOUBLE_HIGH (x); ! 868: for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; ! 869: i++, value >>= 8) ! 870: if (value & 0xff) ! 871: mask |= (1 << (i + sizeof (int))); ! 872: ! 873: fprintf (file, "%ld", mask & 0xff); ! 874: } ! 875: ! 876: else if (GET_CODE (x) == CONST_INT) ! 877: { ! 878: HOST_WIDE_INT mask = 0, value = INTVAL (x); ! 879: ! 880: for (i = 0; i < 8; i++, value >>= 8) ! 881: if (value & 0xff) ! 882: mask |= (1 << i); ! 883: ! 884: fprintf (file, "%ld", mask); ! 885: } ! 886: else ! 887: output_operand_lossage ("invalid %%m value"); ! 888: break; ! 889: ! 890: case 'M': ! 891: /* 'b', 'w', or 'l' as the value of the constant. */ ! 892: if (GET_CODE (x) != CONST_INT ! 893: || (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32)) ! 894: output_operand_lossage ("invalid %%M value"); ! 895: ! 896: fprintf (file, "%s", ! 897: INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l"); ! 898: break; ! 899: ! 900: case 'U': ! 901: /* Similar, except do it from the mask. */ ! 902: if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xff) ! 903: fprintf (file, "b"); ! 904: else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffff) ! 905: fprintf (file, "w"); ! 906: #if HOST_BITS_PER_WIDE_INT == 32 ! 907: else if (GET_CODE (x) == CONST_DOUBLE ! 908: && CONST_DOUBLE_HIGH (x) == 0 ! 909: && CONST_DOUBLE_LOW (x) == -1) ! 910: fprintf (file, "l"); ! 911: #else ! 912: else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff) ! 913: fprintf (file, "l"); ! 914: #endif ! 915: else ! 916: output_operand_lossage ("invalid %%U value"); ! 917: break; ! 918: ! 919: case 's': ! 920: /* Write the constant value divided by 8. */ ! 921: if (GET_CODE (x) != CONST_INT ! 922: && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 ! 923: && (INTVAL (x) & 7) != 8) ! 924: output_operand_lossage ("invalid %%s value"); ! 925: ! 926: fprintf (file, "%ld", INTVAL (x) / 8); ! 927: break; ! 928: ! 929: case 'S': ! 930: /* Same, except compute (64 - c) / 8 */ ! 931: ! 932: if (GET_CODE (x) != CONST_INT ! 933: && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 ! 934: && (INTVAL (x) & 7) != 8) ! 935: output_operand_lossage ("invalid %%s value"); ! 936: ! 937: fprintf (file, "%ld", (64 - INTVAL (x)) / 8); ! 938: break; ! 939: ! 940: case 'C': ! 941: /* Write out comparison name. */ ! 942: if (GET_RTX_CLASS (GET_CODE (x)) != '<') ! 943: output_operand_lossage ("invalid %%C value"); ! 944: ! 945: if (GET_CODE (x) == LEU) ! 946: fprintf (file, "ule"); ! 947: else if (GET_CODE (x) == LTU) ! 948: fprintf (file, "ult"); ! 949: else ! 950: fprintf (file, "%s", GET_RTX_NAME (GET_CODE (x))); ! 951: break; ! 952: ! 953: case 'D': ! 954: /* Similar, but write reversed code. We can't get an unsigned code ! 955: here. */ ! 956: if (GET_RTX_CLASS (GET_CODE (x)) != '<') ! 957: output_operand_lossage ("invalid %%D value"); ! 958: ! 959: fprintf (file, "%s", GET_RTX_NAME (reverse_condition (GET_CODE (x)))); ! 960: break; ! 961: ! 962: case 'E': ! 963: /* Write the divide or modulus operator. */ ! 964: switch (GET_CODE (x)) ! 965: { ! 966: case DIV: ! 967: fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); ! 968: break; ! 969: case UDIV: ! 970: fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); ! 971: break; ! 972: case MOD: ! 973: fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); ! 974: break; ! 975: case UMOD: ! 976: fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); ! 977: break; ! 978: default: ! 979: output_operand_lossage ("invalid %%E value"); ! 980: break; ! 981: } ! 982: break; ! 983: ! 984: case 'F': ! 985: /* Write the symbol; if the current function uses GP, write a ! 986: modified version. */ ! 987: if (GET_CODE (x) != SYMBOL_REF) ! 988: output_operand_lossage ("invalid %%F value"); ! 989: ! 990: output_addr_const (file, x); ! 991: if (alpha_function_needs_gp) ! 992: fprintf (file, "..ng"); ! 993: break; ! 994: ! 995: case 'A': ! 996: /* Write "_u" for unaligned access. */ ! 997: if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND) ! 998: fprintf (file, "_u"); ! 999: break; ! 1000: ! 1001: case 0: ! 1002: if (GET_CODE (x) == REG) ! 1003: fprintf (file, "%s", reg_names[REGNO (x)]); ! 1004: else if (GET_CODE (x) == MEM) ! 1005: output_address (XEXP (x, 0)); ! 1006: else ! 1007: output_addr_const (file, x); ! 1008: break; ! 1009: ! 1010: default: ! 1011: output_operand_lossage ("invalid %%xn code"); ! 1012: } ! 1013: } ! 1014: ! 1015: /* Do what is necessary for `va_start'. The argument is ignored; ! 1016: We look at the current function to determine if stdarg or varargs ! 1017: is used and fill in an initial va_list. A pointer to this constructor ! 1018: is returned. */ ! 1019: ! 1020: struct rtx_def * ! 1021: alpha_builtin_saveregs (arglist) ! 1022: tree arglist; ! 1023: { ! 1024: rtx block, addr, argsize; ! 1025: tree fntype = TREE_TYPE (current_function_decl); ! 1026: int stdarg = (TYPE_ARG_TYPES (fntype) != 0 ! 1027: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ! 1028: != void_type_node)); ! 1029: int nregs = current_function_args_info; ! 1030: ! 1031: /* If we have a variable-sized argument already, we will have used all ! 1032: the registers, so set up to indicate that. */ ! 1033: ! 1034: if (GET_CODE (current_function_arg_offset_rtx) != CONST_INT) ! 1035: { ! 1036: argsize = plus_constant (current_function_arg_offset_rtx, ! 1037: (6 * UNITS_PER_WORD + UNITS_PER_WORD - 1)); ! 1038: argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize, ! 1039: build_int_2 (3, 0), argsize, 0); ! 1040: } ! 1041: else ! 1042: { ! 1043: /* Compute the number of args in memory and number of arguments already ! 1044: processed. Then adjust the number of registers if this is stdarg. */ ! 1045: int memargs = ((INTVAL (current_function_arg_offset_rtx) ! 1046: + UNITS_PER_WORD - 1) ! 1047: / UNITS_PER_WORD); ! 1048: ! 1049: argsize = GEN_INT (MIN (nregs, 6) + memargs); ! 1050: ! 1051: if (nregs <= 6) ! 1052: nregs -= stdarg; ! 1053: } ! 1054: ! 1055: /* Allocate the va_list constructor */ ! 1056: block = assign_stack_local (BLKmode, 4 * UNITS_PER_WORD, BITS_PER_WORD); ! 1057: RTX_UNCHANGING_P (block) = 1; ! 1058: RTX_UNCHANGING_P (XEXP (block, 0)) = 1; ! 1059: ! 1060: /* Store the argsize as the __va_arg member. */ ! 1061: emit_move_insn (change_address (block, DImode, XEXP (block, 0)), ! 1062: argsize); ! 1063: ! 1064: /* Store the arg pointer in the __va_stack member. */ ! 1065: emit_move_insn (change_address (block, Pmode, ! 1066: plus_constant (XEXP (block, 0), ! 1067: UNITS_PER_WORD)), ! 1068: virtual_incoming_args_rtx); ! 1069: ! 1070: /* Allocate the integer register space, and store it as the ! 1071: __va_ireg member. */ ! 1072: addr = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, -1); ! 1073: MEM_IN_STRUCT_P (addr) = 1; ! 1074: RTX_UNCHANGING_P (addr) = 1; ! 1075: RTX_UNCHANGING_P (XEXP (addr, 0)) = 1; ! 1076: ! 1077: emit_move_insn (change_address (block, Pmode, ! 1078: plus_constant (XEXP (block, 0), ! 1079: 2 * UNITS_PER_WORD)), ! 1080: copy_to_reg (XEXP (addr, 0))); ! 1081: ! 1082: /* Now store the incoming integer registers. */ ! 1083: if (nregs < 6) ! 1084: move_block_from_reg ! 1085: (16 + nregs, ! 1086: change_address (addr, Pmode, ! 1087: plus_constant (XEXP (addr, 0), ! 1088: nregs * UNITS_PER_WORD)), ! 1089: 6 - nregs); ! 1090: ! 1091: /* Allocate the FP register space, and store it as the ! 1092: __va_freg member. */ ! 1093: addr = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, -1); ! 1094: MEM_IN_STRUCT_P (addr) = 1; ! 1095: RTX_UNCHANGING_P (addr) = 1; ! 1096: RTX_UNCHANGING_P (XEXP (addr, 0)) = 1; ! 1097: ! 1098: emit_move_insn (change_address (block, Pmode, ! 1099: plus_constant (XEXP (block, 0), ! 1100: 3 * UNITS_PER_WORD)), ! 1101: copy_to_reg (XEXP (addr, 0))); ! 1102: ! 1103: /* Now store the incoming floating-point registers. If we are not ! 1104: to use the floating-point registers, store the integer registers ! 1105: in those locations too. */ ! 1106: if (nregs < 6) ! 1107: move_block_from_reg ! 1108: (16 + 32 * (TARGET_FPREGS != 0) + nregs, ! 1109: change_address (addr, Pmode, ! 1110: plus_constant (XEXP (addr, 0), ! 1111: nregs * UNITS_PER_WORD)), ! 1112: 6 - nregs); ! 1113: ! 1114: /* Return the address of the va_list constructor, but don't put it in a ! 1115: register. This fails when not optimizing and produces worse code when ! 1116: optimizing. */ ! 1117: return XEXP (block, 0); ! 1118: } ! 1119: ! 1120: /* This page contains routines that are used to determine what the function ! 1121: prologue and epilogue code will do and write them out. */ ! 1122: ! 1123: /* Compute the size of the save area in the stack. */ ! 1124: ! 1125: int ! 1126: alpha_sa_size () ! 1127: { ! 1128: int size = 0; ! 1129: int i; ! 1130: ! 1131: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 1132: if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]) ! 1133: size++; ! 1134: ! 1135: return size * 8; ! 1136: } ! 1137: ! 1138: /* Return non-zero if this function needs gp. It does if it has ! 1139: an LDSYM insn. */ ! 1140: ! 1141: int ! 1142: alpha_need_gp () ! 1143: { ! 1144: rtx insn; ! 1145: ! 1146: for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) ! 1147: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' ! 1148: && GET_CODE (PATTERN (insn)) != USE ! 1149: && GET_CODE (PATTERN (insn)) != CLOBBER ! 1150: && get_attr_type (insn) == TYPE_LDSYM) ! 1151: return 1; ! 1152: ! 1153: return 0; ! 1154: } ! 1155: ! 1156: /* Return 1 if GP is dead at after INSN. */ ! 1157: ! 1158: int ! 1159: alpha_gp_dead_after (insn) ! 1160: rtx insn; ! 1161: { ! 1162: int jump_count = 0; ! 1163: int found = 0; ! 1164: rtx p; ! 1165: ! 1166: /* If we aren't optimizing, don't do this optimization. More importantly, ! 1167: JUMP_LABEL isn't properly set when not optimizing. */ ! 1168: ! 1169: if (optimize == 0) ! 1170: return 0; ! 1171: ! 1172: /* If we are followed by a BARRIER, we don't return. */ ! 1173: if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER) ! 1174: return 1; ! 1175: ! 1176: /* Otherwise search for a use of GP before a return. */ ! 1177: ! 1178: for (p = next_active_insn (insn); p; p = next_active_insn (p)) ! 1179: { ! 1180: if (get_attr_type (p) == TYPE_LDSYM ! 1181: || get_attr_type (p) == TYPE_JSR) ! 1182: { ! 1183: found = 1; ! 1184: break; ! 1185: } ! 1186: ! 1187: if (GET_CODE (p) == JUMP_INSN) ! 1188: { ! 1189: if (GET_CODE (PATTERN (p)) == RETURN) ! 1190: break; ! 1191: ! 1192: if (! simplejump_p (p) || jump_count++ > 10) ! 1193: { ! 1194: found = 1; ! 1195: break; ! 1196: } ! 1197: ! 1198: p = JUMP_LABEL (p); ! 1199: } ! 1200: } ! 1201: ! 1202: /* Restore any operands destroyed by the attribute calls above. */ ! 1203: insn_extract (insn); ! 1204: ! 1205: return ! found; ! 1206: } ! 1207: ! 1208: /* Return 1 if this function can directly return via $26. */ ! 1209: ! 1210: int ! 1211: direct_return () ! 1212: { ! 1213: return (reload_completed && alpha_sa_size () == 0 ! 1214: && get_frame_size () == 0 ! 1215: && current_function_pretend_args_size == 0); ! 1216: } ! 1217: ! 1218: /* Write function prologue. */ ! 1219: ! 1220: void ! 1221: output_prolog (file, size) ! 1222: FILE *file; ! 1223: int size; ! 1224: { ! 1225: HOST_WIDE_INT frame_size = ((size + current_function_outgoing_args_size ! 1226: + current_function_pretend_args_size ! 1227: + alpha_sa_size () + 15) & ~15); ! 1228: int reg_offset = current_function_outgoing_args_size; ! 1229: int start_reg_offset = reg_offset; ! 1230: unsigned reg_mask = 0; ! 1231: int i; ! 1232: ! 1233: /* If we need a GP, load it first. */ ! 1234: alpha_function_needs_gp = alpha_need_gp (); ! 1235: ! 1236: if (alpha_function_needs_gp) ! 1237: { ! 1238: rtx insn; ! 1239: ! 1240: fprintf (file, "\tldgp $29,0($27)\n"); ! 1241: ! 1242: /* If we have a recursive call, put a special label here. */ ! 1243: for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) ! 1244: if (GET_CODE (insn) == CALL_INSN ! 1245: && get_attr_type (insn) != TYPE_JSR) ! 1246: { ! 1247: fprintf (file, "%s..ng:\n", current_function_name); ! 1248: break; ! 1249: } ! 1250: } ! 1251: ! 1252: /* Adjust the stack by the frame size. If the frame size is > 32768 ! 1253: bytes, we have to load it into a register first and then subtract ! 1254: from sp. Note that we are only allowed to adjust sp once in the ! 1255: prologue. */ ! 1256: ! 1257: if (frame_size > 32768) ! 1258: { ! 1259: HOST_WIDE_INT low = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); ! 1260: HOST_WIDE_INT tmp1 = frame_size - low; ! 1261: HOST_WIDE_INT high ! 1262: = ((tmp1 >> 16) & 0xfff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1263: HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; ! 1264: HOST_WIDE_INT extra = 0; ! 1265: int in_reg = 31; ! 1266: ! 1267: /* We haven't written code to handle frames > 4GB. */ ! 1268: #if HOST_BITS_PER_LONG_INT == 64 ! 1269: if ((unsigned HOST_WIDE_INT) frame_size >> 32 != 0) ! 1270: abort (); ! 1271: #endif ! 1272: ! 1273: if (tmp2) ! 1274: { ! 1275: extra = 0x4000; ! 1276: tmp1 -= 0x40000000; ! 1277: high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1278: } ! 1279: ! 1280: if (low != 0) ! 1281: { ! 1282: fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); ! 1283: in_reg = 28; ! 1284: } ! 1285: ! 1286: if (extra) ! 1287: { ! 1288: fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); ! 1289: in_reg = 28; ! 1290: } ! 1291: ! 1292: fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); ! 1293: ! 1294: fprintf (file, "\tsubq $30,$28,$30\n"); ! 1295: } ! 1296: else if (frame_size) ! 1297: fprintf (file, "\tlda $30,-%d($30)\n", frame_size); ! 1298: ! 1299: /* Write out the .frame line. If we need a frame pointer, we use ! 1300: an offset of zero. */ ! 1301: ! 1302: if (frame_pointer_needed) ! 1303: fprintf (file, "\t.frame $15,0,$26\n"); ! 1304: else ! 1305: fprintf (file, "\t.frame $30,%d,$26\n", frame_size); ! 1306: ! 1307: ! 1308: /* Save register 26 if it is used. */ ! 1309: if (regs_ever_live[26]) ! 1310: { ! 1311: reg_mask |= 1 << 26; ! 1312: fprintf (file, "\tstq $26,%d($30)\n", reg_offset); ! 1313: reg_offset += 8; ! 1314: } ! 1315: ! 1316: /* Now save any other used register that are required to be saved. */ ! 1317: for (i = 0; i < 32; i++) ! 1318: if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] && i != 26) ! 1319: { ! 1320: reg_mask |= 1 << i; ! 1321: fprintf (file, "\tstq $%d,%d($30)\n", i, reg_offset); ! 1322: reg_offset += 8; ! 1323: } ! 1324: ! 1325: /* Print the register mask and do floating-point saves. */ ! 1326: if (reg_mask) ! 1327: fprintf (file, "\t.mask 0x%x,%d\n", reg_mask, ! 1328: start_reg_offset - frame_size); ! 1329: ! 1330: start_reg_offset = reg_offset; ! 1331: reg_mask = 0; ! 1332: ! 1333: for (i = 0; i < 32; i++) ! 1334: if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] ! 1335: && regs_ever_live[i + 32]) ! 1336: { ! 1337: reg_mask |= 1 << i; ! 1338: fprintf (file, "\tstt $f%d,%d($30)\n", i, reg_offset); ! 1339: reg_offset += 8; ! 1340: } ! 1341: ! 1342: /* Print the floating-point mask, if we've saved any fp register. */ ! 1343: if (reg_mask) ! 1344: fprintf (file, "\t.fmask 0x%x,%d\n", reg_mask, start_reg_offset); ! 1345: ! 1346: /* If we need a frame pointer, set it to the value of incoming stack ! 1347: which we compute by adding back the frame size pointer. Because we ! 1348: can subtract one more than we can add, we have to special-case ! 1349: frame sizes of 32K. Note that there is no restriction that the frame ! 1350: pointer be updated in one instruction. */ ! 1351: ! 1352: if (frame_pointer_needed) ! 1353: { ! 1354: if (frame_size == 32768) ! 1355: fprintf (file, "\tlda $15,16384($30)\n\tlda $15,16384($15)\n"); ! 1356: else if (frame_size > 32768) ! 1357: fprintf (file, "\taddq $30,$28,$15\n"); ! 1358: else ! 1359: fprintf (file, "\tlda $15,%d($30)\n", frame_size); ! 1360: } ! 1361: } ! 1362: ! 1363: /* Write function epilogue. */ ! 1364: ! 1365: void ! 1366: output_epilog (file, size) ! 1367: FILE *file; ! 1368: int size; ! 1369: { ! 1370: rtx insn = get_last_insn (); ! 1371: HOST_WIDE_INT frame_size = ((size + current_function_outgoing_args_size ! 1372: + current_function_pretend_args_size ! 1373: + alpha_sa_size () + 15) & ~15); ! 1374: int reg_offset = current_function_outgoing_args_size; ! 1375: int reg_offset_from = STACK_POINTER_REGNUM; ! 1376: int i; ! 1377: ! 1378: /* If the last insn was a BARRIER, we don't have to write anything except ! 1379: the .end pseudo-op. */ ! 1380: if (GET_CODE (insn) == NOTE) ! 1381: insn = prev_nonnote_insn (insn); ! 1382: if (insn == 0 || GET_CODE (insn) != BARRIER) ! 1383: { ! 1384: /* If we have a frame pointer, we restore the registers from an ! 1385: offset from it, assuming that we can reach the offset. If not, ! 1386: we have to compute the address using a scratch register. This is ! 1387: messy, but should not be common. We have to copy the frame ! 1388: pointer elsewhere here since we will be restoring it before we can ! 1389: use it to restore the stack pointer. We use $25. */ ! 1390: ! 1391: if (frame_pointer_needed) ! 1392: { ! 1393: fprintf (file, "\tbis $15,$15,$25\n"); ! 1394: ! 1395: if (frame_size < 32768) ! 1396: reg_offset -= frame_size, reg_offset_from = 25; ! 1397: else ! 1398: { ! 1399: HOST_WIDE_INT low ! 1400: = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); ! 1401: HOST_WIDE_INT tmp1 = frame_size - low; ! 1402: HOST_WIDE_INT high ! 1403: = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1404: HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; ! 1405: int extra = 0; ! 1406: int in_reg = 31; ! 1407: ! 1408: if (tmp2) ! 1409: { ! 1410: extra = 0x4000; ! 1411: tmp1 -= 0x40000000; ! 1412: high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1413: } ! 1414: ! 1415: if (low != 0) ! 1416: { ! 1417: fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); ! 1418: in_reg = 28; ! 1419: } ! 1420: ! 1421: if (extra) ! 1422: { ! 1423: fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); ! 1424: in_reg = 28; ! 1425: } ! 1426: ! 1427: fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); ! 1428: ! 1429: fprintf (file, "\tsubq $25,$28,$28\n"); ! 1430: ! 1431: reg_offset_from = 28; ! 1432: } ! 1433: } ! 1434: ! 1435: /* Restore all the registers, starting with the return address ! 1436: register. */ ! 1437: if (regs_ever_live[26]) ! 1438: { ! 1439: fprintf (file, "\tldq $26,%d($%d)\n", reg_offset, reg_offset_from); ! 1440: reg_offset += 8; ! 1441: } ! 1442: ! 1443: /* Now restore any other used register that that we saved. */ ! 1444: for (i = 0; i < 32; i++) ! 1445: if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] ! 1446: && i != 26) ! 1447: { ! 1448: fprintf (file, "\tldq $%d,%d($%d)\n", ! 1449: i, reg_offset, reg_offset_from); ! 1450: reg_offset += 8; ! 1451: } ! 1452: ! 1453: for (i = 0; i < 32; i++) ! 1454: if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] ! 1455: && regs_ever_live[i + 32]) ! 1456: { ! 1457: fprintf (file, "\tldt $f%d,%d($%d)\n", ! 1458: i, reg_offset, reg_offset_from); ! 1459: reg_offset += 8; ! 1460: } ! 1461: ! 1462: /* Restore the stack. If we have a frame pointer, use it. Otherwise, ! 1463: add the size back into the stack, handling the large frame size. */ ! 1464: ! 1465: if (frame_pointer_needed) ! 1466: fprintf (file, "\tbis $25,$25,$30\n"); ! 1467: else if (frame_size > 32767) ! 1468: { ! 1469: HOST_WIDE_INT low ! 1470: = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); ! 1471: HOST_WIDE_INT tmp1 = frame_size - low; ! 1472: HOST_WIDE_INT high ! 1473: = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1474: HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; ! 1475: HOST_WIDE_INT extra = 0; ! 1476: int in_reg = 31; ! 1477: ! 1478: /* We haven't written code to handle frames > 4GB. */ ! 1479: #if HOST_BITS_PER_LONG_INT == 64 ! 1480: if ((unsigned HOST_WIDE_INT) frame_size >> 32 != 0) ! 1481: abort (); ! 1482: #endif ! 1483: ! 1484: if (tmp2) ! 1485: { ! 1486: extra = 0x4000; ! 1487: tmp1 -= 0x40000000; ! 1488: high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); ! 1489: } ! 1490: ! 1491: if (low != 0) ! 1492: { ! 1493: fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); ! 1494: in_reg = 28; ! 1495: } ! 1496: ! 1497: if (extra) ! 1498: { ! 1499: fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); ! 1500: in_reg = 28; ! 1501: } ! 1502: ! 1503: fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); ! 1504: ! 1505: fprintf (file, "\taddq $30,$28,$30\n"); ! 1506: } ! 1507: else if (frame_size) ! 1508: fprintf (file, "\tlda $30,%d($30)\n", frame_size); ! 1509: ! 1510: /* Now return to the caller. */ ! 1511: fprintf (file, "\tret $31,($26),1\n"); ! 1512: } ! 1513: ! 1514: /* End the function. */ ! 1515: fprintf (file, "\t.end %s\n", alpha_function_name); ! 1516: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.