Annotation of gcc/config/pa.c, revision 1.1.1.2

1.1       root        1: /* Subroutines for insn-output.c for HPPA.
                      2:    Copyright (C) 1992 Free Software Foundation, Inc.
                      3:    Contributed by Tim Moore ([email protected]), based on sparc.c
                      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: #include <stdio.h>
                     22: #include "config.h"
                     23: #include "rtl.h"
                     24: #include "regs.h"
                     25: #include "hard-reg-set.h"
                     26: #include "real.h"
                     27: #include "insn-config.h"
                     28: #include "conditions.h"
                     29: #include "insn-flags.h"
                     30: #include "output.h"
                     31: #include "insn-attr.h"
                     32: #include "flags.h"
                     33: #include "tree.h"
                     34: #include "c-tree.h"
                     35: #include "expr.h"
1.1.1.2 ! root       36: #include "obstack.h"
1.1       root       37: 
                     38: /* Save the operands last given to a compare for use when we
                     39:    generate a scc or bcc insn.  */
                     40: 
                     41: rtx hppa_compare_op0, hppa_compare_op1;
                     42: enum cmp_type hppa_branch_type;
                     43: 
                     44: /* Set by the FUNCTION_PROFILER macro. */
                     45: int hp_profile_labelno;
                     46: 
                     47: /* Name of where we pretend to think the frame pointer points.
                     48:    Normally, this is "4", but if we are in a leaf procedure,
                     49:    this is "something(30)".  Will this work? */
                     50: char *frame_base_name;
                     51: 
                     52: static rtx find_addr_reg ();
                     53: 
                     54: /* Return non-zero only if OP is a register of mode MODE,
                     55:    or const0_rtx.  */
                     56: int
                     57: reg_or_0_operand (op, mode)
                     58:      rtx op;
                     59:      enum machine_mode mode;
                     60: {
                     61:   return (op == const0_rtx || register_operand (op, mode));
                     62: }
                     63: 
                     64: int
                     65: call_operand_address (op, mode)
                     66:      rtx op;
                     67:      enum machine_mode mode;
                     68: {
1.1.1.2 ! root       69:   return (REG_P (op) 
        !            70:          || (CONSTANT_P (op) && ! TARGET_LONG_CALLS));
1.1       root       71: }
                     72: 
                     73: int
                     74: symbolic_operand (op, mode)
                     75:      register rtx op;
                     76:      enum machine_mode mode;
                     77: {
                     78:   switch (GET_CODE (op))
                     79:     {
                     80:     case SYMBOL_REF:
                     81:     case LABEL_REF:
                     82:       return 1;
                     83:     case CONST:
                     84:       op = XEXP (op, 0);
                     85:       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
                     86:               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
                     87:              && GET_CODE (XEXP (op, 1)) == CONST_INT);
                     88:     default:
                     89:       return 0;
                     90:     }
                     91: }
                     92: 
                     93: /* Return truth value of statement that OP is a symbolic memory
                     94:    operand of mode MODE.  */
                     95: 
                     96: int
                     97: symbolic_memory_operand (op, mode)
                     98:      rtx op;
                     99:      enum machine_mode mode;
                    100: {
                    101:   if (GET_CODE (op) == SUBREG)
                    102:     op = SUBREG_REG (op);
                    103:   if (GET_CODE (op) != MEM)
                    104:     return 0;
                    105:   op = XEXP (op, 0);
                    106:   return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
                    107:          || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
                    108: }
                    109: 
                    110: /* Return 1 if the operand is either a register or a memory operand that is
                    111:    not symbolic.  */
                    112: 
                    113: int
                    114: reg_or_nonsymb_mem_operand (op, mode)
                    115:     register rtx op;
                    116:     enum machine_mode mode;
                    117: {
                    118:   if (register_operand (op, mode))
                    119:     return 1;
                    120: 
                    121:   if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
                    122:     return 1;
                    123: 
                    124:   return 0;
                    125: }
                    126: 
                    127: int
                    128: move_operand (op, mode)
                    129:      rtx op;
                    130:      enum machine_mode mode;
                    131: {
                    132:   if (register_operand (op, mode))
                    133:     return 1;
                    134: 
                    135:   if (op == CONST0_RTX (mode))
                    136:     return 1;
                    137: 
                    138:   if (GET_MODE (op) != mode)
                    139:     return 0;
                    140:   if (GET_CODE (op) == SUBREG)
                    141:     op = SUBREG_REG (op);
                    142:   if (GET_CODE (op) != MEM)
                    143:     return 0;
                    144: 
                    145:   op = XEXP (op, 0);
                    146:   if (GET_CODE (op) == LO_SUM)
                    147:     return (register_operand (XEXP (op, 0), Pmode)
                    148:            && CONSTANT_P (XEXP (op, 1)));
                    149:   return memory_address_p (mode, op);
                    150: }
                    151: 
                    152: int
                    153: pic_operand (op, mode)
                    154:      rtx op;
                    155:      enum machine_mode mode;
                    156: {
                    157:   return flag_pic && GET_CODE (op) == LABEL_REF;
                    158: }
                    159: 
                    160: int
                    161: short_memory_operand (op, mode)
                    162:      rtx op;
                    163:      enum machine_mode mode;
                    164: {
                    165:   if (GET_CODE (op) == MEM)
                    166:     {
                    167:       if (GET_CODE (XEXP (op, 0)) == REG)
                    168:        return 1;
                    169:       else if (GET_CODE (XEXP (op, 0)) == PLUS)
                    170:        {
                    171:          rtx op1 = XEXP (XEXP (op, 0), 0);
                    172:          rtx op2 = XEXP (XEXP (op, 0), 1);
                    173: 
                    174:          if (GET_CODE (op1) == REG)
                    175:            return (GET_CODE (op2) == CONST_INT && INT_5_BITS (op2));
                    176:          else if (GET_CODE (op2) == REG)
                    177:            return (GET_CODE (op1) == CONST_INT && INT_5_BITS (op1));
                    178:        }
                    179:     }
                    180:   return 0;
                    181: }
                    182: 
                    183: int
                    184: register_or_short_operand (op, mode)
                    185:      rtx op;
                    186:      enum machine_mode mode;
                    187: {
                    188:   if (register_operand (op, mode))
                    189:     return 1;
                    190:   if (GET_CODE (op) == SUBREG)
                    191:     op = SUBREG_REG (op);
                    192:   return short_memory_operand (op, mode);
                    193: }
                    194: 
                    195: int
                    196: fp_reg_operand (op, mode)
                    197:      rtx op;
                    198:      enum machine_mode mode;
                    199: {
                    200:   return reg_renumber && FP_REG_P (op);
                    201: }
1.1.1.2 ! root      202: 
        !           203: int
        !           204: check_fp_mov (operands)
        !           205:      rtx *operands;
        !           206: {
        !           207:   enum machine_mode mode = GET_MODE (operands[0]);
        !           208: 
        !           209:   if (fp_reg_operand (operands[0], mode))
        !           210:     return (register_operand (operands[1], mode)
        !           211:            || short_memory_operand (operands[1], mode));
        !           212:   else if (fp_reg_operand (operands[1], mode))
        !           213:     return (register_operand (operands[0], mode)
        !           214:            || short_memory_operand (operands[0], mode));
        !           215:   else
        !           216:     return 1;
        !           217: }
1.1       root      218: 
                    219: extern int current_function_uses_pic_offset_table;
                    220: extern rtx force_reg (), validize_mem ();
                    221: 
                    222: /* The rtx for the global offset table which is a special form
                    223:    that *is* a position independent symbolic constant.  */
                    224: rtx pic_pc_rtx;
                    225: 
                    226: /* Ensure that we are not using patterns that are not OK with PIC.  */
                    227: 
                    228: int
                    229: check_pic (i)
                    230:      int i;
                    231: {
                    232:   extern rtx recog_operand[];
                    233:   switch (flag_pic)
                    234:     {
                    235:     case 1:
                    236:       if (GET_CODE (recog_operand[i]) == SYMBOL_REF
                    237:          || (GET_CODE (recog_operand[i]) == CONST
                    238:              && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
                    239:        abort ();
                    240:     case 2:
                    241:     default:
                    242:       return 1;
                    243:     }
                    244: }
                    245: 
                    246: /* Return truth value of whether OP is EQ or NE.  */
                    247: 
                    248: int
                    249: eq_or_neq (op, mode)
                    250:      rtx op;
                    251:      enum machine_mode mode;
                    252: {
                    253:   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
                    254: }
                    255: 
                    256: /* Return truth value of whether OP can be used as an operand in a
                    257:    three operand arithmetic insn that accepts registers of mode MODE
                    258:    or 14-bit signed integers.  */
                    259: int
                    260: arith_operand (op, mode)
                    261:      rtx op;
                    262:      enum machine_mode mode;
                    263: {
                    264:   return (register_operand (op, mode)
                    265:          || (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
                    266: }
                    267: 
                    268: /* Return truth value of whether OP can be used as an operand in a
                    269:    three operand arithmetic insn that accepts registers of mode MODE
                    270:    or 11-bit signed integers.  */
                    271: int
                    272: arith11_operand (op, mode)
                    273:      rtx op;
                    274:      enum machine_mode mode;
                    275: {
                    276:   return (register_operand (op, mode)
                    277:          || (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
                    278: }
                    279: 
                    280: int
                    281: arith_double_operand (op, mode)
                    282:      rtx op;
                    283:      enum machine_mode mode;
                    284: {
                    285:   return (register_operand (op, mode)
                    286:          || (GET_CODE (op) == CONST_DOUBLE
                    287:              && GET_MODE (op) == mode
                    288:              && VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
                    289:              && (CONST_DOUBLE_HIGH (op) >= 0
                    290:                  == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
                    291: }
                    292: 
                    293: /* Return truth value of whether OP is a integer which fits the
                    294:    range constraining immediate operands in three-address insns.  */
                    295: 
                    296: int
                    297: int5_operand (op, mode)
                    298:      rtx op;
                    299:      enum machine_mode mode;
                    300: {
                    301:   return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
                    302: }
                    303: 
                    304: int
                    305: uint5_operand (op, mode)
                    306:      rtx op;
                    307:      enum machine_mode mode;
                    308: {
                    309:   return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
                    310: }
                    311: 
                    312:   
                    313: int
                    314: int11_operand (op, mode)
                    315:      rtx op;
                    316:      enum machine_mode mode;
                    317: {
                    318:     return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
                    319: }
                    320: 
                    321: int
                    322: arith5_operand (op, mode)
                    323:      rtx op;
                    324:      enum machine_mode mode;
                    325: {
                    326:   return register_operand (op, mode) || int5_operand (op, mode);
                    327: }
                    328: 
1.1.1.2 ! root      329: /* True iff zdepi can be used to generate this CONST_INT.  */
1.1       root      330: int
1.1.1.2 ! root      331: depi_cint_operand (op, mode)
1.1       root      332:      rtx op;
                    333:      enum machine_mode mode;
                    334: {
1.1.1.2 ! root      335:   unsigned x;
        !           336:   unsigned lbmask, t;
        !           337: 
        !           338:   if (GET_CODE (op) != CONST_INT)
        !           339:     return 0;
        !           340: 
        !           341:   /* This might not be obvious, but it's at least fast.
        !           342:      This function is critcal; we don't have the time loops would take.  */
        !           343:   x = INTVAL (op);
        !           344:   lbmask = x & -x;
        !           345:   t = ((x >> 4) + lbmask) & ~(lbmask - 1);
        !           346:   return ((t & (t - 1)) == 0);
        !           347: }
        !           348: 
        !           349: /* True iff depi or extru can be used to compute (reg & mask).  */
        !           350: int
        !           351: consec_zeros_p (mask)
        !           352:      unsigned mask;
        !           353: {
        !           354:   mask = ~mask;
        !           355:   mask += mask & -mask;
        !           356:   return (mask & (mask - 1)) == 0;
        !           357: }
        !           358: 
        !           359: /* True iff depi or extru can be used to compute (reg & OP).  */
        !           360: int
        !           361: and_operand (op, mode)
        !           362:      rtx op;
        !           363:      enum machine_mode mode;
        !           364: {
        !           365:   return (register_operand (op, mode)
        !           366:          || (GET_CODE (op) == CONST_INT && consec_zeros_p (INTVAL (op))));
        !           367: }
        !           368: 
        !           369: /* True iff depi can be used to compute (reg | MASK).  */
        !           370: int
        !           371: ior_mask_p (mask)
        !           372:      unsigned mask;
        !           373: {
        !           374:   mask += mask & -mask;
        !           375:   return (mask & (mask - 1)) == 0;
        !           376: }
        !           377: 
        !           378: /* True iff depi can be used to compute (reg | OP).  */
        !           379: int
        !           380: ior_operand (op, mode)
        !           381:      rtx op;
        !           382:      enum machine_mode mode;
        !           383: {
        !           384:   return (register_operand (op, mode)
        !           385:          || (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op))));
        !           386: }
        !           387: 
        !           388: int
        !           389: arith32_operand (op, mode)
        !           390:      rtx op;
        !           391:      enum machine_mode mode;
        !           392: {
        !           393:   return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
1.1       root      394: }
                    395: 
                    396: /* True iff OP can be the source of a move to a general register.  */
                    397: int
                    398: srcsi_operand (op, mode)
                    399:      rtx op;
                    400:      enum machine_mode mode;
                    401: {
                    402:   /* Not intended for other modes than SImode.  */
                    403:   if (mode != SImode)
                    404:     return 0;
                    405: 
                    406:   /* Accept any register or memory reference.  */
                    407:   if (nonimmediate_operand (op, mode))
                    408:     return 1;
                    409: 
1.1.1.2 ! root      410:   if (depi_cint_operand (op, mode))
        !           411:     return 1;
        !           412: 
1.1       root      413:   /* OK if ldo or ldil can be used.  */
                    414:   return (GET_CODE (op) == CONST_INT
                    415:          && (INT_14_BITS (op) || (INTVAL (op) & 0x7ff) == 0));
                    416: }
                    417: 
                    418: 
                    419: /* Legitimize PIC addresses.  If the address is already
                    420:    position-independent, we return ORIG.  Newly generated
                    421:    position-independent addresses go to REG.  If we need more
                    422:    than one register, we lose.  */
                    423: 
                    424: rtx
                    425: legitimize_pic_address (orig, mode, reg)
                    426:      rtx orig, reg;
                    427:      enum machine_mode mode;
                    428: {
                    429:   rtx pic_ref = orig;
                    430: 
                    431:   if (GET_CODE (orig) == SYMBOL_REF)
                    432:     {
                    433:       if (reg == 0)
                    434:        abort ();
                    435: 
                    436:       if (flag_pic == 2)
                    437:        {
                    438:          emit_insn (gen_rtx (SET, VOIDmode, reg,
                    439:                              gen_rtx (HIGH, Pmode, orig)));
                    440:          emit_insn (gen_rtx (SET, VOIDmode, reg,
                    441:                              gen_rtx (LO_SUM, Pmode, reg, orig)));
                    442:          orig = reg;
                    443:        }
                    444:       pic_ref = gen_rtx (MEM, Pmode,
                    445:                         gen_rtx (PLUS, Pmode,
                    446:                                  pic_offset_table_rtx, orig));
                    447:       current_function_uses_pic_offset_table = 1;
                    448:       RTX_UNCHANGING_P (pic_ref) = 1;
                    449:       emit_move_insn (reg, pic_ref);
                    450:       return reg;
                    451:     }
                    452:   else if (GET_CODE (orig) == CONST)
                    453:     {
                    454:       rtx base, offset;
                    455: 
                    456:       if (GET_CODE (XEXP (orig, 0)) == PLUS
                    457:          && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
                    458:        return orig;
                    459: 
                    460:       if (reg == 0)
                    461:        abort ();
                    462: 
                    463:       if (GET_CODE (XEXP (orig, 0)) == PLUS)
                    464:        {
                    465:          base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
                    466:          orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
                    467:                                         base == reg ? 0 : reg);
                    468:        }
                    469:       else abort ();
                    470:       if (GET_CODE (orig) == CONST_INT)
                    471:        {
                    472:          if (SMALL_INT (orig))
                    473:            return plus_constant_for_output (base, INTVAL (orig));
                    474:          orig = force_reg (Pmode, orig);
                    475:        }
                    476:       pic_ref = gen_rtx (PLUS, Pmode, base, orig);
                    477:       /* Likewise, should we set special REG_NOTEs here?  */
                    478:     }
                    479:   return pic_ref;
                    480: }
                    481: 
                    482: /* Set up PIC-specific rtl.  This should not cause any insns
                    483:    to be emitted.  */
                    484: 
                    485: void
                    486: initialize_pic ()
                    487: {
                    488: }
                    489: 
                    490: /* Emit special PIC prologues and epilogues.  */
                    491: 
                    492: void
                    493: finalize_pic ()
                    494: {
                    495:   /* Need to emit this whether or not we obey regdecls,
                    496:      since setjmp/longjmp can cause life info to screw up.  */
                    497:   emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
                    498: }
                    499: 
                    500: /* For the HPPA, REG and REG+CONST is cost 0
                    501:    and addresses involving symbolic constants are cost 2.
                    502: 
                    503:    PIC addresses are very expensive.
                    504: 
                    505:    It is no coincidence that this has the same structure
                    506:    as GO_IF_LEGITIMATE_ADDRESS.  */
                    507: int
                    508: hppa_address_cost (X)
                    509:      rtx X;
                    510: {
                    511:   if (GET_CODE (X) == PLUS)
                    512:       return 1;
                    513:   else if (GET_CODE (X) == LO_SUM)
                    514:     return 1;
                    515:   else if (GET_CODE (X) == HIGH)
                    516:     return 2;
                    517:   return 4;
                    518: }
                    519: 
                    520: /* Emit insns to move operands[1] into operands[0].
                    521: 
                    522:    Return 1 if we have written out everything that needs to be done to
                    523:    do the move.  Otherwise, return 0 and the caller will emit the move
                    524:    normally.  */
                    525: 
                    526: int
1.1.1.2 ! root      527: emit_move_sequence (operands, mode, scratch_reg)
1.1       root      528:      rtx *operands;
                    529:      enum machine_mode mode;
1.1.1.2 ! root      530:      rtx scratch_reg;
1.1       root      531: {
                    532:   register rtx operand0 = operands[0];
                    533:   register rtx operand1 = operands[1];
                    534: 
1.1.1.2 ! root      535:   if (fp_reg_operand (operand0, mode)
        !           536:       && GET_CODE (operand1) == MEM
        !           537:       && !short_memory_operand  (operand1, mode)
        !           538:       && scratch_reg)
        !           539:     {
        !           540:       emit_move_insn (scratch_reg, XEXP (operand1 , 0));
        !           541:       emit_insn (gen_rtx (SET, VOIDmode, operand0, gen_rtx (MEM, mode,
        !           542:                                                            scratch_reg)));
        !           543:       return 1;
        !           544:     }
        !           545:   else if (fp_reg_operand (operand1, mode)
        !           546:           && GET_CODE (operand0) == MEM
        !           547:           && !short_memory_operand  (operand0, mode)
        !           548:           && scratch_reg)
        !           549:     {
        !           550:       emit_move_insn (scratch_reg, XEXP (operand0 , 0));
        !           551:       emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, mode,  scratch_reg),
        !           552:                          operand1));
        !           553:       return 1;
        !           554:     }
        !           555:   /* Handle most common case: storing into a register.  */
        !           556:   else if (register_operand (operand0, mode))
1.1       root      557:     {
                    558:       if (register_operand (operand1, mode)
                    559:          || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
                    560:          || (GET_CODE (operand1) == HIGH
                    561:              && !symbolic_operand (XEXP (operand1, 0)))
                    562:          /* Only `general_operands' can come here, so MEM is ok.  */
                    563:          || GET_CODE (operand1) == MEM)
                    564:        {
                    565:          /* Run this case quickly.  */
                    566:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
                    567:          return 1;
                    568:        }
                    569:     }
                    570:   else if (GET_CODE (operand0) == MEM)
                    571:     {
                    572:       if (register_operand (operand1, mode) || operand1 == const0_rtx)
                    573:        {
                    574:          /* Run this case quickly.  */
                    575:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
                    576:          return 1;
                    577:        }
                    578:       if (! reload_in_progress)
                    579:        {
                    580:          operands[0] = validize_mem (operand0);
                    581:          operands[1] = operand1 = force_reg (mode, operand1);
                    582:        }
                    583:     }
                    584: 
                    585:   /* Simplify the source if we need to.  */
                    586:   if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
                    587:     {
                    588:       if (symbolic_operand (operand1, mode))
                    589:        {
                    590:          if (flag_pic)
                    591:            {
                    592:              rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (Pmode);
                    593:              operands[1] = legitimize_pic_address (operand1, mode, temp);
                    594:            }
                    595:          /* On the HPPA, references to data space are supposed to */
                    596:          /* use dp, register 27. */
                    597:          else if (read_only_operand (operand1))
                    598:            {
1.1.1.2 ! root      599:              rtx set = gen_rtx (SET, VOIDmode,
1.1       root      600:                                  operand0,
1.1.1.2 ! root      601:                                  gen_rtx (LO_SUM, mode, operand0, operand1));
        !           602:                                 
1.1       root      603:              emit_insn (gen_rtx (SET, VOIDmode,
                    604:                                  operand0,
1.1.1.2 ! root      605:                                  gen_rtx (HIGH, mode, operand1)));
        !           606:              if (TARGET_SHARED_LIBS
        !           607:                  && function_label_operand (operand1, mode))
        !           608:                {
        !           609:                  rtx temp = reload_in_progress ? scratch_reg
        !           610:                    : gen_reg_rtx (mode);
        !           611:                  if (!temp)
        !           612:                    abort ();
        !           613:                  emit_insn (gen_rtx (PARALLEL, VOIDmode,
        !           614:                                      gen_rtvec (2,
        !           615:                                                 set,
        !           616:                                                 gen_rtx (CLOBBER, VOIDmode,
        !           617:                                                          temp))));
        !           618:                }
        !           619:              else
        !           620:                emit_insn (set);
1.1       root      621:              return 1;
                    622:            }
                    623:          else
                    624:            {
                    625:              /* If reload_in_progress, we can't use addil and r1; we */
                    626:              /* have to use the more expensive ldil sequence. */
                    627:              if (reload_in_progress)
                    628:                {
                    629:                  emit_insn (gen_rtx (SET, VOIDmode,
                    630:                                      operand0,
                    631:                                      gen_rtx (HIGH, mode, operand1)));
                    632:                  emit_insn (gen_rtx (SET, VOIDmode,
                    633:                                      operand0,
                    634:                                      gen_rtx (PLUS, mode,
                    635:                                               operand0,
                    636:                                               gen_rtx (REG, mode, 27))));
                    637:                  emit_insn (gen_rtx (SET, VOIDmode,
                    638:                                      operand0,
                    639:                                      gen_rtx (LO_SUM, mode,
                    640:                                               operand0, operand1)));
                    641:                }
                    642:              else
                    643:                {
1.1.1.2 ! root      644:                  rtx temp1, temp2 = gen_reg_rtx (mode);
1.1       root      645: 
1.1.1.2 ! root      646:                  /* For 2.4 we could set RTX_UNCHANGING and add a 
        !           647:                     REG_EQUAL note for the first insn.  This would 
        !           648:                     allow the first insn to be moved out of loops.  */
        !           649:                  temp1 = gen_rtx (HIGH, mode, operand1);
1.1       root      650:                  emit_insn (gen_rtx (SET, VOIDmode,
                    651:                                      temp2,
                    652:                                      gen_rtx (PLUS, mode,
                    653:                                               gen_rtx (REG, mode, 27),
                    654:                                               temp1)));
                    655:                  emit_insn (gen_rtx (SET, VOIDmode,
                    656:                                      operand0,
                    657:                                      gen_rtx (LO_SUM, mode,
                    658:                                               temp2, operand1)));
                    659:                }
                    660:              return 1;
                    661:            }
                    662:        }
1.1.1.2 ! root      663:       else if (depi_cint_operand (operand1, VOIDmode))
        !           664:        return 0;
1.1       root      665:       else if (GET_CODE (operand1) == CONST_INT
                    666:               ? (! SMALL_INT (operand1)
                    667:                  && (INTVAL (operand1) & 0x7ff) != 0) : 1)
                    668:        {
                    669:          rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (mode);
                    670:          emit_insn (gen_rtx (SET, VOIDmode, temp,
                    671:                              gen_rtx (HIGH, mode, operand1)));
                    672:          operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
                    673:        }
                    674:     }
                    675:   /* Now have insn-emit do whatever it normally does.  */
                    676:   return 0;
                    677: }
                    678: 
                    679: /* Does operand (which is a symbolic_operand) live in text space? If
                    680:    so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true.*/
                    681: 
                    682: int
                    683: read_only_operand (operand)
                    684:      rtx operand;
                    685: {
                    686:   if (GET_CODE (operand) == CONST)
                    687:     operand = XEXP (XEXP (operand, 0), 0);
                    688:   if (GET_CODE (operand) == SYMBOL_REF)
                    689:     return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
                    690:   return 1;
                    691: }
                    692:      
                    693: 
                    694: /* Return the best assembler insn template
                    695:    for moving operands[1] into operands[0] as a fullword.  */
                    696: 
                    697: char *
                    698: singlemove_string (operands)
                    699:      rtx *operands;
                    700: {
                    701:   if (GET_CODE (operands[0]) == MEM)
                    702:     return "stw %r1,%0";
                    703:   if (GET_CODE (operands[1]) == MEM)
                    704:     return "ldw %1,%0";
                    705:   if (GET_CODE (operands[1]) == CONST_INT)
                    706:     if (INT_14_BITS (operands[1]))
                    707:       return (INTVAL (operands[1]) == 0 ? "copy 0,%0" : "ldi %1,%0");
                    708:     else
                    709:       return "ldil L'%1,%0\n\tldo R'%1(%0),%0";
                    710:   return "copy %1,%0";
                    711: }
                    712: 
                    713: 
1.1.1.2 ! root      714: /* Compute position (in OPERANDS[2]) and width (in OPERANDS[3])
        !           715:    useful for copying or or'ing IMM to a register using bit field
        !           716:    instructions.  Store the immediate value to insert in OPERANDS[1].  */
        !           717: void
        !           718: compute_xdepi_operands_from_integer (imm, operands)
        !           719:      unsigned imm;
        !           720:      rtx *operands;
        !           721: {
        !           722:   int lsb, len;
        !           723: 
        !           724:   /* Find the least significant set bit in IMM.  */
        !           725:   for (lsb = 0; lsb < 32; lsb++)
        !           726:     {
        !           727:       if ((imm & 1) != 0)
        !           728:         break;
        !           729:       imm >>= 1;
        !           730:     }
        !           731: 
        !           732:   /* Choose variants based on *sign* of the 5-bit field.  */
        !           733:   if ((imm & 0x10) == 0)
        !           734:     len = (lsb <= 28) ? 4 : 32 - lsb;
        !           735:   else
        !           736:     {
        !           737:       /* Find the width of the bitstring in IMM.  */
        !           738:       for (len = 5; len < 32; len++)
        !           739:        {
        !           740:          if ((imm & (1 << len)) == 0)
        !           741:            break;
        !           742:        }
        !           743: 
        !           744:       /* Sign extend IMM as a 5-bit value.  */
        !           745:       imm = (imm & 0xf) - 0x10;
        !           746:     }
        !           747: 
        !           748:   operands[1] = gen_rtx (CONST_INT, VOIDmode, imm);
        !           749:   operands[2] = gen_rtx (CONST_INT, VOIDmode, 31 - lsb);
        !           750:   operands[3] = gen_rtx (CONST_INT, VOIDmode, len);
        !           751: }
        !           752: 
1.1       root      753: /* Output assembler code to perform a doubleword move insn
                    754:    with operands OPERANDS.  */
                    755: 
                    756: char *
                    757: output_move_double (operands)
                    758:      rtx *operands;
                    759: {
                    760:   enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1;
                    761:   rtx latehalf[2];
                    762:   rtx addreg0 = 0, addreg1 = 0;
                    763: 
                    764:   /* First classify both operands.  */
                    765: 
                    766:   if (REG_P (operands[0]))
                    767:     optype0 = REGOP;
                    768:   else if (offsettable_memref_p (operands[0]))
                    769:     optype0 = OFFSOP;
                    770:   else if (GET_CODE (operands[0]) == MEM)
                    771:     optype0 = MEMOP;
                    772:   else
                    773:     optype0 = RNDOP;
                    774: 
                    775:   if (REG_P (operands[1]))
                    776:     optype1 = REGOP;
                    777:   else if (CONSTANT_P (operands[1]))
                    778:     optype1 = CNSTOP;
                    779:   else if (offsettable_memref_p (operands[1]))
                    780:     optype1 = OFFSOP;
                    781:   else if (GET_CODE (operands[1]) == MEM)
                    782:     optype1 = MEMOP;
                    783:   else
                    784:     optype1 = RNDOP;
                    785: 
                    786:   /* Check for the cases that the operand constraints are not
                    787:      supposed to allow to happen.  Abort if we get one,
                    788:      because generating code for these cases is painful.  */
                    789: 
                    790:   if (optype0 != REGOP && optype1 != REGOP)
                    791:     abort ();
                    792: 
                    793:    /* Handle auto decrementing and incrementing loads and stores
                    794:      specifically, since the structure of the function doesn't work
                    795:      for them without major modification.  Do it better when we learn
                    796:      this port about the general inc/dec addressing of PA.
                    797:      (This was written by tege.  Chide him if it doesn't work.)  */
                    798: 
                    799:   if (optype0 == MEMOP)
                    800:     {
1.1.1.2 ! root      801:       /* We have to output the address syntax ourselves, since print_operand
        !           802:         doesn't deal with the addresses we want to use.  Fix this later.  */
        !           803: 
1.1       root      804:       rtx addr = XEXP (operands[0], 0);
1.1.1.2 ! root      805:       if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
        !           806:        {
        !           807:          rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);
        !           808: 
        !           809:          operands[0] = XEXP (addr, 0);
        !           810:          if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
        !           811:            abort ();
        !           812: 
        !           813:          if (!reg_overlap_mentioned_p (high_reg, addr))
        !           814:            {
        !           815:              /* No overlap between high target register and address
        !           816:                 register.  (We do this in a non-obvious way to
        !           817:                 save a register file writeback)  */
        !           818:              if (GET_CODE (addr) == POST_INC)
        !           819:                return "stws,ma %1,8(0,%0)\n\tstw %R1,-4(0,%0)";
        !           820:              return "stws,ma %1,-8(0,%0)\n\tstw %R1,12(0,%0)";
        !           821:            }
        !           822:          else
        !           823:            abort();
        !           824:        }
        !           825:       else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
1.1       root      826:        {
1.1.1.2 ! root      827:          rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);
        !           828: 
        !           829:          operands[0] = XEXP (addr, 0);
        !           830:          if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
        !           831:            abort ();
        !           832: 
        !           833:          if (!reg_overlap_mentioned_p (high_reg, addr))
        !           834:            {
        !           835:              /* No overlap between high target register and address
        !           836:                 register.  (We do this in a non-obvious way to
        !           837:                 save a register file writeback)  */
        !           838:              if (GET_CODE (addr) == PRE_INC)
        !           839:                return "stws,mb %1,8(0,%0)\n\tstw %R1,4(0,%0)";
        !           840:              return "stws,mb %1,-8(0,%0)\n\tstw %R1,4(0,%0)";
        !           841:            }
        !           842:          else
        !           843:            abort();
1.1       root      844:        }
                    845:     }
                    846:   if (optype1 == MEMOP)
                    847:     {
                    848:       /* We have to output the address syntax ourselves, since print_operand
                    849:         doesn't deal with the addresses we want to use.  Fix this later.  */
                    850: 
                    851:       rtx addr = XEXP (operands[1], 0);
                    852:       if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
                    853:        {
                    854:          rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);
                    855: 
                    856:          operands[1] = XEXP (addr, 0);
                    857:          if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
                    858:            abort ();
                    859: 
                    860:          if (!reg_overlap_mentioned_p (high_reg, addr))
                    861:            {
                    862:              /* No overlap between high target register and address
1.1.1.2 ! root      863:                 register.  (We do this in a non-obvious way to
1.1       root      864:                 save a register file writeback)  */
                    865:              if (GET_CODE (addr) == POST_INC)
                    866:                return "ldws,ma 8(0,%1),%0\n\tldw -4(0,%1),%R0";
                    867:              return "ldws,ma -8(0,%1),%0\n\tldw 12(0,%1),%R0";
                    868:            }
                    869:          else
                    870:            {
                    871:              /* This is an undefined situation.  We should load into the
                    872:                 address register *and* update that register.  Probably
                    873:                 we don't need to handle this at all.  */
                    874:              if (GET_CODE (addr) == POST_INC)
                    875:                return "ldw 4(0,%1),%R0\n\tldws,ma 8(0,%1),%0";
                    876:              return "ldw 4(0,%1),%R0\n\tldws,ma -8(0,%1),%0";
                    877:            }
                    878:        }
                    879:       else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
                    880:        {
                    881:          rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);
                    882: 
                    883:          operands[1] = XEXP (addr, 0);
                    884:          if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
                    885:            abort ();
                    886: 
                    887:          if (!reg_overlap_mentioned_p (high_reg, addr))
                    888:            {
                    889:              /* No overlap between high target register and address
1.1.1.2 ! root      890:                 register.  (We do this in a non-obvious way to
1.1       root      891:                 save a register file writeback)  */
                    892:              if (GET_CODE (addr) == PRE_INC)
                    893:                return "ldws,mb 8(0,%1),%0\n\tldw 4(0,%1),%R0";
                    894:              return "ldws,mb -8(0,%1),%0\n\tldw 4(0,%1),%R0";
                    895:            }
                    896:          else
                    897:            {
                    898:              /* This is an undefined situation.  We should load into the
                    899:                 address register *and* update that register.  Probably
                    900:                 we don't need to handle this at all.  */
                    901:              if (GET_CODE (addr) == PRE_INC)
                    902:                return "ldw 12(0,%1),%R0\n\tldws,mb 8(0,%1),%0";
                    903:              return "ldw -4(0,%1),%R0\n\tldws,mb -8(0,%1),%0";
                    904:            }
                    905:        }
                    906:     }
                    907: 
                    908:   /* If an operand is an unoffsettable memory ref, find a register
                    909:      we can increment temporarily to make it refer to the second word.  */
                    910: 
                    911:   if (optype0 == MEMOP)
                    912:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    913: 
                    914:   if (optype1 == MEMOP)
                    915:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    916: 
                    917:   /* Ok, we can do one word at a time.
                    918:      Normally we do the low-numbered word first.
                    919: 
                    920:      In either case, set up in LATEHALF the operands to use
                    921:      for the high-numbered word and in some cases alter the
                    922:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    923: 
                    924:   if (optype0 == REGOP)
                    925:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    926:   else if (optype0 == OFFSOP)
                    927:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    928:   else
                    929:     latehalf[0] = operands[0];
                    930: 
                    931:   if (optype1 == REGOP)
                    932:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    933:   else if (optype1 == OFFSOP)
                    934:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    935:   else if (optype1 == CNSTOP)
                    936:     split_double (operands[1], &operands[1], &latehalf[1]);
                    937:   else
                    938:     latehalf[1] = operands[1];
                    939: 
                    940:   /* If the first move would clobber the source of the second one,
                    941:      do them in the other order.
                    942: 
                    943:      RMS says "This happens only for registers;
                    944:      such overlap can't happen in memory unless the user explicitly
                    945:      sets it up, and that is an undefined circumstance."
                    946: 
                    947:      but it happens on the HP-PA when loading parameter registers,
                    948:      so I am going to define that circumstance, and make it work
                    949:      as expected.  */
                    950: 
                    951:   if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP)
                    952:           && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
                    953:     {
                    954:       /* XXX THIS PROBABLY DOESN'T WORK.  */
                    955:       /* Do the late half first.  */
                    956:       if (addreg1)
1.1.1.2 ! root      957:        output_asm_insn ("ldo 4(%0),%0", &addreg1);
1.1       root      958:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    959:       if (addreg1)
1.1.1.2 ! root      960:        output_asm_insn ("ldo -4(%0),%0", &addreg1);
1.1       root      961:       /* Then clobber.  */
                    962:       return singlemove_string (operands);
                    963:     }
                    964: 
                    965:   if (optype0 == REGOP && optype1 == REGOP
                    966:       && REGNO (operands[0]) == REGNO (operands[1]) + 1)
                    967:     {
                    968:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    969:       return singlemove_string (operands);
                    970:     }
                    971: 
                    972:   /* Normal case: do the two words, low-numbered first.  */
                    973: 
                    974:   output_asm_insn (singlemove_string (operands), operands);
                    975: 
                    976:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    977:   if (addreg0)
1.1.1.2 ! root      978:     output_asm_insn ("ldo 4(%0),%0", &addreg0);
1.1       root      979:   if (addreg1)
1.1.1.2 ! root      980:     output_asm_insn ("ldo 4(%0),%0", &addreg1);
1.1       root      981: 
                    982:   /* Do that word.  */
                    983:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    984: 
                    985:   /* Undo the adds we just did.  */
                    986:   if (addreg0)
1.1.1.2 ! root      987:     output_asm_insn ("ldo -4(%0),%0", &addreg0);
1.1       root      988:   if (addreg1)
1.1.1.2 ! root      989:     output_asm_insn ("ldo -4(%0),%0", &addreg1);
1.1       root      990: 
                    991:   return "";
                    992: }
                    993: 
                    994: char *
                    995: output_fp_move_double (operands)
                    996:      rtx *operands;
                    997: {
                    998:   if (FP_REG_P (operands[0]))
                    999:     {
                   1000:       if (FP_REG_P (operands[1]))
                   1001:        output_asm_insn ("fcpy,dbl %1,%0", operands);
                   1002:       else if (GET_CODE (operands[1]) == REG)
                   1003:        {
                   1004:          rtx xoperands[3];
                   1005:          xoperands[0] = operands[0];
                   1006:          xoperands[1] = operands[1];
                   1007:          xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                   1008:          output_asm_insn
                   1009:            ("stw %1,-16(0,30)\n\tstw %2,-12(0,30)\n\tfldds -16(0,30),%0",
                   1010:                           xoperands);
                   1011:        }
                   1012:       else 
                   1013:        output_asm_insn ("fldds%F1 %1,%0", operands);
                   1014:     }
                   1015:   else if (FP_REG_P (operands[1]))
                   1016:     {
                   1017:       if (GET_CODE (operands[0]) == REG)
                   1018:        {
                   1019:          rtx xoperands[3];
                   1020:          xoperands[2] = operands[1];
                   1021:          xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                   1022:          xoperands[0] = operands[0];
                   1023:          output_asm_insn
                   1024:            ("fstds %2,-16(0,30)\n\tldw -12(0,30),%1\n\tldw -16(0,30),%0",
                   1025:             xoperands);
                   1026:        }
                   1027:       else
                   1028:        output_asm_insn ("fstds%F0 %1,%0", operands);
                   1029:     }
                   1030:   else abort ();
                   1031:   return "";
                   1032: }
                   1033: 
                   1034: /* Return a REG that occurs in ADDR with coefficient 1.
                   1035:    ADDR can be effectively incremented by incrementing REG.  */
                   1036: 
                   1037: static rtx
                   1038: find_addr_reg (addr)
                   1039:      rtx addr;
                   1040: {
                   1041:   while (GET_CODE (addr) == PLUS)
                   1042:     {
                   1043:       if (GET_CODE (XEXP (addr, 0)) == REG)
                   1044:        addr = XEXP (addr, 0);
                   1045:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                   1046:        addr = XEXP (addr, 1);
                   1047:       else if (CONSTANT_P (XEXP (addr, 0)))
                   1048:        addr = XEXP (addr, 1);
                   1049:       else if (CONSTANT_P (XEXP (addr, 1)))
                   1050:        addr = XEXP (addr, 0);
                   1051:       else
                   1052:        abort ();
                   1053:     }
                   1054:   if (GET_CODE (addr) == REG)
                   1055:     return addr;
                   1056:   abort ();
                   1057: }
                   1058: 
                   1059: /* Emit code to perform a block move.
                   1060: 
                   1061:    Restriction: If the length argument is non-constant, alignment
                   1062:    must be 4.
                   1063: 
                   1064:    OPERANDS[0] is the destination pointer as a REG, clobbered.
                   1065:    OPERANDS[1] is the source pointer as a REG, clobbered.
                   1066:    if SIZE_IS_CONSTANT
                   1067:      OPERANDS[2] is a register for temporary storage.
                   1068:      OPERANDS[4] is the size as a CONST_INT
                   1069:    else
                   1070:      OPERANDS[2] is a REG which will contain the size, clobbered.
                   1071:    OPERANDS[3] is a register for temporary storage.
                   1072:    OPERANDS[5] is the alignment safe to use, as a CONST_INT.  */
                   1073: 
                   1074: char *
                   1075: output_block_move (operands, size_is_constant)
                   1076:      rtx *operands;
                   1077:      int size_is_constant;
                   1078: {
                   1079:   int align = INTVAL (operands[5]);
                   1080:   unsigned long n_bytes;
                   1081: 
                   1082:   /* We can't move more than four bytes at a time because the PA
                   1083:      has no longer integer move insns.  (Could use fp mem ops?)  */
                   1084:   if (align > 4)
                   1085:     align = 4;
                   1086: 
                   1087:   if (size_is_constant)
                   1088:     {
                   1089:       unsigned long n_items;
                   1090:       unsigned long offset;
                   1091:       rtx temp;
                   1092: 
                   1093:       n_bytes = INTVAL (operands[4]);
                   1094:       if (n_bytes == 0)
                   1095:        return "";
                   1096: 
                   1097:       if (align >= 4)
                   1098:        {
                   1099:          /* Don't unroll too large blocks.  */
                   1100:          if (n_bytes > 64)
                   1101:            goto copy_with_loop;
                   1102: 
                   1103:          /* Read and store using two registers, and hide latency
                   1104:             by deferring the stores until three instructions after
                   1105:             the corresponding load.  The last load insn will read
                   1106:             the entire word were the last bytes are, possibly past
                   1107:             the end of the source block, but since loads are aligned,
                   1108:             this is harmless.  */
                   1109: 
                   1110:          output_asm_insn ("ldws,ma 4(0,%1),%2", operands);
                   1111: 
                   1112:          for (offset = 4; offset < n_bytes; offset += 4)
                   1113:            {
                   1114:              output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
                   1115:              output_asm_insn ("stws,ma %2,4(0,%0)", operands);
                   1116: 
                   1117:              temp = operands[2];
                   1118:              operands[2] = operands[3];
                   1119:              operands[3] = temp;
                   1120:            }
                   1121:          if (n_bytes % 4 == 0)
                   1122:            /* Store the last word.  */
                   1123:            output_asm_insn ("stw %2,0(0,%0)", operands);
                   1124:          else
                   1125:            {
                   1126:              /* Store the last, partial word.  */
                   1127:              operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);
                   1128:              output_asm_insn ("stbys,e %2,%4(0,%0)", operands);
                   1129:            }
                   1130:          return "";
                   1131:        }
                   1132: 
                   1133:       if (align >= 2 && n_bytes >= 2)
                   1134:        {
                   1135:          output_asm_insn ("ldhs,ma 2(0,%1),%2", operands);
                   1136: 
                   1137:          for (offset = 2; offset + 2 <= n_bytes; offset += 2)
                   1138:            {
                   1139:              output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);
                   1140:              output_asm_insn ("sths,ma %2,2(0,%0)", operands);
                   1141: 
                   1142:              temp = operands[2];
                   1143:              operands[2] = operands[3];
                   1144:              operands[3] = temp;
                   1145:            }
                   1146:          if (n_bytes % 2 != 0)
                   1147:            output_asm_insn ("ldb 0(0,%1),%3", operands);
                   1148: 
                   1149:          output_asm_insn ("sths,ma %2,2(0,%0)", operands);
                   1150: 
                   1151:          if (n_bytes % 2 != 0)
                   1152:            output_asm_insn ("stb %3,0(0,%0)", operands);
                   1153: 
                   1154:          return "";
                   1155:        }
                   1156: 
                   1157:       output_asm_insn ("ldbs,ma 1(0,%1),%2", operands);
                   1158: 
                   1159:       for (offset = 1; offset + 1 <= n_bytes; offset += 1)
                   1160:        {
                   1161:          output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);
                   1162:          output_asm_insn ("stbs,ma %2,1(0,%0)", operands);
                   1163: 
                   1164:          temp = operands[2];
                   1165:          operands[2] = operands[3];
                   1166:          operands[3] = temp;
                   1167:        }
                   1168:       output_asm_insn ("stb %2,0(0,%0)", operands);
                   1169: 
                   1170:       return "";
                   1171:     }
                   1172: 
                   1173:   if (align != 4)
                   1174:     abort();
                   1175:      
                   1176:  copy_with_loop:
                   1177: 
                   1178:   if (size_is_constant)
                   1179:     {
1.1.1.2 ! root     1180:       /* Size is compile-time determined, and also not
1.1       root     1181:         very small (such small cases are handled above).  */
                   1182:       operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes - 4);
                   1183:       output_asm_insn ("ldo %4(0),%2", operands);
                   1184:     }
                   1185:   else
                   1186:     {
                   1187:       /* Decrement counter by 4, and if it becomes negative, jump past the
                   1188:         word copying loop.  */
                   1189:       output_asm_insn ("addib,<,n -4,%2,.+16", operands);
                   1190:     }
                   1191: 
                   1192:   /* Copying loop.  Note that the first load is in the annulled delay slot
                   1193:      of addib.  Is it OK on PA to have a load in a delay slot, i.e. is a
                   1194:      possible page fault stopped in time?  */
                   1195:   output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
                   1196:   output_asm_insn ("addib,>= -4,%2,.-4", operands);
                   1197:   output_asm_insn ("stws,ma %3,4(0,%0)", operands);
                   1198: 
                   1199:   /* The counter is negative, >= -4.  The remaining number of bytes are
                   1200:      determined by the two least significant bits.  */
                   1201: 
                   1202:   if (size_is_constant)
                   1203:     {
                   1204:       if (n_bytes % 4 != 0)
                   1205:        {
                   1206:          /* Read the entire word of the source block tail.  */
                   1207:          output_asm_insn ("ldw 0(0,%1),%3", operands);
                   1208:          operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);
                   1209:          output_asm_insn ("stbys,e %3,%4(0,%0)", operands);
                   1210:        }
                   1211:     }
                   1212:   else
                   1213:     {
                   1214:       /* Add 4 to counter.  If it becomes zero, we're done.  */
                   1215:       output_asm_insn ("addib,=,n 4,%2,.+16", operands);
                   1216: 
                   1217:       /* Read the entire word of the source block tail.  (Also this
                   1218:         load is in an annulled delay slot.)  */
                   1219:       output_asm_insn ("ldw 0(0,%1),%3", operands);
                   1220: 
                   1221:       /* Make %0 point at the first byte after the destination block.  */
                   1222:       output_asm_insn ("add %2,%0,%0", operands);
                   1223:       /* Store the leftmost bytes, up to, but not including, the address
                   1224:         in %0.  */
                   1225:       output_asm_insn ("stbys,e %3,0(0,%0)", operands);
                   1226:     }
                   1227:   return "";
                   1228: }
                   1229: 
                   1230: 
1.1.1.2 ! root     1231: char *
        !          1232: output_and (operands)
        !          1233:      rtx *operands;
        !          1234: {
        !          1235:   if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
        !          1236:     {
        !          1237:       unsigned mask = INTVAL (operands[2]);
        !          1238:       int ls0, ls1, ms0, p, len;
        !          1239: 
        !          1240:       for (ls0 = 0; ls0 < 32; ls0++)
        !          1241:        if ((mask & (1 << ls0)) == 0)
        !          1242:          break;
        !          1243: 
        !          1244:       for (ls1 = ls0; ls1 < 32; ls1++)
        !          1245:        if ((mask & (1 << ls1)) != 0)
        !          1246:          break;
        !          1247: 
        !          1248:       for (ms0 = ls1; ms0 < 32; ms0++)
        !          1249:        if ((mask & (1 << ms0)) == 0)
        !          1250:          break;
        !          1251: 
        !          1252:       if (ms0 != 32)
        !          1253:        abort();
        !          1254: 
        !          1255:       if (ls1 == 32)
        !          1256:        {
        !          1257:          len = ls0;
        !          1258: 
        !          1259:          if (len == 0)
        !          1260:            abort ();
        !          1261: 
        !          1262:          operands[2] = gen_rtx (CONST_INT, VOIDmode, len);
        !          1263:          return "extru %1,31,%2,%0";
        !          1264:        }
        !          1265:       else
        !          1266:        {
        !          1267:          /* We could use this `depi' for the case above as well, but `depi'
        !          1268:             requires one more register file access than an `extru'.  */
        !          1269: 
        !          1270:          p = 31 - ls0;
        !          1271:          len = ls1 - ls0;
        !          1272: 
        !          1273:          operands[2] = gen_rtx (CONST_INT, VOIDmode, p);
        !          1274:          operands[3] = gen_rtx (CONST_INT, VOIDmode, len);
        !          1275:          return "depi 0,%2,%3,%0";
        !          1276:        }
        !          1277:     }
        !          1278:   else
        !          1279:     return "and %1,%2,%0";
        !          1280: }
        !          1281: 
        !          1282: char *
        !          1283: output_ior (operands)
        !          1284:      rtx *operands;
        !          1285: {
        !          1286:   if (GET_CODE (operands[2]) == CONST_INT)
        !          1287:     {
        !          1288:       unsigned mask = INTVAL (operands[2]);
        !          1289:       int bs0, bs1, bs2, p, len;
        !          1290:  
        !          1291:       if (INTVAL (operands[2]) == 0)
        !          1292:        return "copy %1,%0";
        !          1293: 
        !          1294:       for (bs0 = 0; bs0 < 32; bs0++)
        !          1295:        if ((mask & (1 << bs0)) != 0)
        !          1296:          break;
        !          1297: 
        !          1298:       for (bs1 = bs0; bs1 < 32; bs1++)
        !          1299:        if ((mask & (1 << bs1)) == 0)
        !          1300:          break;
        !          1301: 
        !          1302:       if (bs1 != 32 && ((unsigned) 1 << bs1) <= mask)
        !          1303:        abort();
        !          1304: 
        !          1305:       p = 31 - bs0;
        !          1306:       len = bs1 - bs0;
        !          1307: 
        !          1308:       operands[2] = gen_rtx (CONST_INT, VOIDmode, p);
        !          1309:       operands[3] = gen_rtx (CONST_INT, VOIDmode, len);
        !          1310:       return "depi -1,%2,%3,%0";
        !          1311:     }
        !          1312:   else
        !          1313:     return "or %1,%2,%0";
        !          1314: }
        !          1315: 
1.1       root     1316: /* Output an ascii string.  */
                   1317: output_ascii (file, p, size)
                   1318:      FILE *file;
                   1319:      unsigned char *p;
                   1320:      int size;
                   1321: {
                   1322:   int i;
                   1323:   int chars_output;
                   1324:   unsigned char partial_output[16];    /* Max space 4 chars can occupy.   */
                   1325: 
                   1326:   /* The HP assembler can only take strings of 256 characters at one
                   1327:      time.  This is a limitation on input line length, *not* the
                   1328:      length of the string.  Sigh.  Even worse, it seems that the
                   1329:      restriction is in number of input characters (see \xnn &
                   1330:      \whatever).  So we have to do this very carefully.  */
                   1331: 
                   1332:   fprintf (file, "\t.STRING \"");
                   1333: 
                   1334:   chars_output = 0;
                   1335:   for (i = 0; i < size; i += 4)
                   1336:     {
                   1337:       int co = 0;
                   1338:       int io = 0;
                   1339:       for (io = 0, co = 0; io < MIN (4, size - i); io++)
                   1340:        {
                   1341:          register unsigned int c = p[i + io];
                   1342: 
                   1343:          if (c == '\"' || c == '\\')
                   1344:            partial_output[co++] = '\\';
                   1345:          if (c >= ' ' && c < 0177)
                   1346:            partial_output[co++] = c;
                   1347:          else
                   1348:            {
                   1349:              unsigned int hexd;
                   1350:              partial_output[co++] = '\\';
                   1351:              partial_output[co++] = 'x';
                   1352:              hexd =  c  / 16 - 0 + '0';
                   1353:              if (hexd > '9')
                   1354:                hexd -= '9' - 'a' + 1;
                   1355:              partial_output[co++] = hexd;
                   1356:              hexd =  c % 16 - 0 + '0';
                   1357:              if (hexd > '9')
                   1358:                hexd -= '9' - 'a' + 1;
                   1359:              partial_output[co++] = hexd;
                   1360:            }
                   1361:        }
                   1362:       if (chars_output + co > 243)
                   1363:        {
                   1364:          fprintf (file, "\"\n\t.STRING \"");
                   1365:          chars_output = 0;
                   1366:        }
                   1367:       fwrite (partial_output, 1, co, file);
                   1368:       chars_output += co;
                   1369:       co = 0;
                   1370:     }
                   1371:   fprintf (file, "\"\n");
                   1372: }
                   1373: 
                   1374: /* You may have trouble believing this, but this is the HP825 stack
                   1375:    layout.  Wow.
                   1376: 
                   1377:    Offset              Contents
                   1378: 
                   1379:    Variable arguments  (optional; any number may be allocated)
                   1380: 
                   1381:    SP-(4*(N+9))                arg word N
                   1382:        :                   :
                   1383:       SP-56            arg word 5
                   1384:       SP-52            arg word 4
                   1385: 
                   1386:    Fixed arguments     (must be allocated; may remain unused)
                   1387: 
                   1388:       SP-48            arg word 3
                   1389:       SP-44            arg word 2
                   1390:       SP-40            arg word 1
                   1391:       SP-36            arg word 0
                   1392: 
                   1393:    Frame Marker
                   1394: 
                   1395:       SP-32            External Data Pointer (DP)
                   1396:       SP-28            External sr4
                   1397:       SP-24            External/stub RP (RP')
                   1398:       SP-20            Current RP
                   1399:       SP-16            Static Link
                   1400:       SP-12            Clean up
                   1401:       SP-8             Calling Stub RP (RP'')
                   1402:       SP-4             Previous SP
                   1403: 
                   1404:    Top of Frame
                   1405: 
                   1406:       SP-0             Stack Pointer (points to next available address)
                   1407: 
                   1408: */
                   1409: 
                   1410: /* This function saves registers as follows.  Registers marked with ' are
                   1411:    this function's registers (as opposed to the previous function's).
                   1412:    If a frame_pointer isn't needed, r4 is saved as a general register;
                   1413:    the space for the frame pointer is still allocated, though, to keep
                   1414:    things simple.
                   1415: 
                   1416: 
                   1417:    Top of Frame
                   1418: 
                   1419:        SP (FP')                Previous FP
                   1420:        SP + 4          Alignment filler (sigh)
                   1421:        SP + 8          Space for locals reserved here.
                   1422:        .
                   1423:        .
                   1424:        .
                   1425:        SP + n          All call saved register used.
                   1426:        .
                   1427:        .
                   1428:        .
                   1429:        SP + o          All call saved fp registers used.
                   1430:        .
                   1431:        .
                   1432:        .
                   1433:        SP + p (SP')    points to next available address.
                   1434:        
                   1435: */
                   1436: 
                   1437: /* Helper functions */
                   1438: void
                   1439: print_stw (file, r, disp, base)
                   1440:      FILE *file;
                   1441:      int r, disp, base;
                   1442: {
                   1443:   if (VAL_14_BITS_P (disp))
                   1444:     fprintf (file, "\tstw %d,%d(0,%d)\n", r, disp, base);
                   1445:   else
                   1446:     fprintf (file, "\taddil L'%d,%d\n\tstw %d,R'%d(0,1)\n", disp, base,
                   1447:             r, disp);
                   1448: }
                   1449: 
                   1450: void
                   1451: print_ldw (file, r, disp, base)
                   1452:      FILE *file;
                   1453:      int r, disp, base;
                   1454: {
                   1455:   if (VAL_14_BITS_P (disp))
                   1456:     fprintf (file, "\tldw %d(0,%d),%d\n", disp, base, r);
                   1457:   else
                   1458:     fprintf (file, "\taddil L'%d,%d\n\tldw R'%d(0,1),%d\n", disp, base,
                   1459:             disp, r);
                   1460: }
                   1461: 
1.1.1.2 ! root     1462: /* Global variables set by FUNCTION_PROLOGUE.  */
        !          1463: /* Size of frame.  Need to know this to emit return insns from
        !          1464:    leaf procedures.  */
        !          1465: int apparent_fsize;
        !          1466: int actual_fsize;
        !          1467: int local_fsize, save_fregs;
        !          1468: 
1.1       root     1469: int
1.1.1.2 ! root     1470: compute_frame_size (size, leaf_function, fregs_live)
1.1       root     1471:      int size;
                   1472:      int leaf_function;
1.1.1.2 ! root     1473:      int *fregs_live;
1.1       root     1474: {
                   1475:   extern int current_function_outgoing_args_size;
                   1476:   int i;
                   1477: 
                   1478:   /* 8 is space for frame pointer + filler */
                   1479:   local_fsize = actual_fsize = size + 8;
                   1480: 
                   1481:   /* fp is stored in a special place. */
                   1482:   for (i = 18; i >= 5; i--)
                   1483:     if (regs_ever_live[i])
                   1484:       actual_fsize += 4;
                   1485: 
                   1486:   if (regs_ever_live[3])
                   1487:     actual_fsize += 4;
                   1488:   actual_fsize = (actual_fsize + 7) & ~7;
                   1489: 
                   1490:   if (!TARGET_SNAKE)
                   1491:     {
                   1492:       for (i = 47; i >= 44; i--)
                   1493:        if (regs_ever_live[i])
                   1494:          {
1.1.1.2 ! root     1495:            actual_fsize += 8;
        !          1496:            if (fregs_live)
        !          1497:              *fregs_live = 1;
1.1       root     1498:          }
                   1499:     }
                   1500:   else
                   1501:     {
                   1502:       for (i = 90; i >= 72; i -= 2)
                   1503:        if (regs_ever_live[i] || regs_ever_live[i + 1])
                   1504:          {
1.1.1.2 ! root     1505:            actual_fsize += 8;
        !          1506:            if (fregs_live)
        !          1507:              *fregs_live = 1;
1.1       root     1508:          }
                   1509:     }
                   1510:   return actual_fsize + current_function_outgoing_args_size;
                   1511: }
                   1512:      
                   1513: void
                   1514: output_function_prologue (file, size, leaf_function)
                   1515:      FILE *file;
                   1516:      int size;
                   1517:      int leaf_function;
                   1518: {
                   1519:   extern char call_used_regs[];
                   1520:   extern int frame_pointer_needed;
1.1.1.2 ! root     1521:   extern int current_function_returns_struct;
1.1       root     1522:   int i, offset;
                   1523: 
1.1.1.2 ! root     1524:   save_fregs = 0;
        !          1525:   actual_fsize = compute_frame_size (size, leaf_function, &save_fregs) + 32;
1.1       root     1526:   if (TARGET_SNAKE)
                   1527:     actual_fsize = (actual_fsize + 63) & ~63;
                   1528: 
                   1529:   /* Let's not try to bullshit more than we need to here. */
                   1530:   /* This might be right a lot of the time */
                   1531:   fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize);
1.1.1.2 ! root     1532:     if (regs_ever_live[2] || profile_flag)
1.1       root     1533:       fprintf (file, ",CALLS,SAVE_RP\n");
                   1534:     else
                   1535:       fprintf (file, ",NO_CALLS\n");
                   1536:   fprintf (file, "\t.ENTRY\n");
                   1537: 
                   1538:   /* Some registers have places to go in the current stack
                   1539:      structure.  */
                   1540: 
                   1541:   if (regs_ever_live[2] || profile_flag)
                   1542:     fprintf (file, "\tstw 2,-20(0,30)\n");
                   1543: 
                   1544:   /* Reserve space for local variables.  */
                   1545:   if (frame_pointer_needed)
                   1546:     {
                   1547:       if (VAL_14_BITS_P (actual_fsize))
                   1548:        fprintf (file, "\tcopy 4,1\n\tcopy 30,4\n\tstwm 1,%d(0,30)\n",
                   1549:                 actual_fsize);
                   1550:       else
                   1551:        {
                   1552:          fprintf (file, "\tcopy 4,1\n\tcopy 30,4\n\tstw 1,0(0,4)\n");
                   1553:          fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),30\n",
                   1554:                   actual_fsize, actual_fsize);
                   1555:        }
                   1556:     }
                   1557:   else
                   1558:     /* Used to be abort ();  */
                   1559:     {
                   1560:       if (VAL_14_BITS_P (actual_fsize))
                   1561:        fprintf (file, "\tldo %d(30),30\n", actual_fsize);
                   1562:       else
                   1563:        fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),30\n",
                   1564:                 actual_fsize, actual_fsize);
                   1565:     }
1.1.1.2 ! root     1566:   /* The hppa calling conventions say that that %r19, the pic offset 
        !          1567:      register, is saved at sp - 32 (in this function's frame) */
        !          1568:   if (flag_pic)
        !          1569:     {
        !          1570:       fprintf (file, "\tstw %%r19,-32(%%r30)\n");
        !          1571:     }
1.1       root     1572:   /* Instead of taking one argument, the counter label, as most normal
                   1573:      mcounts do, _mcount appears to behave differently on the HPPA. It
                   1574:      takes the return address of the caller, the address of this
                   1575:      routine, and the address of the label. Also, it isn't magic, so
                   1576:      argument registers have to be preserved. */
                   1577: 
                   1578:   if (profile_flag)
                   1579:     {
                   1580:       unsigned int pc_offset =
                   1581:        (4 + (frame_pointer_needed
                   1582:              ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20)
                   1583:              : (VAL_14_BITS_P (actual_fsize) ? 4 : 8)));
                   1584:       int i, arg_offset;
1.1.1.2 ! root     1585:       int basereg, offsetadj;
1.1       root     1586: 
1.1.1.2 ! root     1587:       /* When the function has a frame pointer, use that as the base 
        !          1588:         register for saving/restoring registers.  Else use the stack
        !          1589:         pointer.  Adjust the offset according to the frame size if this
        !          1590:         function does not have a frame pointer.  */
        !          1591: 
        !          1592:       basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM
        !          1593:                                     : STACK_POINTER_REGNUM;
        !          1594:       offsetadj = frame_pointer_needed ? 0 : actual_fsize;
        !          1595: 
        !          1596:       if (current_function_returns_struct)
        !          1597:        print_stw (file, STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg);
        !          1598:       for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
1.1       root     1599:        if (regs_ever_live[i])
                   1600:          {
1.1.1.2 ! root     1601:            print_stw (file, i, arg_offset, basereg);
        !          1602:            /* It is possible for the arg_offset not to fit in 14 bits 
        !          1603:                when profiling a function without a frame pointer.  Deal
        !          1604:               with such cases.  */
        !          1605:            pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8;
1.1       root     1606:          }
                   1607:       fprintf (file,
                   1608:               "\tcopy %%r2,%%r26\n\taddil L'LP$%04d-$global$,%%r27\n\
                   1609: \tldo R'LP$%04d-$global$(%%r1),%%r24\n\tbl _mcount,%%r2\n\
                   1610: \tldo %d(%%r2),%%r25\n",
                   1611:               hp_profile_labelno, hp_profile_labelno, -pc_offset - 12 - 8);
1.1.1.2 ! root     1612:       for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
1.1       root     1613:        if (regs_ever_live[i])
1.1.1.2 ! root     1614:          print_ldw (file, i, arg_offset, basereg);
        !          1615:       if (current_function_returns_struct)
        !          1616:        print_ldw (file, STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg);
1.1       root     1617:     }
                   1618: 
                   1619:   /* Normal register save. */
                   1620:   if (frame_pointer_needed)
                   1621:     {
                   1622:       for (i = 18, offset = local_fsize; i >= 5; i--)
                   1623:        if (regs_ever_live[i] && ! call_used_regs[i])
                   1624:          {
                   1625:            print_stw (file, i, offset, 4);  offset += 4;
                   1626:          }
                   1627:       if (regs_ever_live[3] && ! call_used_regs[3])
                   1628:        {
                   1629:          print_stw (file, 3, offset, 4);  offset += 4;
                   1630:        }
                   1631:     }
                   1632:   else
                   1633:     {
                   1634:       for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--)
                   1635:        if (regs_ever_live[i] && ! call_used_regs[i])
                   1636:          {
                   1637:            print_stw (file, i, offset, 30);  offset += 4;
                   1638:          }
                   1639:       if (regs_ever_live[3] && ! call_used_regs[3])
                   1640:        {
                   1641:          print_stw (file, 3, offset, 30);  offset += 4;
                   1642:        }
                   1643:     }
                   1644:       
                   1645:   /* Align pointer properly (doubleword boundary).  */
                   1646:   offset = (offset + 7) & ~7;
                   1647: 
                   1648:   /* Floating point register store.  */
                   1649:   if (save_fregs)
                   1650:     if (frame_pointer_needed)
                   1651:       {
                   1652:        if (VAL_14_BITS_P (offset))
                   1653:          fprintf (file, "\tldo %d(4),1\n", offset);
                   1654:        else
                   1655:          fprintf (file, "\taddil L'%d,4\n\tldo R'%d(1),1\n", offset, offset);
                   1656:       }
                   1657:     else
                   1658:       {
                   1659:        if (VAL_14_BITS_P (offset))
                   1660:          fprintf (file, "\tldo %d(30),1\n", offset);
                   1661:        else
                   1662:          fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),1\n", offset, offset);
                   1663:       }
                   1664:   if (!TARGET_SNAKE)
                   1665:     {
                   1666:       for (i = 47; i >= 44; i--)
                   1667:        {
                   1668:          if (regs_ever_live[i])
                   1669:            fprintf (file, "\tfstds,ma %s,8(0,1)\n", reg_names[i]);
                   1670:        }
                   1671:     }
                   1672:   else
                   1673:     {
                   1674:       for (i = 90; i >= 72; i -= 2)
                   1675:        if (regs_ever_live[i] || regs_ever_live[i + 1])
                   1676:          {
                   1677:            fprintf (file, "\tfstds,ma %s,8(0,1)\n", reg_names[i]);
                   1678:          }
                   1679:     }
                   1680: }
                   1681: 
                   1682: void
                   1683: output_function_epilogue (file, size, leaf_function)
                   1684:      FILE *file;
                   1685:      int size;
                   1686:      int leaf_function;
                   1687: {
                   1688:   extern char call_used_regs[];
                   1689:   extern int frame_pointer_needed;
                   1690:   int  i, offset;
                   1691: 
                   1692:   if (frame_pointer_needed)
                   1693:     {
                   1694:       for (i = 18, offset = local_fsize; i >= 5; i--)
                   1695:        if (regs_ever_live[i] && ! call_used_regs[i])
                   1696:          {
                   1697:            print_ldw (file, i, offset, 4);  offset += 4;
                   1698:          }
                   1699:       if (regs_ever_live[3] && ! call_used_regs[3])
                   1700:        {
                   1701:          print_ldw (file, 3, offset, 4);  offset += 4;   
                   1702:        }
                   1703:     }
                   1704:   else
                   1705:     {
                   1706:       for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--)
                   1707:        if (regs_ever_live[i] && ! call_used_regs[i])
                   1708:          {
                   1709:            print_ldw (file, i, offset, 30);  offset += 4;
                   1710:          }
                   1711:       if (regs_ever_live[3] && ! call_used_regs[3])
                   1712:        {
                   1713:          print_ldw (file, 3, offset, 30);  offset += 4;
                   1714:        }
                   1715:     }
                   1716:       
                   1717:   /* Align pointer properly (doubleword boundary).  */
                   1718:   offset = (offset + 7) & ~7;
                   1719: 
                   1720:   /* Floating point register restore.  */
                   1721:   if (save_fregs)
                   1722:     if (frame_pointer_needed)
                   1723:       {
                   1724:        if (VAL_14_BITS_P (offset))
                   1725:          fprintf (file, "\tldo %d(4),1\n", offset);
                   1726:        else
                   1727:          fprintf (file, "\taddil L'%d,4\n\tldo R'%d(1),1\n", offset, offset);
                   1728:       }
                   1729:     else
                   1730:       {
                   1731:        if (VAL_14_BITS_P (offset))
                   1732:          fprintf (file, "\tldo %d(30),1\n", offset);
                   1733:        else
                   1734:          fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),1\n", offset, offset);
                   1735:       }
                   1736:   if (!TARGET_SNAKE)
                   1737:     {
                   1738:       for (i = 47; i >= 44; i--)
                   1739:        {
                   1740:          if (regs_ever_live[i])
                   1741:            fprintf (file, "\tfldds,ma 8(0,1),%s\n", reg_names[i]);
                   1742:        }
                   1743:     }
                   1744:   else
                   1745:     {
                   1746:       for (i = 90; i >= 72; i -= 2)
                   1747:        if (regs_ever_live[i] || regs_ever_live[i + 1])
                   1748:          {
                   1749:            fprintf (file, "\tfldds,ma 8(0,1),%s\n", reg_names[i]);
                   1750:          }
                   1751:     }
                   1752:   /* Reset stack pointer (and possibly frame pointer).  The stack */
                   1753:   /* pointer is initially set to fp + 8 to avoid a race condition. */
                   1754:   if (frame_pointer_needed)
                   1755:     {
                   1756:       fprintf (file, "\tldo 8(4),30\n");
1.1.1.2 ! root     1757:       if (regs_ever_live[2] || profile_flag)
1.1       root     1758:        fprintf (file, "\tldw -28(0,30),2\n");
                   1759:       fprintf (file, "\tbv 0(2)\n\tldwm -8(30),4\n");
                   1760:     }
                   1761:   else if (actual_fsize)
                   1762:     {
1.1.1.2 ! root     1763:       if ((regs_ever_live[2] || profile_flag)
        !          1764:           && VAL_14_BITS_P (actual_fsize + 20))
1.1       root     1765:        fprintf (file, "\tldw %d(30),2\n\tbv 0(2)\n\tldo %d(30),30\n",
                   1766:                 -(actual_fsize + 20), -actual_fsize);
1.1.1.2 ! root     1767:       else if (regs_ever_live[2] || profile_flag)
1.1       root     1768:        fprintf (file,
                   1769:                 "\taddil L'%d,30\n\tldw %d(1),2\n\tbv 0(2)\n\tldo R'%d(1),30\n",
                   1770:                 - actual_fsize,
                   1771:                 - (actual_fsize + 20 + ((-actual_fsize) & ~0x7ff)),
                   1772:                 /* - ((actual_fsize + 20) - (actual_fsize & ~0x7ff)), */
                   1773:                 - actual_fsize);
                   1774:       else if (VAL_14_BITS_P (actual_fsize))
                   1775:        fprintf (file, "\tbv 0(2)\n\tldo %d(30),30\n", - actual_fsize);
                   1776:       else
                   1777:        fprintf (file, "\taddil L'%d,30\n\tbv 0(2)\n\tldo R'%d(1),30\n");
                   1778:     }
                   1779:   else if (current_function_epilogue_delay_list)
                   1780:     {
                   1781:       fprintf (file, "\tbv 0(2)\n");
                   1782:       final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
                   1783:                       file, write_symbols, 1, 0, 1);
                   1784:     }
                   1785:   else
                   1786:     fprintf (file, "\tbv,n 0(2)\n");
                   1787:   fprintf (file, "\t.EXIT\n\t.PROCEND\n");
                   1788: }
                   1789: 
                   1790: rtx
                   1791: gen_compare_reg (code, x, y)
                   1792:      enum rtx_code code;
                   1793:      rtx x, y;
                   1794: {
1.1.1.2 ! root     1795:   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
1.1       root     1796:   rtx cc_reg = gen_rtx (REG, mode, 0);
                   1797: 
                   1798:   emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
                   1799:                      gen_rtx (COMPARE, mode, x, y)));
                   1800: 
                   1801:   return cc_reg;
                   1802: }
                   1803: 
                   1804: /* Return nonzero if TRIAL can go into the function epilogue's
                   1805:    delay slot.  SLOT is the slot we are trying to fill.  */
                   1806: 
                   1807: int
                   1808: eligible_for_epilogue_delay (trial, slot)
                   1809:      rtx trial;
                   1810:      int slot;
                   1811: {
                   1812:   if (slot >= 1)
                   1813:     return 0;
                   1814:   if (GET_CODE (trial) != INSN
                   1815:       || GET_CODE (PATTERN (trial)) != SET)
                   1816:     return 0;
                   1817:   if (get_attr_length (trial) != 1)
                   1818:     return 0;
                   1819:   return (leaf_function &&
                   1820:          get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
                   1821: }
                   1822: 
                   1823: rtx
                   1824: gen_scond_fp (code, operand0)
                   1825:      enum rtx_code code;
                   1826:      rtx operand0;
                   1827: {
                   1828:   return gen_rtx (SET, VOIDmode, operand0,
                   1829:                  gen_rtx (code, CCFPmode,
                   1830:                           gen_rtx (REG, CCFPmode, 0), const0_rtx));
                   1831: }
                   1832: 
                   1833: void
                   1834: emit_bcond_fp (code, operand0)
                   1835:      enum rtx_code code;
                   1836:      rtx operand0;
                   1837: {
                   1838:   emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
                   1839:                           gen_rtx (IF_THEN_ELSE, VOIDmode,
                   1840:                                    gen_rtx (code, VOIDmode, 
                   1841:                                             gen_rtx (REG, CCFPmode, 0),
                   1842:                                             const0_rtx),
                   1843:                                    gen_rtx (LABEL_REF, VOIDmode, operand0),
                   1844:                                    pc_rtx)));
                   1845: 
                   1846: }
                   1847: 
                   1848: rtx
                   1849: gen_cmp_fp (code, operand0, operand1)
                   1850:      enum rtx_code code;
                   1851:      rtx operand0, operand1;
                   1852: {
                   1853:   return gen_rtx (SET, VOIDmode, gen_rtx (REG, CCFPmode, 0),
                   1854:                  gen_rtx (code, CCFPmode, operand0, operand1));
                   1855: }
                   1856: 
                   1857: 
                   1858: /* Print operand X (an rtx) in assembler syntax to file FILE.
                   1859:    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
                   1860:    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
                   1861: 
                   1862: void
                   1863: print_operand (file, x, code)
                   1864:      FILE *file;
                   1865:      rtx x;
                   1866:      int code;
                   1867: {
                   1868:   switch (code)
                   1869:     {
                   1870:     case '#':
                   1871:       /* Output a 'nop' if there's nothing for the delay slot.  */
                   1872:       if (dbr_sequence_length () == 0)
                   1873:        fputs ("\n\tnop", file);
                   1874:       return;
                   1875:     case '*':
                   1876:       /* Output an nullification completer if there's nothing for the */
                   1877:       /* delay slot or nullification is requested.  */ 
                   1878:       if (dbr_sequence_length () == 0 ||
                   1879:          (final_sequence &&
                   1880:           INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))))
                   1881:         fputs (",n", file);
                   1882:       return;
                   1883:     case 'R':
                   1884:       /* Print out the second register name of a register pair.
                   1885:         I.e., R (6) => 7.  */
                   1886:       fputs (reg_names[REGNO (x)+1], file);
                   1887:       return;
                   1888:     case 'r':
                   1889:       /* A register or zero. */
                   1890:       if (x == const0_rtx)
                   1891:        {
                   1892:          fputs ("0", file);
                   1893:          return;
                   1894:        }
                   1895:       else
                   1896:        break;
                   1897:     case 'O':
                   1898:       switch (GET_CODE (x))
                   1899:        {
                   1900:        case PLUS:
                   1901:          fprintf (file, "add%s",
                   1902:                   GET_CODE (XEXP (x, 1)) == CONST_INT ? "i" : "");  break;
                   1903:        case MINUS:
                   1904:          fprintf (file, "sub%s",
                   1905:                   GET_CODE (XEXP (x, 0)) == CONST_INT ? "i" : "");  break;
                   1906:        case AND:
                   1907:          fprintf (file, "and%s",
                   1908:                   GET_CODE (XEXP (x, 1)) == NOT ? "cm" : "");  break;
                   1909:        case IOR:
                   1910:          fprintf (file, "or");  break;
                   1911:        case XOR:
                   1912:          fprintf (file, "xor");  break;
                   1913:        case ASHIFT:
                   1914:          fprintf (file, "sh%dadd", INTVAL (XEXP (x, 1)));  break;
                   1915:          /* Too lazy to handle bitfield conditions yet.  */
                   1916:        default:
                   1917:          printf ("Can't grok '%c' operator:\n", code);
                   1918:          debug_rtx (x);
                   1919:          abort ();
                   1920:        }
                   1921:       return;
                   1922:     case 'C':
                   1923:     case 'X':
                   1924:       switch (GET_CODE (x))
                   1925:        {       
                   1926:        case EQ:
                   1927:          fprintf (file, "=");  break;
                   1928:        case NE:
                   1929:          if (code == 'C')
                   1930:            fprintf (file, "<>");
                   1931:          else
                   1932:            fprintf (file, "!=");
                   1933:          break;
                   1934:        case GT:
                   1935:          fprintf (file, ">");  break;
                   1936:        case GE:
                   1937:          fprintf (file, ">=");  break;
                   1938:        case GEU:
                   1939:          fprintf (file, ">>=");  break;
                   1940:        case GTU:
                   1941:          fprintf (file, ">>");  break;
                   1942:        case LT:
                   1943:          fprintf (file, "<");  break;
                   1944:        case LE:
                   1945:          fprintf (file, "<=");  break;
                   1946:        case LEU:
                   1947:          fprintf (file, "<<=");  break;
                   1948:        case LTU:
                   1949:          fprintf (file, "<<");  break;
                   1950:        default:
                   1951:          printf ("Can't grok '%c' operator:\n", code);
                   1952:          debug_rtx (x);
                   1953:          abort ();
                   1954:        }
                   1955:       return;
                   1956:     case 'N':
                   1957:     case 'Y':
                   1958:       switch (GET_CODE (x))
                   1959:        {
                   1960:        case EQ:
                   1961:          if (code == 'N')
                   1962:            fprintf (file, "<>");
                   1963:          else
                   1964:            fprintf (file, "!=");
                   1965:          break;
                   1966:        case NE:
                   1967:          fprintf (file, "=");  break;
                   1968:        case GT:
                   1969:          fprintf (file, "<=");  break;
                   1970:        case GE:
                   1971:          fprintf (file, "<");  break;
                   1972:        case GEU:
                   1973:          fprintf (file, "<<");  break;
                   1974:        case GTU:
                   1975:          fprintf (file, "<<=");  break;
                   1976:        case LT:
                   1977:          fprintf (file, ">=");  break;
                   1978:        case LE:
                   1979:          fprintf (file, ">");  break;
                   1980:        case LEU:
                   1981:          fprintf (file, ">>");  break;
                   1982:        case LTU:
                   1983:          fprintf (file, ">>=");  break;
                   1984:        default:
                   1985:          printf ("Can't grok '%c' operator:\n", code);
                   1986:          debug_rtx (x);
                   1987:          abort ();
                   1988:        }
                   1989:       return;
                   1990:     case 'M':
                   1991:       switch (GET_CODE (XEXP (x, 0)))
                   1992:        {
                   1993:        case PRE_DEC:
                   1994:        case PRE_INC:
                   1995:          fprintf (file, "s,mb");
                   1996:          break;
                   1997:        case POST_DEC:
                   1998:        case POST_INC:
                   1999:          fprintf (file, "s,ma");
                   2000:          break;
                   2001:        default:
                   2002:          break;
                   2003:        }
                   2004:       return;
                   2005:     case 'F':
                   2006:       switch (GET_CODE (XEXP (x, 0)))
                   2007:        {
                   2008:        case PRE_DEC:
                   2009:        case PRE_INC:
                   2010:          fprintf (file, ",mb");
                   2011:          break;
                   2012:        case POST_DEC:
                   2013:        case POST_INC:
                   2014:          fprintf (file, ",ma");
                   2015:          break;
                   2016:        default:
                   2017:          break;
                   2018:        }
                   2019:       return;
                   2020:     case 'G':
                   2021:       output_global_address (file, x);
                   2022:       return;
                   2023:     case 0:                    /* Don't do anything special */
                   2024:       break;
                   2025:     default:
                   2026:       abort ();
                   2027:     }
                   2028:   if (GET_CODE (x) == REG)
                   2029:     fprintf (file, "%s", reg_names [REGNO (x)]);
                   2030:   else if (GET_CODE (x) == MEM)
                   2031:     {
                   2032:       int size = GET_MODE_SIZE (GET_MODE (x));
                   2033:       rtx base = XEXP (XEXP (x, 0), 0);
                   2034:       switch (GET_CODE (XEXP (x, 0)))
                   2035:        {
                   2036:        case PRE_DEC:
                   2037:        case POST_DEC:
                   2038:          fprintf (file, "-%d(0,%s)", size, reg_names [REGNO (base)]);
                   2039:          break;
                   2040:        case PRE_INC:
                   2041:        case POST_INC:
                   2042:          fprintf (file, "%d(0,%s)", size, reg_names [REGNO (base)]);
                   2043:          break;
                   2044:        default:
                   2045:          output_address (XEXP (x, 0));
                   2046:          break;
                   2047:        }
                   2048:     }
                   2049:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
                   2050:     {
                   2051:       union { double d; int i[2]; } u;
                   2052:       union { float f; int i; } u1;
                   2053:       u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
                   2054:       u1.f = u.d;
                   2055:       if (code == 'f')
                   2056:        fprintf (file, "0r%.9g", u1.f);
                   2057:       else
                   2058:        fprintf (file, "0x%x", u1.i);
                   2059:     }
                   2060:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
                   2061:     {
                   2062:       union { double d; int i[2]; } u;
                   2063:       u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
                   2064:       fprintf (file, "0r%.20g", u.d);
                   2065:     }
                   2066:   else
                   2067:     output_addr_const (file, x);
                   2068: }
                   2069: 
                   2070: /* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF. */
                   2071: 
                   2072: void
                   2073: output_global_address (file, x)
                   2074:      FILE *file;
                   2075:      rtx x;
                   2076: {
                   2077:   if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
                   2078:     assemble_name (file, XSTR (x, 0));
                   2079:   else if (GET_CODE (x) == SYMBOL_REF)
                   2080:     {
                   2081:       assemble_name (file, XSTR (x, 0));
                   2082:       fprintf (file, "-$global$");
                   2083:     }
                   2084:   else if (GET_CODE (x) == CONST)
                   2085:     {
                   2086:       char *sep = "";
                   2087:       int offset = 0;          /* assembler wants -$global$ at end */
                   2088:       rtx base;
                   2089:          
                   2090:       if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
                   2091:        {
                   2092:          base = XEXP (XEXP (x, 0), 0);
                   2093:          output_addr_const (file, base);
                   2094:        }
                   2095:       else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == CONST_INT)
                   2096:        offset = INTVAL (XEXP (XEXP (x, 0), 0));
                   2097:       else abort ();
                   2098: 
                   2099:       if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF)
                   2100:        {
                   2101:          base = XEXP (XEXP (x, 0), 1);
                   2102:          output_addr_const (file, base);
                   2103:        }
                   2104:       else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
                   2105:        offset = INTVAL (XEXP (XEXP (x, 0),1));
                   2106:       else abort ();
                   2107: 
                   2108:       if (GET_CODE (XEXP (x, 0)) == PLUS)
                   2109:        {
                   2110:          if (offset < 0)
                   2111:            {
                   2112:              offset = -offset;
                   2113:              sep = "-";
                   2114:            }
                   2115:          else
                   2116:            sep = "+";
                   2117:        }
                   2118:       else if (GET_CODE (XEXP (x, 0)) == MINUS
                   2119:               && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
                   2120:        sep = "-";
                   2121:       else abort ();
                   2122: 
                   2123:       if (!read_only_operand (base))
                   2124:        fprintf (file, "-$global$");
                   2125:       fprintf (file, "%s", sep);
                   2126:       if (offset) fprintf (file,"%d", offset);
                   2127:     }
                   2128:   else
                   2129:     output_addr_const (file, x);
                   2130: }
                   2131: 
                   2132: /* MEM rtls here are never SYMBOL_REFs (I think), so fldws is safe. */
                   2133: 
                   2134: char *
                   2135: output_floatsisf2 (operands)
                   2136:      rtx *operands;
                   2137: {
                   2138:   if (GET_CODE (operands[1]) == MEM)
                   2139:     return "fldws %1,%0\n\tfcnvxf,sgl,sgl %0,%0";
                   2140:   else if (FP_REG_P (operands[1]))
                   2141:     return "fcnvxf,sgl,sgl %1,%0";
                   2142:   return "stwm %r1,4(0,30)\n\tfldws,mb -4(0,30),%0\n\tfcnvxf,sgl,sgl %0,%0";
                   2143: }
                   2144: 
                   2145: char *
                   2146: output_floatsidf2 (operands)
                   2147:      rtx *operands;
                   2148: {
                   2149:   if (GET_CODE (operands[1]) == MEM)
                   2150:     return "fldws %1,%0\n\tfcnvxf,sgl,dbl %0,%0";
                   2151:   else if (FP_REG_P (operands[1]))
                   2152:     return "fcnvxf,sgl,dbl %1,%0";
                   2153:   return "stwm %r1,4(0,30)\n\tfldws,mb -4(0,30),%0\n\tfcnvxf,sgl,dbl %0,%0";
                   2154: }
                   2155: 
                   2156: enum rtx_code
                   2157: reverse_relop (code)
                   2158:      enum rtx_code code;
                   2159: {
                   2160:   switch (code)
                   2161:     {
                   2162:     case GT:
                   2163:       return LT;
                   2164:     case LT:
                   2165:       return GT;
                   2166:     case GE:
                   2167:       return LE;
                   2168:     case LE:
                   2169:       return GE;
                   2170:     case LTU:
                   2171:       return GTU;
                   2172:     case GTU:
                   2173:       return LTU;
                   2174:     case GEU:
                   2175:       return LEU;
                   2176:     case LEU:
                   2177:       return GEU;
                   2178:     default:
                   2179:       abort ();
                   2180:     }
                   2181: }
                   2182: 
                   2183: /* HP's millicode routines mean something special to the assembler.
                   2184:    Keep track of which ones we have used.  */
                   2185: 
                   2186: enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 };
                   2187: static char imported[(int)end1000];
                   2188: static char *milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
                   2189: static char import_string[] = ".IMPORT $$....,MILLICODE";
                   2190: #define MILLI_START 10
                   2191: 
                   2192: static int
                   2193: import_milli (code)
                   2194:      enum millicodes code;
                   2195: {
                   2196:   char str[sizeof (import_string)];
                   2197:   
                   2198:   if (!imported[(int)code])
                   2199:     {
                   2200:       imported[(int)code] = 1;
                   2201:       strcpy (str, import_string);
                   2202:       strncpy (str + MILLI_START, milli_names[(int)code], 4);
                   2203:       output_asm_insn (str, 0);
                   2204:     }
                   2205: }
                   2206: 
                   2207: /* The register constraints have put the operands and return value in 
                   2208:    the proper registers. */
                   2209: 
                   2210: char *
                   2211: output_mul_insn (unsignedp)
                   2212:      int unsignedp;
                   2213: {
                   2214:   if (unsignedp)
                   2215:     {
                   2216:       import_milli (mulU);
1.1.1.2 ! root     2217:       return "bl $$mulU,31%#";
1.1       root     2218:     }
                   2219:   else
                   2220:     {
                   2221:       import_milli (mulI);
1.1.1.2 ! root     2222:       return "bl $$mulI,31%#";
1.1       root     2223:     }
                   2224: }
                   2225: 
                   2226: /* If operands isn't NULL, then it's a CONST_INT with which we can do
                   2227:    something */
                   2228: 
                   2229: 
                   2230: /* Emit the rtl for doing a division by a constant. */
                   2231: 
                   2232:  /* Do magic division millicodes exist for this value? */
                   2233: 
                   2234: static int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
                   2235:                             1, 1};
                   2236: 
                   2237: /* We'll use an array to keep track of the magic millicodes and 
                   2238:    whether or not we've used them already. [n][0] is signed, [n][1] is
                   2239:    unsigned. */
                   2240: 
                   2241: 
                   2242: static int div_milli[16][2];
                   2243: 
                   2244: int
                   2245: div_operand (op, mode)
                   2246:      rtx op;
                   2247:      enum machine_mode mode;
                   2248: {
                   2249:   return (mode == SImode
                   2250:          && ((GET_CODE (op) == REG && REGNO (op) == 25)
                   2251:              || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
                   2252:                  && INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
                   2253: }
                   2254: 
                   2255: int
                   2256: emit_hpdiv_const (operands, unsignedp)
                   2257:      rtx *operands;
                   2258:      int unsignedp;
                   2259: {
                   2260:   if (GET_CODE (operands[2]) == CONST_INT
                   2261:       && INTVAL (operands[2]) > 0
                   2262:       && INTVAL (operands[2]) < 16
                   2263:       && magic_milli[INTVAL (operands[2])])
                   2264:     {
                   2265:       emit_move_insn ( gen_rtx (REG, SImode, 26), operands[1]);
                   2266:       emit
                   2267:        (gen_rtx
                   2268:         (PARALLEL, VOIDmode,
                   2269:          gen_rtvec (5, gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 29),
                   2270:                                 gen_rtx (unsignedp ? UDIV : DIV, SImode,
                   2271:                                          gen_rtx (REG, SImode, 26),
                   2272:                                          operands[2])),
                   2273:                     gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, SImode, 0)),
                   2274:                     gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 26)),
                   2275:                     gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 25)),
                   2276:                     gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 31)))));
                   2277:       emit_move_insn (operands[0], gen_rtx (REG, SImode, 29));
                   2278:       return 1;
                   2279:     }
                   2280:   return 0;
                   2281: }
                   2282: 
                   2283: char *
                   2284: output_div_insn (operands, unsignedp)
                   2285:      rtx *operands;
                   2286:      int unsignedp;
                   2287: {
                   2288:   int divisor;
                   2289:   
                   2290:   /* If the divisor is a constant, try to use one of the special 
                   2291:      opcodes .*/
                   2292:   if (GET_CODE (operands[0]) == CONST_INT)
                   2293:     {
                   2294:       divisor = INTVAL (operands[0]);
                   2295:       if (!div_milli[divisor][unsignedp])
                   2296:        {
                   2297:          if (unsignedp)
                   2298:            output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands);
                   2299:          else
                   2300:            output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands);
                   2301:          div_milli[divisor][unsignedp] = 1;
                   2302:        }
                   2303:       if (unsignedp)
                   2304:        return "bl $$divU_%0,31%#";
                   2305:       return "bl $$divI_%0,31%#";
                   2306:     }
                   2307:   /* Divisor isn't a special constant. */
                   2308:   else
                   2309:     {
                   2310:       if (unsignedp)
                   2311:        {
                   2312:          import_milli (divU);
                   2313:          return "bl $$divU,31%#";
                   2314:        }
                   2315:       else
                   2316:        {
                   2317:          import_milli (divI);
                   2318:          return "bl $$divI,31%#";
                   2319:        }
                   2320:     }
                   2321: }
                   2322: 
                   2323: /* Output a $$rem millicode to do mod. */
                   2324: 
                   2325: char *
                   2326: output_mod_insn (unsignedp)
                   2327:      int unsignedp;
                   2328: {
                   2329:   if (unsignedp)
                   2330:     {
                   2331:       import_milli (remU);
                   2332:       return "bl $$remU,31%#";
                   2333:     }
                   2334:   else
                   2335:     {
                   2336:       import_milli (remI);
                   2337:       return "bl $$remI,31%#";
                   2338:     }
                   2339: }
                   2340: 
                   2341: void
                   2342: output_arg_descriptor (insn)
                   2343:      rtx insn;
                   2344: {
                   2345:   char *arg_regs[4];
                   2346:   enum machine_mode arg_mode;
                   2347:   rtx prev_insn;
                   2348:   int i, output_flag = 0;
                   2349:   int regno;
                   2350:   
                   2351:   for (i = 0; i < 4; i++)
                   2352:     arg_regs[i] = 0;
                   2353: 
                   2354:   for (prev_insn = PREV_INSN (insn); GET_CODE (prev_insn) == INSN;
                   2355:        prev_insn = PREV_INSN (prev_insn))
                   2356:     {
                   2357:       if (!(GET_CODE (PATTERN (prev_insn)) == USE &&
                   2358:            GET_CODE (XEXP (PATTERN (prev_insn), 0)) == REG &&
                   2359:            FUNCTION_ARG_REGNO_P (REGNO (XEXP (PATTERN (prev_insn), 0)))))
                   2360:        break;
                   2361:       arg_mode = GET_MODE (XEXP (PATTERN (prev_insn), 0));
                   2362:       regno = REGNO (XEXP (PATTERN (prev_insn), 0));
                   2363:       if (regno >= 23 && regno <= 26)
                   2364:        {
                   2365:          arg_regs[26 - regno] = "GR";
                   2366:          if (arg_mode == DImode)
                   2367:            arg_regs[25 - regno] = "GR";
                   2368:        }
                   2369:       else if (!TARGET_SNAKE)  /* fp args */
                   2370:        {
                   2371:          if (arg_mode == SFmode)
                   2372:            arg_regs[regno - 36] = "FR";
                   2373:          else
                   2374:            {
                   2375: #ifdef HP_FP_ARG_DESCRIPTOR_REVERSED
                   2376:              arg_regs[regno - 37] = "FR";
                   2377:              arg_regs[regno - 36] = "FU";
                   2378: #else
                   2379:              arg_regs[regno - 37] = "FU";
                   2380:              arg_regs[regno - 36] = "FR";
                   2381: #endif
                   2382:            }
                   2383:        }
                   2384:       else
                   2385:        {
                   2386:          if (arg_mode == SFmode)
                   2387:            arg_regs[(regno - 56) / 2] = "FR";
                   2388:          else
                   2389:            {
                   2390: #ifdef HP_FP_ARG_DESCRIPTOR_REVERSED
                   2391:              arg_regs[(regno - 58) / 2] = "FR";
                   2392:              arg_regs[(regno - 58) / 2 + 1] = "FU";
                   2393: #else
                   2394:              arg_regs[(regno - 58) / 2] = "FU";
                   2395:              arg_regs[(regno - 58) / 2 + 1] = "FR";
                   2396: #endif
                   2397:            }
                   2398:        }
                   2399:     }
                   2400:   fputs ("\t.CALL ", asm_out_file);
                   2401:   for (i = 0; i < 4; i++)
                   2402:     {
                   2403:       if (arg_regs[i])
                   2404:        {
                   2405:          if (output_flag++)
                   2406:            fputc (',', asm_out_file);
                   2407:          fprintf (asm_out_file, "ARGW%d=%s", i, arg_regs[i]);
                   2408:        }
                   2409:     }
                   2410:   fputc ('\n', asm_out_file);
                   2411: }
                   2412: 
1.1.1.2 ! root     2413: /* Memory loads/stores to/from the shift need to go through
        !          2414:    the general registers.  */
1.1       root     2415: 
                   2416: enum reg_class
                   2417: secondary_reload_class (class, mode, in)
                   2418:      enum reg_class class;
                   2419:      enum machine_mode mode;
                   2420:      rtx in;
                   2421: {
                   2422:   int regno = true_regnum (in);
                   2423: 
1.1.1.2 ! root     2424:   if ((TARGET_SHARED_LIBS && function_label_operand (in, mode))
        !          2425:       || ((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
        !          2426:          && ((mode == QImode || mode == HImode || mode == SImode
        !          2427:               || mode == DImode) 
        !          2428:              && (class == FP_REGS || class == SNAKE_FP_REGS
        !          2429:                  || class == HI_SNAKE_FP_REGS)))
        !          2430:       || (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
        !          2431:     return GENERAL_REGS;
1.1       root     2432: 
                   2433:   return NO_REGS;
                   2434: }
                   2435: 
                   2436: enum direction
                   2437: function_arg_padding (mode, type)
                   2438:      enum machine_mode mode;
                   2439:      tree type;
                   2440: {
                   2441:   int size;
                   2442: 
                   2443:   if (mode == BLKmode)
                   2444:     {
                   2445:       if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
                   2446:        size = int_size_in_bytes (type) * BITS_PER_UNIT;
                   2447:       else
                   2448:        return upward;          /* Don't know if this is right, but */
                   2449:                                /* same as old definition. */
                   2450:     }
                   2451:   else
                   2452:     size = GET_MODE_BITSIZE (mode);
                   2453:   if (size < PARM_BOUNDARY)
                   2454:     return downward;
                   2455:   else if (size % PARM_BOUNDARY)
                   2456:     return upward;
                   2457:   else
                   2458:     return none;
                   2459: }
                   2460: 
                   2461: 
                   2462: /* Do what is necessary for `va_start'.  The argument is ignored;
                   2463:    We look at the current function to determine if stdargs or varargs
                   2464:    is used and fill in an initial va_list.  A pointer to this constructor
                   2465:    is returned.  */
                   2466: 
                   2467: struct rtx_def *
                   2468: hppa_builtin_saveregs (arglist)
                   2469:      tree arglist;
                   2470: {
                   2471:   rtx block, float_addr, offset, float_mem;
                   2472:   tree fntype = TREE_TYPE (current_function_decl);
                   2473:   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
                   2474:                   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
                   2475:                       != void_type_node)))
                   2476:                ? UNITS_PER_WORD : 0);
                   2477: 
                   2478:   if (argadj)
                   2479:     offset = plus_constant (current_function_arg_offset_rtx, argadj);
                   2480:   else
                   2481:     offset = current_function_arg_offset_rtx;
1.1.1.2 ! root     2482: 
1.1       root     2483:   /* Store general registers on the stack. */
                   2484:   move_block_from_reg (23,
                   2485:                       gen_rtx (MEM, BLKmode,
                   2486:                                plus_constant
                   2487:                                (current_function_internal_arg_pointer, -16)),
                   2488:                       4); 
1.1.1.2 ! root     2489:   return copy_to_reg (expand_binop (Pmode, add_optab,
        !          2490:                                    current_function_internal_arg_pointer,
        !          2491:                                    offset, 0, 0, OPTAB_LIB_WIDEN));
        !          2492: }
        !          2493: 
        !          2494: extern struct obstack *saveable_obstack;
        !          2495: 
        !          2496: /* In HPUX 8.0's shared library scheme, special relocations are needed
        !          2497:    for function labels if they might be passed to a function 
        !          2498:    in a shared library (because shared libraries don't live in code
        !          2499:    space), and special magic is needed to construct their address. */
        !          2500: 
        !          2501: void
        !          2502: hppa_encode_label (sym)
        !          2503:      rtx sym;
        !          2504: {
        !          2505:   char *str = XSTR (sym, 0);
        !          2506:   int len = strlen (str);
        !          2507:   char *newstr = obstack_alloc (saveable_obstack, len + 2) ;
        !          2508: 
        !          2509:   if (str[0] == '*')
        !          2510:     *newstr++ = *str++;
        !          2511:   strcpy (newstr + 1, str);
        !          2512:   *newstr = '@';
        !          2513:   XSTR (sym,0) = newstr;
        !          2514: }
        !          2515:   
        !          2516: int
        !          2517: function_label_operand  (op, mode)
        !          2518:      rtx op;
        !          2519:      enum machine_mode mode;
        !          2520: {
        !          2521:   return GET_CODE (op) == SYMBOL_REF && FUNCTION_NAME_P (XSTR (op, 0));
        !          2522: }
        !          2523: 
        !          2524: /* Return 1 if OP is suitable for the second add operand (the unshifed 
        !          2525:    operand) in an shadd instruction.   Allow CONST_INT to work around
        !          2526:    a reload bug.  */
        !          2527: int
        !          2528: shadd_operand (op, mode)
        !          2529:      rtx op;
        !          2530:      enum machine_mode mode;
        !          2531: {
        !          2532:   if (GET_CODE (op) == REG)
        !          2533:     return 1;
        !          2534:   if (GET_CODE (op) == CONST_INT)
        !          2535:     return 1;
        !          2536:   return 0;
1.1       root     2537: }

unix.superglobalmegacorp.com

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