home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / NeXT / GnuSource / cplusplus-8 / config / out-i860.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-14  |  38.8 KB  |  1,508 lines

  1. /* Subroutines for insn-output.c for Intel 860
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.    Derived from out-sparc.c.
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, 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.  
  22. /* Global variables for machine-dependend things.  */
  23.  
  24. /* This should go away if we pass floats to regs via
  25.    the stack instead of the frame, and if we learn how
  26.    to renumber all the registers when we don't do a save (hard!).  */
  27. extern int frame_pointer_needed;
  28.  
  29. static rtx find_addr_reg ();
  30.  
  31. /* Return non-zero only if OP is a register of mode MODE,
  32.    or const0_rtx.  */
  33. int
  34. reg_or_0_operand (op, mode)
  35.      rtx op;
  36.      enum machine_mode mode;
  37. {
  38.   return (op == const0_rtx || register_operand (op, mode)
  39.       || op == CONST0_RTX (mode));
  40. }
  41.  
  42. /* Return non-zero if this pattern, can be evaluated safely, even if it
  43.    was not asked for.  */
  44. int
  45. safe_insn_src_p (op, mode)
  46.      rtx op;
  47.      enum machine_mode mode;
  48. {
  49.   /* Just experimenting.  */
  50.  
  51.   /* No floating point src is safe if it contains an arithmetic
  52.      operation, since that operation may trap.  */
  53.   switch (GET_CODE (op))
  54.     {
  55.     case CONST_INT:
  56.     case LABEL_REF:
  57.     case SYMBOL_REF:
  58.     case CONST:
  59.       return 1;
  60.  
  61.     case REG:
  62.       return 1;
  63.  
  64.     case MEM:
  65.       return CONSTANT_ADDRESS_P (XEXP (op, 0));
  66.  
  67.       /* We never need to negate or complement constants.  */
  68.     case NEG:
  69.       return (mode != SFmode && mode != DFmode);
  70.     case NOT:
  71.     case ZERO_EXTEND:
  72.       return 1;
  73.  
  74.     case EQ:
  75.     case NE:
  76.     case LT:
  77.     case GT:
  78.     case LE:
  79.     case GE:
  80.     case LTU:
  81.     case GTU:
  82.     case LEU:
  83.     case GEU:
  84.     case MINUS:
  85.     case PLUS:
  86.       return (mode != SFmode && mode != DFmode);
  87.     case AND:
  88.     case IOR:
  89.     case XOR:
  90.     case LSHIFT:
  91.     case ASHIFT:
  92.     case ASHIFTRT:
  93.     case LSHIFTRT:
  94.       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
  95.       || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
  96.     return 0;
  97.       return 1;
  98.  
  99.     default:
  100.       return 0;
  101.     }
  102. }
  103.  
  104. /* Return 1 if REG is clobbered in IN.
  105.    Return 2 if REG is used in IN. 
  106.    Return 3 if REG is both used and clobbered in IN.
  107.    Return 0 if neither.  */
  108.  
  109. static int
  110. reg_clobbered_p (reg, in)
  111.      rtx reg;
  112.      rtx in;
  113. {
  114.   register enum rtx_code code;
  115.  
  116.   if (in == 0)
  117.     return 0;
  118.  
  119.   code = GET_CODE (in);
  120.  
  121.   if (code == SET || code == CLOBBER)
  122.     {
  123.       rtx dest = SET_DEST (in);
  124.       int set = 0;
  125.       int used = 0;
  126.  
  127.       while (GET_CODE (dest) == STRICT_LOW_PART
  128.          || GET_CODE (dest) == SUBREG
  129.          || GET_CODE (dest) == SIGN_EXTRACT
  130.          || GET_CODE (dest) == ZERO_EXTRACT)
  131.     dest = XEXP (dest, 0);
  132.  
  133.       if (dest == reg)
  134.     set = 1;
  135.       else if (GET_CODE (dest) == REG
  136.            && refers_to_regno_p (REGNO (reg),
  137.                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  138.                      SET_DEST (in), 0))
  139.     {
  140.       set = 1;
  141.       /* Anything that sets just part of the register
  142.          is considered using as well as setting it.
  143.          But note that a straight SUBREG of a single-word value
  144.          clobbers the entire value.   */
  145.       if (dest != SET_DEST (in)
  146.           && ! (GET_CODE (SET_DEST (in)) == SUBREG
  147.             || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
  148.         used = 1;
  149.     }
  150.  
  151.       if (code == SET)
  152.     {
  153.       if (set)
  154.         used = refers_to_regno_p (REGNO (reg),
  155.                       REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  156.                       SET_SRC (in), 0);
  157.       else
  158.         used = refers_to_regno_p (REGNO (reg),
  159.                       REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  160.                       in, 0);
  161.     }
  162.  
  163.       return set + used * 2;
  164.     }
  165.  
  166.   if (refers_to_regno_p (REGNO (reg),
  167.              REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  168.              in, 0))
  169.     return 2;
  170.   return 0;
  171. }
  172.  
  173. /* Return non-zero if OP can be written to without screwing up
  174.    GCC's model of what's going on.  It is assumed that this operand
  175.    appears in the dest position of a SET insn in a conditional
  176.    branch's delay slot.  AFTER is the label to start looking from.  */
  177. int
  178. operand_clobbered_before_used_after (op, after)
  179.      rtx op;
  180.      rtx after;
  181. {
  182.   extern char call_used_regs[];
  183.  
  184.   /* Just experimenting.  */
  185.   if (GET_CODE (op) == CC0)
  186.     return 1;
  187.   if (GET_CODE (op) == REG)
  188.     {
  189.       rtx insn;
  190.  
  191.       if (op == stack_pointer_rtx)
  192.     return 0;
  193.  
  194.       /* Scan forward from the label, to see if the value of OP
  195.      is clobbered before the first use.  */
  196.  
  197.       for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
  198.     {
  199.       if (GET_CODE (insn) == NOTE)
  200.         continue;
  201.       if (GET_CODE (insn) == INSN
  202.           || GET_CODE (insn) == JUMP_INSN
  203.           || GET_CODE (insn) == CALL_INSN)
  204.         {
  205.           switch (reg_clobbered_p (op, PATTERN (insn)))
  206.         {
  207.         default:
  208.           return 0;
  209.         case 1:
  210.           return 1;
  211.         case 0:
  212.           break;
  213.         }
  214.         }
  215.       /* If we reach another label without clobbering OP,
  216.          then we cannot safely write it here.  */
  217.       else if (GET_CODE (insn) == CODE_LABEL)
  218.         return 0;
  219.       if (GET_CODE (insn) == JUMP_INSN)
  220.         {
  221.           if (condjump_p (insn))
  222.         return 0;
  223.           /* This is a jump insn which has already
  224.          been mangled.  We can't tell what it does.  */
  225.           if (GET_CODE (PATTERN (insn)) == PARALLEL)
  226.         return 0;
  227.           if (! JUMP_LABEL (insn))
  228.         return 0;
  229.           /* Keep following jumps.  */
  230.           insn = JUMP_LABEL (insn);
  231.         }
  232.     }
  233.       return 1;
  234.     }
  235.  
  236.   /* In both of these cases, the first insn executed
  237.      for this op will be a orh whatever%h,r0,r31,
  238.      which is tolerable.  */
  239.   if (GET_CODE (op) == MEM)
  240.     return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
  241.  
  242.   return 0;
  243. }
  244.  
  245. /* Return non-zero if this pattern, as a source to a "SET",
  246.    is known to yield an instruction of unit size.  */
  247. int
  248. single_insn_src_p (op, mode)
  249.      rtx op;
  250.      enum machine_mode mode;
  251. {
  252.   switch (GET_CODE (op))
  253.     {
  254.     case CONST_INT:
  255.       /* This is not always a single insn src, technically,
  256.      but output_delayed_branch knows how to deal with it.  */
  257.       return 1;
  258.  
  259.     case SYMBOL_REF:
  260.     case CONST:
  261.       /* This is not a single insn src, technically,
  262.      but output_delayed_branch knows how to deal with it.  */
  263.       return 1;
  264.  
  265.     case REG:
  266.       return 1;
  267.  
  268.     case MEM:
  269.       return 1;
  270.  
  271.       /* We never need to negate or complement constants.  */
  272.     case NEG:
  273.       return (mode != DFmode);
  274.     case NOT:
  275.     case ZERO_EXTEND:
  276.       return 1;
  277.  
  278.     case PLUS:
  279.     case MINUS:
  280.       /* Detect cases that require multiple instructions.  */
  281.       if (CONSTANT_P (XEXP (op, 1))
  282.       && !(GET_CODE (XEXP (op, 1)) == CONST_INT
  283.            && SMALL_INT (XEXP (op, 1))))
  284.     return 0;
  285.     case EQ:
  286.     case NE:
  287.     case LT:
  288.     case GT:
  289.     case LE:
  290.     case GE:
  291.     case LTU:
  292.     case GTU:
  293.     case LEU:
  294.     case GEU:
  295.       /* Not doing floating point, since they probably
  296.      take longer than the branch slot they might fill.  */
  297.       return (mode != SFmode && mode != DFmode);
  298.  
  299.     case AND:
  300.       if (GET_CODE (XEXP (op, 1)) == NOT)
  301.     {
  302.       rtx arg = XEXP (XEXP (op, 1), 0);
  303.       if (CONSTANT_P (arg)
  304.           && !(GET_CODE (arg) == CONST_INT
  305.            && (SMALL_INT (arg)
  306.                || INTVAL (arg) & 0xffff == 0)))
  307.         return 0;
  308.     }
  309.     case IOR:
  310.     case XOR:
  311.       /* Both small and round numbers take one instruction;
  312.      others take two.  */
  313.       if (CONSTANT_P (XEXP (op, 1))
  314.       && !(GET_CODE (XEXP (op, 1)) == CONST_INT
  315.            && (SMALL_INT (XEXP (op, 1))
  316.            || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
  317.     return 0;
  318.  
  319.     case LSHIFT:
  320.     case ASHIFT:
  321.     case ASHIFTRT:
  322.     case LSHIFTRT:
  323.       return 1;
  324.  
  325.     case SUBREG:
  326.       if (SUBREG_WORD (op) != 0)
  327.     return 0;
  328.       return single_insn_src_p (SUBREG_REG (op), mode);
  329.  
  330.       /* Not doing floating point, since they probably
  331.      take longer than the branch slot they might fill.  */
  332.     case FLOAT_EXTEND:
  333.     case FLOAT_TRUNCATE:
  334.     case FLOAT:
  335.     case FIX:
  336.     case UNSIGNED_FLOAT:
  337.     case UNSIGNED_FIX:
  338.       return 0;
  339.  
  340.     default:
  341.       return 0;
  342.     }
  343. }
  344.  
  345. /* Nonzero only if this *really* is a single insn operand.  */
  346. int
  347. strict_single_insn_op_p (op, mode)
  348.      rtx op;
  349.      enum machine_mode mode;
  350. {
  351.   if (mode == VOIDmode)
  352.     mode = GET_MODE (op);
  353.  
  354.   switch (GET_CODE (op))
  355.     {
  356.     case CC0:
  357.       return 1;
  358.  
  359.     case CONST_INT:
  360.       if (SMALL_INT (op))
  361.     return 1;
  362.       /* We can put this set insn into delay slot, because this is one
  363.      insn; 'sethi'.  */
  364.       if ((INTVAL (op) & 0x3ff) == 0)
  365.     return 1;
  366.       return 0;
  367.  
  368.     case SYMBOL_REF:
  369.       return 0;
  370.  
  371.     case REG:
  372. #if 0
  373.       /* This loses when moving an freg to a general reg.  */
  374.       return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
  375. #endif
  376.       return (mode != DFmode && mode != DImode);
  377.  
  378.     case MEM:
  379.       if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
  380.     return (mode != DFmode && mode != DImode);
  381.       return 0;
  382.  
  383.       /* We never need to negate or complement constants.  */
  384.     case NEG:
  385.       return (mode != DFmode);
  386.     case NOT:
  387.     case ZERO_EXTEND:
  388.       return 1;
  389.  
  390.     case PLUS:
  391.     case MINUS:
  392.       /* Detect cases that require multiple instructions.  */
  393.       if (CONSTANT_P (XEXP (op, 1))
  394.       && !(GET_CODE (XEXP (op, 1)) == CONST_INT
  395.            && SMALL_INT (XEXP (op, 1))))
  396.     return 0;
  397.     case EQ:
  398.     case NE:
  399.     case LT:
  400.     case GT:
  401.     case LE:
  402.     case GE:
  403.     case LTU:
  404.     case GTU:
  405.     case LEU:
  406.     case GEU:
  407.       return 1;
  408.  
  409.     case AND:
  410.       if (GET_CODE (XEXP (op, 1)) == NOT)
  411.     {
  412.       rtx arg = XEXP (XEXP (op, 1), 0);
  413.       if (CONSTANT_P (arg)
  414.           && !(GET_CODE (arg) == CONST_INT
  415.            && (SMALL_INT (arg)
  416.                || INTVAL (arg) & 0xffff == 0)))
  417.         return 0;
  418.     }
  419.     case IOR:
  420.     case XOR:
  421.       /* Both small and round numbers take one instruction;
  422.      others take two.  */
  423.       if (CONSTANT_P (XEXP (op, 1))
  424.       && !(GET_CODE (XEXP (op, 1)) == CONST_INT
  425.            && (SMALL_INT (XEXP (op, 1))
  426.            || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
  427.     return 0;
  428.     case LSHIFT:
  429.     case ASHIFT:
  430.     case ASHIFTRT:
  431.     case LSHIFTRT:
  432.       return 1;
  433.  
  434.     case SUBREG:
  435.       if (SUBREG_WORD (op) != 0)
  436.     return 0;
  437.       return strict_single_insn_op_p (SUBREG_REG (op), mode);
  438.  
  439.     case SIGN_EXTEND:
  440.       if (GET_CODE (XEXP (op, 0)) == MEM
  441.       && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
  442.     return 1;
  443.       return 0;
  444.  
  445.       /* Not doing floating point, since they probably
  446.      take longer than the branch slot they might fill.  */
  447.     case FLOAT_EXTEND:
  448.     case FLOAT_TRUNCATE:
  449.     case FLOAT:
  450.     case FIX:
  451.     case UNSIGNED_FLOAT:
  452.     case UNSIGNED_FIX:
  453.       return 0;
  454.  
  455.     default:
  456.       return 0;
  457.     }
  458. }
  459.  
  460. /* Return truth value of whether OP is a relational operator.  */
  461. int
  462. relop (op, mode)
  463.      rtx op;
  464.      enum machine_mode mode;
  465. {
  466.   switch (GET_CODE (op))
  467.     {
  468.     case EQ:
  469.     case NE:
  470.     case GT:
  471.     case GE:
  472.     case LT:
  473.     case LE:
  474.     case GTU:
  475.     case GEU:
  476.     case LTU:
  477.     case LEU:
  478.       return 1;
  479.     }
  480.   return 0;
  481. }
  482.  
  483. /* Return truth value of whether OP can be used as an operands in a three
  484.    address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */
  485.  
  486. int
  487. arith_operand (op, mode)
  488.      rtx op;
  489.      enum machine_mode mode;
  490. {
  491.   return (register_operand (op, mode)
  492.       || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
  493. }
  494.  
  495. /* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */
  496.  
  497. int
  498. logic_operand (op, mode)
  499.      rtx op;
  500.      enum machine_mode mode;
  501. {
  502.   return (register_operand (op, mode)
  503.       || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
  504. }
  505.  
  506. /* Return 1 if OP is a valid first operand for either a logical insn
  507.    or an add insn of mode MODE.  */
  508.  
  509. int
  510. compare_operand (op, mode)
  511.      rtx op;
  512.      enum machine_mode mode;
  513. {
  514.   return (register_operand (op, mode)
  515.       || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
  516. }
  517.  
  518. /* Return truth value of whether OP can be used as an operand
  519.    of a bte insn.  */
  520.  
  521. int
  522. bte_operand (op, mode)
  523.      rtx op;
  524.      enum machine_mode mode;
  525. {
  526.   return (register_operand (op, mode)
  527.       || (GET_CODE (op) == CONST_INT
  528.           && (unsigned) INTVAL (op) < 0x20));
  529. }
  530.  
  531. /* Return 1 if OP is an indexed memory reference of mode MODE.  */
  532.  
  533. int
  534. indexed_operand (op, mode)
  535.      rtx op;
  536.      enum machine_mode mode;
  537. {
  538.   return (GET_CODE (op) == MEM && GET_MODE (op) == mode
  539.       && GET_CODE (XEXP (op, 0)) == PLUS
  540.       && GET_MODE (XEXP (op, 0)) == SImode
  541.       && register_operand (XEXP (XEXP (op, 0), 0), SImode)
  542.       && register_operand (XEXP (XEXP (op, 0), 1), SImode));
  543. }
  544.  
  545. /* Return 1 if OP is a suitable source operand for a load insn
  546.    with mode MODE.  */
  547.  
  548. int
  549. load_operand (op, mode)
  550.      rtx op;
  551.      enum machine_mode mode;
  552. {
  553.   return (memory_operand (op, mode) || indexed_operand (op, mode));
  554. }
  555.  
  556. /* Return truth value of whether OP is a integer which fits the
  557.    range constraining immediate operands in add/subtract insns.  */
  558.  
  559. int
  560. small_int (op, mode)
  561.      rtx op;
  562.      enum machine_mode mode;
  563. {
  564.   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
  565. }
  566.  
  567. /* Return truth value of whether OP is a integer which fits the
  568.    range constraining immediate operands in logic insns.  */
  569.  
  570. int
  571. logic_int (op, mode)
  572.      rtx op;
  573.      enum machine_mode mode;
  574. {
  575.   return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
  576. }
  577.  
  578. /* Return the best assembler insn template
  579.    for moving operands[1] into operands[0] as a fullword.  */
  580.  
  581. static char *
  582. singlemove_string (operands)
  583.      rtx *operands;
  584. {
  585.   if (GET_CODE (operands[0]) == MEM)
  586.     {
  587.       if (GET_CODE (operands[1]) != MEM)
  588.     if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
  589.       {
  590.         if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  591.            && (cc_prev_status.flags & CC_HI_R31_ADJ)
  592.            && cc_prev_status.mdep == XEXP (operands[0], 0)))
  593.           output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  594.         cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  595.         cc_status.mdep = XEXP (operands[0], 0);
  596.         return "st.l %r1,l%%%m0(r31)";
  597.       }
  598.     else
  599.       return "st.l %r1,%0";
  600.       else
  601.     abort ();
  602. #if 0
  603.     {
  604.       rtx xoperands[2];
  605.  
  606.       cc_status.flags &= ~CC_F0_IS_0;
  607.       xoperands[0] = gen_rtx (REG, SFmode, 32);
  608.       xoperands[1] = operands[1];
  609.       output_asm_insn (singlemove_string (xoperands), xoperands);
  610.       xoperands[1] = xoperands[0];
  611.       xoperands[0] = operands[0];
  612.       output_asm_insn (singlemove_string (xoperands), xoperands);
  613.       return "";
  614.     }
  615. #endif
  616.     }
  617.   if (GET_CODE (operands[1]) == MEM)
  618.     {
  619.       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
  620.     {
  621.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  622.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  623.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  624.         output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  625.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  626.       cc_status.mdep = XEXP (operands[1], 0);
  627.       return "ld.l l%%%m1(r31),%0";
  628.     }
  629.       return "ld.l %1,%0";
  630.     }
  631.   return "mov %1,%0";
  632. }
  633.  
  634. /* Output assembler code to perform a doubleword move insn
  635.    with operands OPERANDS.  */
  636.  
  637. char *
  638. output_move_double (operands)
  639.      rtx *operands;
  640. {
  641.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  642.   rtx latehalf[2];
  643.   rtx addreg0 = 0, addreg1 = 0;
  644.  
  645.   /* First classify both operands.  */
  646.  
  647.   if (REG_P (operands[0]))
  648.     optype0 = REGOP;
  649.   else if (offsettable_memref_p (operands[0]))
  650.     optype0 = OFFSOP;
  651.   else if (GET_CODE (operands[0]) == MEM)
  652.     optype0 = MEMOP;
  653.   else
  654.     optype0 = RNDOP;
  655.  
  656.   if (REG_P (operands[1]))
  657.     optype1 = REGOP;
  658.   else if (CONSTANT_P (operands[1])
  659.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  660.     optype1 = CNSTOP;
  661.   else if (offsettable_memref_p (operands[1]))
  662.     optype1 = OFFSOP;
  663.   else if (GET_CODE (operands[1]) == MEM)
  664.     optype1 = MEMOP;
  665.   else
  666.     optype1 = RNDOP;
  667.  
  668.   /* Check for the cases that the operand constraints are not
  669.      supposed to allow to happen.  Abort if we get one,
  670.      because generating code for these cases is painful.  */
  671.  
  672.   if (optype0 == RNDOP || optype1 == RNDOP)
  673.     abort ();
  674.  
  675.   /* If an operand is an unoffsettable memory ref, find a register
  676.      we can increment temporarily to make it refer to the second word.  */
  677.  
  678.   if (optype0 == MEMOP)
  679.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  680.  
  681.   if (optype1 == MEMOP)
  682.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  683.  
  684. /* ??? Perhaps in some cases move double words
  685.    if there is a spare pair of floating regs.  */
  686.  
  687.   /* Ok, we can do one word at a time.
  688.      Normally we do the low-numbered word first,
  689.      but if either operand is autodecrementing then we
  690.      do the high-numbered word first.
  691.  
  692.      In either case, set up in LATEHALF the operands to use
  693.      for the high-numbered word and in some cases alter the
  694.      operands in OPERANDS to be suitable for the low-numbered word.  */
  695.  
  696.   if (optype0 == REGOP)
  697.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  698.   else if (optype0 == OFFSOP)
  699.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  700.   else
  701.     latehalf[0] = operands[0];
  702.  
  703.   if (optype1 == REGOP)
  704.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  705.   else if (optype1 == OFFSOP)
  706.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  707.   else if (optype1 == CNSTOP)
  708.     {
  709.       if (CONSTANT_P (operands[1]))
  710.     latehalf[1] = const0_rtx;
  711.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  712.     {
  713.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  714.                  CONST_DOUBLE_HIGH (operands[1]));
  715.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  716.                  CONST_DOUBLE_LOW (operands[1]));
  717.     }
  718.     }
  719.   else
  720.     latehalf[1] = operands[1];
  721.  
  722.   /* If the first move would clobber the source of the second one,
  723.      do them in the other order.
  724.  
  725.      RMS says "This happens only for registers;
  726.      such overlap can't happen in memory unless the user explicitly
  727.      sets it up, and that is an undefined circumstance."
  728.  
  729.      but it happens on the sparc when loading parameter registers,
  730.      so I am going to define that circumstance, and make it work
  731.      as expected.  */
  732.  
  733.   if (optype0 == REGOP && optype1 == REGOP
  734.       && REGNO (operands[0]) == REGNO (latehalf[1]))
  735.     {
  736.       /* Make any unoffsettable addresses point at high-numbered word.  */
  737.       if (addreg0)
  738.     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
  739.       if (addreg1)
  740.     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
  741.  
  742.       /* Do that word.  */
  743.       output_asm_insn (singlemove_string (latehalf), latehalf);
  744.  
  745.       /* Undo the adds we just did.  */
  746.       if (addreg0)
  747.     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
  748.       if (addreg1)
  749.     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
  750.  
  751.       /* Do low-numbered word.  */
  752.       return singlemove_string (operands);
  753.     }
  754.   else if (optype0 == REGOP && optype1 != REGOP
  755.        && reg_overlap_mentioned_p (operands[0], operands[1]))
  756.     {
  757.       /* Do the late half first.  */
  758.       output_asm_insn (singlemove_string (latehalf), latehalf);
  759.       /* Then clobber.  */
  760.       return singlemove_string (operands);
  761.     }
  762.  
  763.   /* Normal case: do the two words, low-numbered first.  */
  764.  
  765.   output_asm_insn (singlemove_string (operands), operands);
  766.  
  767.   /* Make any unoffsettable addresses point at high-numbered word.  */
  768.   if (addreg0)
  769.     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
  770.   if (addreg1)
  771.     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
  772.  
  773.   /* Do that word.  */
  774.   output_asm_insn (singlemove_string (latehalf), latehalf);
  775.  
  776.   /* Undo the adds we just did.  */
  777.   if (addreg0)
  778.     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
  779.   if (addreg1)
  780.     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
  781.  
  782.   return "";
  783. }
  784.  
  785. static char *
  786. output_fp_move_double (operands)
  787.      rtx *operands;
  788. {
  789.   if (FP_REG_P (operands[0]))
  790.     {
  791.       if (FP_REG_P (operands[1]))
  792.     return "fmov.dd %1,%0";
  793.       if (GET_CODE (operands[1]) == REG)
  794.     {
  795.       output_asm_insn ("ixfr %1,%0", operands);
  796.       operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
  797.       operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
  798.       return "ixfr %1,%0";
  799.     }
  800.       if (operands[1] == dconst0_rtx)
  801.     return "fmov.dd f0,%0";
  802.       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
  803.     {
  804.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  805.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  806.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  807.         output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  808.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  809.       cc_status.mdep = XEXP (operands[1], 0);
  810.       return "fld.d l%%%m1(r31),%0";
  811.     }
  812.       return "fld.d %1,%0";
  813.     }
  814.   else if (FP_REG_P (operands[1]))
  815.     {
  816.       if (GET_CODE (operands[0]) == REG)
  817.     {
  818.       output_asm_insn ("fxfr %1,%0", operands);
  819.       operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
  820.       operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
  821.       return "fxfr %1,%0";
  822.     }
  823.       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
  824.     {
  825.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  826.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  827.          && cc_prev_status.mdep == XEXP (operands[0], 0)))
  828.         output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  829.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  830.       cc_status.mdep = XEXP (operands[0], 0);
  831.       return "fst.d %1,l%%%m0(r31)";
  832.     }
  833.       return "fst.d %1,%0";
  834.     }
  835.   else abort ();
  836. }
  837.  
  838. /* Return a REG that occurs in ADDR with coefficient 1.
  839.    ADDR can be effectively incremented by incrementing REG.  */
  840.  
  841. static rtx
  842. find_addr_reg (addr)
  843.      rtx addr;
  844. {
  845.   while (GET_CODE (addr) == PLUS)
  846.     {
  847.       if (GET_CODE (XEXP (addr, 0)) == REG)
  848.     addr = XEXP (addr, 0);
  849.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  850.     addr = XEXP (addr, 1);
  851.       else if (CONSTANT_P (XEXP (addr, 0)))
  852.     addr = XEXP (addr, 1);
  853.       else if (CONSTANT_P (XEXP (addr, 1)))
  854.     addr = XEXP (addr, 0);
  855.       else
  856.     abort ();
  857.     }
  858.   if (GET_CODE (addr) == REG)
  859.     return addr;
  860.   abort ();
  861. }
  862.  
  863. /* Return a template for a load instruction with mode MODE and
  864.    arguments from the string ARGS.
  865.  
  866.    This string is in static storage.   */
  867.  
  868. static char *
  869. load_opcode (mode, args, reg)
  870.      enum machine_mode mode;
  871.      char *args;
  872.      rtx reg;
  873. {
  874.   static char buf[30];
  875.   char *opcode;
  876.  
  877.   switch (mode)
  878.     {
  879.     case QImode:
  880.       opcode = "ld.b";
  881.       break;
  882.  
  883.     case HImode:
  884.       opcode = "ld.s";
  885.       break;
  886.  
  887.     case SImode:
  888.     case SFmode:
  889.       if (FP_REG_P (reg))
  890.     opcode = "fld.l";
  891.       else
  892.     opcode = "ld.l";
  893.       break;
  894.  
  895.     case DImode:
  896.       if (!FP_REG_P (reg))
  897.     abort ();
  898.     case DFmode:
  899.       opcode = "fld.d";
  900.       break;
  901.  
  902.     default:
  903.       abort ();
  904.     }
  905.  
  906.   sprintf (buf, "%s %s", opcode, args);
  907.   return buf;
  908. }
  909.  
  910. /* Return a template for a store instruction with mode MODE and
  911.    arguments from the string ARGS.
  912.  
  913.    This string is in static storage.   */
  914.  
  915. static char *
  916. store_opcode (mode, args, reg)
  917.      enum machine_mode mode;
  918.      char *args;
  919.      rtx reg;
  920. {
  921.   static char buf[30];
  922.   char *opcode;
  923.  
  924.   switch (mode)
  925.     {
  926.     case QImode:
  927.       opcode = "st.b";
  928.       break;
  929.  
  930.     case HImode:
  931.       opcode = "st.s";
  932.       break;
  933.  
  934.     case SImode:
  935.     case SFmode:
  936.       if (FP_REG_P (reg))
  937.     opcode = "fst.l";
  938.       else
  939.     opcode = "st.l";
  940.       break;
  941.  
  942.     case DImode:
  943.       if (!FP_REG_P (reg))
  944.     abort ();
  945.     case DFmode:
  946.       opcode = "fst.d";
  947.       break;
  948.  
  949.     default:
  950.       abort ();
  951.     }
  952.  
  953.   sprintf (buf, "%s %s", opcode, args);
  954.   return buf;
  955. }
  956.  
  957. /* Output a store-in-memory whose operands are OPERANDS[0,1].
  958.    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
  959.  
  960.    This function returns a template for an insn.
  961.    This is in static storage.
  962.  
  963.    It may also output some insns directly.
  964.    It may alter the values of operands[0] and operands[1].  */
  965.  
  966. char *
  967. output_store (operands)
  968.      rtx *operands;
  969. {
  970.   enum machine_mode mode = GET_MODE (operands[0]);
  971.   rtx address = XEXP (operands[0], 0);
  972.   char *string;
  973.  
  974.   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  975.   cc_status.mdep = address;
  976.  
  977.   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  978.      && (cc_prev_status.flags & CC_HI_R31_ADJ)
  979.      && address == cc_prev_status.mdep))
  980.     {
  981.       output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  982.       cc_prev_status.mdep = address;
  983.     }
  984.  
  985.   /* Store zero in two parts when appropriate.  */
  986.   if (mode == DFmode && operands[1] == dconst0_rtx)
  987.     return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
  988.  
  989.   /* Code below isn't smart enough to move a doubleword in two parts,
  990.      so use output_move_double to do that in the cases that require it.  */
  991.   if ((mode == DImode || mode == DFmode)
  992.       && ! FP_REG_P (operands[1]))
  993.     return output_move_double (operands);
  994.  
  995.   return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
  996. }
  997.  
  998. /* Output a load-from-memory whose operands are OPERANDS[0,1].
  999.    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
  1000.  
  1001.    This function returns a template for an insn.
  1002.    This is in static storage.
  1003.  
  1004.    It may also output some insns directly.
  1005.    It may alter the values of operands[0] and operands[1].  */
  1006.  
  1007. char *
  1008. output_load (operands)
  1009.      rtx *operands;
  1010. {
  1011.   enum machine_mode mode = GET_MODE (operands[0]);
  1012.   rtx address = XEXP (operands[1], 0);
  1013.  
  1014.   /* We don't bother trying to see if we know %hi(address).
  1015.      This is because we are doing a load, and if we know the
  1016.      %hi value, we probably also know that value in memory.  */
  1017.   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  1018.   cc_status.mdep = address;
  1019.  
  1020.   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  1021.      && (cc_prev_status.flags & CC_HI_R31_ADJ)
  1022.      && address == cc_prev_status.mdep
  1023.      && cc_prev_status.mdep == cc_status.mdep))
  1024.     {
  1025.       output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  1026.       cc_prev_status.mdep = address;
  1027.     }
  1028.  
  1029.   /* Code below isn't smart enough to move a doubleword in two parts,
  1030.      so use output_move_double to do that in the cases that require it.  */
  1031.   if ((mode == DImode || mode == DFmode)
  1032.       && ! FP_REG_P (operands[0]))
  1033.     return output_move_double (operands);
  1034.  
  1035.   return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
  1036. }
  1037.  
  1038. /* Load the address specified by OPERANDS[3] into the register
  1039.    specified by OPERANDS[0].
  1040.  
  1041.    OPERANDS[3] may be the result of a sum, hence it could either be:
  1042.  
  1043.    (1) CONST
  1044.    (2) REG
  1045.    (2) REG + CONST_INT
  1046.    (3) REG + REG + CONST_INT
  1047.    (4) REG + REG  (special case of 3).
  1048.  
  1049.    Note that (3) is not a legitimate address.
  1050.    All cases are handled here.  */
  1051.  
  1052. void
  1053. output_load_address (operands)
  1054.      rtx *operands;
  1055. {
  1056.   rtx base, offset;
  1057.  
  1058.   if (CONSTANT_P (operands[3]))
  1059.     {
  1060.       output_asm_insn ("mov %3,%0", operands);
  1061.       return;
  1062.     }
  1063.  
  1064.   if (REG_P (operands[3]))
  1065.     {
  1066.       if (REGNO (operands[0]) != REGNO (operands[3]))
  1067.     output_asm_insn ("mov %3,%0", operands);
  1068.       return;
  1069.     }
  1070.  
  1071.   if (GET_CODE (operands[3]) != PLUS)
  1072.     abort ();
  1073.  
  1074.   base = XEXP (operands[3], 0);
  1075.   offset = XEXP (operands[3], 1);
  1076.  
  1077.   if (GET_CODE (base) == CONST_INT)
  1078.     {
  1079.       rtx tmp = base;
  1080.       base = offset;
  1081.       offset = tmp;
  1082.     }
  1083.  
  1084.   if (GET_CODE (offset) != CONST_INT)
  1085.     {
  1086.       /* Operand is (PLUS (REG) (REG)).  */
  1087.       base = operands[3];
  1088.       offset = const0_rtx;
  1089.     }
  1090.  
  1091.   if (REG_P (base))
  1092.     {
  1093.       operands[6] = base;
  1094.       operands[7] = offset;
  1095.       if (SMALL_INT (offset))
  1096.     output_asm_insn ("adds %7,%6,%0", operands);
  1097.       else
  1098.     output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
  1099.     }
  1100.   else if (GET_CODE (base) == PLUS)
  1101.     {
  1102.       operands[6] = XEXP (base, 0);
  1103.       operands[7] = XEXP (base, 1);
  1104.       operands[8] = offset;
  1105.  
  1106.       if (SMALL_INT (offset))
  1107.     output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
  1108.       else
  1109.     output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
  1110.     }
  1111.   else
  1112.     abort ();
  1113. }
  1114.  
  1115. /* Output code to place a size count SIZE in register REG.  */
  1116.  
  1117. static void
  1118. output_size_for_block_move (size, reg, align)
  1119.      rtx size, reg, align;
  1120. {
  1121.   rtx xoperands[3];
  1122.  
  1123.   xoperands[0] = reg;
  1124.   xoperands[1] = size;
  1125.   xoperands[2] = align;
  1126.  
  1127. #if 1
  1128.   cc_status.flags &= ~ CC_KNOW_HI_R31;
  1129.   output_asm_insn ("mov %1,%0", xoperands);
  1130. #else
  1131.   if (GET_CODE (size) == REG)
  1132.     output_asm_insn ("sub %2,%1,%0", xoperands);
  1133.   else
  1134.     {
  1135.       xoperands[1]
  1136.     = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
  1137.       cc_status.flags &= ~ CC_KNOW_HI_R31;
  1138.       output_asm_insn ("mov %1,%0", xoperands);
  1139.     }
  1140. #endif
  1141. }
  1142.  
  1143. /* Emit code to perform a block move.
  1144.  
  1145.    OPERANDS[0] is the destination.
  1146.    OPERANDS[1] is the source.
  1147.    OPERANDS[2] is the size.
  1148.    OPERANDS[3] is the known safe alignment.
  1149.    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
  1150.  
  1151. char *
  1152. output_block_move (operands)
  1153.      rtx *operands;
  1154. {
  1155.   /* A vector for our computed operands.  Note that load_output_address
  1156.      makes use of (and can clobber) up to the 8th element of this vector.  */
  1157.   rtx xoperands[10];
  1158.   rtx zoperands[10];
  1159.   static int movstrsi_label = 0;
  1160.   int i, j;
  1161.   rtx temp1 = operands[4];
  1162.   rtx alignrtx = operands[3];
  1163.   int align = INTVAL (alignrtx);
  1164.  
  1165.   xoperands[0] = operands[0];
  1166.   xoperands[1] = operands[1];
  1167.   xoperands[2] = temp1;
  1168.  
  1169.   /* We can't move more than four bytes at a time
  1170.      because we have only one register to move them through.  */
  1171.   if (align > 4)
  1172.     {
  1173.       align = 4;
  1174.       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
  1175.     }
  1176.  
  1177.   /* Since we clobber untold things, nix the condition codes.  */
  1178.   CC_STATUS_INIT;
  1179.  
  1180.   /* Recognize special cases of block moves.  These occur
  1181.      when GNU C++ is forced to treat something as BLKmode
  1182.      to keep it in memory, when its mode could be represented
  1183.      with something smaller.
  1184.  
  1185.      We cannot do this for global variables, since we don't know
  1186.      what pages they don't cross.  Sigh.  */
  1187.   if (GET_CODE (operands[2]) == CONST_INT
  1188.       && INTVAL (operands[2]) <= 16
  1189.       && ! CONSTANT_ADDRESS_P (operands[0])
  1190.       && ! CONSTANT_ADDRESS_P (operands[1]))
  1191.     {
  1192.       int size = INTVAL (operands[2]);
  1193.       rtx op0 = xoperands[0];
  1194.       rtx op1 = xoperands[1];
  1195.  
  1196.       cc_status.flags &= ~CC_KNOW_HI_R31;
  1197.       if (align == 1)
  1198.     {
  1199.       if (memory_address_p (QImode, plus_constant (op0, size))
  1200.           && memory_address_p (QImode, plus_constant (op1, size)))
  1201.         {
  1202.           for (i = size-1; i >= 0; i--)
  1203.         {
  1204.           xoperands[0] = plus_constant (op0, i);
  1205.           xoperands[1] = plus_constant (op1, i);
  1206.           output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
  1207.                    xoperands);
  1208.         }
  1209.           return "";
  1210.         }
  1211.     }
  1212.       else if (align == 2)
  1213.     {
  1214.       if (memory_address_p (HImode, plus_constant (op0, size))
  1215.           && memory_address_p (HImode, plus_constant (op1, size)))
  1216.         {
  1217.           for (i = (size>>1)-1; i >= 0; i--)
  1218.         {
  1219.           xoperands[0] = plus_constant (op0, i * 2);
  1220.           xoperands[1] = plus_constant (op1, i * 2);
  1221.           output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
  1222.                    xoperands);
  1223.         }
  1224.           return "";
  1225.         }
  1226.     }
  1227.       else
  1228.     {
  1229.       if (memory_address_p (SImode, plus_constant (op0, size))
  1230.           && memory_address_p (SImode, plus_constant (op1, size)))
  1231.         {
  1232.           for (i = (size>>2)-1; i >= 0; i--)
  1233.         {
  1234.           xoperands[0] = plus_constant (op0, i * 4);
  1235.           xoperands[1] = plus_constant (op1, i * 4);
  1236.           output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
  1237.                    xoperands);
  1238.         }
  1239.           return "";
  1240.         }
  1241.     }
  1242.     }
  1243.  
  1244.   /* This is the size of the transfer.
  1245.      Either use the register which already contains the size,
  1246.      or use a free register (used by no operands).  */
  1247.   output_size_for_block_move (operands[2], operands[4], alignrtx);
  1248.  
  1249. #if 0
  1250.   /* Also emit code to decrement the size value by ALIGN.  */
  1251.   zoperands[0] = operands[0];
  1252.   zoperands[3] = plus_constant (operands[0], align);
  1253.   output_load_address (zoperands);
  1254. #endif
  1255.  
  1256.   /* Generate number for unique label.  */
  1257.  
  1258.   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
  1259.  
  1260.   /* Copy the increment (negative) to a register for bla insn.  */
  1261.  
  1262.   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
  1263.   xoperands[5] = operands[5];
  1264.   output_asm_insn ("mov %4,%5", xoperands);
  1265.  
  1266.   /* Make available a register which is a temporary.  */
  1267.  
  1268.   xoperands[6] = operands[6];
  1269.  
  1270.   /* Now the actual loop.
  1271.      In xoperands, elements 1 and 0 are the input and output vectors.
  1272.      Element 2 is the loop index.  Element 5 is the increment.  */
  1273.  
  1274.   if (align == 1)
  1275.     {
  1276.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1277.       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
  1278.  
  1279.       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
  1280.  
  1281.       output_asm_insn ("adds %1,%2,%1", xoperands);
  1282.       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
  1283.       output_asm_insn ("ld.b 0(%1),r31", xoperands);
  1284.       output_asm_insn ("adds %5,%1,%1", xoperands);
  1285.       output_asm_insn ("st.b r31,0(%6)", xoperands);
  1286.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1287.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1288.     }
  1289.   if (align == 2)
  1290.     {
  1291.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1292.       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
  1293.  
  1294.       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
  1295.  
  1296.       output_asm_insn ("adds %1,%2,%1", xoperands);
  1297.       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
  1298.       output_asm_insn ("ld.s 0(%1),r31", xoperands);
  1299.       output_asm_insn ("adds %5,%1,%1", xoperands);
  1300.       output_asm_insn ("st.s r31,0(%6)", xoperands);
  1301.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1302.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1303.     }
  1304.   if (align == 4)
  1305.     {
  1306.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1307.       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
  1308.  
  1309.       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
  1310.  
  1311.       output_asm_insn ("adds %1,%2,%1", xoperands);
  1312.       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
  1313.       output_asm_insn ("ld.l 0(%1),r31", xoperands);
  1314.       output_asm_insn ("adds %5,%1,%1", xoperands);
  1315.       output_asm_insn ("st.l r31,0(%6)", xoperands);
  1316.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1317.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1318.     }
  1319.  
  1320.   return "";
  1321. }
  1322.  
  1323. /* Output a delayed branch insn with the delay insn in its
  1324.    branch slot.  The delayed branch insn template is in TEMPLATE,
  1325.    with operands OPERANDS.  The insn in its delay slot is INSN.
  1326.  
  1327.    As a special case, since we know that all memory transfers are via
  1328.    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
  1329.    reference around the branch as
  1330.  
  1331.     orh ha%x,r0,r31
  1332.     b ...
  1333.     ld/st l%x(r31),...
  1334.  
  1335.    As another special case, we handle loading (SYMBOL_REF ...) and
  1336.    other large constants around branches as well:
  1337.  
  1338.     orh h%x,r0,%0
  1339.     b ...
  1340.     or l%x,%0,%1
  1341.  
  1342.    */
  1343.  
  1344. char *
  1345. output_delayed_branch (template, operands, insn)
  1346.      char *template;
  1347.      rtx *operands;
  1348.      rtx insn;
  1349. {
  1350.   extern rtx recog_operand[];
  1351.   rtx src = XVECEXP (PATTERN (insn), 0, 1);
  1352.   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
  1353.  
  1354.   if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
  1355.       || (GET_CODE (src) == CONST_INT
  1356.       && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0)))
  1357.     {
  1358.       rtx xoperands[2];
  1359.       xoperands[0] = dest;
  1360.       xoperands[1] = src;
  1361.  
  1362.       /* Output the `orh' insn.  */
  1363.       output_asm_insn ("orh h%%%1,r0,%0", xoperands);
  1364.  
  1365.       /* Output the branch instruction next.  */
  1366.       output_asm_insn (template, operands);
  1367.  
  1368.       /* Now output the `or' insn.  */
  1369.       output_asm_insn ("or l%%%1,%0,%0", xoperands);
  1370.     }
  1371.   else if ((GET_CODE (src) == MEM
  1372.         && CONSTANT_ADDRESS_P (XEXP (src, 0)))
  1373.        || (GET_CODE (dest) == MEM
  1374.            && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
  1375.     {
  1376.       rtx xoperands[2];
  1377.       char *split_template;
  1378.       xoperands[0] = dest;
  1379.       xoperands[1] = src;
  1380.  
  1381.       /* Output the `orh' insn.  */
  1382.       if (GET_CODE (src) == MEM)
  1383.     {
  1384.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  1385.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  1386.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  1387.         output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
  1388.       split_template = load_opcode (GET_MODE (dest),
  1389.                     "l%%%m1(r31),%0", dest);
  1390.     }
  1391.       else
  1392.     {
  1393.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  1394.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  1395.          && cc_prev_status.mdep == XEXP (operands[0], 0)))
  1396.         output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
  1397.       split_template = store_opcode (GET_MODE (dest),
  1398.                      "%r1,l%%%m0(r31)", src);
  1399.     }
  1400.  
  1401.       /* Output the branch instruction next.  */
  1402.       output_asm_insn (template, operands);
  1403.  
  1404.       /* Now output the load or store.
  1405.      No need to do a CC_STATUS_INIT, because we are branching anyway.  */
  1406.       output_asm_insn (split_template, xoperands);
  1407.     }
  1408.   else
  1409.     {
  1410.       extern char *insn_template[];
  1411.       extern char *(*insn_outfun[])();
  1412.       extern int insn_n_operands[];
  1413.       extern rtx alter_subreg();
  1414.       int insn_code_number;
  1415.       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
  1416.       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
  1417.       int i;
  1418.  
  1419.       /* Output the branch instruction first.  */
  1420.       output_asm_insn (template, operands);
  1421.  
  1422.       /* Now recognize the insn which we put in its delay slot.
  1423.      We must do this after outputing the branch insn,
  1424.      since operands may just be a pointer to `recog_operand'.  */
  1425.       insn_code_number = recog (pat, delay_insn);
  1426.       if (insn_code_number == -1)
  1427.     abort ();
  1428.  
  1429.       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
  1430.     {
  1431.       if (GET_CODE (recog_operand[i]) == SUBREG)
  1432.         recog_operand[i] = alter_subreg (recog_operand[i]);
  1433.     }
  1434.  
  1435.       /* Now get the template for what this insn would
  1436.      have been, without the branch.  Its operands are
  1437.      exactly the same as they would be, so we don't
  1438.      need to do an insn_extract.  */
  1439.       template = insn_template[insn_code_number];
  1440.       if (template == 0)
  1441.     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
  1442.       output_asm_insn (template, recog_operand);
  1443.     }
  1444.   CC_STATUS_INIT;
  1445.   return "";
  1446. }
  1447.  
  1448. /* Output a newly constructed insn DELAY_INSN.  */
  1449. char *
  1450. output_delay_insn (delay_insn)
  1451.      rtx delay_insn;
  1452. {
  1453.   char *template;
  1454.   extern rtx recog_operand[];
  1455.   extern char call_used_regs[];
  1456.   extern char *insn_template[];
  1457.   extern int insn_n_operands[];
  1458.   extern char *(*insn_outfun[])();
  1459.   extern rtx alter_subreg();
  1460.   int insn_code_number;
  1461.   extern int insn_n_operands[];
  1462.   int i;
  1463.  
  1464.   /* Now recognize the insn which we put in its delay slot.
  1465.      We must do this after outputing the branch insn,
  1466.      since operands may just be a pointer to `recog_operand'.  */
  1467.   insn_code_number = recog_memoized (delay_insn);
  1468.   if (insn_code_number == -1)
  1469.     abort ();
  1470.  
  1471.   /* Extract the operands of this delay insn.  */
  1472.   INSN_CODE (delay_insn) = insn_code_number;
  1473.   insn_extract (delay_insn);
  1474.  
  1475.   /* It is possible that this insn has not been properly scaned by final
  1476.      yet.  If this insn's operands don't appear in the peephole's
  1477.      actual operands, then they won't be fixed up by final, so we
  1478.      make sure they get fixed up here.  -- This is a kludge.  */
  1479.   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
  1480.     {
  1481.       if (GET_CODE (recog_operand[i]) == SUBREG)
  1482.     recog_operand[i] = alter_subreg (recog_operand[i]);
  1483.     }
  1484.  
  1485. #ifdef REGISTER_CONSTRAINTS
  1486.   if (! constrain_operands (insn_code_number))
  1487.     abort ();
  1488. #endif
  1489.  
  1490.   cc_prev_status = cc_status;
  1491.  
  1492.   /* Update `cc_status' for this instruction.
  1493.      The instruction's output routine may change it further.
  1494.      If the output routine for a jump insn needs to depend
  1495.      on the cc status, it should look at cc_prev_status.  */
  1496.  
  1497.   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
  1498.  
  1499.   /* Now get the template for what this insn would
  1500.      have been, without the branch.  */
  1501.  
  1502.   template = insn_template[insn_code_number];
  1503.   if (template == 0)
  1504.     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
  1505.   output_asm_insn (template, recog_operand);
  1506.   return "";
  1507. }
  1508.