Annotation of gcc/config/alpha.c, revision 1.1.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.