OSDN Git Service

2005-11-09 Andreas Krebbel <krebbel1@de.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / s390 / s390.c
index 445f4e1..75192e4 100644 (file)
@@ -1721,6 +1721,58 @@ s390_decompose_address (rtx addr, struct s390_address *out)
   return true;
 }
 
+/* Decompose a RTL expression OP for a shift count into its components,
+   and return the base register in BASE and the offset in OFFSET.
+
+   If BITS is non-zero, the expression is used in a context where only
+   that number to low-order bits is significant.  We then allow OP to
+   contain and outer AND that does not affect significant bits.  If BITS
+   is zero, we allow OP to contain any outer AND with a constant.
+
+   Return true if OP is a valid shift count, false if not.  */
+
+bool
+s390_decompose_shift_count (rtx op, rtx *base, HOST_WIDE_INT *offset, int bits)
+{
+  HOST_WIDE_INT off = 0;
+
+  /* Drop outer ANDs.  */
+  if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << bits) - 1;
+      if ((INTVAL (XEXP (op, 1)) & mask) != mask)
+       return false;
+
+      op = XEXP (op, 0);
+    }
+
+  /* We can have an integer constant, an address register,
+     or a sum of the two.  */
+  if (GET_CODE (op) == CONST_INT)
+    {
+      off = INTVAL (op);
+      op = NULL_RTX;
+    }
+  if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
+    {
+      off = INTVAL (XEXP (op, 1));
+      op = XEXP (op, 0);
+    }
+  while (op && GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  if (op && GET_CODE (op) != REG)
+    return false;
+
+  if (offset)
+    *offset = off;
+  if (base)
+    *base = op;
+
+   return true;
+}
+
+
 /* Return true if CODE is a valid address without index.  */
 
 bool
@@ -1851,7 +1903,11 @@ s390_extra_constraint_str (rtx op, int c, const char * str)
       break;
 
     case 'Y':
-      return shift_count_operand (op, VOIDmode);
+      /* Simply check for the basic form of a shift count.  Reload will
+        take care of making sure we have a proper base register.  */
+      if (!s390_decompose_shift_count (op, NULL, NULL, 0))
+       return 0;
+      break;
 
     default:
       return 0;
@@ -3815,6 +3871,101 @@ s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1,
   return false;
 }
 
+/* Expand code for the insv template. Return true if successful, false else.  */
+
+bool 
+s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
+{
+  int bitsize = INTVAL (op1);
+  int bitpos = INTVAL (op2);
+
+  /* We need byte alignment.  */
+  if (bitsize % BITS_PER_UNIT)
+    return false;
+
+  if (bitpos == 0
+      && memory_operand (dest, VOIDmode)
+      && (register_operand (src, word_mode)
+         || const_int_operand (src, VOIDmode)))
+    {
+      /* Emit standard pattern if possible.  */
+      enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT);
+      if (GET_MODE_BITSIZE (mode) == bitsize)
+       emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src));
+
+      /* (set (ze (mem)) (const_int)).  */
+      else if (const_int_operand (src, VOIDmode))
+       {
+         int size = bitsize / BITS_PER_UNIT;
+         rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode,
+                                       GET_MODE_SIZE (word_mode) - size);
+
+         dest = adjust_address (dest, BLKmode, 0);
+         set_mem_size (dest, GEN_INT (size));
+         s390_expand_movmem (dest, src_mem, GEN_INT (size));
+       }
+         
+      /* (set (ze (mem)) (reg)).  */
+      else if (register_operand (src, word_mode))
+       {
+         if (bitsize <= GET_MODE_BITSIZE (SImode))
+           emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1,
+                                                 const0_rtx), src);
+         else
+           {
+             /* Emit st,stcmh sequence.  */
+             int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode);
+             int size = stcmh_width / BITS_PER_UNIT;
+
+             emit_move_insn (adjust_address (dest, SImode, size), 
+                             gen_lowpart (SImode, src));
+             set_mem_size (dest, GEN_INT (size));
+             emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT
+                                                   (stcmh_width), const0_rtx),
+                             gen_rtx_LSHIFTRT (word_mode, src, GEN_INT
+                                               (GET_MODE_BITSIZE (SImode))));
+           }
+       }
+      else
+       return false;
+
+      return true;
+    }
+
+  /* (set (ze (reg)) (const_int)).  */
+  if (TARGET_ZARCH
+      && register_operand (dest, word_mode) 
+      && (bitpos % 16) == 0
+      && (bitsize % 16) == 0
+      && const_int_operand (src, VOIDmode))
+    {
+      HOST_WIDE_INT val = INTVAL (src);
+      int regpos = bitpos + bitsize;
+
+      while (regpos > bitpos)
+       {
+         enum machine_mode putmode;
+         int putsize;
+
+         if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32))
+           putmode = SImode;
+         else
+           putmode = HImode;
+
+         putsize = GET_MODE_BITSIZE (putmode);
+         regpos -= putsize;
+         emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, 
+                                               GEN_INT (putsize),
+                                               GEN_INT (regpos)), 
+                         gen_int_mode (val, putmode));
+         val >>= putsize;
+       }
+      gcc_assert (regpos == bitpos);
+      return true;
+    }
+
+  return false;
+}
 
 /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
@@ -3883,46 +4034,25 @@ s390_delegitimize_address (rtx orig_x)
 static void
 print_shift_count_operand (FILE *file, rtx op)
 {
-  HOST_WIDE_INT offset = 0;
-
-  /* Shift count operands are always truncated to the 6 least significant bits and
-     the setmem padding byte to the least 8 significant bits.  Hence we can drop
-     pointless ANDs.  */
-  if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT)
-    {
-      if ((INTVAL (XEXP (op, 1)) & 63) != 63)
-       gcc_unreachable ();
-
-      op = XEXP (op, 0);
-    }
+  HOST_WIDE_INT offset;
+  rtx base;
 
-  /* We can have an integer constant, an address register,
-     or a sum of the two.  */
-  if (GET_CODE (op) == CONST_INT)
-    {
-      offset = INTVAL (op);
-      op = NULL_RTX;
-    }
-  if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
-    {
-      offset = INTVAL (XEXP (op, 1));
-      op = XEXP (op, 0);
-    }
-  while (op && GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
+  /* Extract base register and offset.  */
+  if (!s390_decompose_shift_count (op, &base, &offset, 0))
+    gcc_unreachable ();
 
   /* Sanity check.  */
-  if (op)
+  if (base)
     {
-      gcc_assert (GET_CODE (op) == REG);
-      gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER);
-      gcc_assert (REGNO_REG_CLASS (REGNO (op)) == ADDR_REGS);
+      gcc_assert (GET_CODE (base) == REG);
+      gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER);
+      gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS);
     }
 
   /* Offsets are constricted to twelve bits.  */
   fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1));
-  if (op)
-    fprintf (file, "(%s)", reg_names[REGNO (op)]);
+  if (base)
+    fprintf (file, "(%s)", reg_names[REGNO (base)]);
 }
 
 /* See 'get_some_local_dynamic_name'.  */
@@ -5879,7 +6009,10 @@ s390_regs_ever_clobbered (int *regs_ever_clobbered)
      deal with this automatically.  */
   if (current_function_calls_eh_return || cfun->machine->has_landing_pad_p)
     for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++)
-      regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1;
+      if (current_function_calls_eh_return 
+         || (cfun->machine->has_landing_pad_p 
+             && regs_ever_live [EH_RETURN_DATA_REGNO (i)]))
+       regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1;
 
   /* For nonlocal gotos all call-saved registers have to be saved.
      This flag is also set for the unwinding code in libgcc.