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