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

unix.superglobalmegacorp.com

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