Annotation of gcc/config/alpha.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.