diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1491f6ecd07730dcb76be4fb927a5f8ee8ea9ea5..2d2b1a0eed48b1e81588bfe33b019f10ee165508 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2005-07-13  Adrian Straeç·£ling  <straetling@de.ibm.com>
+
+	* config/s390/s390.c: (s390_cc_modes_compatible): Move before
+	"s390_emit_compare".  Add handling of CCZ1mode.
+	(s390_canonicalize_comparison): Simplify cascaded EQ, NE.
+	(390_emit_compare): Use "s390_cc_modes_compatible" for mode
+	checking.
+	(s390_branch_condition_mask): Add CCZ1mode handling.
+	* config/s390/s390.md: ("seq", "*seq"): New pattern.
+	("sync_compare_and_swap_cc<mode>", "*sync_compare_and_swap_cc<mode>"):
+	Use CCZ1mode instead of CCZmode.
+	* config/s390/s390-modes.def: Add CCZ1mode.  Comment new mode.
+
 2006-07-13  Adrian Straeç·£ling  <straetling@de.ibm.com>
 
 	* config/s390/s390.md: ("cmpstrsi", "*cmpstr<mode>"): New
diff --git a/gcc/config/s390/s390-modes.def b/gcc/config/s390/s390-modes.def
index 62be9863ed8b2bb6126480e2f6be940ee339faae..afcfb1b69e647f508172914106a39e551e6c9fc2 100644
--- a/gcc/config/s390/s390-modes.def
+++ b/gcc/config/s390/s390-modes.def
@@ -35,6 +35,7 @@ Condition Codes
 Check for zero
 
 CCZ:  EQ          NE           NE          NE
+CCZ1: EQ          NE                                  (CS)
 
 Unsigned compares
 
@@ -146,10 +147,17 @@ CCL3 mode. Together with the CCU mode this mode is used for jumpless
 implementations of several if-constructs - see s390_expand_addcc for more
 details.
 
+CCZ1
+
+The compare and swap instructions sets the condition code to 0/1 if the
+operands were equal/unequal. The CCZ1 mode ensures the result can be
+effectively placed into a register.
+
 */   
 
 
 CC_MODE (CCZ);
+CC_MODE (CCZ1);
 CC_MODE (CCA);
 CC_MODE (CCAP);
 CC_MODE (CCAN);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 3573db59e41b2b89fca1379c5b18ba6b62e253f0..e10afafabdf41ea0294004a98223909c627416a2 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -272,6 +272,41 @@ s390_set_has_landing_pad_p (bool value)
   cfun->machine->has_landing_pad_p = value;
 }
 
+/* If two condition code modes are compatible, return a condition code
+   mode which is compatible with both.  Otherwise, return
+   VOIDmode.  */
+
+static enum machine_mode
+s390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
+{
+  if (m1 == m2)
+    return m1;
+
+  switch (m1)
+    {
+    case CCZmode:
+      if (m2 == CCUmode || m2 == CCTmode || m2 == CCZ1mode
+	  || m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode)
+        return m2;
+      return VOIDmode;
+
+    case CCSmode:
+    case CCUmode:
+    case CCTmode:
+    case CCSRmode:
+    case CCURmode:
+    case CCZ1mode:
+      if (m2 == CCZmode)
+	return m1;
+      
+      return VOIDmode;
+
+    default:
+      return VOIDmode;
+    }
+  return VOIDmode;
+}
+
 /* Return true if SET either doesn't set the CC register, or else
    the source and destination have matching CC modes and that
    CC mode is at least as constrained as REQ_MODE.  */
@@ -612,6 +647,23 @@ s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
 	  *code = new_code;
 	}
     }
+
+  /* Simplify cascaded EQ, NE with const0_rtx.  */
+  if ((*code == NE || *code == EQ)
+      && (GET_CODE (*op0) == EQ || GET_CODE (*op0) == NE)
+      && GET_MODE (*op0) == SImode
+      && GET_MODE (XEXP (*op0, 0)) == CCZ1mode
+      && REG_P (XEXP (*op0, 0))
+      && XEXP (*op0, 1) == const0_rtx
+      && *op1 == const0_rtx)
+    {
+      if ((*code == EQ && GET_CODE (*op0) == NE)
+          || (*code == NE && GET_CODE (*op0) == EQ))
+	*code = EQ;
+      else
+	*code = NE;
+      *op0 = XEXP (*op0, 0);
+    }
 }
 
 /* Emit a compare instruction suitable to implement the comparison
@@ -625,8 +677,10 @@ s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
   rtx ret = NULL_RTX;
 
   /* Do not output a redundant compare instruction if a compare_and_swap
-     pattern already computed the result and the machine modes match.  */
-  if (s390_compare_emitted && GET_MODE (s390_compare_emitted) == mode)
+     pattern already computed the result and the machine modes are compatible.  */
+  if (s390_compare_emitted 
+      && (s390_cc_modes_compatible (GET_MODE (s390_compare_emitted), mode)
+	  == GET_MODE (s390_compare_emitted)))
     ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx); 
   else
     {
@@ -673,6 +727,7 @@ s390_branch_condition_mask (rtx code)
   switch (GET_MODE (XEXP (code, 0)))
     {
     case CCZmode:
+    case CCZ1mode:
       switch (GET_CODE (code))
         {
         case EQ:	return CC0;
@@ -7910,40 +7965,6 @@ s390_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
   return true;
 }
 
-/* If two condition code modes are compatible, return a condition code
-   mode which is compatible with both.  Otherwise, return
-   VOIDmode.  */
-
-static enum machine_mode
-s390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
-{
-  if (m1 == m2)
-    return m1;
-
-  switch (m1)
-    {
-    case CCZmode:
-      if (m2 == CCUmode || m2 == CCTmode
-	  || m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode)
-        return m2;
-      return VOIDmode;
-
-    case CCSmode:
-    case CCUmode:
-    case CCTmode:
-    case CCSRmode:
-    case CCURmode:
-      if (m2 == CCZmode)
-	return m1;
-      
-      return VOIDmode;
-
-    default:
-      return VOIDmode;
-    }
-  return VOIDmode;
-}
-
 /* This function is used by the call expanders of the machine description.
    It emits the call insn itself together with the necessary operations
    to adjust the target address and returns the emitted insn.
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 6aaed96e97080f199e0a9dc15bbfbbb1ed05639f..453191457d69b61b0100a30fa639c11ab7973f06 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -3973,6 +3973,34 @@
   "if (!s390_expand_addcc (<CODE>, s390_compare_op0, s390_compare_op1,
 			   operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
 
+(define_expand "seq"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "=d")
+          (match_dup 1))
+     (clobber (reg:CC CC_REGNUM))])
+   (parallel
+    [(set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))
+     (clobber (reg:CC CC_REGNUM))])]
+  ""
+{ 
+  if (!s390_compare_emitted || GET_MODE (s390_compare_emitted) != CCZ1mode)
+    FAIL;
+  operands[1] = s390_emit_compare (NE, s390_compare_op0, s390_compare_op1);
+  PUT_MODE (operands[1], SImode);
+})
+
+(define_insn_and_split "*sne"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+	(ne:SI (match_operand:CCZ1 1 "register_operand" "0") 
+	       (const_int 0)))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "#"
+  "reload_completed"
+  [(parallel
+    [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 28)))
+     (clobber (reg:CC CC_REGNUM))])])
+
 
 ;;
 ;;- Multiply instructions.
@@ -6797,10 +6825,10 @@
 	     (match_operand:GPR 3 "register_operand" "")]
 	    UNSPECV_CAS))
      (set (match_dup 4)
-	  (compare:CCZ (match_dup 1) (match_dup 2)))])]
+	  (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
   ""
 {
-  operands[4] = gen_rtx_REG (CCZmode, CC_REGNUM);
+  operands[4] = gen_rtx_REG (CCZ1mode, CC_REGNUM);
   s390_compare_op0 = operands[1];
   s390_compare_op1 = operands[2];
   s390_compare_emitted = operands[4];
@@ -6815,8 +6843,8 @@
 	   (match_operand:GPR 2 "register_operand" "0")
 	   (match_operand:GPR 3 "register_operand" "r")]
 	  UNSPECV_CAS))
-   (set (reg:CCZ CC_REGNUM)
-	(compare:CCZ (match_dup 1) (match_dup 2)))]
+   (set (reg:CCZ1 CC_REGNUM)
+	(compare:CCZ1 (match_dup 1) (match_dup 2)))]
   "" 
   "cs<g>\t%0,%3,%S1"
   [(set_attr "op_type" "RS<E>")