Annotation of GNUtools/cc/config/alpha/alpha.c, revision 1.1

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

unix.superglobalmegacorp.com

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