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

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

unix.superglobalmegacorp.com

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