diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8e7e28c7ffcc59420c12ce66d29ed859aeded18f..7302097021b7ad7fa2ffc1058ca07d746cf0c02a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2003-10-14  Ulrich Weigand  <uweigand@de.ibm.com>
+
+	* config/s390/s390-protos.h (s390_alc_comparison): Add prototype.
+	(s390_slb_comparison): Likewise.
+	* config/s390/s390.c (s390_alc_comparison, s390_slb_comparison):
+	New functions.
+	* config/s390/s390.h (PREDICATE_CODES): Add s390_alc_comparison
+	and s390_slb_comparison.
+	* config/s390/s390.md ("*adddi3_31", "*subdi3_31"): Do not use on 
+	zSeries machines.
+	("*adddi3_31z", "*subdi3_31z"): New insns.
+	("*adddi3_alc_cc", "*adddi3_alc", "*subdi3_slb_cc", "*subdi3_slb",
+	"*addsi3_alc_cc", "*addsi3_alc", "*subsi3_slb_cc", "*subsi3_slb"):
+	New insns.
+	
 2003-10-14  Nathanael Nerode  <neroden@gcc.gnu.org>
 
 	* configure.in: Clean up some feedback echoes.
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 40026d3b85f66b056e3364c56be2ab9e416c7e13..76ceccdc5127c1ca0023927019dd75fb5452f3df 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -49,6 +49,8 @@ extern int tls_symbolic_operand (rtx);
 extern int s390_match_ccmode (rtx, enum machine_mode);
 extern enum machine_mode s390_tm_ccmode (rtx, rtx, int);
 extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
+extern int s390_alc_comparison (rtx op, enum machine_mode mode);
+extern int s390_slb_comparison (rtx op, enum machine_mode mode);
 extern int symbolic_reference_mentioned_p (rtx);
 extern int tls_symbolic_reference_mentioned_p (rtx);
 extern rtx s390_tls_get_offset (void);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index cf68a5210278e7f3eef6dc52454e428902526159..6d56b0278b15a7b4ee26ade329b024833a056e62 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -447,6 +447,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 (GET_RTX_CLASS (GET_CODE (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 (GET_RTX_CLASS (GET_CODE (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.  */
 
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 0a605505dfacb349598ff7126b4ed1fce3bc2378..1c3241c63e3b708c3ff0ffe02fe7635a093488e7 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -1030,7 +1030,9 @@ do {									\
   {"const0_operand",  { CONST_INT, CONST_DOUBLE }},			\
   {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, 		\
 			   CONST_INT, CONST_DOUBLE }},			\
-  {"s390_plus_operand", { PLUS }},
+  {"s390_plus_operand", { PLUS }},					\
+  {"s390_alc_comparison", { LTU, GTU, LEU, GEU }},			\
+  {"s390_slb_comparison", { LTU, GTU, LEU, GEU }},
 
 /* Specify the machine mode that this machine uses for the index in the
    tablejump instruction.  */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 9cdce811405dde602d94b396fb29163d0ceec27d..5f49e6ab1d138f8b64483eb2221464a6ab754dbc 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -3254,12 +3254,37 @@
    ag\t%0,%2"
   [(set_attr "op_type"  "RRE,RI,RXY")])
 
+(define_insn_and_split "*adddi3_31z"
+  [(set (match_operand:DI 0 "register_operand" "=&d")
+        (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0")
+                 (match_operand:DI 2 "general_operand" "do") ) )
+   (clobber (reg:CC 33))]
+  "!TARGET_64BIT && TARGET_CPU_ZARCH"
+  "#"
+  "&& reload_completed"
+  [(parallel
+    [(set (reg:CCL1 33)
+          (compare:CCL1 (plus:SI (match_dup 7) (match_dup 8))
+                        (match_dup 7)))
+     (set (match_dup 6) (plus:SI (match_dup 7) (match_dup 8)))])
+   (parallel
+    [(set (match_dup 3) (plus:SI (plus:SI (match_dup 4) (match_dup 5))
+                                 (ltu:SI (reg:CCL1 33) (const_int 0))))
+     (clobber (reg:CC 33))])]
+  "operands[3] = operand_subword (operands[0], 0, 0, DImode);
+   operands[4] = operand_subword (operands[1], 0, 0, DImode);
+   operands[5] = operand_subword (operands[2], 0, 0, DImode);
+   operands[6] = operand_subword (operands[0], 1, 0, DImode);
+   operands[7] = operand_subword (operands[1], 1, 0, DImode);
+   operands[8] = operand_subword (operands[2], 1, 0, DImode);"
+  [(set_attr "op_type"  "NN")])
+
 (define_insn_and_split "*adddi3_31"
   [(set (match_operand:DI 0 "register_operand" "=&d")
         (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0")
                  (match_operand:DI 2 "general_operand" "do") ) )
    (clobber (reg:CC 33))]
-  "!TARGET_64BIT"
+  "!TARGET_CPU_ZARCH"
   "#"
   "&& reload_completed"
   [(parallel
@@ -3804,12 +3829,37 @@
    sg\t%0,%2"
   [(set_attr "op_type"  "RRE,RRE")])
 
+(define_insn_and_split "*subdi3_31z"
+  [(set (match_operand:DI 0 "register_operand" "=&d")
+        (minus:DI (match_operand:DI 1 "register_operand" "0")
+                  (match_operand:DI 2 "general_operand" "do") ) )
+   (clobber (reg:CC 33))]
+  "!TARGET_64BIT && TARGET_CPU_ZARCH"
+  "#"
+  "&& reload_completed"
+  [(parallel
+    [(set (reg:CCL2 33)
+          (compare:CCL2 (minus:SI (match_dup 7) (match_dup 8))
+                        (match_dup 7)))
+     (set (match_dup 6) (minus:SI (match_dup 7) (match_dup 8)))])
+   (parallel
+    [(set (match_dup 3) (minus:SI (minus:SI (match_dup 4) (match_dup 5))
+                                  (gtu:SI (reg:CCL2 33) (const_int 0))))
+     (clobber (reg:CC 33))])]
+  "operands[3] = operand_subword (operands[0], 0, 0, DImode);
+   operands[4] = operand_subword (operands[1], 0, 0, DImode);
+   operands[5] = operand_subword (operands[2], 0, 0, DImode);
+   operands[6] = operand_subword (operands[0], 1, 0, DImode);
+   operands[7] = operand_subword (operands[1], 1, 0, DImode);
+   operands[8] = operand_subword (operands[2], 1, 0, DImode);"
+  [(set_attr "op_type"  "NN")])
+
 (define_insn_and_split "*subdi3_31"
   [(set (match_operand:DI 0 "register_operand" "=&d")
         (minus:DI (match_operand:DI 1 "register_operand" "0")
                   (match_operand:DI 2 "general_operand" "do") ) )
    (clobber (reg:CC 33))]
-  "!TARGET_64BIT"
+  "!TARGET_CPU_ZARCH"
   "#"
   "&& reload_completed"
   [(parallel
@@ -4057,6 +4107,127 @@
    (set_attr "type"     "fsimps,fsimps")])
 
 
+;;
+;;- Conditional add/subtract instructions.
+;;
+
+;
+; adddicc instruction pattern(s).
+;
+
+(define_insn "*adddi3_alc_cc"
+  [(set (reg 33) 
+        (compare
+          (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+                            (match_operand:DI 2 "general_operand" "d,m"))
+                   (match_operand:DI 3 "s390_alc_comparison" ""))
+          (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=d,d")
+        (plus:DI (plus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+  "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" 
+  "@
+   alcgr\\t%0,%2
+   alcg\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*adddi3_alc"
+  [(set (match_operand:DI 0 "register_operand" "=d,d")
+        (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+                          (match_operand:DI 2 "general_operand" "d,m"))
+                 (match_operand:DI 3 "s390_alc_comparison" "")))
+   (clobber (reg:CC 33))] 
+  "TARGET_64BIT" 
+  "@
+   alcgr\\t%0,%2
+   alcg\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*subdi3_slb_cc"
+  [(set (reg 33) 
+        (compare
+          (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0")
+                              (match_operand:DI 2 "general_operand" "d,m"))
+                    (match_operand:DI 3 "s390_slb_comparison" ""))
+          (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=d,d")
+        (minus:DI (minus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+  "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" 
+  "@
+   slbgr\\t%0,%2
+   slbg\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*subdi3_slb"
+  [(set (match_operand:DI 0 "register_operand" "=d,d")
+        (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0")
+                            (match_operand:DI 2 "general_operand" "d,m"))
+                  (match_operand:DI 3 "s390_slb_comparison" "")))
+   (clobber (reg:CC 33))] 
+  "TARGET_64BIT" 
+  "@
+   slbgr\\t%0,%2
+   slbg\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+;
+; addsicc instruction pattern(s).
+;
+
+(define_insn "*addsi3_alc_cc"
+  [(set (reg 33) 
+        (compare
+          (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+                            (match_operand:SI 2 "general_operand" "d,m"))
+                   (match_operand:SI 3 "s390_alc_comparison" ""))
+          (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d,d")
+        (plus:SI (plus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+  "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" 
+  "@
+   alcr\\t%0,%2
+   alc\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*addsi3_alc"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+        (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+                          (match_operand:SI 2 "general_operand" "d,m"))
+                 (match_operand:SI 3 "s390_alc_comparison" "")))
+   (clobber (reg:CC 33))]
+  "TARGET_CPU_ZARCH" 
+  "@
+   alcr\\t%0,%2
+   alc\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*subsi3_slb_cc"
+  [(set (reg 33) 
+        (compare
+          (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+                              (match_operand:SI 2 "general_operand" "d,m"))
+                    (match_operand:SI 3 "s390_slb_comparison" ""))
+          (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d,d")
+        (minus:SI (minus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+  "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" 
+  "@
+   slbr\\t%0,%2
+   slb\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+(define_insn "*subsi3_slb"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+        (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+                            (match_operand:SI 2 "general_operand" "d,m"))
+                  (match_operand:SI 3 "s390_slb_comparison" "")))
+   (clobber (reg:CC 33))] 
+  "TARGET_CPU_ZARCH" 
+  "@
+   slbr\\t%0,%2
+   slb\\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
+
 ;;
 ;;- Multiply instructions.
 ;;