home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gcc-2.7.2.1-base.tgz / gcc-2.7.2.1-base.tar / fsf / gcc / config / pdp11 / pdp11.c < prev    next >
C/C++ Source or Header  |  1995-07-29  |  35KB  |  1,427 lines

  1. /* Subroutines for gcc2 for pdp11.
  2.    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
  3.    Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
  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, 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.  */
  21.  
  22. #ifndef FILE
  23. #include <stdio.h>
  24. #endif
  25. #include "config.h"
  26. #include "rtl.h"
  27. #include "regs.h"
  28. #include "hard-reg-set.h"
  29. #include "real.h"
  30. #include "insn-config.h"
  31. #include "conditions.h"
  32. #include "insn-flags.h"
  33. #include "output.h"
  34. #include "insn-attr.h"
  35.  
  36. /*
  37. #define FPU_REG_P(X)    ((X)>=8 && (X)<14)
  38. #define CPU_REG_P(X)    ((X)>=0 && (X)<8)
  39. */
  40.  
  41. /* this is the current value returned by the macro FIRST_PARM_OFFSET 
  42.    defined in tm.h */
  43. int current_first_parm_offset;
  44.  
  45. /* This is where the condition code register lives.  */
  46. /* rtx cc0_reg_rtx; - no longer needed? */
  47.  
  48. static rtx find_addr_reg (); 
  49.  
  50. /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
  51.  
  52. int
  53. arith_operand (op, mode)
  54.      rtx op;
  55.      enum machine_mode mode;
  56. {
  57.   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
  58. }
  59.  
  60. int
  61. const_immediate_operand (op, mode)
  62.      rtx op;
  63.      enum machine_mode mode;
  64. {
  65.   return (GET_CODE (op) == CONST_INT);
  66. }
  67.  
  68. int 
  69. immediate15_operand (op, mode)
  70.      rtx op;
  71.      enum machine_mode mode;
  72. {
  73.     return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
  74. }
  75.  
  76. int
  77. expand_shift_operand (op, mode)
  78.   rtx op;
  79.   enum machine_mode mode;
  80. {
  81.     return (GET_CODE (op) == CONST_INT 
  82.         && abs (INTVAL(op)) > 1 
  83.         && abs (INTVAL(op)) <= 4);
  84. }
  85.  
  86. /*
  87.    stream is a stdio stream to output the code to.
  88.    size is an int: how many units of temporary storage to allocate.
  89.    Refer to the array `regs_ever_live' to determine which registers
  90.    to save; `regs_ever_live[I]' is nonzero if register number I
  91.    is ever used in the function.  This macro is responsible for
  92.    knowing which registers should not be saved even if used.  
  93. */
  94.  
  95. void 
  96. output_function_prologue(stream, size)
  97.   FILE *stream;
  98.   int size;
  99. {                                   
  100.     extern char call_used_regs[];                    
  101.     extern int frame_pointer_needed;                
  102.  
  103.     int fsize = ((size) + 1) & ~1;                      
  104.     int regno, nregs, i;                        
  105.     int offset = 0;
  106.  
  107.     int via_ac = -1;
  108.     
  109.     fprintf (stream, "\n\t;    /* function prologue %s*/\n", current_function_name);        
  110.  
  111.     /* if we are outputting code for main, 
  112.        the switch FPU to right mode if TARGET_FPU */
  113.     if ( (strcmp ("main", current_function_name) == 0)
  114.      && TARGET_FPU)
  115.     {
  116.     fprintf(stream, "\t;/* switch cpu to double float, single integer */\n");
  117.     fprintf(stream, "\tsetd\n");
  118.     fprintf(stream, "\tseti\n\n");
  119.     }
  120.     
  121.     if (frame_pointer_needed)                     
  122.     {                                
  123.     fprintf(stream, "\tmov fp, -(sp)\n");            
  124.     fprintf(stream, "\tmov sp, fp\n");                
  125.     }                                
  126.     else                                 
  127.     {                                
  128.     /* DON'T SAVE FP */
  129.     }                                
  130.  
  131.     /* make frame */
  132.     if (fsize)                            
  133.     fprintf (stream, "\tsub $%d, sp\n", fsize);            
  134.  
  135.     /* save CPU registers  */
  136.     for (regno = 0; regno < 8; regno++)                
  137.     if (regs_ever_live[regno] && ! call_used_regs[regno])    
  138.         if (! ((regno == FRAME_POINTER_REGNUM)            
  139.            && frame_pointer_needed))                
  140.         fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);    
  141.     /* fpu regs saving */
  142.     
  143.     /* via_ac specifies the ac to use for saving ac4, ac5 */
  144.     via_ac = -1;
  145.     
  146.     for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 
  147.     {
  148.     /* ac0 - ac3 */                        
  149.     if (LOAD_FPU_REG_P(regno)
  150.         && regs_ever_live[regno] 
  151.         && ! call_used_regs[regno])
  152.     {
  153.         fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
  154.         via_ac = regno;
  155.     }
  156.     
  157.     /* maybe make ac4, ac5 call used regs?? */
  158.     /* ac4 - ac5 */
  159.     if (NO_LOAD_FPU_REG_P(regno)
  160.         && regs_ever_live[regno]
  161.         && ! call_used_regs[regno])
  162.     {
  163.         if (via_ac == -1)
  164.         abort();
  165.         
  166.         fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
  167.         fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
  168.     }
  169.     }
  170.  
  171.     fprintf (stream, "\t;/* end of prologue */\n\n");        
  172. }
  173.  
  174. /*
  175.    The function epilogue should not depend on the current stack pointer!
  176.    It should use the frame pointer only.  This is mandatory because
  177.    of alloca; we also take advantage of it to omit stack adjustments
  178.    before returning.  */
  179.  
  180. /* maybe we can make leaf functions faster by switching to the
  181.    second register file - this way we don't have to save regs!
  182.    leaf functions are ~ 50% of all functions (dynamically!) 
  183.  
  184.    set/clear bit 11 (dec. 2048) of status word for switching register files - 
  185.    but how can we do this? the pdp11/45 manual says bit may only 
  186.    be set (p.24), but not cleared!
  187.  
  188.    switching to kernel is probably more expensive, so we'll leave it 
  189.    like this and not use the second set of registers... 
  190.  
  191.    maybe as option if you want to generate code for kernel mode? */
  192.  
  193.  
  194. void 
  195. output_function_epilogue(stream, size)
  196.   FILE *stream;
  197.   int size;
  198. {                                
  199.     extern char call_used_regs[];                    
  200.     extern int may_call_alloca;
  201.  
  202.     int fsize = ((size) + 1) & ~1;                      
  203.     int nregs, regno, i, j, k, adjust_fp;                
  204.  
  205.     int via_ac;
  206.     
  207.     fprintf (stream, "\n\t;    /*function epilogue */\n");        
  208.  
  209.     if (frame_pointer_needed)                    
  210.     {                                
  211.     /* hope this is safe - m68k does it also .... */        
  212.     regs_ever_live[FRAME_POINTER_REGNUM] = 0;            
  213.                                 
  214.     for (i =7, j = 0 ; i >= 0 ; i--)                
  215.         if (regs_ever_live[i] && ! call_used_regs[i])        
  216.         j++;
  217.     
  218.     /* remember # of pushed bytes for CPU regs */
  219.     k = 2*j;
  220.     
  221.     for (i =7 ; i >= 0 ; i--)                    
  222.         if (regs_ever_live[i] && ! call_used_regs[i])        
  223.         fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
  224.  
  225.     /* get ACs */                        
  226.     via_ac = FIRST_PSEUDO_REGISTER -1;
  227.     
  228.     for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
  229.         if (regs_ever_live[i] && ! call_used_regs[i])
  230.         {
  231.         via_ac = i;
  232.         k += 8;
  233.         }
  234.     
  235.     for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
  236.     {
  237.         if (LOAD_FPU_REG_P(i)
  238.         && regs_ever_live[i]
  239.         && ! call_used_regs[i])
  240.         {
  241.         fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
  242.         k -= 8;
  243.         }
  244.         
  245.         if (NO_LOAD_FPU_REG_P(i)
  246.         && regs_ever_live[i]
  247.         && ! call_used_regs[i])
  248.         {
  249.         if (! LOAD_FPU_REG_P(via_ac))
  250.             abort();
  251.             
  252.         fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
  253.         fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
  254.         k -= 8;
  255.         }
  256.     }
  257.     
  258.     fprintf(stream, "\tmov fp, sp\n");                
  259.     fprintf (stream, "\tmov (sp)+, fp\n");                 
  260.     }                                
  261.     else                                
  262.     {           
  263.     via_ac = FIRST_PSEUDO_REGISTER -1;
  264.     
  265.     /* get ACs */
  266.     for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
  267.         if (regs_ever_live[i] && call_used_regs[i])
  268.         via_ac = i;
  269.     
  270.     for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
  271.     {
  272.         if (LOAD_FPU_REG_P(i)
  273.         && regs_ever_live[i]
  274.         && ! call_used_regs[i])
  275.           fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
  276.         
  277.         if (NO_LOAD_FPU_REG_P(i)
  278.         && regs_ever_live[i]
  279.         && ! call_used_regs[i])
  280.         {
  281.         if (! LOAD_FPU_REG_P(via_ac))
  282.             abort();
  283.             
  284.         fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
  285.         fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
  286.         }
  287.     }
  288.  
  289.     for (i=7; i >= 0; i--)                    
  290.         if (regs_ever_live[i] && !call_used_regs[i])        
  291.         fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);    
  292.                                 
  293.     if (fsize)                        
  294.         fprintf((stream), "\tadd $%d, sp\n", fsize);              
  295.     }            
  296.                     
  297.     fprintf (stream, "\trts pc\n");                    
  298.     fprintf (stream, "\t;/* end of epilogue*/\n\n\n");        
  299. }
  300.     
  301. /* Return the best assembler insn template
  302.    for moving operands[1] into operands[0] as a fullword.  */
  303. static char *
  304. singlemove_string (operands)
  305.      rtx *operands;
  306. {
  307.   if (operands[1] != const0_rtx)
  308.     return "mov %1,%0";
  309.  
  310.   return "clr %0";
  311. }
  312.  
  313.  
  314. /* Output assembler code to perform a doubleword move insn
  315.    with operands OPERANDS.  */
  316.  
  317. char *
  318. output_move_double (operands)
  319.      rtx *operands;
  320. {
  321.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  322.   rtx latehalf[2];
  323.   rtx addreg0 = 0, addreg1 = 0;
  324.  
  325.   /* First classify both operands.  */
  326.  
  327.   if (REG_P (operands[0]))
  328.     optype0 = REGOP;
  329.   else if (offsettable_memref_p (operands[0]))
  330.     optype0 = OFFSOP;
  331.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  332.     optype0 = POPOP;
  333.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  334.     optype0 = PUSHOP;
  335.   else if (GET_CODE (operands[0]) == MEM)
  336.     optype0 = MEMOP;
  337.   else
  338.     optype0 = RNDOP;
  339.  
  340.   if (REG_P (operands[1]))
  341.     optype1 = REGOP;
  342.   else if (CONSTANT_P (operands[1]))
  343. #if 0
  344.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  345. #endif
  346.     optype1 = CNSTOP;
  347.   else if (offsettable_memref_p (operands[1]))
  348.     optype1 = OFFSOP;
  349.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  350.     optype1 = POPOP;
  351.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  352.     optype1 = PUSHOP;
  353.   else if (GET_CODE (operands[1]) == MEM)
  354.     optype1 = MEMOP;
  355.   else
  356.     optype1 = RNDOP;
  357.  
  358.   /* Check for the cases that the operand constraints are not
  359.      supposed to allow to happen.  Abort if we get one,
  360.      because generating code for these cases is painful.  */
  361.  
  362.   if (optype0 == RNDOP || optype1 == RNDOP)
  363.     abort ();
  364.  
  365.   /* If one operand is decrementing and one is incrementing
  366.      decrement the former register explicitly
  367.      and change that operand into ordinary indexing.  */
  368.  
  369.   if (optype0 == PUSHOP && optype1 == POPOP)
  370.     {
  371.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  372.       output_asm_insn ("sub $4,%0", operands);
  373.       operands[0] = gen_rtx (MEM, SImode, operands[0]);
  374.       optype0 = OFFSOP;
  375.     }
  376.   if (optype0 == POPOP && optype1 == PUSHOP)
  377.     {
  378.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  379.       output_asm_insn ("sub $4,%1", operands);
  380.       operands[1] = gen_rtx (MEM, SImode, operands[1]);
  381.       optype1 = OFFSOP;
  382.     }
  383.  
  384.   /* If an operand is an unoffsettable memory ref, find a register
  385.      we can increment temporarily to make it refer to the second word.  */
  386.  
  387.   if (optype0 == MEMOP)
  388.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  389.  
  390.   if (optype1 == MEMOP)
  391.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  392.  
  393.   /* Ok, we can do one word at a time.
  394.      Normally we do the low-numbered word first,
  395.      but if either operand is autodecrementing then we
  396.      do the high-numbered word first.
  397.  
  398.      In either case, set up in LATEHALF the operands to use
  399.      for the high-numbered word and in some cases alter the
  400.      operands in OPERANDS to be suitable for the low-numbered word.  */
  401.  
  402.   if (optype0 == REGOP)
  403.     latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
  404.   else if (optype0 == OFFSOP)
  405.     latehalf[0] = adj_offsettable_operand (operands[0], 2);
  406.   else
  407.     latehalf[0] = operands[0];
  408.  
  409.   if (optype1 == REGOP)
  410.     latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
  411.   else if (optype1 == OFFSOP)
  412.     latehalf[1] = adj_offsettable_operand (operands[1], 2);
  413.   else if (optype1 == CNSTOP)
  414.     {
  415.     if (CONSTANT_P (operands[1]))
  416.     {
  417.         /* now the mess begins, high word is in lower word??? 
  418.  
  419.            that's what ashc makes me think, but I don't remember :-( */
  420.         latehalf[1] = gen_rtx(CONST_INT, VOIDmode, 
  421.                   INTVAL(operands[1])>>16);
  422.         operands[1] = gen_rtx(CONST_INT, VOIDmode,
  423.                   INTVAL(operands[1])&0xff);
  424.     }
  425.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  426.     {
  427.         /* immediate 32 bit values not allowed */
  428.         abort();
  429.     }
  430.     }
  431.   else
  432.     latehalf[1] = operands[1];
  433.  
  434.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  435.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  436.      for the low word as well, to compensate for the first decrement of sp.  */
  437.   if (optype0 == PUSHOP
  438.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  439.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  440.     operands[1] = latehalf[1];
  441.  
  442.   /* If one or both operands autodecrementing,
  443.      do the two words, high-numbered first.  */
  444.  
  445.   /* Likewise,  the first move would clobber the source of the second one,
  446.      do them in the other order.  This happens only for registers;
  447.      such overlap can't happen in memory unless the user explicitly
  448.      sets it up, and that is an undefined circumstance.  */
  449.  
  450.   if (optype0 == PUSHOP || optype1 == PUSHOP
  451.       || (optype0 == REGOP && optype1 == REGOP
  452.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  453.     {
  454.       /* Make any unoffsettable addresses point at high-numbered word.  */
  455.       if (addreg0)
  456.     output_asm_insn ("add $2,%0", &addreg0);
  457.       if (addreg1)
  458.     output_asm_insn ("add $2,%0", &addreg1);
  459.  
  460.       /* Do that word.  */
  461.       output_asm_insn (singlemove_string (latehalf), latehalf);
  462.  
  463.       /* Undo the adds we just did.  */
  464.       if (addreg0)
  465.     output_asm_insn ("sub $2,%0", &addreg0);
  466.       if (addreg1)
  467.     output_asm_insn ("sub $2,%0", &addreg1);
  468.  
  469.       /* Do low-numbered word.  */
  470.       return singlemove_string (operands);
  471.     }
  472.  
  473.   /* Normal case: do the two words, low-numbered first.  */
  474.  
  475.   output_asm_insn (singlemove_string (operands), operands);
  476.  
  477.   /* Make any unoffsettable addresses point at high-numbered word.  */
  478.   if (addreg0)
  479.     output_asm_insn ("add $2,%0", &addreg0);
  480.   if (addreg1)
  481.     output_asm_insn ("add $2,%0", &addreg1);
  482.  
  483.   /* Do that word.  */
  484.   output_asm_insn (singlemove_string (latehalf), latehalf);
  485.  
  486.   /* Undo the adds we just did.  */
  487.   if (addreg0)
  488.     output_asm_insn ("sub $2,%0", &addreg0);
  489.   if (addreg1)
  490.     output_asm_insn ("sub $2,%0", &addreg1);
  491.  
  492.   return "";
  493. }
  494. /* Output assembler code to perform a quadword move insn
  495.    with operands OPERANDS.  */
  496.  
  497. char *
  498. output_move_quad (operands)
  499.      rtx *operands;
  500. {
  501.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  502.   rtx latehalf[2];
  503.   rtx addreg0 = 0, addreg1 = 0;
  504.  
  505.   output_asm_insn(";; movdi/df: %1 -> %0", operands);
  506.   
  507.   if (REG_P (operands[0]))
  508.     optype0 = REGOP;
  509.   else if (offsettable_memref_p (operands[0]))
  510.     optype0 = OFFSOP;
  511.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  512.     optype0 = POPOP;
  513.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  514.     optype0 = PUSHOP;
  515.   else if (GET_CODE (operands[0]) == MEM)
  516.     optype0 = MEMOP;
  517.   else
  518.     optype0 = RNDOP;
  519.  
  520.   if (REG_P (operands[1]))
  521.     optype1 = REGOP;
  522.   else if (CONSTANT_P (operands[1])
  523.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  524.     optype1 = CNSTOP;
  525.   else if (offsettable_memref_p (operands[1]))
  526.     optype1 = OFFSOP;
  527.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  528.     optype1 = POPOP;
  529.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  530.     optype1 = PUSHOP;
  531.   else if (GET_CODE (operands[1]) == MEM)
  532.     optype1 = MEMOP;
  533.   else
  534.     optype1 = RNDOP;
  535.  
  536.   /* Check for the cases that the operand constraints are not
  537.      supposed to allow to happen.  Abort if we get one,
  538.      because generating code for these cases is painful.  */
  539.  
  540.   if (optype0 == RNDOP || optype1 == RNDOP)
  541.     abort ();
  542.   
  543.   /* check if we move a CPU reg to an FPU reg, or vice versa! */
  544.   if (optype0 == REGOP && optype1 == REGOP)
  545.       /* bogus - 64 bit cannot reside in CPU! */
  546.       if (CPU_REG_P(REGNO(operands[0]))
  547.       || CPU_REG_P (REGNO(operands[1])))
  548.       abort();
  549.   
  550.   if (optype0 == REGOP || optype1 == REGOP)
  551.   {
  552.       /* check for use of clrd???? 
  553.          if you ever allow ac4 and ac5 (now we require secondary load) 
  554.      you must check whether 
  555.      you want to load into them or store from them - 
  556.      then dump ac0 into $help$ movce ac4/5 to ac0, do the 
  557.      store from ac0, and restore ac0 - if you can find 
  558.      an unused ac[0-3], use that and you save a store and a load!*/
  559.  
  560.       if (FPU_REG_P(REGNO(operands[0])))
  561.       {
  562.       if (GET_CODE(operands[1]) == CONST_DOUBLE)
  563.       {
  564.           union { double d; int i[2]; } u;
  565.           u.i[0] = CONST_DOUBLE_LOW (operands[1]); 
  566.           u.i[1] = CONST_DOUBLE_HIGH (operands[1]); 
  567.           
  568.           if (u.d == 0.0)
  569.           return "clrd %0";
  570.       }
  571.           
  572.       return "ldd %1, %0";
  573.       }
  574.       
  575.       if (FPU_REG_P(REGNO(operands[1])))
  576.       return "std %1, %0";
  577.   }
  578.       
  579.   /* If one operand is decrementing and one is incrementing
  580.      decrement the former register explicitly
  581.      and change that operand into ordinary indexing.  */
  582.  
  583.   if (optype0 == PUSHOP && optype1 == POPOP)
  584.     {
  585.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  586.       output_asm_insn ("sub $8,%0", operands);
  587.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  588.       optype0 = OFFSOP;
  589.     }
  590.   if (optype0 == POPOP && optype1 == PUSHOP)
  591.     {
  592.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  593.       output_asm_insn ("sub $8,%1", operands);
  594.       operands[1] = gen_rtx (MEM, SImode, operands[1]);
  595.       optype1 = OFFSOP;
  596.     }
  597.  
  598.   /* If an operand is an unoffsettable memory ref, find a register
  599.      we can increment temporarily to make it refer to the second word.  */
  600.  
  601.   if (optype0 == MEMOP)
  602.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  603.  
  604.   if (optype1 == MEMOP)
  605.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  606.  
  607.   /* Ok, we can do one word at a time.
  608.      Normally we do the low-numbered word first,
  609.      but if either operand is autodecrementing then we
  610.      do the high-numbered word first.
  611.  
  612.      In either case, set up in LATEHALF the operands to use
  613.      for the high-numbered word and in some cases alter the
  614.      operands in OPERANDS to be suitable for the low-numbered word.  */
  615.  
  616.   if (optype0 == REGOP)
  617.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
  618.   else if (optype0 == OFFSOP)
  619.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  620.   else
  621.     latehalf[0] = operands[0];
  622.  
  623.   if (optype1 == REGOP)
  624.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
  625.   else if (optype1 == OFFSOP)
  626.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  627.   else if (optype1 == CNSTOP)
  628.     {
  629.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  630.     {
  631.         /* floats only. not yet supported!
  632.  
  633.          -- compute it into PDP float format, - internally,
  634.          just use IEEE and ignore possible problems ;-)
  635.  
  636.          we might get away with it !!!! */
  637.  
  638.         abort();
  639.         
  640. #ifndef HOST_WORDS_BIG_ENDIAN
  641.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  642.                  CONST_DOUBLE_LOW (operands[1]));
  643.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  644.                  CONST_DOUBLE_HIGH (operands[1]));
  645. #else /* HOST_WORDS_BIG_ENDIAN */
  646.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  647.                  CONST_DOUBLE_HIGH (operands[1]));
  648.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  649.                  CONST_DOUBLE_LOW (operands[1]));
  650. #endif /* HOST_WORDS_BIG_ENDIAN */
  651.     }
  652.       else if (GET_CODE(operands[1]) == CONST_INT)
  653.       {
  654.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 0);
  655.       }
  656.       else
  657.       abort();
  658.       
  659.     }
  660.   else
  661.     latehalf[1] = operands[1];
  662.  
  663.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  664.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  665.      for the low word as well, to compensate for the first decrement of sp.  */
  666.   if (optype0 == PUSHOP
  667.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  668.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  669.     operands[1] = latehalf[1];
  670.  
  671.   /* If one or both operands autodecrementing,
  672.      do the two words, high-numbered first.  */
  673.  
  674.   /* Likewise,  the first move would clobber the source of the second one,
  675.      do them in the other order.  This happens only for registers;
  676.      such overlap can't happen in memory unless the user explicitly
  677.      sets it up, and that is an undefined circumstance.  */
  678.  
  679.   if (optype0 == PUSHOP || optype1 == PUSHOP
  680.       || (optype0 == REGOP && optype1 == REGOP
  681.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  682.     {
  683.       /* Make any unoffsettable addresses point at high-numbered word.  */
  684.       if (addreg0)
  685.     output_asm_insn ("add $4,%0", &addreg0);
  686.       if (addreg1)
  687.     output_asm_insn ("add $4,%0", &addreg1);
  688.  
  689.       /* Do that word.  */
  690.       output_asm_insn(output_move_double(latehalf), latehalf);
  691.  
  692.       /* Undo the adds we just did.  */
  693.       if (addreg0)
  694.     output_asm_insn ("sub $4,%0", &addreg0);
  695.       if (addreg1)
  696.     output_asm_insn ("sub $4,%0", &addreg1);
  697.  
  698.       /* Do low-numbered word.  */
  699.       return output_move_double (operands);
  700.     }
  701.  
  702.   /* Normal case: do the two words, low-numbered first.  */
  703.  
  704.   output_asm_insn (output_move_double (operands), operands);
  705.  
  706.   /* Make any unoffsettable addresses point at high-numbered word.  */
  707.   if (addreg0)
  708.     output_asm_insn ("add $4,%0", &addreg0);
  709.   if (addreg1)
  710.     output_asm_insn ("add $4,%0", &addreg1);
  711.  
  712.   /* Do that word.  */
  713.   output_asm_insn (output_move_double (latehalf), latehalf);
  714.  
  715.   /* Undo the adds we just did.  */
  716.   if (addreg0)
  717.     output_asm_insn ("sub $4,%0", &addreg0);
  718.   if (addreg1)
  719.     output_asm_insn ("sub $4,%0", &addreg1);
  720.  
  721.   return "";
  722. }
  723.  
  724.  
  725. /* Return a REG that occurs in ADDR with coefficient 1.
  726.    ADDR can be effectively incremented by incrementing REG.  */
  727.  
  728. static rtx
  729. find_addr_reg (addr)
  730.      rtx addr;
  731. {
  732.   while (GET_CODE (addr) == PLUS)
  733.     {
  734.       if (GET_CODE (XEXP (addr, 0)) == REG)
  735.     addr = XEXP (addr, 0);
  736.       if (GET_CODE (XEXP (addr, 1)) == REG)
  737.     addr = XEXP (addr, 1);
  738.       if (CONSTANT_P (XEXP (addr, 0)))
  739.     addr = XEXP (addr, 1);
  740.       if (CONSTANT_P (XEXP (addr, 1)))
  741.     addr = XEXP (addr, 0);
  742.     }
  743.   if (GET_CODE (addr) == REG)
  744.     return addr;
  745.   return 0;
  746. }
  747.  
  748. /* Output an ascii string.  */
  749. output_ascii (file, p, size)
  750.      FILE *file;
  751.      char *p;
  752.      int size;
  753. {
  754.   int i;
  755.  
  756.   fprintf (file, "\t.byte \"");
  757.  
  758.   for (i = 0; i < size; i++)
  759.     {
  760.       register int c = p[i];
  761.       if (c == '\"' || c == '\\')
  762.     putc ('\\', file);
  763.       if (c >= ' ' && c < 0177)
  764.     putc (c, file);
  765.       else
  766.     {
  767.       fprintf (file, "\\%03o", c);
  768.       /* After an octal-escape, if a digit follows,
  769.          terminate one string constant and start another.
  770.          The Vax assembler fails to stop reading the escape
  771.          after three digits, so this is the only way we
  772.          can get it to parse the data properly.  */
  773.       if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
  774.         fprintf (file, "\"\n\tstring \"");
  775.     }
  776.     }
  777.   fprintf (file, "\"\n");
  778. }
  779.  
  780.  
  781. /* --- stole from out-vax, needs changes */
  782.  
  783. print_operand_address (file, addr)
  784.      FILE *file;
  785.      register rtx addr;
  786. {
  787.   register rtx reg1, reg2, breg, ireg;
  788.   rtx offset;
  789.  
  790.  retry:
  791.  
  792.   switch (GET_CODE (addr))
  793.     {
  794.     case MEM:
  795.       fprintf (file, "@");
  796.       addr = XEXP (addr, 0);
  797.       goto retry;
  798.  
  799.     case REG:
  800.       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
  801.       break;
  802.  
  803.     case PRE_DEC:
  804.       fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
  805.       break;
  806.  
  807.     case POST_INC:
  808.       fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
  809.       break;
  810.  
  811.     case PLUS:
  812.       reg1 = 0;    reg2 = 0;
  813.       ireg = 0;    breg = 0;
  814.       offset = 0;
  815.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  816.       || GET_CODE (XEXP (addr, 0)) == MEM)
  817.     {
  818.       offset = XEXP (addr, 0);
  819.       addr = XEXP (addr, 1);
  820.     }
  821.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  822.            || GET_CODE (XEXP (addr, 1)) == MEM)
  823.     {
  824.       offset = XEXP (addr, 1);
  825.       addr = XEXP (addr, 0);
  826.     }
  827.       if (GET_CODE (addr) != PLUS)
  828.     ;
  829.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  830.     {
  831.       reg1 = XEXP (addr, 0);
  832.       addr = XEXP (addr, 1);
  833.     }
  834.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  835.     {
  836.       reg1 = XEXP (addr, 1);
  837.       addr = XEXP (addr, 0);
  838.     }
  839.       else if (GET_CODE (XEXP (addr, 0)) == REG)
  840.     {
  841.       reg1 = XEXP (addr, 0);
  842.       addr = XEXP (addr, 1);
  843.     }
  844.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  845.     {
  846.       reg1 = XEXP (addr, 1);
  847.       addr = XEXP (addr, 0);
  848.     }
  849.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  850.     {
  851.       if (reg1 == 0)
  852.         reg1 = addr;
  853.       else
  854.         reg2 = addr;
  855.       addr = 0;
  856.     }
  857.       if (offset != 0)
  858.     {
  859.       if (addr != 0) abort ();
  860.       addr = offset;
  861.     }
  862.       if (reg1 != 0 && GET_CODE (reg1) == MULT)
  863.     {
  864.       breg = reg2;
  865.       ireg = reg1;
  866.     }
  867.       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
  868.     {
  869.       breg = reg1;
  870.       ireg = reg2;
  871.     }
  872.       else if (reg2 != 0 || GET_CODE (addr) == MEM)
  873.     {
  874.       breg = reg2;
  875.       ireg = reg1;
  876.     }
  877.       else
  878.     {
  879.       breg = reg1;
  880.       ireg = reg2;
  881.     }
  882.       if (addr != 0)
  883.     output_address (addr);
  884.       if (breg != 0)
  885.     {
  886.       if (GET_CODE (breg) != REG)
  887.         abort ();
  888.       fprintf (file, "(%s)", reg_names[REGNO (breg)]);
  889.     }
  890.       if (ireg != 0)
  891.     {
  892.       if (GET_CODE (ireg) == MULT)
  893.         ireg = XEXP (ireg, 0);
  894.       if (GET_CODE (ireg) != REG)
  895.         abort ();
  896.       abort();
  897.       fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
  898.     }
  899.       break;
  900.  
  901.     default:
  902.       output_addr_const (file, addr);
  903.     }
  904. }
  905.  
  906. /* register move costs, indexed by regs */
  907.  
  908. static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
  909. {
  910.              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
  911.  
  912. /* NO */     {  0,   0,   0,    0,    0,    0,   0},
  913. /* MUL */    {  0,   2,   2,   10,   22,   22,  22},
  914. /* GEN */    {  0,   2,   2,   10,   22,   22,  22},
  915. /* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
  916. /* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
  917. /* FPU */    {  0,  22,  22,    2,    2,    2,  22},
  918. /* ALL */    {  0,  22,  22,   10,   22,   22,  22}
  919. }  ;
  920.  
  921.  
  922. /* -- note that some moves are tremendously expensive, 
  923.    because they require lots of tricks! do we have to 
  924.    charge the costs incurred by secondary reload class 
  925.    -- as we do here with 22 -- or not ? */
  926.  
  927. int 
  928. register_move_cost(c1, c2)
  929.   enum reg_class c1, c2;
  930. {
  931.     return move_costs[(int)c1][(int)c2];
  932. }
  933.  
  934. char *
  935. output_jump(pos, neg, length)
  936.   int length;
  937.   char *pos, *neg;
  938. {
  939.     static int x = 0;
  940.     
  941.     static char buf[1000];
  942.  
  943. #if 0
  944. /* currently we don't need this, because the tstdf and cmpdf 
  945.    copy the condition code immediately, and other float operations are not 
  946.    yet recognized as changing the FCC - if so, then the length-cost of all
  947.    jump insns increases by one, because we have to potentially copy the 
  948.    FCC! */
  949.     if (cc_status.flags & CC_IN_FPU)
  950.     output_asm_insn("cfcc", NULL);
  951. #endif
  952.     
  953.     switch (length)
  954.     {
  955.       case 1:
  956.     
  957.     strcpy(buf, pos);
  958.     strcat(buf, " %l0");
  959.     
  960.     return buf;
  961.     
  962.       case 3:
  963.     
  964.     sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
  965.     
  966.     x++;
  967.     
  968.     return buf;
  969.     
  970.       default:
  971.     
  972.     abort();
  973.     }
  974.     
  975. }
  976.  
  977. void
  978. notice_update_cc_on_set(exp, insn)
  979.   rtx exp;
  980.   rtx insn;
  981. {
  982.     if (GET_CODE (SET_DEST (exp)) == CC0)
  983.     { 
  984.     cc_status.flags = 0;                    
  985.     cc_status.value1 = SET_DEST (exp);            
  986.     cc_status.value2 = SET_SRC (exp);            
  987.  
  988. /*
  989.     if (GET_MODE(SET_SRC(exp)) == DFmode)
  990.         cc_status.flags |= CC_IN_FPU;
  991. */    
  992.     }                            
  993.     else if ((GET_CODE (SET_DEST (exp)) == REG        
  994.           || GET_CODE (SET_DEST (exp)) == MEM)        
  995.          && GET_CODE (SET_SRC (exp)) != PC        
  996.          && (GET_MODE (SET_DEST(exp)) == HImode        
  997.          || GET_MODE (SET_DEST(exp)) == QImode)    
  998.         && (GET_CODE (SET_SRC(exp)) == PLUS        
  999.             || GET_CODE (SET_SRC(exp)) == MINUS    
  1000.             || GET_CODE (SET_SRC(exp)) == AND    
  1001.             || GET_CODE (SET_SRC(exp)) == IOR    
  1002.             || GET_CODE (SET_SRC(exp)) == XOR    
  1003.             || GET_CODE (SET_SRC(exp)) == NOT    
  1004.             || GET_CODE (SET_SRC(exp)) == NEG    
  1005.             || GET_CODE (SET_SRC(exp)) == REG    
  1006.             || GET_CODE (SET_SRC(exp)) == MEM))    
  1007.     { 
  1008.     cc_status.flags = 0;                    
  1009.     cc_status.value1 = SET_SRC (exp);               
  1010.     cc_status.value2 = SET_DEST (exp);            
  1011.     
  1012.     if (cc_status.value1 && GET_CODE (cc_status.value1) == REG    
  1013.         && cc_status.value2                    
  1014.         && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
  1015.             cc_status.value2 = 0;                    
  1016.     if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM    
  1017.         && cc_status.value2                    
  1018.         && GET_CODE (cc_status.value2) == MEM)            
  1019.         cc_status.value2 = 0;                     
  1020.     }                            
  1021.     else if (GET_CODE (SET_SRC (exp)) == CALL)        
  1022.     { 
  1023.     CC_STATUS_INIT; 
  1024.     }
  1025.     else if (GET_CODE (SET_DEST (exp)) == REG)               
  1026.     /* what's this ? */                    
  1027.     { 
  1028.     if ((cc_status.value1                    
  1029.          && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
  1030.         cc_status.value1 = 0;                
  1031.     if ((cc_status.value2                    
  1032.          && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
  1033.         cc_status.value2 = 0;                
  1034.     }                            
  1035.     else if (SET_DEST(exp) == pc_rtx)
  1036.     { 
  1037.     /* jump */
  1038.     }
  1039.     else /* if (GET_CODE (SET_DEST (exp)) == MEM)    */    
  1040.     {  
  1041.     /* the last else is a bit paranoiac, but since nearly all instructions 
  1042.        play with condition codes, it's reasonable! */
  1043.  
  1044.     CC_STATUS_INIT; /* paranoia*/ 
  1045.     }                
  1046. }
  1047.  
  1048.  
  1049. int simple_memory_operand(op, mode)
  1050.   rtx op;
  1051.   enum machine_mode mode;
  1052. {
  1053.     rtx addr, plus0, plus1;
  1054.     int offset = 0;
  1055.  
  1056.     /* Eliminate non-memory operations */
  1057.     if (GET_CODE (op) != MEM)
  1058.     return FALSE;
  1059.  
  1060. #if 0
  1061.     /* dword operations really put out 2 instructions, so eliminate them.  */
  1062.     if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
  1063.     return FALSE;
  1064. #endif
  1065.  
  1066.     /* Decode the address now.  */
  1067.  
  1068.   indirection:
  1069.     
  1070.     addr = XEXP (op, 0);
  1071.  
  1072.     switch (GET_CODE (addr))
  1073.     {
  1074.       case REG:
  1075.     /* (R0) - no extra cost */
  1076.     return 1;
  1077.     
  1078.       case PRE_DEC:
  1079.       case POST_INC:
  1080.     /* -(R0), (R0)+ - cheap! */
  1081.     return 0;
  1082.     
  1083.       case MEM:
  1084.     /* cheap - is encoded in addressing mode info! 
  1085.  
  1086.        -- except for @(R0), which has to be @0(R0) !!! */
  1087.  
  1088.     if (GET_CODE (XEXP (addr, 0)) == REG)
  1089.         return 0;
  1090.     
  1091.     op=addr;
  1092.     goto indirection;
  1093.     
  1094.       case CONST_INT:
  1095.       case LABEL_REF:           
  1096.       case CONST:
  1097.       case SYMBOL_REF:
  1098.     /* @#address - extra cost */
  1099.     return 0;
  1100.  
  1101.       case PLUS:
  1102.     /* X(R0) - extra cost */
  1103.     return 0;
  1104.     }
  1105.     
  1106.     return FALSE;
  1107. }
  1108.  
  1109.  
  1110. /*
  1111.  * output a block move:
  1112.  *
  1113.  * operands[0]    ... to
  1114.  * operands[1]  ... from
  1115.  * operands[2]  ... length
  1116.  * operands[3]  ... alignment
  1117.  * operands[4]  ... scratch register
  1118.  */
  1119.  
  1120.  
  1121. char *
  1122. output_block_move(operands)
  1123.   rtx *operands;
  1124. {
  1125.     static int count = 0;
  1126.     char buf[200];
  1127.     
  1128.     if (GET_CODE(operands[2]) == CONST_INT
  1129.     && TARGET_TIME)
  1130.     {
  1131.     if (INTVAL(operands[2]) < 16
  1132.         && INTVAL(operands[3]) == 1)
  1133.     {
  1134.         register int i;
  1135.         
  1136.         for (i = 1; i <= INTVAL(operands[2]); i++)
  1137.         output_asm_insn("movb (%1)+, (%0)+", operands);
  1138.  
  1139.         return "";
  1140.     }
  1141.     else if (INTVAL(operands[2]) < 32)
  1142.     {
  1143.         register int i;
  1144.         
  1145.         for (i = 1; i <= INTVAL(operands[2])/2; i++)
  1146.         output_asm_insn("mov (%1)+, (%0)+", operands);
  1147.         
  1148.         /* may I assume that moved quantity is 
  1149.            multiple of alignment ???
  1150.  
  1151.            I HOPE SO !
  1152.         */
  1153.  
  1154.         return "";
  1155.     }
  1156.     
  1157.  
  1158.     /* can do other clever things, maybe... */
  1159.     }
  1160.  
  1161.     if (CONSTANT_P(operands[2]) )
  1162.     {
  1163.     /* just move count to scratch */
  1164.     output_asm_insn("mov %2, %4", operands);
  1165.     }
  1166.     else
  1167.     {
  1168.     /* just clobber the register */
  1169.     operands[4] = operands[2];
  1170.     }
  1171.     
  1172.  
  1173.     /* switch over alignment */
  1174.     switch (INTVAL(operands[3]))
  1175.     {
  1176.       case 1:
  1177.     
  1178.     /* 
  1179.       x:
  1180.       movb (%1)+, (%0)+
  1181.       
  1182.       if (TARGET_45)
  1183.          sob %4,x
  1184.       else
  1185.          dec %4
  1186.          bgt x
  1187.  
  1188.     */
  1189.  
  1190.     sprintf(buf, "\nmovestrhi%d:", count);
  1191.     output_asm_insn(buf, NULL);
  1192.     
  1193.     output_asm_insn("movb (%1)+, (%0)+", operands);
  1194.     
  1195.     if (TARGET_45)
  1196.     {
  1197.         sprintf(buf, "sob %%4, movestrhi%d", count);
  1198.         output_asm_insn(buf, operands);
  1199.     }
  1200.     else
  1201.     {
  1202.         output_asm_insn("dec %4", operands);
  1203.         
  1204.         sprintf(buf, "bgt movestrhi%d", count);
  1205.         output_asm_insn(buf, NULL);
  1206.     }
  1207.     
  1208.     count ++;
  1209.     break;
  1210.     
  1211.       case 2:
  1212.     
  1213.     /* 
  1214.        asr %4
  1215.  
  1216.        x:
  1217.  
  1218.        mov (%1)+, (%0)+
  1219.  
  1220.        if (TARGET_45)
  1221.          sob %4, x
  1222.        else
  1223.          dec %4
  1224.          bgt x
  1225.     */
  1226.  
  1227.       generate_compact_code:
  1228.  
  1229.     output_asm_insn("asr %4", operands);
  1230.  
  1231.     sprintf(buf, "\nmovestrhi%d:", count);
  1232.     output_asm_insn(buf, NULL);
  1233.     
  1234.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1235.     
  1236.     if (TARGET_45)
  1237.     {
  1238.         sprintf(buf, "sob %%4, movestrhi%d", count);
  1239.         output_asm_insn(buf, operands);
  1240.     }
  1241.     else
  1242.     {
  1243.         output_asm_insn("dec %4", operands);
  1244.         
  1245.         sprintf(buf, "bgt movestrhi%d", count);
  1246.         output_asm_insn(buf, NULL);
  1247.     }
  1248.     
  1249.     count ++;
  1250.     break;
  1251.  
  1252.       case 4:
  1253.     
  1254.     /*
  1255.  
  1256.        asr %4
  1257.        asr %4
  1258.  
  1259.        x:
  1260.  
  1261.        mov (%1)+, (%0)+
  1262.        mov (%1)+, (%0)+
  1263.  
  1264.        if (TARGET_45)
  1265.          sob %4, x
  1266.        else
  1267.          dec %4
  1268.          bgt x
  1269.     */
  1270.  
  1271.     if (TARGET_SPACE)
  1272.         goto generate_compact_code;
  1273.     
  1274.     output_asm_insn("asr %4", operands);
  1275.     output_asm_insn("asr %4", operands);
  1276.  
  1277.     sprintf(buf, "\nmovestrhi%d:", count);
  1278.     output_asm_insn(buf, NULL);
  1279.     
  1280.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1281.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1282.     
  1283.     if (TARGET_45)
  1284.     {
  1285.         sprintf(buf, "sob %%4, movestrhi%d", count);
  1286.         output_asm_insn(buf, operands);
  1287.     }
  1288.     else
  1289.     {
  1290.         output_asm_insn("dec %4", operands);
  1291.         
  1292.         sprintf(buf, "bgt movestrhi%d", count);
  1293.         output_asm_insn(buf, NULL);
  1294.     }
  1295.     
  1296.     count ++;
  1297.     break;
  1298.        
  1299.       default:
  1300.     
  1301.     /*
  1302.        
  1303.        asr %4
  1304.        asr %4
  1305.        asr %4
  1306.  
  1307.        x:
  1308.  
  1309.        mov (%1)+, (%0)+
  1310.        mov (%1)+, (%0)+
  1311.        mov (%1)+, (%0)+
  1312.        mov (%1)+, (%0)+
  1313.        
  1314.        if (TARGET_45)
  1315.          sob %4, x
  1316.        else
  1317.          dec %4
  1318.          bgt x
  1319.     */
  1320.  
  1321.  
  1322.     if (TARGET_SPACE)
  1323.         goto generate_compact_code;
  1324.     
  1325.     output_asm_insn("asr %4", operands);
  1326.     output_asm_insn("asr %4", operands);
  1327.     output_asm_insn("asr %4", operands);
  1328.  
  1329.     sprintf(buf, "\nmovestrhi%d:", count);
  1330.     output_asm_insn(buf, NULL);
  1331.     
  1332.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1333.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1334.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1335.     output_asm_insn("mov (%1)+, (%0)+", operands);
  1336.     
  1337.     if (TARGET_45)
  1338.     {
  1339.         sprintf(buf, "sob %%4, movestrhi%d", count);
  1340.         output_asm_insn(buf, operands);
  1341.     }
  1342.     else
  1343.     {
  1344.         output_asm_insn("dec %4", operands);
  1345.         
  1346.         sprintf(buf, "bgt movestrhi%d", count);
  1347.         output_asm_insn(buf, NULL);
  1348.     }
  1349.     
  1350.     count ++;
  1351.     break;
  1352.     
  1353.     ;
  1354.     
  1355.     }
  1356.     
  1357.     return "";
  1358. }
  1359.  
  1360. /* for future use */
  1361. int
  1362. comparison_operator_index(op)
  1363.   rtx op;
  1364. {
  1365.     switch (GET_CODE(op))
  1366.     {
  1367.       case NE:
  1368.     return 0;
  1369.     
  1370.       case EQ:
  1371.     return 1;
  1372.     
  1373.       case GE:
  1374.     return 2;
  1375.     
  1376.       case GT:
  1377.     return 3;
  1378.     
  1379.       case LE:
  1380.     return 4;
  1381.     
  1382.       case LT:
  1383.     return 5;
  1384.     
  1385.       case GEU:
  1386.     return 6;
  1387.     
  1388.       case GTU:
  1389.     return 7;
  1390.  
  1391.       case LEU:
  1392.     return 8;
  1393.     
  1394.       case LTU:
  1395.     return 9;
  1396.     
  1397.       default:
  1398.     return -1;
  1399.     }
  1400. }    
  1401.     
  1402. /* tests whether the rtx is a comparison operator */
  1403. int
  1404. comp_operator (op, mode)
  1405.   rtx op;
  1406.   enum machine_mode mode;
  1407. {
  1408.     return comparison_operator_index(op) >= 0;
  1409. }
  1410.  
  1411.     
  1412. int
  1413. legitimate_address_p (mode, address)
  1414.   enum machine_mode mode;
  1415.   rtx address;
  1416. {
  1417. /* #define REG_OK_STRICT */
  1418.     GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
  1419.     
  1420.     return 0;
  1421.     
  1422.   win:
  1423.     return 1;
  1424.  
  1425. /* #undef REG_OK_STRICT */
  1426. }
  1427.