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

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

unix.superglobalmegacorp.com

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