OSDN Git Service

x
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 1026f0d..cacbf1f 100644 (file)
@@ -719,6 +719,151 @@ move_operand (op, mode)
          && ! (mips_split_addresses && mips_check_split (op, mode)));
 }
 
+/* Return true if OPERAND is valid as a source operand for movdi.
+   This accepts not only general_operand, but also sign extended
+   constants and registers.  We need to accept sign extended constants
+   in case a sign extended register which is used in an expression,
+   and is equivalent to a constant, is spilled.  */
+
+int
+movdi_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && (GET_MODE (XEXP (op, 0)) == SImode
+         || (GET_CODE (XEXP (op, 0)) == CONST_INT
+             && GET_MODE (XEXP (op, 0)) == VOIDmode))
+      && (register_operand (XEXP (op, 0), SImode)
+         || immediate_operand (XEXP (op, 0), SImode)))
+    return 1;
+
+  return general_operand (op, mode);
+}
+
+/* Like register_operand, but when in 64 bit mode also accept a sign
+   extend of a 32 bit register, since the value is known to be already
+   sign extended.  */
+
+int
+se_register_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return register_operand (op, mode);
+}
+
+/* Like reg_or_0_operand, but when in 64 bit mode also accept a sign
+   extend of a 32 bit register, since the value is known to be already
+   sign extended.  */
+
+int
+se_reg_or_0_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return reg_or_0_operand (op, mode);
+}
+
+/* Like uns_arith_operand, but when in 64 bit mode also accept a sign
+   extend of a 32 bit register, since the value is known to be already
+   sign extended.  */
+
+int
+se_uns_arith_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return uns_arith_operand (op, mode);
+}
+
+/* Like arith_operand, but when in 64 bit mode also accept a sign
+   extend of a 32 bit register, since the value is known to be already
+   sign extended.  */
+
+int
+se_arith_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return arith_operand (op, mode);
+}
+
+/* Like nonmemory_operand, but when in 64 bit mode also accept a sign
+   extend of a 32 bit register, since the value is known to be already
+   sign extended.  */
+
+int
+se_nonmemory_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return nonmemory_operand (op, mode);
+}
+
+/* Like nonimmediate_operand, but when in 64 bit mode also accept a
+   sign extend of a 32 bit register, since the value is known to be
+   already sign extended.  */
+
+int
+se_nonimmediate_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (TARGET_64BIT
+      && mode == DImode
+      && GET_CODE (op) == SIGN_EXTEND
+      && GET_MODE (op) == DImode
+      && GET_MODE (XEXP (op, 0)) == SImode
+      && register_operand (XEXP (op, 0), SImode))
+    return 1;
+
+  return nonimmediate_operand (op, mode);
+}
+
 /* Return true if we split the address into high and low parts.  */
 
 /* ??? We should also handle reg+array somewhere.  We get four
@@ -1382,6 +1527,12 @@ mips_move_2words (operands, insn)
       code0 = GET_CODE (op0);
     }
 
+  if (code1 == SIGN_EXTEND)
+    {
+      op1 = XEXP (op1, 0);
+      code1 = GET_CODE (op1);
+    }
+
   while (code1 == SUBREG)
     {
       subreg_word1 += SUBREG_WORD (op1);
@@ -1389,6 +1540,12 @@ mips_move_2words (operands, insn)
       code1 = GET_CODE (op1);
     }
       
+  /* Sanity check.  */
+  if (GET_CODE (operands[1]) == SIGN_EXTEND
+      && code1 != REG
+      && code1 != CONST_INT)
+    abort ();
+
   if (code0 == REG)
     {
       int regno0 = REGNO (op0) + subreg_word0;
@@ -1567,7 +1724,9 @@ mips_move_2words (operands, insn)
        {
          if (TARGET_64BIT)
            {
-             if (HOST_BITS_PER_WIDE_INT < 64)
+             if (GET_CODE (operands[1]) == SIGN_EXTEND)
+               ret = "li\t%0,%1\t\t# %X1";
+             else if (HOST_BITS_PER_WIDE_INT < 64)
                /* We can't use 'X' for negative numbers, because then we won't
                   get the right value for the upper 32 bits.  */
                ret = ((INTVAL (op1) < 0) ? "dli\t%0,%1\t\t\t# %X1"
@@ -3862,6 +4021,13 @@ print_operand (file, op, letter)
     }
 
   code = GET_CODE (op);
+
+  if (code == SIGN_EXTEND)
+    {
+      op = XEXP (op, 0);
+      code = GET_CODE (op);
+    }
+
   if (letter == 'C')
     switch (code)
       {
@@ -3919,9 +4085,14 @@ print_operand (file, op, letter)
        fprintf (file, "%s,", reg_names[regnum]);
     }
 
-  else if (code == REG)
+  else if (code == REG || code == SUBREG)
     {
-      register int regnum = REGNO (op);
+      register int regnum;
+
+      if (code == REG)
+       regnum = REGNO (op);
+      else
+       regnum = true_regnum (op);
 
       if ((letter == 'M' && ! WORDS_BIG_ENDIAN)
          || (letter == 'L' && WORDS_BIG_ENDIAN)
@@ -4769,7 +4940,7 @@ compute_frame_size (size)
                              + gp_reg_rounded + fp_reg_size
                              - fp_inc * UNITS_PER_FPREG);
       current_frame_info.fp_sp_offset = offset;
-      current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
+      current_frame_info.fp_save_offset = offset - total_size;
     }
   else
     {
@@ -4895,7 +5066,10 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                                                  GEN_INT (gp_offset - base_offset)));
 
                  if (store_p)
-                   emit_move_insn (mem_rtx, reg_rtx);
+                   {
+                     rtx insn = emit_move_insn (mem_rtx, reg_rtx);
+                     RTX_FRAME_RELATED_P (insn) = 1;
+                   }
                  else if (!TARGET_ABICALLS || mips_abi != ABI_32
                           || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
                    emit_move_insn (reg_rtx, mem_rtx);
@@ -5008,7 +5182,10 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                                                  GEN_INT (fp_offset - base_offset)));
 
                  if (store_p)
-                   emit_move_insn (mem_rtx, reg_rtx);
+                   {
+                     rtx insn = emit_move_insn (mem_rtx, reg_rtx);
+                     RTX_FRAME_RELATED_P (insn) = 1;
+                   }
                  else
                    emit_move_insn (reg_rtx, mem_rtx);
                }
@@ -5234,6 +5411,8 @@ mips_expand_prologue ()
       /* If we are doing svr4-abi, sp move is done by function_prologue.  */
       if (!TARGET_ABICALLS || mips_abi != ABI_32)
        {
+         rtx insn;
+
          if (tsize > 32767)
            {
              tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
@@ -5242,21 +5421,27 @@ mips_expand_prologue ()
            }
 
          if (TARGET_LONG64)
-           emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                  tsize_rtx));
+           insn = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                         tsize_rtx));
          else
-           emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                  tsize_rtx));
+           insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                         tsize_rtx));
+
+         RTX_FRAME_RELATED_P (insn) = 1;
        }
 
       save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0);
 
       if (frame_pointer_needed)
        {
+         rtx insn;
+
          if (TARGET_64BIT)
-           emit_insn (gen_movdi (frame_pointer_rtx, stack_pointer_rtx));
+           insn= emit_insn (gen_movdi (frame_pointer_rtx, stack_pointer_rtx));
          else
-           emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+           insn= emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+
+         RTX_FRAME_RELATED_P (insn) = 1;
        }
 
       if (TARGET_ABICALLS && mips_abi != ABI_32)
@@ -5832,7 +6017,28 @@ mips_secondary_reload_class (class, mode, x, in_p)
 {
   int regno = -1;
 
-  if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+  if (GET_CODE (x) == SIGN_EXTEND)
+    {
+      int off = 0;
+
+      x = XEXP (x, 0);
+
+      /* We may be called with reg_renumber NULL from regclass.
+        ??? This is probably a bug.  */
+      if (reg_renumber)
+       regno = true_regnum (x);
+      else
+       {
+         while (GET_CODE (x) == SUBREG)
+           {
+             off += SUBREG_WORD (x);
+             x = SUBREG_REG (x);
+           }
+         if (GET_CODE (x) == REG)
+           regno = REGNO (x) + off;
+       }
+    }
+  else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
     regno = true_regnum (x);
 
   /* We always require a general register when copying anything to