OSDN Git Service

Fix mips64vr4100-elf build failure.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 442c740..854b989 100644 (file)
@@ -35,12 +35,12 @@ Boston, MA 02111-1307, USA.  */
    is the kind of rtx's they make and what arguments they use.  */
 
 #include "config.h"
-#include <stdio.h>
 #ifdef __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
+#include "system.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -53,6 +53,7 @@ Boston, MA 02111-1307, USA.  */
 #include "recog.h"
 #include "real.h"
 #include "obstack.h"
+#include "bitmap.h"
 
 /* Commonly used modes.  */
 
@@ -384,6 +385,14 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
              XVEC (rt_val, i) = va_arg (p, rtvec);
              break;
 
+           case 'b':           /* A bitmap? */
+             XBITMAP (rt_val, i) = va_arg (p, bitmap);
+             break;
+
+           case 't':           /* A tree? */
+             XTREE (rt_val, i) = va_arg (p, tree);
+             break;
+
            default:
              abort ();
            }
@@ -652,6 +661,17 @@ gen_lowpart_common (mode, x)
            : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word));
   else if (GET_CODE (x) == REG)
     {
+      /* Let the backend decide how many registers to skip.  This is needed
+         in particular for Sparc64 where fp regs are smaller than a word.  */
+      /* ??? Note that subregs are now ambiguous, in that those against
+        pseudos are sized by the Word Size, while those against hard
+        regs are sized by the underlying register size.  Better would be
+        to always interpret the subreg offset parameter as bytes or bits.  */
+
+      if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER)
+       word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
+               - HARD_REGNO_NREGS (REGNO (x), mode));
+
       /* If the register is not valid for MODE, return 0.  If we don't
         do this, there is no way to fix up the resulting REG later.  
         But we do do this if the current REG is not valid for its
@@ -709,14 +729,13 @@ gen_lowpart_common (mode, x)
                : GEN_INT (CONST_DOUBLE_LOW (x)));
       else
        {
-         /* MODE must be narrower than HOST_BITS_PER_INT.  */
+         /* MODE must be narrower than HOST_BITS_PER_WIDE_INT.  */
          int width = GET_MODE_BITSIZE (mode);
          HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
                               : CONST_DOUBLE_LOW (x));
 
-         if (((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-              != ((HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((HOST_WIDE_INT) 1 << width) - 1;
+         /* Sign extend to HOST_WIDE_INT.  */
+         val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width);
 
          return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
                  : GEN_INT (val));
@@ -973,7 +992,11 @@ gen_highpart (mode, x)
       )
     return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
   else if (GET_CODE (x) == CONST_INT)
-    return const0_rtx;
+    {
+      if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD)
+       return const0_rtx;
+      return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD));
+    }
   else if (GET_CODE (x) == MEM)
     {
       register int offset = 0;
@@ -1000,20 +1023,25 @@ gen_highpart (mode, x)
     }
   else if (GET_CODE (x) == REG)
     {
-      int word = 0;
+      int word;
 
-      if (! WORDS_BIG_ENDIAN
-         && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+      /* Let the backend decide how many registers to skip.  This is needed
+         in particular for sparc64 where fp regs are smaller than a word.  */
+      /* ??? Note that subregs are now ambiguous, in that those against
+        pseudos are sized by the word size, while those against hard
+        regs are sized by the underlying register size.  Better would be
+        to always interpret the subreg offset parameter as bytes or bits.  */
+
+      if (WORDS_BIG_ENDIAN)
+       word = 0;
+      else if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+       word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
+               - HARD_REGNO_NREGS (REGNO (x), mode));
+      else
        word = ((GET_MODE_SIZE (GET_MODE (x))
                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
                / UNITS_PER_WORD);
 
-      /*
-       * ??? This fails miserably for complex values being passed in registers
-       * where the sizeof the real and imaginary part are not equal to the
-       * sizeof SImode.  FIXME
-       */
-
       if (REGNO (x) < FIRST_PSEUDO_REGISTER
          /* integrate.c can't handle parts of a return value register.  */
          && (! REG_FUNCTION_VALUE_P (x)
@@ -1081,6 +1109,7 @@ operand_subword (op, i, validate_address, mode)
 {
   HOST_WIDE_INT val;
   int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
+  int bits_per_word = BITS_PER_WORD;
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -1321,11 +1350,30 @@ operand_subword (op, i, validate_address, mode)
         : (GET_CODE (op) == CONST_INT
            ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
 
-  /* If BITS_PER_WORD is smaller than an int, get the appropriate bits.  */
+  /* Get the value we want into the low bits of val.  */
   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
-    val = ((val >> ((i % size_ratio) * BITS_PER_WORD))
-          & (((HOST_WIDE_INT) 1
-              << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1));
+    val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
+
+  /* Clear the bits that don't belong in our mode, unless they and our sign
+     bit are all one.  So we get either a reasonable negative value or a
+     reasonable unsigned value for this mode.  */
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+      && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))
+          != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))))
+    val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1;
+
+  /* If this would be an entire word for the target, but is not for
+     the host, then sign-extend on the host so that the number will look
+     the same way on the host that it would on the target.
+
+     For example, when building a 64 bit alpha hosted 32 bit sparc
+     targeted compiler, then we want the 32 bit unsigned value -1 to be
+     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+     The later confuses the sparc backend.  */
+
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+      && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1))))
+    val |= ((HOST_WIDE_INT) (-1) << bits_per_word);
 
   return GEN_INT (val);
 }
@@ -1350,7 +1398,14 @@ operand_subword_force (op, i, mode)
     return result;
 
   if (mode != BLKmode && mode != VOIDmode)
-    op = force_reg (mode, op);
+    {
+      /* If this is a register which can not be accessed by words, copy it
+        to a pseudo register.  */
+      if (GET_CODE (op) == REG)
+       op = copy_to_reg (op);
+      else
+       op = force_reg (mode, op);
+    }
 
   result = operand_subword (op, i, 1, mode);
   if (result == 0)
@@ -3112,7 +3167,7 @@ push_to_sequence (first)
 void
 push_topmost_sequence ()
 {
-  struct sequence_stack *stack, *top;
+  struct sequence_stack *stack, *top = NULL;
 
   start_sequence ();
 
@@ -3130,7 +3185,7 @@ push_topmost_sequence ()
 void
 pop_topmost_sequence ()
 {
-  struct sequence_stack *stack, *top;
+  struct sequence_stack *stack, *top = NULL;
 
   for (stack = sequence_stack; stack; stack = stack->next)
     top = stack;