OSDN Git Service

2004-02-07 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / config / s390 / s390.c
index b89fcee..7e7489a 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines used for code generation on IBM S/390 and zSeries
-   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
    Contributed by Hartmut Penner (hpenner@de.ibm.com) and
                   Ulrich Weigand (uweigand@de.ibm.com).
 
@@ -60,6 +61,7 @@ static void s390_select_rtx_section (enum machine_mode, rtx,
 static void s390_encode_section_info (tree, rtx, int);
 static bool s390_cannot_force_const_mem (rtx);
 static rtx s390_delegitimize_address (rtx);
+static bool s390_return_in_memory (tree, tree);
 static void s390_init_builtins (void);
 static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
@@ -71,11 +73,11 @@ static int s390_adjust_priority (rtx, int);
 static int s390_issue_rate (void);
 static int s390_use_dfa_pipeline_interface (void);
 static int s390_first_cycle_multipass_dfa_lookahead (void);
-static int s390_sched_reorder2 (FILE *, int, rtx *, int *, int);
 static bool s390_rtx_costs (rtx, int, int, int *);
 static int s390_address_cost (rtx);
 static void s390_reorg (void);
 static bool s390_valid_pointer_mode (enum machine_mode);
+static tree s390_build_builtin_va_list (void);
 
 #undef  TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
@@ -106,6 +108,9 @@ static bool s390_valid_pointer_mode (enum machine_mode);
 #undef TARGET_DELEGITIMIZE_ADDRESS
 #define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address
 
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY s390_return_in_memory
+
 #undef  TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS s390_init_builtins
 #undef  TARGET_EXPAND_BUILTIN
@@ -126,8 +131,6 @@ static bool s390_valid_pointer_mode (enum machine_mode);
 #define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE s390_use_dfa_pipeline_interface
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead
-#undef TARGET_SCHED_REORDER2
-#define TARGET_SCHED_REORDER2 s390_sched_reorder2
 
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS s390_rtx_costs
@@ -140,6 +143,14 @@ static bool s390_valid_pointer_mode (enum machine_mode);
 #undef TARGET_VALID_POINTER_MODE
 #define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode
 
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 extern int reload_completed;
@@ -183,14 +194,10 @@ const char *s390_arch_string;             /* for -march=<xxx> */
 
 struct machine_function GTY(())
 {
-  /* Label of start of initial literal pool.  */
-  rtx literal_pool_label;
-
   /* Set, if some of the fprs 8-15 need to be saved (64 bit abi).  */
   int save_fprs_p;
 
-  /* Set if return address needs to be saved because the current
-     function uses __builtin_return_addr (0).  */
+  /* Set if return address needs to be saved.  */
   bool save_return_addr_p;
 
   /* Number of first and last gpr to be saved, restored.  */
@@ -214,16 +221,17 @@ static int s390_short_displacement (rtx);
 static int s390_decompose_address (rtx, struct s390_address *);
 static rtx get_thread_pointer (void);
 static rtx legitimize_tls_address (rtx, rtx);
+static void print_shift_count_operand (FILE *, rtx);
 static const char *get_some_local_dynamic_name (void);
 static int get_some_local_dynamic_name_1 (rtx *, void *);
 static int reg_used_in_mem_p (int, rtx);
 static int addr_generation_dependency_p (rtx, rtx);
-static int s390_split_branches (rtx, bool *);
+static int s390_split_branches (void);
 static void find_constant_pool_ref (rtx, rtx *);
 static void replace_constant_pool_ref (rtx *, rtx, rtx);
 static rtx find_ltrel_base (rtx);
 static void replace_ltrel_base (rtx *, rtx);
-static void s390_optimize_prolog (int);
+static void s390_optimize_prolog (bool);
 static int find_unused_clobbered_reg (void);
 static void s390_frame_info (void);
 static rtx save_fpr (rtx, int, int);
@@ -367,7 +375,7 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
       case EQ:
       case NE:
        if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
-           && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K'))
+           && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
          return CCAPmode;
        if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
             || GET_CODE (op1) == NEG)
@@ -403,7 +411,7 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
       case GE:
       case GT:
          if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K'))
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
             {
              if (INTVAL (XEXP((op0), 1)) < 0)
                return CCANmode;
@@ -450,6 +458,90 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
     }
 }
 
+/* Return nonzero if OP is a valid comparison operator
+   for an ALC condition in mode MODE.  */
+
+int
+s390_alc_comparison (rtx op, enum machine_mode mode)
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (!COMPARISON_P (op))
+    return 0;
+
+  if (GET_CODE (XEXP (op, 0)) != REG
+      || REGNO (XEXP (op, 0)) != CC_REGNUM
+      || XEXP (op, 1) != const0_rtx)
+    return 0;
+
+  switch (GET_MODE (XEXP (op, 0)))
+    {
+    case CCL1mode:
+      return GET_CODE (op) == LTU;
+
+    case CCL2mode:
+      return GET_CODE (op) == LEU;
+
+    case CCUmode:
+      return GET_CODE (op) == GTU;
+
+    case CCURmode:
+      return GET_CODE (op) == LTU;
+
+    case CCSmode:
+      return GET_CODE (op) == UNGT;
+
+    case CCSRmode:
+      return GET_CODE (op) == UNLT;
+
+    default:
+      return 0;
+    }
+}
+
+/* Return nonzero if OP is a valid comparison operator
+   for an SLB condition in mode MODE.  */
+
+int
+s390_slb_comparison (rtx op, enum machine_mode mode)
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (!COMPARISON_P (op))
+    return 0;
+
+  if (GET_CODE (XEXP (op, 0)) != REG
+      || REGNO (XEXP (op, 0)) != CC_REGNUM
+      || XEXP (op, 1) != const0_rtx)
+    return 0;
+
+  switch (GET_MODE (XEXP (op, 0)))
+    {
+    case CCL1mode:
+      return GET_CODE (op) == GEU;
+
+    case CCL2mode:
+      return GET_CODE (op) == GTU;
+
+    case CCUmode:
+      return GET_CODE (op) == LEU;
+
+    case CCURmode:
+      return GET_CODE (op) == GEU;
+
+    case CCSmode:
+      return GET_CODE (op) == LE;
+
+    case CCSRmode:
+      return GET_CODE (op) == GE;
+
+    default:
+      return 0;
+    }
+}
+
 /* Return branch condition mask to implement a branch
    specified by CODE.  */
 
@@ -669,198 +761,68 @@ s390_branch_condition_mnemonic (rtx code, int inv)
   return mnemonic[mask];
 }
 
-/* If OP is an integer constant of mode MODE with exactly one
-   HImode subpart unequal to DEF, return the number of that
-   subpart.  As a special case, all HImode subparts of OP are
-   equal to DEF, return zero.  Otherwise, return -1.  */
-
-int
-s390_single_hi (rtx op, enum machine_mode mode, int def)
-{
-  if (GET_CODE (op) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT value = 0;
-      int n_parts = GET_MODE_SIZE (mode) / 2;
-      int i, part = -1;
-
-      for (i = 0; i < n_parts; i++)
-        {
-          if (i == 0)
-            value = (unsigned HOST_WIDE_INT) INTVAL (op);
-          else
-            value >>= 16;
-
-          if ((value & 0xffff) != (unsigned)(def & 0xffff))
-            {
-              if (part != -1)
-                return -1;
-              else
-                part = i;
-            }
-        }
-
-      return part == -1 ? 0 : (n_parts - 1 - part);
-    }
-
-  else if (GET_CODE (op) == CONST_DOUBLE
-           && GET_MODE (op) == VOIDmode)
-    {
-      unsigned HOST_WIDE_INT value = 0;
-      int n_parts = GET_MODE_SIZE (mode) / 2;
-      int i, part = -1;
-
-      for (i = 0; i < n_parts; i++)
-        {
-          if (i == 0)
-            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
-          else if (i == HOST_BITS_PER_WIDE_INT / 16)
-            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
-          else
-            value >>= 16;
-
-          if ((value & 0xffff) != (unsigned)(def & 0xffff))
-            {
-              if (part != -1)
-                return -1;
-              else
-                part = i;
-            }
-        }
-
-      return part == -1 ? 0 : (n_parts - 1 - part);
-    }
-
-  return -1;
-}
-
-/* Extract the HImode part number PART from integer
-   constant OP of mode MODE.  */
+/* Return the part of op which has a value different from def.
+   The size of the part is determined by mode.
+   Use this function only if you already know that op really 
+   contains such a part.  */
 
-int
-s390_extract_hi (rtx op, enum machine_mode mode, int part)
+unsigned HOST_WIDE_INT
+s390_extract_part (rtx op, enum machine_mode mode, int def)
 {
-  int n_parts = GET_MODE_SIZE (mode) / 2;
-  if (part < 0 || part >= n_parts)
-    abort();
-  else
-    part = n_parts - 1 - part;
-
-  if (GET_CODE (op) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
-      return ((value >> (16 * part)) & 0xffff);
-    }
-  else if (GET_CODE (op) == CONST_DOUBLE
-           && GET_MODE (op) == VOIDmode)
+  unsigned HOST_WIDE_INT value = 0;
+  int max_parts = HOST_BITS_PER_WIDE_INT / GET_MODE_BITSIZE (mode);
+  int part_bits = GET_MODE_BITSIZE (mode);
+  unsigned HOST_WIDE_INT part_mask = (1 << part_bits) - 1;
+  int i;
+  
+  for (i = 0; i < max_parts; i++)
     {
-      unsigned HOST_WIDE_INT value;
-      if (part < HOST_BITS_PER_WIDE_INT / 16)
-        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+      if (i == 0)
+       value = (unsigned HOST_WIDE_INT) INTVAL (op);
       else
-        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
-        part -= HOST_BITS_PER_WIDE_INT / 16;
-
-      return ((value >> (16 * part)) & 0xffff);
+       value >>= part_bits;
+      
+      if ((value & part_mask) != (def & part_mask))
+       return value & part_mask;
     }
-
+  
   abort ();
 }
 
 /* If OP is an integer constant of mode MODE with exactly one
-   QImode subpart unequal to DEF, return the number of that
-   subpart.  As a special case, all QImode subparts of OP are
-   equal to DEF, return zero.  Otherwise, return -1.  */
-
-int
-s390_single_qi (rtx op, enum machine_mode mode, int def)
-{
-  if (GET_CODE (op) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT value = 0;
-      int n_parts = GET_MODE_SIZE (mode);
-      int i, part = -1;
-
-      for (i = 0; i < n_parts; i++)
-        {
-          if (i == 0)
-            value = (unsigned HOST_WIDE_INT) INTVAL (op);
-          else
-            value >>= 8;
-
-          if ((value & 0xff) != (unsigned)(def & 0xff))
-            {
-              if (part != -1)
-                return -1;
-              else
-                part = i;
-            }
-        }
-
-      return part == -1 ? 0 : (n_parts - 1 - part);
-    }
-
-  else if (GET_CODE (op) == CONST_DOUBLE
-           && GET_MODE (op) == VOIDmode)
-    {
-      unsigned HOST_WIDE_INT value = 0;
-      int n_parts = GET_MODE_SIZE (mode);
-      int i, part = -1;
-
-      for (i = 0; i < n_parts; i++)
-        {
-          if (i == 0)
-            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
-          else if (i == HOST_BITS_PER_WIDE_INT / 8)
-            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
-          else
-            value >>= 8;
-
-          if ((value & 0xff) != (unsigned)(def & 0xff))
-            {
-              if (part != -1)
-                return -1;
-              else
-                part = i;
-            }
-        }
-
-      return part == -1 ? 0 : (n_parts - 1 - part);
-    }
-
-  return -1;
-}
-
-/* Extract the QImode part number PART from integer
-   constant OP of mode MODE.  */
+   part of mode PART_MODE unequal to DEF, return the number of that
+   part. Otherwise, return -1.  */
 
 int
-s390_extract_qi (rtx op, enum machine_mode mode, int part)
+s390_single_part (rtx op, 
+                 enum machine_mode mode, 
+                 enum machine_mode part_mode,
+                 int def)
 {
-  int n_parts = GET_MODE_SIZE (mode);
-  if (part < 0 || part >= n_parts)
-    abort();
-  else
-    part = n_parts - 1 - part;
-
-  if (GET_CODE (op) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
-      return ((value >> (8 * part)) & 0xff);
-    }
-  else if (GET_CODE (op) == CONST_DOUBLE
-           && GET_MODE (op) == VOIDmode)
-    {
-      unsigned HOST_WIDE_INT value;
-      if (part < HOST_BITS_PER_WIDE_INT / 8)
-        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+  unsigned HOST_WIDE_INT value = 0;
+  int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode);
+  unsigned HOST_WIDE_INT part_mask = (1 << GET_MODE_BITSIZE (part_mode)) - 1;
+  int i, part = -1;
+
+  if (GET_CODE (op) != CONST_INT)
+    return -1;
+  
+  for (i = 0; i < n_parts; i++)
+    {
+      if (i == 0)
+       value = (unsigned HOST_WIDE_INT) INTVAL (op);
       else
-        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
-        part -= HOST_BITS_PER_WIDE_INT / 8;
-
-      return ((value >> (8 * part)) & 0xff);
+       value >>= GET_MODE_BITSIZE (part_mode);
+      
+      if ((value & part_mask) != (def & part_mask))
+       {
+         if (part != -1)
+           return -1;
+         else
+           part = i;
+       }
     }
-
-  abort ();
+  return part == -1 ? -1 : n_parts - 1 - part;
 }
 
 /* Check whether we can (and want to) split a double-word
@@ -1139,30 +1101,30 @@ general_s_operand (register rtx op, enum machine_mode mode,
 
   switch (GET_CODE (op))
     {
-      /* Constants that we are sure will be forced to the
-         literal pool in reload are OK as s-operand.  Note
-        that we cannot call s390_preferred_reload_class here
-        because it might not be known yet at this point
-        whether the current function is a leaf or not.  */
+      /* Constants are OK as s-operand if ALLOW_IMMEDIATE
+        is true and we are still before reload.  */
       case CONST_INT:
       case CONST_DOUBLE:
        if (!allow_immediate || reload_completed)
-         break;
-       if (!legitimate_reload_constant_p (op))
-         return 1;
-       if (!TARGET_64BIT)
-         return 1;
-       break;
+         return 0;
+       return 1;
 
       /* Memory operands are OK unless they already use an
         index register.  */
       case MEM:
        if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
          return 1;
-       if (s390_decompose_address (XEXP (op, 0), &addr)
-           && !addr.indx)
-         return 1;
-       break;
+       if (!s390_decompose_address (XEXP (op, 0), &addr))
+         return 0;
+       if (addr.indx)
+         return 0;
+       /* Do not allow literal pool references unless ALLOW_IMMEDIATE 
+          is true.  This prevents compares between two literal pool 
+          entries from being accepted.  */
+       if (!allow_immediate 
+           && addr.base && REGNO (addr.base) == BASE_REGISTER)
+         return 0;
+       return 1;
 
       default:
        break;
@@ -1193,6 +1155,45 @@ s_imm_operand (register rtx op, enum machine_mode mode)
   return general_s_operand (op, mode, 1);
 }
 
+/* Return true if OP a valid shift count operand.
+   OP is the current operation.
+   MODE is the current operation mode.  */
+
+int
+shift_count_operand (rtx op, enum machine_mode mode)
+{
+  HOST_WIDE_INT offset = 0;
+
+  if (! check_mode (op, &mode))
+    return 0;
+
+  /* We can have an integer constant, an address register,
+     or a sum of the two.  Note that reload already checks
+     that any register present is an address register, so
+     we just check for any register here.  */
+  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);
+  if (op && GET_CODE (op) != REG)
+    return 0;
+
+  /* Unfortunately we have to reject constants that are invalid
+     for an address, or else reload will get confused.  */
+  if (!DISP_IN_RANGE (offset))
+    return 0;
+
+  return 1;
+}
+
 /* Return true if DISP is a valid short displacement.  */
 
 static int
@@ -1223,10 +1224,13 @@ s390_short_displacement (rtx disp)
 /* Return true if OP is a valid operand for a C constraint.  */
 
 int
-s390_extra_constraint (rtx op, int c)
+s390_extra_constraint_str (rtx op, int c, const char * str)
 {
   struct s390_address addr;
 
+  if (c != str[0])
+    abort ();
+
   switch (c)
     {
     case 'Q':
@@ -1302,6 +1306,81 @@ s390_extra_constraint (rtx op, int c)
        return 0;
       break;
 
+    case 'Y':
+      return shift_count_operand (op, VOIDmode);
+
+    default:
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Return true if VALUE matches the constraint STR.  */
+
+int
+s390_const_ok_for_constraint_p (HOST_WIDE_INT value,
+                               int c,
+                               const char * str)
+{
+  enum machine_mode mode, part_mode;
+  int def;
+  unsigned char part;
+
+  if (c != str[0])
+    abort ();
+
+  switch (str[0])
+    {
+    case 'I':
+      return (unsigned int)value < 256;
+
+    case 'J':
+      return (unsigned int)value < 4096;
+
+    case 'K':
+      return value >= -32768 && value < 32768;
+
+    case 'L':
+      return (TARGET_LONG_DISPLACEMENT ? 
+             (value >= -524288 && value <= 524287) 
+             : (value >= 0 && value <= 4095));
+    case 'M':
+      return value == 2147483647;
+
+    case 'N':
+      part = str[1] - '0';
+
+      switch (str[2])
+       {
+       case 'H': part_mode = HImode; break;
+       case 'Q': part_mode = QImode; break;
+       default:  return 0;
+       }
+      
+      switch (str[3])
+       {
+       case 'H': mode = HImode; break;
+       case 'S': mode = SImode; break;
+       case 'D': mode = DImode; break;
+       default: return 0;
+       }
+
+      switch (str[4])
+       {
+       case '0': def = 0;  break;
+       case 'F': def = -1; break;
+       default: return 0;
+       }
+
+      if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode))
+       return 0;
+
+      if (s390_single_part (GEN_INT (value), mode, part_mode, def) != part)
+       return 0;
+
+      break;
+
     default:
       return 0;
     }
@@ -1431,6 +1510,7 @@ tls_symbolic_operand (register rtx op)
 int
 load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
+  enum machine_mode elt_mode;
   int count = XVECLEN (op, 0);
   unsigned int dest_regno;
   rtx src_addr;
@@ -1446,6 +1526,7 @@ load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 
   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
   src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+  elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
 
   /* Check, is base, or base + displacement.  */
 
@@ -1470,15 +1551,15 @@ load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 
       if (GET_CODE (elt) != SET
          || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != Pmode
+         || GET_MODE (SET_DEST (elt)) != elt_mode
          || REGNO (SET_DEST (elt)) != dest_regno + i
          || GET_CODE (SET_SRC (elt)) != MEM
-         || GET_MODE (SET_SRC (elt)) != Pmode
+         || GET_MODE (SET_SRC (elt)) != elt_mode
          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
          || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
          || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
          || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
-            != off + i * UNITS_PER_WORD)
+            != off + i * GET_MODE_SIZE (elt_mode))
        return 0;
     }
 
@@ -1493,6 +1574,7 @@ load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 int
 store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
+  enum machine_mode elt_mode;
   int count = XVECLEN (op, 0);
   unsigned int src_regno;
   rtx dest_addr;
@@ -1507,6 +1589,7 @@ store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 
   src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
   dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+  elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
 
   /* Check, is base, or base + displacement.  */
 
@@ -1531,15 +1614,15 @@ store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 
       if (GET_CODE (elt) != SET
          || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != Pmode
+         || GET_MODE (SET_SRC (elt)) != elt_mode
          || REGNO (SET_SRC (elt)) != src_regno + i
          || GET_CODE (SET_DEST (elt)) != MEM
-         || GET_MODE (SET_DEST (elt)) != Pmode
+         || GET_MODE (SET_DEST (elt)) != elt_mode
          || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
          || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
          || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
          || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
-            != off + i * UNITS_PER_WORD)
+            != off + i * GET_MODE_SIZE (elt_mode))
        return 0;
     }
   return 1;
@@ -1634,7 +1717,7 @@ legitimate_constant_p (register rtx op)
     return 1;
 
   /* Accept immediate LARL operands.  */
-  if (TARGET_64BIT && larl_operand (op, VOIDmode))
+  if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode))
     return 1;
 
   /* Thread-local symbols are never legal constants.  This is
@@ -1729,16 +1812,16 @@ legitimate_reload_constant_p (register rtx op)
 
   /* Accept l(g)hi operands.  */
   if (GET_CODE (op) == CONST_INT
-      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
+      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', "K"))
     return 1;
 
   /* Accept lliXX operands.  */
-  if (TARGET_64BIT
-      && s390_single_hi (op, DImode, 0) >= 0)
+  if (TARGET_ZARCH
+      && s390_single_part (op, DImode, HImode, 0) >= 0)
   return 1;
 
   /* Accept larl operands.  */
-  if (TARGET_64BIT
+  if (TARGET_CPU_ZARCH
       && larl_operand (op, VOIDmode))
     return 1;
 
@@ -1992,8 +2075,6 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
              && frame_pointer_needed
              && REGNO (base) == HARD_FRAME_POINTER_REGNUM)
          || REGNO (base) == ARG_POINTER_REGNUM
-         || (REGNO (base) >= FIRST_VIRTUAL_REGISTER
-             && REGNO (base) <= LAST_VIRTUAL_REGISTER)
           || (flag_pic
               && REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
         pointer = base_ptr = TRUE;
@@ -2019,8 +2100,6 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
              && frame_pointer_needed
              && REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
          || REGNO (indx) == ARG_POINTER_REGNUM
-         || (REGNO (indx) >= FIRST_VIRTUAL_REGISTER
-             && REGNO (indx) <= LAST_VIRTUAL_REGISTER)
           || (flag_pic
               && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
         pointer = indx_ptr = TRUE;
@@ -2263,7 +2342,7 @@ legitimize_pic_address (rtx orig, rtx reg)
       || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)))
     {
       /* This is a local symbol.  */
-      if (TARGET_64BIT && larl_operand (addr, VOIDmode))
+      if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode))
         {
           /* Access local symbols PC-relative via LARL.
              This is the same as in the non-PIC case, so it is
@@ -2312,7 +2391,7 @@ legitimize_pic_address (rtx orig, rtx reg)
           emit_move_insn (reg, new);
           new = reg;
         }
-      else if (TARGET_64BIT)
+      else if (TARGET_CPU_ZARCH)
         {
           /* If the GOT offset might be >= 4k, we determine the position
              of the GOT entry via a PC-relative LARL (@GOTENT).  */
@@ -2381,7 +2460,7 @@ legitimize_pic_address (rtx orig, rtx reg)
                   /* @PLT is OK as is on 64-bit, must be converted to
                      GOT-relative @PLTOFF on 31-bit.  */
                   case UNSPEC_PLT:
-                    if (!TARGET_64BIT)
+                    if (!TARGET_CPU_ZARCH)
                       {
                         rtx temp = reg? reg : gen_reg_rtx (Pmode);
 
@@ -2421,7 +2500,7 @@ legitimize_pic_address (rtx orig, rtx reg)
                || (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0)))
              && GET_CODE (op1) == CONST_INT)
            {
-              if (TARGET_64BIT && larl_operand (op0, VOIDmode))
+              if (TARGET_CPU_ZARCH && larl_operand (op0, VOIDmode))
                 {
                   if (INTVAL (op1) & 1)
                     {
@@ -2434,7 +2513,7 @@ legitimize_pic_address (rtx orig, rtx reg)
                           int even = INTVAL (op1) - 1;
                           op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
                          op0 = gen_rtx_CONST (Pmode, op0);
-                          op1 = GEN_INT (1);
+                          op1 = const1_rtx;
                         }
 
                       emit_move_insn (temp, op0);
@@ -2628,7 +2707,7 @@ legitimize_tls_address (rtx addr, rtx reg)
            temp = gen_reg_rtx (Pmode);
            emit_move_insn (temp, new);
          }
-       else if (TARGET_64BIT)
+       else if (TARGET_CPU_ZARCH)
          {
            /* If the GOT offset might be >= 4k, we determine the position
               of the GOT entry via a PC-relative LARL.  */
@@ -2717,7 +2796,7 @@ legitimize_tls_address (rtx addr, rtx reg)
       switch (XINT (XEXP (addr, 0), 1))
        {
        case UNSPEC_INDNTPOFF:
-         if (TARGET_64BIT)
+         if (TARGET_CPU_ZARCH)
            new = addr;
          else
            abort ();
@@ -2846,34 +2925,15 @@ legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
 void
 s390_expand_movstr (rtx dst, rtx src, rtx len)
 {
-  rtx (*gen_short) (rtx, rtx, rtx) =
-    TARGET_64BIT ? gen_movstr_short_64 : gen_movstr_short_31;
-  rtx (*gen_long) (rtx, rtx, rtx, rtx) =
-    TARGET_64BIT ? gen_movstr_long_64 : gen_movstr_long_31;
-
-
   if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
     {
       if (INTVAL (len) > 0)
-        emit_insn (gen_short (dst, src, GEN_INT (INTVAL (len) - 1)));
+        emit_insn (gen_movstr_short (dst, src, GEN_INT (INTVAL (len) - 1)));
     }
 
   else if (TARGET_MVCLE)
     {
-      enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
-      enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
-      rtx reg0 = gen_reg_rtx (double_mode);
-      rtx reg1 = gen_reg_rtx (double_mode);
-
-      emit_move_insn (gen_highpart (single_mode, reg0),
-                     force_operand (XEXP (dst, 0), NULL_RTX));
-      emit_move_insn (gen_highpart (single_mode, reg1),
-                     force_operand (XEXP (src, 0), NULL_RTX));
-
-      convert_move (gen_lowpart (single_mode, reg0), len, 1);
-      convert_move (gen_lowpart (single_mode, reg1), len, 1);
-
-      emit_insn (gen_long (reg0, reg1, reg0, reg1));
+      emit_insn (gen_movstr_long (dst, src, convert_to_mode (Pmode, len, 1)));
     }
 
   else
@@ -2885,7 +2945,7 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
 
       mode = GET_MODE (len);
       if (mode == VOIDmode)
-        mode = word_mode;
+        mode = Pmode;
 
       type = lang_hooks.types.type_for_mode (mode, 1);
       if (!type)
@@ -2918,7 +2978,7 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
                                           make_tree (type, blocks),
                                           make_tree (type, const0_rtx)));
 
-      emit_insn (gen_short (dst, src, GEN_INT (255)));
+      emit_insn (gen_movstr_short (dst, src, GEN_INT (255)));
       s390_load_address (dst_addr,
                         gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
       s390_load_address (src_addr,
@@ -2930,7 +2990,8 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
 
       expand_end_loop ();
 
-      emit_insn (gen_short (dst, src, convert_to_mode (word_mode, count, 1)));
+      emit_insn (gen_movstr_short (dst, src, 
+                                  convert_to_mode (Pmode, count, 1)));
       emit_label (end_label);
     }
 }
@@ -2940,33 +3001,15 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
 void
 s390_expand_clrstr (rtx dst, rtx len)
 {
-  rtx (*gen_short) (rtx, rtx) =
-    TARGET_64BIT ? gen_clrstr_short_64 : gen_clrstr_short_31;
-  rtx (*gen_long) (rtx, rtx, rtx) =
-    TARGET_64BIT ? gen_clrstr_long_64 : gen_clrstr_long_31;
-
-
   if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
     {
       if (INTVAL (len) > 0)
-        emit_insn (gen_short (dst, GEN_INT (INTVAL (len) - 1)));
+        emit_insn (gen_clrstr_short (dst, GEN_INT (INTVAL (len) - 1)));
     }
 
   else if (TARGET_MVCLE)
     {
-      enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
-      enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
-      rtx reg0 = gen_reg_rtx (double_mode);
-      rtx reg1 = gen_reg_rtx (double_mode);
-
-      emit_move_insn (gen_highpart (single_mode, reg0),
-                     force_operand (XEXP (dst, 0), NULL_RTX));
-      convert_move (gen_lowpart (single_mode, reg0), len, 1);
-
-      emit_move_insn (gen_highpart (single_mode, reg1), const0_rtx);
-      emit_move_insn (gen_lowpart (single_mode, reg1), const0_rtx);
-
-      emit_insn (gen_long (reg0, reg1, reg0));
+      emit_insn (gen_clrstr_long (dst, convert_to_mode (Pmode, len, 1)));
     }
 
   else
@@ -2978,7 +3021,7 @@ s390_expand_clrstr (rtx dst, rtx len)
 
       mode = GET_MODE (len);
       if (mode == VOIDmode)
-        mode = word_mode;
+        mode = Pmode;
 
       type = lang_hooks.types.type_for_mode (mode, 1);
       if (!type)
@@ -3009,7 +3052,7 @@ s390_expand_clrstr (rtx dst, rtx len)
                                           make_tree (type, blocks),
                                           make_tree (type, const0_rtx)));
 
-      emit_insn (gen_short (dst, GEN_INT (255)));
+      emit_insn (gen_clrstr_short (dst, GEN_INT (255)));
       s390_load_address (dst_addr,
                         gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
 
@@ -3019,7 +3062,7 @@ s390_expand_clrstr (rtx dst, rtx len)
 
       expand_end_loop ();
 
-      emit_insn (gen_short (dst, convert_to_mode (word_mode, count, 1)));
+      emit_insn (gen_clrstr_short (dst, convert_to_mode (Pmode, count, 1)));
       emit_label (end_label);
     }
 }
@@ -3030,10 +3073,6 @@ s390_expand_clrstr (rtx dst, rtx len)
 void
 s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
 {
-  rtx (*gen_short) (rtx, rtx, rtx) =
-    TARGET_64BIT ? gen_cmpmem_short_64 : gen_cmpmem_short_31;
-  rtx (*gen_long) (rtx, rtx, rtx, rtx) =
-    TARGET_64BIT ? gen_cmpmem_long_64 : gen_cmpmem_long_31;
   rtx (*gen_result) (rtx) =
     GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si;
 
@@ -3045,7 +3084,7 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
     {
       if (INTVAL (len) > 0)
         {
-          emit_insn (gen_short (op0, op1, GEN_INT (INTVAL (len) - 1)));
+          emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1)));
           emit_insn (gen_result (target));
         }
       else
@@ -3054,20 +3093,7 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
 
   else /* if (TARGET_MVCLE) */
     {
-      enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
-      enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
-      rtx reg0 = gen_reg_rtx (double_mode);
-      rtx reg1 = gen_reg_rtx (double_mode);
-
-      emit_move_insn (gen_highpart (single_mode, reg0),
-                     force_operand (XEXP (op0, 0), NULL_RTX));
-      emit_move_insn (gen_highpart (single_mode, reg1),
-                     force_operand (XEXP (op1, 0), NULL_RTX));
-
-      convert_move (gen_lowpart (single_mode, reg0), len, 1);
-      convert_move (gen_lowpart (single_mode, reg1), len, 1);
-
-      emit_insn (gen_long (reg0, reg1, reg0, reg1));
+      emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1)));
       emit_insn (gen_result (target));
     }
 
@@ -3083,7 +3109,7 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
 
       mode = GET_MODE (len);
       if (mode == VOIDmode)
-        mode = word_mode;
+        mode = Pmode;
 
       type = lang_hooks.types.type_for_mode (mode, 1);
       if (!type)
@@ -3116,7 +3142,7 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
                                           make_tree (type, blocks),
                                           make_tree (type, const0_rtx)));
 
-      emit_insn (gen_short (op0, op1, GEN_INT (255)));
+      emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255)));
       temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx);
       temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
                        gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx);
@@ -3134,7 +3160,8 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
 
       expand_end_loop ();
 
-      emit_insn (gen_short (op0, op1, convert_to_mode (word_mode, count, 1)));
+      emit_insn (gen_cmpmem_short (op0, op1, 
+                                  convert_to_mode (Pmode, count, 1)));
       emit_label (end_label);
 
       emit_insn (gen_result (target));
@@ -3200,6 +3227,40 @@ s390_delegitimize_address (rtx orig_x)
   return orig_x;
 }
 
+/* Output shift count operand OP to stdio stream FILE.  */
+
+static void
+print_shift_count_operand (FILE *file, rtx op)
+{
+  HOST_WIDE_INT offset = 0;
+
+  /* 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);
+
+  /* Sanity check.  */
+  if (op && (GET_CODE (op) != REG
+            || REGNO (op) >= FIRST_PSEUDO_REGISTER
+            || REGNO_REG_CLASS (REGNO (op)) != ADDR_REGS))
+    abort ();
+
+  /* Shift counts are truncated to the low six bits anyway.  */
+  fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & 63);
+  if (op)
+    fprintf (file, "(%s)", reg_names[REGNO (op)]);
+}
+
 /* Locate some local-dynamic symbol still in use by this function
    so that we can print its name in local-dynamic base patterns.  */
 
@@ -3240,103 +3301,63 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
   return 0;
 }
 
-/* Output symbolic constant X in assembler syntax to
-   stdio stream FILE.  */
+/* Output machine-dependent UNSPECs occurring in address constant X 
+   in assembler syntax to stdio stream FILE.  Returns true if the
+   constant X could be recognized, false otherwise.  */
 
-void
-s390_output_symbolic_const (FILE *file, rtx x)
+bool
+s390_output_addr_const_extra (FILE *file, rtx x)
 {
-  switch (GET_CODE (x))
-    {
-    case CONST:
-    case ZERO_EXTEND:
-    case SIGN_EXTEND:
-      s390_output_symbolic_const (file, XEXP (x, 0));
-      break;
-
-    case PLUS:
-      s390_output_symbolic_const (file, XEXP (x, 0));
-      fprintf (file, "+");
-      s390_output_symbolic_const (file, XEXP (x, 1));
-      break;
-
-    case MINUS:
-      s390_output_symbolic_const (file, XEXP (x, 0));
-      fprintf (file, "-");
-      s390_output_symbolic_const (file, XEXP (x, 1));
-      break;
-
-    case CONST_INT:
-    case LABEL_REF:
-    case CODE_LABEL:
-    case SYMBOL_REF:
-      output_addr_const (file, x);
-      break;
-
-    case UNSPEC:
-      if (XVECLEN (x, 0) != 1)
-        output_operand_lossage ("invalid UNSPEC as operand (1)");
-      switch (XINT (x, 1))
-        {
-        case UNSPEC_LTREL_OFFSET:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-          fprintf (file, "-");
-         s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
-         break;
-       case UNSPEC_GOTENT:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@GOTENT");
-         break;
-       case UNSPEC_GOT:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@GOT");
-         break;
-       case UNSPEC_GOTOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@GOTOFF");
-         break;
-       case UNSPEC_PLT:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@PLT");
-         break;
-       case UNSPEC_PLTOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@PLTOFF");
-         break;
-       case UNSPEC_TLSGD:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@TLSGD");
-         break;
-       case UNSPEC_TLSLDM:
-         assemble_name (file, get_some_local_dynamic_name ());
-         fprintf (file, "@TLSLDM");
-         break;
-       case UNSPEC_DTPOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@DTPOFF");
-         break;
-       case UNSPEC_NTPOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@NTPOFF");
-         break;
-       case UNSPEC_GOTNTPOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@GOTNTPOFF");
-         break;
-       case UNSPEC_INDNTPOFF:
-         s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-         fprintf (file, "@INDNTPOFF");
-         break;
-       default:
-         output_operand_lossage ("invalid UNSPEC as operand (2)");
-         break;
-        }
-      break;
+  if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1)
+    switch (XINT (x, 1))
+      {
+      case UNSPEC_GOTENT:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@GOTENT");
+       return true;
+      case UNSPEC_GOT:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@GOT");
+       return true;
+      case UNSPEC_GOTOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@GOTOFF");
+       return true;
+      case UNSPEC_PLT:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@PLT");
+       return true;
+      case UNSPEC_PLTOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@PLTOFF");
+       return true;
+      case UNSPEC_TLSGD:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@TLSGD");
+       return true;
+      case UNSPEC_TLSLDM:
+       assemble_name (file, get_some_local_dynamic_name ());
+       fprintf (file, "@TLSLDM");
+       return true;
+      case UNSPEC_DTPOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@DTPOFF");
+       return true;
+      case UNSPEC_NTPOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@NTPOFF");
+       return true;
+      case UNSPEC_GOTNTPOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@GOTNTPOFF");
+       return true;
+      case UNSPEC_INDNTPOFF:
+       output_addr_const (file, XVECEXP (x, 0, 0));
+       fprintf (file, "@INDNTPOFF");
+       return true;
+      }
 
-    default:
-      fatal_insn ("UNKNOWN in s390_output_symbolic_const !?", x);
-      break;
-    }
+  return false;
 }
 
 /* Output address operand ADDR in assembler syntax to
@@ -3353,7 +3374,7 @@ print_operand_address (FILE *file, rtx addr)
     output_operand_lossage ("Cannot decompose address.");
 
   if (ad.disp)
-    s390_output_symbolic_const (file, ad.disp);
+    output_addr_const (file, ad.disp);
   else
     fprintf (file, "0");
 
@@ -3375,10 +3396,13 @@ print_operand_address (FILE *file, rtx addr)
     'R': print only the base register of a memory reference.
     'N': print the second word of a DImode operand.
     'M': print the second word of a TImode operand.
+    'Y': print shift count operand.
 
     'b': print integer X as if it's an unsigned byte.
     'x': print integer X as if it's an unsigned word.
-    'h': print integer X as if it's a signed word.  */
+    'h': print integer X as if it's a signed word.
+    'i': print the first nonzero HImode part of X.
+    'j': print the first HImode part unequal to 0xffff of X.  */
 
 void
 print_operand (FILE *file, rtx x, int code)
@@ -3424,7 +3448,7 @@ print_operand (FILE *file, rtx x, int code)
           abort ();
 
         if (ad.disp)
-          s390_output_symbolic_const (file, ad.disp);
+          output_addr_const (file, ad.disp);
         else
           fprintf (file, "0");
       }
@@ -3464,6 +3488,10 @@ print_operand (FILE *file, rtx x, int code)
       else
         abort ();
       break;
+
+    case 'Y':
+      print_shift_count_operand (file, x);
+      return;
     }
 
   switch (GET_CODE (x))
@@ -3480,7 +3508,7 @@ print_operand (FILE *file, rtx x, int code)
     case CODE_LABEL:
     case LABEL_REF:
     case SYMBOL_REF:
-      s390_output_symbolic_const (file, x);
+      output_addr_const (file, x);
       break;
 
     case CONST_INT:
@@ -3490,6 +3518,12 @@ print_operand (FILE *file, rtx x, int code)
         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
       else if (code == 'h')
         fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000);
+      else if (code == 'i')
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, 
+                s390_extract_part (x, HImode, 0));
+      else if (code == 'j')
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, 
+                s390_extract_part (x, HImode, -1));    
       else
         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       break;
@@ -3753,30 +3787,14 @@ s390_first_cycle_multipass_dfa_lookahead (void)
   return s390_use_dfa_pipeline_interface () ? 4 : 0;
 }
 
-/* Called after issuing each insn.
-   Triggers default sort algorithm to better slot instructions.  */
-
-static int
-s390_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
-                    int sched_verbose ATTRIBUTE_UNUSED,
-                    rtx *ready ATTRIBUTE_UNUSED,
-                    int *pn_ready ATTRIBUTE_UNUSED,
-                    int clock_var ATTRIBUTE_UNUSED)
-{
-    return s390_issue_rate();
-}
-
 
 /* Split all branches that exceed the maximum distance.
-   Returns true if this created a new literal pool entry.
-
-   Code generated by this routine is allowed to use
-   TEMP_REG as temporary scratch register.  If this is
-   done, TEMP_USED is set to true.  */
+   Returns true if this created a new literal pool entry.  */
 
 static int
-s390_split_branches (rtx temp_reg, bool *temp_used)
+s390_split_branches (void)
 {
+  rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
   int new_literal = 0;
   rtx insn, pat, tmp, target;
   rtx *label;
@@ -3814,19 +3832,14 @@ s390_split_branches (rtx temp_reg, bool *temp_used)
       else
        continue;
 
-      if (get_attr_length (insn) <= (TARGET_64BIT ? 6 : 4))
+      if (get_attr_length (insn) <= 4)
        continue;
 
-      *temp_used = 1;
+      /* We are going to use the return register as scratch register,
+        make sure it will be saved/restored by the prologue/epilogue.  */
+      cfun->machine->save_return_addr_p = 1;
 
-      if (TARGET_64BIT)
-       {
-         tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, *label), insn);
-         INSN_ADDRESSES_NEW (tmp, -1);
-
-         target = temp_reg;
-       }
-      else if (!flag_pic)
+      if (!flag_pic)
        {
          new_literal = 1;
          tmp = force_const_mem (Pmode, *label);
@@ -3876,6 +3889,10 @@ find_constant_pool_ref (rtx x, rtx *ref)
   if (GET_CODE (x) == UNSPEC
       && XINT (x, 1) == UNSPEC_LTREL_BASE)
     return;
+  /* Likewise POOL_ENTRY insns.  */
+  if (GET_CODE (x) == UNSPEC_VOLATILE
+      && XINT (x, 1) == UNSPECV_POOL_ENTRY)
+    return;
 
   if (GET_CODE (x) == SYMBOL_REF
       && CONSTANT_POOL_ADDRESS_P (x))
@@ -4071,8 +4088,12 @@ struct constant_pool
   int size;
 };
 
-static struct constant_pool * s390_chunkify_start (void);
-static void s390_chunkify_finish (struct constant_pool *);
+static struct constant_pool * s390_mainpool_start (void);
+static void s390_mainpool_finish (struct constant_pool *, rtx base_reg);
+static void s390_mainpool_cancel (struct constant_pool *);
+
+static struct constant_pool * s390_chunkify_start (rtx base_reg);
+static void s390_chunkify_finish (struct constant_pool *, rtx base_reg);
 static void s390_chunkify_cancel (struct constant_pool *);
 
 static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
@@ -4081,7 +4102,8 @@ static void s390_add_pool_insn (struct constant_pool *, rtx);
 static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
 static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
 static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
-static rtx s390_dump_pool (struct constant_pool *);
+static rtx s390_dump_pool (struct constant_pool *, bool);
+static struct constant_pool *s390_alloc_pool (void);
 static void s390_free_pool (struct constant_pool *);
 
 /* Create new constant pool covering instructions starting at INSN
@@ -4091,18 +4113,9 @@ static struct constant_pool *
 s390_start_pool (struct constant_pool **pool_list, rtx insn)
 {
   struct constant_pool *pool, **prev;
-  int i;
 
-  pool = (struct constant_pool *) xmalloc (sizeof *pool);
-  pool->next = NULL;
-  for (i = 0; i < NR_C_MODES; i++)
-    pool->constants[i] = NULL;
-
-  pool->label = gen_label_rtx ();
+  pool = s390_alloc_pool ();
   pool->first_insn = insn;
-  pool->pool_insn = NULL_RTX;
-  pool->insns = BITMAP_XMALLOC ();
-  pool->size = 0;
 
   for (prev = pool_list; *prev; prev = &(*prev)->next)
     ;
@@ -4208,10 +4221,11 @@ s390_find_constant (struct constant_pool *pool, rtx val,
   return offset;
 }
 
-/* Dump out the constants in POOL.  */
+/* Dump out the constants in POOL.  If REMOTE_LABEL is true,
+   do not emit the pool base label.  */
 
 static rtx
-s390_dump_pool (struct constant_pool *pool)
+s390_dump_pool (struct constant_pool *pool, bool remote_label)
 {
   struct constant *c;
   rtx insn;
@@ -4219,14 +4233,17 @@ s390_dump_pool (struct constant_pool *pool)
 
   /* Pool start insn switches to proper section
      and guarantees necessary alignment.  */
-  if (TARGET_64BIT)
+  if (TARGET_CPU_ZARCH)
     insn = emit_insn_after (gen_pool_start_64 (), pool->pool_insn);
   else
     insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
   INSN_ADDRESSES_NEW (insn, -1);
 
-  insn = emit_label_after (pool->label, insn);
-  INSN_ADDRESSES_NEW (insn, -1);
+  if (!remote_label)
+    {
+      insn = emit_label_after (pool->label, insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+    }
 
   /* Dump constants in descending alignment requirement order,
      ensuring proper alignment for every constant.  */
@@ -4257,7 +4274,7 @@ s390_dump_pool (struct constant_pool *pool)
 
   /* Pool end insn switches back to previous section
      and guarantees necessary alignment.  */
-  if (TARGET_64BIT)
+  if (TARGET_CPU_ZARCH)
     insn = emit_insn_after (gen_pool_end_64 (), insn);
   else
     insn = emit_insn_after (gen_pool_end_31 (), insn);
@@ -4272,6 +4289,28 @@ s390_dump_pool (struct constant_pool *pool)
   return insn;
 }
 
+/* Allocate new constant_pool structure.  */
+
+static struct constant_pool *
+s390_alloc_pool (void)
+{
+  struct constant_pool *pool;
+  int i;
+
+  pool = (struct constant_pool *) xmalloc (sizeof *pool);
+  pool->next = NULL;
+  for (i = 0; i < NR_C_MODES; i++)
+    pool->constants[i] = NULL;
+
+  pool->label = gen_label_rtx ();
+  pool->first_insn = NULL_RTX;
+  pool->pool_insn = NULL_RTX;
+  pool->insns = BITMAP_XMALLOC ();
+  pool->size = 0;
+
+  return pool;
+}
+
 /* Free all memory used by POOL.  */
 
 static void
@@ -4295,16 +4334,186 @@ s390_free_pool (struct constant_pool *pool)
 }
 
 
-/* Chunkify the literal pool if required.  */
+/* Collect main literal pool.  Return NULL on overflow.  */
+
+static struct constant_pool *
+s390_mainpool_start (void)
+{
+  struct constant_pool *pool;
+  rtx insn;
+
+  pool = s390_alloc_pool ();
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == INSN
+         && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+         && XINT (PATTERN (insn), 1) == UNSPECV_MAIN_POOL)
+       {
+         if (pool->pool_insn)
+           abort ();
+         pool->pool_insn = insn;
+       }
+
+      if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+       {
+         rtx pool_ref = NULL_RTX;
+         find_constant_pool_ref (PATTERN (insn), &pool_ref);
+         if (pool_ref)
+           {
+             rtx constant = get_pool_constant (pool_ref);
+             enum machine_mode mode = get_pool_mode (pool_ref);
+             s390_add_constant (pool, constant, mode);
+           }
+       }
+    }
+
+  if (!pool->pool_insn)
+    abort ();
+
+  if (pool->size >= 4096)
+    {
+      /* We're going to chunkify the pool, so remove the main
+        pool placeholder insn.  */
+      remove_insn (pool->pool_insn);
+
+      s390_free_pool (pool);
+      pool = NULL;
+    }
+
+  return pool;
+}
+
+/* POOL holds the main literal pool as collected by s390_mainpool_start.
+   Modify the current function to output the pool constants as well as
+   the pool register setup instruction.  BASE_REG is the register to
+   be used as pool base register.  */
+
+static void
+s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
+{
+  rtx insn;
+
+  /* If the pool is empty, we're done.  */
+  if (pool->size == 0)
+    {
+      remove_insn (pool->pool_insn);
+      s390_free_pool (pool);
+      return;
+    }
+
+  /* We need correct insn addresses.  */
+  shorten_branches (get_insns ());
+
+  /* On zSeries, we use a LARL to load the pool register.  The pool is
+     located in the .rodata section, so we emit it after the function.  */
+  if (TARGET_CPU_ZARCH)
+    {
+      insn = gen_main_base_64 (base_reg, pool->label);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+     
+      insn = get_last_insn (); 
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      s390_dump_pool (pool, 0);
+    }
+
+  /* On S/390, if the total size of the function's code plus literal pool
+     does not exceed 4096 bytes, we use BASR to set up a function base
+     pointer, and emit the literal pool at the end of the function.  */
+  else if (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
+          + pool->size + 8 /* alignment slop */ < 4096)
+    {
+      insn = gen_main_base_31_small (base_reg, pool->label);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+
+      insn = emit_label_after (pool->label, insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      insn = get_last_insn ();
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      s390_dump_pool (pool, 1);
+    }
+
+  /* Otherwise, we emit an inline literal pool and use BASR to branch
+     over it, setting up the pool register at the same time.  */
+  else
+    {
+      rtx pool_end = gen_label_rtx ();
+
+      insn = gen_main_base_31_large (base_reg, pool->label, pool_end);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+
+      insn = emit_label_after (pool->label, insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      insn = emit_label_after (pool_end, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      s390_dump_pool (pool, 1);
+    }
+
+
+  /* Replace all literal pool references.  */
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       replace_ltrel_base (&PATTERN (insn), base_reg);
+
+      if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+        {
+          rtx addr, pool_ref = NULL_RTX;
+          find_constant_pool_ref (PATTERN (insn), &pool_ref);
+          if (pool_ref)
+            {
+              addr = s390_find_constant (pool, get_pool_constant (pool_ref),
+                                               get_pool_mode (pool_ref));
+              addr = gen_rtx_PLUS (Pmode, base_reg, addr);
+              replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
+              INSN_CODE (insn) = -1;
+            }
+        }
+    }
+
+
+  /* Free the pool.  */
+  s390_free_pool (pool);
+}
+
+/* POOL holds the main literal pool as collected by s390_mainpool_start.
+   We have decided we cannot use this pool, so revert all changes
+   to the current function that were done by s390_mainpool_start.  */
+static void
+s390_mainpool_cancel (struct constant_pool *pool)
+{
+  /* We didn't actually change the instruction stream, so simply
+     free the pool memory.  */
+  s390_free_pool (pool);
+}
+
+
+/* Chunkify the literal pool.  BASE_REG is to be used as pool
+   register.  */
 
 #define S390_POOL_CHUNK_MIN    0xc00
 #define S390_POOL_CHUNK_MAX    0xe00
 
 static struct constant_pool *
-s390_chunkify_start (void)
+s390_chunkify_start (rtx base_reg)
 {
-  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
-
   struct constant_pool *curr_pool = NULL, *pool_list = NULL;
   int extra_size = 0;
   bitmap far_labels;
@@ -4312,14 +4521,9 @@ s390_chunkify_start (void)
   rtx insn;
 
   rtx (*gen_reload_base) (rtx, rtx) =
-    TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31;
+    TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31;
 
 
-  /* Do we need to chunkify the literal pool?  */
-
-  if (get_pool_size () < S390_POOL_CHUNK_MAX)
-    return NULL;
-
   /* We need correct insn addresses.  */
 
   shorten_branches (get_insns ());
@@ -4383,7 +4587,7 @@ s390_chunkify_start (void)
           || INSN_ADDRESSES (INSN_UID (insn)) == -1)
        continue;
 
-      if (TARGET_64BIT)
+      if (TARGET_CPU_ZARCH)
        {
          if (curr_pool->size < S390_POOL_CHUNK_MAX)
            continue;
@@ -4568,12 +4772,12 @@ s390_chunkify_start (void)
 
 /* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
    After we have decided to use this list, finish implementing
-   all changes to the current function as required.  */
+   all changes to the current function as required.  BASE_REG is
+   to be used as pool base register.  */
 
 static void
-s390_chunkify_finish (struct constant_pool *pool_list)
+s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
 {
-  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
   struct constant_pool *curr_pool = NULL;
   rtx insn;
 
@@ -4607,7 +4811,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
   /* Dump out all literal pools.  */
 
   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
-    s390_dump_pool (curr_pool);
+    s390_dump_pool (curr_pool, 0);
 
   /* Free pool list.  */
 
@@ -4680,51 +4884,10 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
 }
 
 
-/* Index of constant pool chunk that is currently being processed.
-   Set to -1 before function output has started.  */
-int s390_pool_count = -1;
-
-/* Number of elements of current constant pool.  */
-int s390_nr_constants;
-
-/* Output main constant pool to stdio stream FILE.  */
+/* Output the constant pool entry EXP in mode MODE with alignment ALIGN.  */
 
 void
-s390_output_constant_pool (rtx start_label, rtx end_label)
-{
-  if (TARGET_64BIT)
-    {
-      readonly_data_section ();
-      ASM_OUTPUT_ALIGN (asm_out_file, 3);
-      targetm.asm_out.internal_label (asm_out_file, "L",
-                                     CODE_LABEL_NUMBER (start_label));
-    }
-  else
-    {
-      targetm.asm_out.internal_label (asm_out_file, "L",
-                                     CODE_LABEL_NUMBER (start_label));
-      ASM_OUTPUT_ALIGN (asm_out_file, 2);
-    }
-
-  s390_pool_count = 0;
-  output_constant_pool (current_function_name, current_function_decl);
-  s390_pool_count = -1;
-  if (TARGET_64BIT)
-    function_section (current_function_decl);
-  else
-    {
-      ASM_OUTPUT_ALIGN (asm_out_file, 1);
-      targetm.asm_out.internal_label (asm_out_file, "L",
-                                     CODE_LABEL_NUMBER (end_label));
-    }
-}
-
-/* Output to FILE the constant pool entry EXP in mode MODE
-   with alignment ALIGN.  */
-
-void
-s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode, 
-                       unsigned int align)
+s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
 {
   REAL_VALUE_TYPE r;
 
@@ -4739,18 +4902,7 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
       break;
 
     case MODE_INT:
-      if (GET_CODE (exp) == CONST
-         || GET_CODE (exp) == SYMBOL_REF
-         || GET_CODE (exp) == LABEL_REF)
-       {
-         fputs (integer_asm_op (GET_MODE_SIZE (mode), TRUE), file);
-         s390_output_symbolic_const (file, exp);
-         fputc ('\n', file);
-       }
-      else
-       {
-         assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
-       }
+      assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
       break;
 
     default:
@@ -4760,41 +4912,21 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
 
 
 /* Rework the prolog/epilog to avoid saving/restoring
-   registers unnecessarily.  If TEMP_REGNO is nonnegative,
-   it specifies the number of a caller-saved register used
-   as temporary scratch register by code emitted during
-   machine dependent reorg.  */
+   registers unnecessarily.  BASE_USED specifies whether
+   the literal pool base register needs to be saved.  */
 
 static void
-s390_optimize_prolog (int temp_regno)
+s390_optimize_prolog (bool base_used)
 {
   int save_first, save_last, restore_first, restore_last;
   int i, j;
   rtx insn, new_insn, next_insn;
 
   /* Recompute regs_ever_live data for special registers.  */
-  regs_ever_live[BASE_REGISTER] = 0;
-  regs_ever_live[RETURN_REGNUM] = 0;
+  regs_ever_live[BASE_REGISTER] = base_used;
+  regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p;
   regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
 
-  /* If there is (possibly) any pool entry, we need to
-     load the base register.
-     ??? FIXME: this should be more precise.  */
-  if (get_pool_size ())
-    regs_ever_live[BASE_REGISTER] = 1;
-
-  /* In non-leaf functions, the prolog/epilog code relies
-     on RETURN_REGNUM being saved in any case.  We also need
-     to save the return register if __builtin_return_address (0)
-     was used in the current function.  */
-  if (!current_function_is_leaf 
-      || cfun->machine->save_return_addr_p)
-    regs_ever_live[RETURN_REGNUM] = 1;
-
-  /* We need to save/restore the temporary register.  */
-  if (temp_regno >= 0)
-    regs_ever_live[temp_regno] = 1;
-
 
   /* Find first and last gpr to be saved.  */
 
@@ -4841,7 +4973,7 @@ s390_optimize_prolog (int temp_regno)
   /* If all special registers are in fact used, there's nothing we
      can do, so no point in walking the insn list.  */
   if (i <= BASE_REGISTER && j >= BASE_REGISTER
-      && i <= RETURN_REGNUM && j >= RETURN_REGNUM)
+      && (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM)))
     return;
 
 
@@ -4856,10 +4988,9 @@ s390_optimize_prolog (int temp_regno)
 
       if (GET_CODE (insn) != INSN)
        continue;
-      if (GET_CODE (PATTERN (insn)) != PARALLEL)
-       continue;
 
-      if (store_multiple_operation (PATTERN (insn), VOIDmode))
+      if (GET_CODE (PATTERN (insn)) == PARALLEL
+         && store_multiple_operation (PATTERN (insn), VOIDmode))
        {
          set = XVECEXP (PATTERN (insn), 0, 0);
          first = REGNO (SET_SRC (set));
@@ -4870,9 +5001,31 @@ s390_optimize_prolog (int temp_regno)
 
          if (GET_CODE (base) != REG || off < 0)
            continue;
-         if (first > BASE_REGISTER && first > RETURN_REGNUM)
+         if (first > BASE_REGISTER || last < BASE_REGISTER)
            continue;
-         if (last < BASE_REGISTER && last < RETURN_REGNUM)
+
+         if (save_first != -1)
+           {
+             new_insn = save_gprs (base, off, save_first, save_last);
+             new_insn = emit_insn_before (new_insn, insn);
+             INSN_ADDRESSES_NEW (new_insn, -1);
+           }
+
+         remove_insn (insn);
+         continue;
+       }
+
+      if (GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (SET_SRC (PATTERN (insn))) == REG
+         && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGISTER
+         && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
+       {
+         set = PATTERN (insn);
+         offset = const0_rtx;
+         base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
+         off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+
+         if (GET_CODE (base) != REG || off < 0)
            continue;
 
          if (save_first != -1)
@@ -4883,9 +5036,11 @@ s390_optimize_prolog (int temp_regno)
            }
 
          remove_insn (insn);
+         continue;
        }
 
-      if (load_multiple_operation (PATTERN (insn), VOIDmode))
+      if (GET_CODE (PATTERN (insn)) == PARALLEL
+         && load_multiple_operation (PATTERN (insn), VOIDmode))
        {
          set = XVECEXP (PATTERN (insn), 0, 0);
          first = REGNO (SET_DEST (set));
@@ -4896,9 +5051,31 @@ s390_optimize_prolog (int temp_regno)
 
          if (GET_CODE (base) != REG || off < 0)
            continue;
-         if (first > BASE_REGISTER && first > RETURN_REGNUM)
+         if (first > BASE_REGISTER || last < BASE_REGISTER)
            continue;
-         if (last < BASE_REGISTER && last < RETURN_REGNUM)
+
+         if (restore_first != -1)
+           {
+             new_insn = restore_gprs (base, off, restore_first, restore_last);
+             new_insn = emit_insn_before (new_insn, insn);
+             INSN_ADDRESSES_NEW (new_insn, -1);
+           }
+
+         remove_insn (insn);
+         continue;
+       }
+
+      if (GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+         && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGISTER
+         && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
+       {
+         set = PATTERN (insn);
+         offset = const0_rtx;
+         base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
+         off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+
+         if (GET_CODE (base) != REG || off < 0)
            continue;
 
          if (restore_first != -1)
@@ -4909,6 +5086,7 @@ s390_optimize_prolog (int temp_regno)
            }
 
          remove_insn (insn);
+         continue;
        }
     }
 }
@@ -4918,15 +5096,26 @@ s390_optimize_prolog (int temp_regno)
 static void
 s390_reorg (void)
 {
-  rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
-  bool temp_used = 0;
+  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
+  bool base_used = false;
+  bool pool_overflow = false;
 
   /* Make sure all splits have been performed; splits after
      machine_dependent_reorg might confuse insn length counts.  */
   split_all_insns_noflow ();
 
 
-  /* There are two problematic situations we need to correct:
+  /* In small leaf functions, try to use an unused call-clobbered
+     register as base register to avoid save/restore overhead.  */
+  if (current_function_is_leaf && !regs_ever_live[5])
+    base_reg = gen_rtx_REG (Pmode, 5);
+
+
+  /* Install the main literal pool and the associated base
+     register load insns.
+
+     In addition, there are two problematic situations we need 
+     to correct:
 
      - the literal pool might be > 4096 bytes in size, so that
        some of its elements cannot be directly accessed
@@ -4957,31 +5146,49 @@ s390_reorg (void)
 
   for (;;)
     {
-      struct constant_pool *pool_list;
+      struct constant_pool *pool = NULL;
 
-      /* Try to chunkify the literal pool.  */
-      pool_list = s390_chunkify_start ();
+      /* Collect the literal pool.  */
+      if (!pool_overflow)
+       {
+         pool = s390_mainpool_start ();
+         if (!pool)
+           pool_overflow = true;
+       }
+
+      /* If literal pool overflowed, start to chunkify it.  */
+      if (pool_overflow)
+        pool = s390_chunkify_start (base_reg);
 
       /* Split out-of-range branches.  If this has created new
         literal pool entries, cancel current chunk list and
-        recompute it.  */
-      if (s390_split_branches (temp_reg, &temp_used))
+        recompute it.  zSeries machines have large branch
+        instructions, so we never need to split a branch.  */
+      if (!TARGET_CPU_ZARCH && s390_split_branches ())
         {
-          if (pool_list)
-            s390_chunkify_cancel (pool_list);
+          if (pool_overflow)
+            s390_chunkify_cancel (pool);
+         else
+            s390_mainpool_cancel (pool);
 
           continue;
         }
 
       /* If we made it up to here, both conditions are satisfied.
-        Finish up pool chunkification if required.  */
-      if (pool_list)
-       s390_chunkify_finish (pool_list);
+        Finish up literal pool related changes.  */
+      if ((pool_overflow || pool->size > 0)
+          && REGNO (base_reg) == BASE_REGISTER)
+       base_used = true;
+
+      if (pool_overflow)
+       s390_chunkify_finish (pool, base_reg);
+      else
+       s390_mainpool_finish (pool, base_reg);
 
       break;
     }
 
-  s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
+  s390_optimize_prolog (base_used);
 }
 
 
@@ -4994,6 +5201,11 @@ s390_return_addr_rtx (int count, rtx frame)
 {
   rtx addr;
 
+  /* Without backchain, we fail for all but the current frame.  */
+
+  if (!TARGET_BACKCHAIN && count > 0)
+    return NULL_RTX;
+
   /* For the current frame, we need to make sure the initial
      value of RETURN_REGNUM is actually saved.  */
 
@@ -5027,11 +5239,10 @@ find_unused_clobbered_reg (void)
 static void
 s390_frame_info (void)
 {
-  char gprs_ever_live[16];
   int i, j;
   HOST_WIDE_INT fsize = get_frame_size ();
 
-  if (fsize > 0x7fff0000)
+  if (!TARGET_64BIT && fsize > 0x7fff0000)
     fatal_error ("Total size of local variables exceeds architecture limit.");
 
   /* fprs 8 - 15 are caller saved for 64 Bit ABI.  */
@@ -5054,31 +5265,42 @@ s390_frame_info (void)
       || current_function_stdarg)
     cfun->machine->frame_size += STARTING_FRAME_OFFSET;
 
+  /* If we use the return register, we'll need to make sure
+     it is going to be saved/restored.  */
+
+  if (!current_function_is_leaf
+      || regs_ever_live[RETURN_REGNUM])
+    cfun->machine->save_return_addr_p = 1;
+
   /* Find first and last gpr to be saved.  Note that at this point,
-     we assume the return register and the base register always
-     need to be saved.  This is done because the usage of these
+     we assume the base register and -on S/390- the return register
+     always need to be saved.  This is done because the usage of these
      register might change even after the prolog was emitted.
      If it turns out later that we really don't need them, the
      prolog/epilog code is modified again.  */
 
-  for (i = 0; i < 16; i++)
-    gprs_ever_live[i] = regs_ever_live[i] && !global_regs[i];
-
-  if (flag_pic)
-    gprs_ever_live[PIC_OFFSET_TABLE_REGNUM] =
-    regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
-  gprs_ever_live[BASE_REGISTER] = 1;
-  gprs_ever_live[RETURN_REGNUM] = 1;
-  gprs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
+  regs_ever_live[BASE_REGISTER] = 1;
+  if (!TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p)
+    regs_ever_live[RETURN_REGNUM] = 1;
+  regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
 
   for (i = 6; i < 16; i++)
-    if (gprs_ever_live[i])
-      break;
+    if (regs_ever_live[i])
+      if (!global_regs[i]
+         || i == STACK_POINTER_REGNUM
+          || i == RETURN_REGNUM
+          || i == BASE_REGISTER
+          || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
+       break;
 
   for (j = 15; j > i; j--)
-    if (gprs_ever_live[j])
-      break;
-
+    if (regs_ever_live[j])
+      if (!global_regs[j]
+         || j == STACK_POINTER_REGNUM
+          || j == RETURN_REGNUM
+          || j == BASE_REGISTER
+          || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM))
+       break;
 
   /* Save / Restore from gpr i to j.  */
   cfun->machine->first_save_gpr = i;
@@ -5093,7 +5315,7 @@ s390_frame_info (void)
 /* Return offset between argument pointer and frame pointer
    initially after prologue.  */
 
-int
+HOST_WIDE_INT
 s390_arg_frame_offset (void)
 {
   HOST_WIDE_INT fsize = get_frame_size ();
@@ -5266,7 +5488,7 @@ s390_load_got (int maybe_dead)
       SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
     }
 
-  if (TARGET_64BIT)
+  if (TARGET_CPU_ZARCH)
     {
       rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
       if (maybe_dead)
@@ -5305,7 +5527,6 @@ s390_emit_prologue (void)
 {
   rtx insn, addr;
   rtx temp_reg;
-  rtx pool_start_label, pool_end_label;
   int i;
 
   /* Compute frame_info.  */
@@ -5316,7 +5537,6 @@ s390_emit_prologue (void)
      See below for why TPF must use the register 1.  */
 
   if (!current_function_is_leaf
-      && get_pool_size () < S390_POOL_CHUNK_MAX / 2
       && !TARGET_TPF)
     temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
   else
@@ -5328,53 +5548,25 @@ s390_emit_prologue (void)
                    cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
   emit_insn (insn);
 
-  /* Dump constant pool and set constant pool register.  */
+  /* Dummy insn to mark literal pool slot.  */
 
-  pool_start_label = gen_label_rtx();
-  pool_end_label = gen_label_rtx();
-  cfun->machine->literal_pool_label = pool_start_label;
-
-  if (TARGET_64BIT)
-    insn = emit_insn (gen_literal_pool_64 (gen_rtx_REG (Pmode, BASE_REGISTER),
-                          pool_start_label, pool_end_label));
-  else
-    insn = emit_insn (gen_literal_pool_31 (gen_rtx_REG (Pmode, BASE_REGISTER),
-                                            pool_start_label, pool_end_label));
+  emit_insn (gen_main_pool ());
 
   /* Save fprs for variable args.  */
 
   if (current_function_stdarg)
-    {
-      /* Save fpr 0 and 2.  */
-
-      save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 32, 16);
-      save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 24, 17);
-
-      if (TARGET_64BIT)
-       {
-         /* Save fpr 4 and 6.  */
-
-         save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
-         save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
-       }
-    }
+    for (i = 16; i < (TARGET_64BIT ? 20 : 18); i++)
+      save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i);
 
   /* Save fprs 4 and 6 if used (31 bit ABI).  */
 
   if (!TARGET_64BIT)
-    {
-      /* Save fpr 4 and 6.  */
-      if (regs_ever_live[18] && !global_regs[18])
-       {
-         insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
-         RTX_FRAME_RELATED_P (insn) = 1;
-       }
-      if (regs_ever_live[19] && !global_regs[19])
+    for (i = 18; i < 20; i++)
+      if (regs_ever_live[i] && !global_regs[i])
        {
-         insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
+         insn = save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i);
          RTX_FRAME_RELATED_P (insn) = 1;
        }
-    }
 
   /* Decrement stack pointer.  */
 
@@ -5400,7 +5592,7 @@ s390_emit_prologue (void)
        }
       else
        {
-         if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K'))
+         if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
            frame_off = force_const_mem (Pmode, frame_off);
 
           insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
@@ -5501,6 +5693,7 @@ s390_emit_epilogue (void)
   rtx frame_pointer, return_reg;
   int area_bottom, area_top, offset = 0;
   rtvec p;
+  int i;
 
   if (TARGET_TPF)
     {
@@ -5556,20 +5749,14 @@ s390_emit_epilogue (void)
     }
   else
     {
-      if (regs_ever_live[18] && !global_regs[18])
-       {
-         if (area_bottom > STACK_POINTER_OFFSET - 16)
-           area_bottom = STACK_POINTER_OFFSET - 16;
-         if (area_top < STACK_POINTER_OFFSET - 8)
-           area_top = STACK_POINTER_OFFSET - 8;
-       }
-      if (regs_ever_live[19] && !global_regs[19])
-       {
-         if (area_bottom > STACK_POINTER_OFFSET - 8)
-           area_bottom = STACK_POINTER_OFFSET - 8;
-         if (area_top < STACK_POINTER_OFFSET)
-           area_top = STACK_POINTER_OFFSET;
-       }
+      for (i = 18; i < 20; i++)
+       if (regs_ever_live[i] && !global_regs[i])
+         {
+           if (area_bottom > 16*UNITS_PER_WORD + 8*(i-16))
+             area_bottom = 16*UNITS_PER_WORD + 8*(i-16);
+           if (area_top < 16*UNITS_PER_WORD + 8*(i-16) + 8)
+             area_top = 16*UNITS_PER_WORD + 8*(i-16) + 8;
+         } 
     }
 
   /* Check whether we can access the register save area.
@@ -5600,7 +5787,7 @@ s390_emit_epilogue (void)
        }
       else
        {
-         if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K'))
+         if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
            frame_off = force_const_mem (Pmode, frame_off);
 
          insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
@@ -5611,8 +5798,6 @@ s390_emit_epilogue (void)
 
   if (TARGET_64BIT)
     {
-      int i;
-
       if (cfun->machine->save_fprs_p)
        for (i = 24; i < 32; i++)
          if (regs_ever_live[i] && !global_regs[i])
@@ -5621,10 +5806,10 @@ s390_emit_epilogue (void)
     }
   else
     {
-      if (regs_ever_live[18] && !global_regs[18])
-       restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 16, 18);
-      if (regs_ever_live[19] && !global_regs[19])
-       restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 8, 19);
+      for (i = 18; i < 20; i++)
+       if (regs_ever_live[i] && !global_regs[i])
+         restore_fpr (frame_pointer, 
+                      offset + 16*UNITS_PER_WORD + 8*(i-16), i);
     }
 
   /* Return register.  */
@@ -5666,7 +5851,9 @@ s390_emit_epilogue (void)
       /* Fetch return address from stack before load multiple,
         this will do good for scheduling.  */
 
-      if (!current_function_is_leaf)
+      if (cfun->machine->save_return_addr_p
+         || (cfun->machine->first_restore_gpr < BASE_REGISTER
+             && cfun->machine->last_save_gpr > RETURN_REGNUM))
        {
          int return_regnum = find_unused_clobbered_reg();
          if (!return_regnum)
@@ -5726,6 +5913,10 @@ s390_function_arg_size (enum machine_mode mode, tree type)
 static bool
 s390_function_arg_float (enum machine_mode mode, tree type)
 {
+  int size = s390_function_arg_size (mode, type);
+  if (size > 8)
+    return false;
+
   /* Soft-float changes the ABI: no floating-point registers are used.  */
   if (TARGET_SOFT_FLOAT)
     return false;
@@ -5760,6 +5951,39 @@ s390_function_arg_float (enum machine_mode mode, tree type)
   return TREE_CODE (type) == REAL_TYPE;
 }
 
+/* Return true if a function argument of type TYPE and mode MODE
+   is to be passed in an integer register, or a pair of integer
+   registers, if available.  */
+
+static bool
+s390_function_arg_integer (enum machine_mode mode, tree type)
+{
+  int size = s390_function_arg_size (mode, type);
+  if (size > 8)
+    return false;
+
+  /* No type info available for some library calls ...  */
+  if (!type)
+    return GET_MODE_CLASS (mode) == MODE_INT
+          || (TARGET_SOFT_FLOAT &&  GET_MODE_CLASS (mode) == MODE_FLOAT);
+
+  /* We accept small integral (and similar) types.  */
+  if (INTEGRAL_TYPE_P (type)
+      || POINTER_TYPE_P (type) 
+      || TREE_CODE (type) == OFFSET_TYPE
+      || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
+    return true;
+
+  /* We also accept structs of size 1, 2, 4, 8 that are not
+     passed in floating-point registers.  */  
+  if (AGGREGATE_TYPE_P (type)
+      && exact_log2 (size) >= 0
+      && !s390_function_arg_float (mode, type))
+    return true;
+
+  return false;
+}
+
 /* Return 1 if a function argument of type TYPE and mode MODE
    is to be passed by reference.  The ABI specifies that only
    structures of size 1, 2, 4, or 8 bytes are passed by value,
@@ -5770,15 +5994,16 @@ int
 s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
 {
   int size = s390_function_arg_size (mode, type);
+  if (size > 8)
+    return true;
 
   if (type)
     {
-      if (AGGREGATE_TYPE_P (type) &&
-          size != 1 && size != 2 && size != 4 && size != 8
-         && !s390_function_arg_float (mode, type))
+      if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0)
         return 1;
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
+      if (TREE_CODE (type) == COMPLEX_TYPE
+         || TREE_CODE (type) == VECTOR_TYPE)
         return 1;
     }
 
@@ -5803,11 +6028,13 @@ s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       cum->fprs += 1;
     }
-  else
+  else if (s390_function_arg_integer (mode, type))
     {
       int size = s390_function_arg_size (mode, type);
       cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
     }
+  else
+    abort ();
 }
 
 /* Define where to put the arguments to a function.
@@ -5841,9 +6068,9 @@ s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
       if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
        return 0;
       else
-       return gen_rtx (REG, mode, cum->fprs + 16);
+       return gen_rtx_REG (mode, cum->fprs + 16);
     }
-  else
+  else if (s390_function_arg_integer (mode, type))
     {
       int size = s390_function_arg_size (mode, type);
       int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
@@ -5851,8 +6078,70 @@ s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
       if (cum->gprs + n_gprs > 5)
        return 0;
       else
-       return gen_rtx (REG, mode, cum->gprs + 2);
+       return gen_rtx_REG (mode, cum->gprs + 2);
+    }
+
+  /* After the real arguments, expand_call calls us once again
+     with a void_type_node type.  Whatever we return here is
+     passed as operand 2 to the call expanders.
+
+     We don't need this feature ...  */
+  else if (type == void_type_node)
+    return const0_rtx;
+
+  abort ();
+}
+
+/* Return true if return values of type TYPE should be returned
+   in a memory buffer whose address is passed by the caller as
+   hidden first argument.  */
+
+static bool
+s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED)
+{
+  /* We accept small integral (and similar) types.  */
+  if (INTEGRAL_TYPE_P (type)
+      || POINTER_TYPE_P (type) 
+      || TREE_CODE (type) == OFFSET_TYPE
+      || TREE_CODE (type) == REAL_TYPE)
+    return int_size_in_bytes (type) > 8;
+
+  /* Aggregates and similar constructs are always returned
+     in memory.  */
+  if (AGGREGATE_TYPE_P (type)
+      || TREE_CODE (type) == COMPLEX_TYPE
+      || TREE_CODE (type) == VECTOR_TYPE)
+    return true;
+
+  /* ??? We get called on all sorts of random stuff from
+     aggregate_value_p.  We can't abort, but it's not clear
+     what's safe to return.  Pretend it's a struct I guess.  */
+  return true;
+}
+
+/* Define where to return a (scalar) value of type TYPE.
+   If TYPE is null, define where to return a (scalar)
+   value of mode MODE from a libcall.  */
+
+rtx
+s390_function_value (tree type, enum machine_mode mode)
+{
+  if (type)
+    {
+      int unsignedp = TREE_UNSIGNED (type);
+      mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
     }
+
+  if (GET_MODE_CLASS (mode) != MODE_INT 
+      && GET_MODE_CLASS (mode) != MODE_FLOAT)
+    abort ();
+  if (GET_MODE_SIZE (mode) > 8)
+    abort ();
+
+  if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    return gen_rtx_REG (mode, 16);
+  else
+    return gen_rtx_REG (mode, 2);
 }
 
 
@@ -5866,7 +6155,6 @@ s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
             long __fpr;
             void *__overflow_arg_area;
             void *__reg_save_area;
-
         } va_list[1];
 
    where __gpr and __fpr hold the number of general purpose
@@ -5878,8 +6166,8 @@ s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
    saves all registers used for argument passing into this
    area if the function uses variable arguments.  */
 
-tree
-s390_build_va_list (void)
+static tree
+s390_build_builtin_va_list (void)
 {
   tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
 
@@ -6326,12 +6614,10 @@ s390_trampoline_template (FILE *file)
 void
 s390_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
 {
-  emit_move_insn (gen_rtx
-                 (MEM, Pmode,
+  emit_move_insn (gen_rtx_MEM (Pmode,
                   memory_address (Pmode,
                   plus_constant (addr, (TARGET_64BIT ? 20 : 12) ))), cxt);
-  emit_move_insn (gen_rtx
-                 (MEM, Pmode,
+  emit_move_insn (gen_rtx_MEM (Pmode,
                   memory_address (Pmode,
                   plus_constant (addr, (TARGET_64BIT ? 28 : 16) ))), fnaddr);
 }
@@ -6434,7 +6720,7 @@ s390_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
                         rtx x ATTRIBUTE_UNUSED,
                         unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  if (TARGET_64BIT)
+  if (TARGET_CPU_ZARCH)
     readonly_data_section ();
   else
     function_section (current_function_decl);
@@ -6480,7 +6766,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
     }
 
   /* Operand 1 is the 'this' pointer.  */
-  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
     op[1] = gen_rtx_REG (Pmode, 3);
   else
     op[1] = gen_rtx_REG (Pmode, 2);
@@ -6508,9 +6794,9 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
     {
       /* Setup literal pool pointer if required.  */
       if ((!DISP_IN_RANGE (delta)
-          && !CONST_OK_FOR_LETTER_P (delta, 'K'))
+          && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
          || (!DISP_IN_RANGE (vcall_offset)
-             && !CONST_OK_FOR_LETTER_P (vcall_offset, 'K')))
+             && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
        {
          op[5] = gen_label_rtx ();
          output_asm_insn ("larl\t%4,%5", op);
@@ -6519,11 +6805,11 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       /* Add DELTA to this pointer.  */
       if (delta)
        {
-         if (CONST_OK_FOR_LETTER_P (delta, 'J'))
+         if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
            output_asm_insn ("la\t%1,%2(%1)", op);
          else if (DISP_IN_RANGE (delta))
            output_asm_insn ("lay\t%1,%2(%1)", op);
-         else if (CONST_OK_FOR_LETTER_P (delta, 'K'))
+         else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
            output_asm_insn ("aghi\t%1,%2", op);
          else
            {
@@ -6540,7 +6826,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
              output_asm_insn ("lg\t%4,0(%1)", op);
              output_asm_insn ("ag\t%1,%3(%4)", op);
            }
-         else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+         else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
            {
              output_asm_insn ("lghi\t%4,%3", op);
              output_asm_insn ("ag\t%4,0(%1)", op);
@@ -6583,9 +6869,9 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       /* Setup base pointer if required.  */
       if (!vcall_offset
          || (!DISP_IN_RANGE (delta)
-              && !CONST_OK_FOR_LETTER_P (delta, 'K'))
+              && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
          || (!DISP_IN_RANGE (delta)
-              && !CONST_OK_FOR_LETTER_P (vcall_offset, 'K')))
+              && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
        {
          op[5] = gen_label_rtx ();
          output_asm_insn ("basr\t%4,0", op);
@@ -6596,11 +6882,11 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       /* Add DELTA to this pointer.  */
       if (delta)
        {
-         if (CONST_OK_FOR_LETTER_P (delta, 'J'))
+         if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
            output_asm_insn ("la\t%1,%2(%1)", op);
          else if (DISP_IN_RANGE (delta))
            output_asm_insn ("lay\t%1,%2(%1)", op);
-         else if (CONST_OK_FOR_LETTER_P (delta, 'K'))
+         else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
            output_asm_insn ("ahi\t%1,%2", op);
          else
            {
@@ -6612,7 +6898,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       /* Perform vcall adjustment.  */
       if (vcall_offset)
         {
-         if (CONST_OK_FOR_LETTER_P (vcall_offset, 'J'))
+         if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'J', "J"))
            {
              output_asm_insn ("lg\t%4,0(%1)", op);
              output_asm_insn ("a\t%1,%3(%4)", op);
@@ -6622,7 +6908,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
              output_asm_insn ("lg\t%4,0(%1)", op);
              output_asm_insn ("ay\t%1,%3(%4)", op);
            }
-         else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+         else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
            {
              output_asm_insn ("lhi\t%4,%3", op);
              output_asm_insn ("a\t%4,0(%1)", op);