OSDN Git Service

*** empty log message ***
authorrms <rms@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 22 Mar 1992 02:54:46 +0000 (02:54 +0000)
committerrms <rms@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 22 Mar 1992 02:54:46 +0000 (02:54 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@561 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/sparc/sparc.c

index c2803ab..0979e80 100644 (file)
@@ -1059,16 +1059,13 @@ output_move_double (operands)
        op1 = operands[1], op2 = operands[0];
 
       /* Now see if we can trust the address to be 8-byte aligned.  */
-      /* Trust global variables.  */
+      /* Trust double-precision floats in global variables.  */
 
-      if (GET_CODE (op2) == LO_SUM)
+      if (GET_CODE (XEXP (op2, 0)) == LO_SUM && GET_MODE (op2) == DFmode)
        {
-         operands[0] = op1;
-         operands[1] = op2;
-
          if (final_sequence)
            abort ();
-         return "ldd %1,%0";
+         return (op1 == operands[0] ? "ldd %1,%0" : "std %1,%0");
        }
 
       if (GET_CODE (XEXP (op2, 0)) == PLUS)
@@ -1102,12 +1099,12 @@ output_move_double (operands)
               && GET_MODE (operands[1]) == DFmode
               && (CONSTANT_P (XEXP (operands[1], 0))
                   /* Let user ask for it anyway.  */
-                  || TARGET_ALIGN))
+                  || TARGET_HOPE_ALIGN))
        return "ldd %1,%0";
       else if (GET_CODE (operands[0]) == MEM
               && GET_MODE (operands[0]) == DFmode
               && (CONSTANT_P (XEXP (operands[0], 0))
-                  || TARGET_ALIGN))
+                  || TARGET_HOPE_ALIGN))
        return "std %1,%0";
     }
 
@@ -1183,7 +1180,7 @@ output_fp_move_double (operands)
       addr = XEXP (operands[1], 0);
 
       /* Use ldd if known to be aligned.  */
-      if (TARGET_ALIGN
+      if (TARGET_HOPE_ALIGN
          || (GET_CODE (addr) == PLUS
              && (((XEXP (addr, 0) == frame_pointer_rtx
                    || XEXP (addr, 0) == stack_pointer_rtx)
@@ -1215,7 +1212,7 @@ output_fp_move_double (operands)
       addr = XEXP (operands[0], 0);
 
       /* Use std if we can be sure it is well-aligned.  */
-      if (TARGET_ALIGN
+      if (TARGET_HOPE_ALIGN
          || (GET_CODE (addr) == PLUS
              && (((XEXP (addr, 0) == frame_pointer_rtx
                    || XEXP (addr, 0) == stack_pointer_rtx)
@@ -1433,111 +1430,101 @@ output_block_move (operands)
   xoperands[1] = operands[1];
   xoperands[2] = temp1;
 
-  /* We can't move more than this many bytes at a time
-     because we have only one register to move them through.  */
-  if (align > GET_MODE_SIZE (GET_MODE (temp1)))
+  /* We can't move more than this many bytes at a time because we have only
+     one register, %g1, to move them through.  */
+  if (align > UNITS_PER_WORD)
     {
-      align = GET_MODE_SIZE (GET_MODE (temp1));
-      alignrtx = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (temp1)));
+      align = UNITS_PER_WORD;
+      alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD);
     }
 
-  /* If the size isn't known to be a multiple of the alignment,
-     we have to do it in smaller pieces.  If we could determine that
-     the size was a multiple of 2 (or whatever), we could be smarter
-     about this.  */
-  if (GET_CODE (sizertx) != CONST_INT)
-    align = 1;
-  else
+  /* We consider 8 ld/st pairs, for a total of 16 inline insns to be
+     reasonable here.  (Actually will emit a maximum of 18 inline insns for
+     the case of size == 31 and align == 4).  */
+
+  if (GET_CODE (sizertx) == CONST_INT && (INTVAL (sizertx) / align) <= 8
+      && memory_address_p (QImode, plus_constant_for_output (xoperands[0],
+                                                            INTVAL (sizertx)))
+      && memory_address_p (QImode, plus_constant_for_output (xoperands[1],
+                                                            INTVAL (sizertx))))
     {
       int size = INTVAL (sizertx);
-      while (size % align)
-       align >>= 1;
-    }
+      int offset = 0;
 
-  if (align != INTVAL (alignrtx))
-    alignrtx = gen_rtx (CONST_INT, VOIDmode, align);
-
-  /* Recognize special cases of block moves.  These occur
-     when GNU C++ is forced to treat something as BLKmode
-     to keep it in memory, when its mode could be represented
-     with something smaller.
+      /* We will store different integers into this particular RTX.  */
+      xoperands[2] = rtx_alloc (CONST_INT);
+      PUT_MODE (xoperands[2], VOIDmode);
 
-     We cannot do this for global variables, since we don't know
-     what pages they don't cross.  Sigh.  */
-  if (GET_CODE (sizertx) == CONST_INT && INTVAL (sizertx) <= 16)
-    {
-      int size = INTVAL (sizertx);
+      /* This case is currently not handled.  Abort instead of generating
+        bad code.  */
+      if (align > 4)
+       abort ();
 
-      if (align == 1)
+      if (align >= 4)
        {
-         if (memory_address_p (QImode,
-                               plus_constant_for_output (xoperands[0], size))
-             && memory_address_p (QImode,
-                                  plus_constant_for_output (xoperands[1],
-                                                            size)))
+         for (i = (size >> 2) - 1; i >= 0; i--)
            {
-             /* We will store different integers into this particular RTX.  */
-             xoperands[2] = rtx_alloc (CONST_INT);
-             PUT_MODE (xoperands[2], VOIDmode);
-             for (i = size-1; i >= 0; i--)
-               {
-                 INTVAL (xoperands[2]) = i;
-                 output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
-                                  xoperands);
-               }
-             return "";
+             INTVAL (xoperands[2]) = (i << 2) + offset;
+             output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
+                              xoperands);
            }
+         offset += (size & ~0x3);
+         size = size & 0x3;
+         if (size == 0)
+           return "";
        }
-      else if (align == 2)
+
+      if (align >= 2)
        {
-         if (memory_address_p (HImode,
-                               plus_constant_for_output (xoperands[0], size))
-             && memory_address_p (HImode,
-                                  plus_constant_for_output (xoperands[1],
-                                                            size)))
+         for (i = (size >> 1) - 1; i >= 0; i--)
            {
-             /* We will store different integers into this particular RTX.  */
-             xoperands[2] = rtx_alloc (CONST_INT);
-             PUT_MODE (xoperands[2], VOIDmode);
-             for (i = (size>>1)-1; i >= 0; i--)
-               {
-                 INTVAL (xoperands[2]) = i<<1;
-                 output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
-                                  xoperands);
-               }
-             return "";
+             INTVAL (xoperands[2]) = (i << 1) + offset;
+             output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
+                              xoperands);
            }
+         offset += (size & ~0x1);
+         size = size & 0x1;
+         if (size == 0)
+           return "";
        }
-      else
+
+      if (align >= 1)
        {
-         if (memory_address_p (SImode,
-                               plus_constant_for_output (xoperands[0], size))
-             && memory_address_p (SImode,
-                                  plus_constant_for_output (xoperands[1],
-                                                            size)))
+         for (i = size - 1; i >= 0; i--)
            {
-             /* We will store different integers into this particular RTX.  */
-             xoperands[2] = rtx_alloc (CONST_INT);
-             PUT_MODE (xoperands[2], VOIDmode);
-             for (i = (size>>2)-1; i >= 0; i--)
-               {
-                 INTVAL (xoperands[2]) = i<<2;
-                 output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
-                                  xoperands);
-               }
-             return "";
+             INTVAL (xoperands[2]) = i + offset;
+             output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
+                              xoperands);
            }
+         return "";
        }
+
+      /* We should never reach here.  */
+      abort ();
+    }
+
+  /* If the size isn't known to be a multiple of the alignment,
+     we have to do it in smaller pieces.  If we could determine that
+     the size was a multiple of 2 (or whatever), we could be smarter
+     about this.  */
+  if (GET_CODE (sizertx) != CONST_INT)
+    align = 1;
+  else
+    {
+      int size = INTVAL (sizertx);
+      while (size % align)
+       align >>= 1;
     }
 
+  if (align != INTVAL (alignrtx))
+    alignrtx = gen_rtx (CONST_INT, VOIDmode, align);
+
   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
   xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
 
-  /* This is the size of the transfer.
-     Either use the register which already contains the size,
-     or use a free register (used by no operands).
-     Also emit code to decrement the size value by ALIGN.  */
+  /* This is the size of the transfer.  Emit code to decrement the size
+     value by ALIGN, and store the result in the temp1 register.  */
   output_size_for_block_move (sizertx, temp1, alignrtx);
 
   /* Must handle the case when the size is zero or negative, so the first thing