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

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

unix.superglobalmegacorp.com

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