public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Dominik Vogt <vogt@linux.vnet.ibm.com>
To: gcc-patches@gcc.gnu.org
Cc: Andreas Krebbel <krebbel@linux.vnet.ibm.com>,
	       Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Subject: Re: [PATCH] S/390: Optimize atomic_compare_exchange and atomic_compare builtins.
Date: Fri, 07 Apr 2017 14:14:00 -0000	[thread overview]
Message-ID: <20170407141407.GA5569@linux.vnet.ibm.com> (raw)
In-Reply-To: <20170405135200.GA3230@linux.vnet.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 919 bytes --]

On Wed, Apr 05, 2017 at 02:52:00PM +0100, Dominik Vogt wrote:
> On Mon, Mar 27, 2017 at 09:27:35PM +0100, Dominik Vogt wrote:
> > The attached patch optimizes the atomic_exchange and
> > atomic_compare patterns on s390 and s390x (mostly limited to
> > SImode and DImode).  Among general optimizaation, the changes fix
> > most of the problems reported in PR 80080:
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80080
> > 
> > Bootstrapped and regression tested on a zEC12 with s390 and s390x
> > biarch.

New version attached.

v4:

  * Remoce CCZZ1 iterator. 
  * Remove duplicates of CS patterns. 
  * Move the skip_cs_label so that output is moved to vtarget even 
    if the CS instruction was not used. 
  * Removed leftover from "sne" (from an earlier version of the
  * patch). 

Bootstrapped and regression tested on a zEC12 with s390 and s390x
biarch.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

[-- Attachment #2: 0001-v4-ChangeLog --]
[-- Type: text/plain, Size: 1662 bytes --]

gcc/ChangeLog-dv-atomic-gcc7

	* s390-protos.h (s390_expand_cs_hqi): Removed.
	(s390_expand_cs, s390_expand_atomic_exchange_tdsi): New prototypes.
	* config/s390/s390.c (s390_emit_compare_and_swap): Handle all integer
	modes as well as CCZ1mode and CCZmode.
	(s390_expand_atomic_exchange_tdsi, s390_expand_atomic): Adapt to new
	signature of s390_emit_compare_and_swap.
	(s390_expand_cs_hqi): Likewise, make static.
	(s390_expand_cs_tdsi): Generate an explicit compare before trying
	compare-and-swap, in some cases.
	(s390_expand_cs): Wrapper function.
	(s390_expand_atomic_exchange_tdsi): New backend specific expander for
	atomic_exchange.
	(s390_match_ccmode_set): Allow CCZmode <-> CCZ1 mode.
	* config/s390/s390.md (define_peephole2): New peephole to help
	combining the load-and-test pattern with volatile memory.
	("cstorecc4"): Use load-on-condition and deal with CCZmode for
	TARGET_Z196.
	("atomic_compare_and_swap<mode>"): Merge the patterns for small and
	large integers.  Forbid symref memory operands.  Move expander to
	s390.c.  Require cc register.
	("atomic_compare_and_swap<DGPR:mode><CCZZ1:mode>_internal")
	("*atomic_compare_and_swap<TDI:mode><CCZZ1:mode>_1")
	("*atomic_compare_and_swapdi<CCZZ1:mode>_2")
	("*atomic_compare_and_swapsi<CCZZ1:mode>_3"): Use s_operand to forbid
	symref memory operands.  Remove CC mode and call s390_match_ccmode
	instead.
	("atomic_exchange<mode>"): Allow and implement all integer modes.
gcc/testsuite/ChangeLog-dv-atomic-gcc7

	* gcc.target/s390/md/atomic_compare_exchange-1.c: New test.
	* gcc.target/s390/md/atomic_compare_exchange-1.inc: New test.
	* gcc.target/s390/md/atomic_exchange-1.inc: New test.

[-- Attachment #3: 0001-v4-S-390-Optimize-atomic_compare_exchange-and-atomic_co.patch --]
[-- Type: text/plain, Size: 34382 bytes --]

From 0dbcab9152b3d1b7c3a6e72f6d45b8eb56ab40ae Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@linux.vnet.ibm.com>
Date: Thu, 23 Feb 2017 17:23:11 +0100
Subject: [PATCH] S/390: Optimize atomic_compare_exchange and
 atomic_compare builtins.

1) Use the load-and-test instructions for atomic_exchange if the value is 0.
2) If IS_WEAK is true, compare the memory contents before a compare-and-swap
   and skip the CS instructions if the value is not the expected one.
---
 gcc/config/s390/s390-protos.h                      |   4 +-
 gcc/config/s390/s390.c                             | 171 ++++++++++-
 gcc/config/s390/s390.md                            | 150 +++++----
 .../gcc.target/s390/md/atomic_compare_exchange-1.c |  84 ++++++
 .../s390/md/atomic_compare_exchange-1.inc          | 336 +++++++++++++++++++++
 .../gcc.target/s390/md/atomic_exchange-1.c         | 309 +++++++++++++++++++
 6 files changed, 977 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.c
 create mode 100644 gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.inc
 create mode 100644 gcc/testsuite/gcc.target/s390/md/atomic_exchange-1.c

diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 7f06a20..3fdb320 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -112,8 +112,8 @@ extern void s390_expand_vec_strlen (rtx, rtx, rtx);
 extern void s390_expand_vec_movstr (rtx, rtx, rtx);
 extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern bool s390_expand_insv (rtx, rtx, rtx, rtx);
-extern void s390_expand_cs_hqi (machine_mode, rtx, rtx, rtx,
-				rtx, rtx, bool);
+extern void s390_expand_cs (machine_mode, rtx, rtx, rtx, rtx, rtx, bool);
+extern void s390_expand_atomic_exchange_tdsi (rtx, rtx, rtx);
 extern void s390_expand_atomic (machine_mode, enum rtx_code,
 				rtx, rtx, rtx, bool);
 extern void s390_expand_tbegin (rtx, rtx, rtx, bool);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 2cb8947..fe16647 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -1306,6 +1306,7 @@ s390_match_ccmode_set (rtx set, machine_mode req_mode)
   set_mode = GET_MODE (SET_DEST (set));
   switch (set_mode)
     {
+    case CCZ1mode:
     case CCSmode:
     case CCSRmode:
     case CCUmode:
@@ -1328,7 +1329,8 @@ s390_match_ccmode_set (rtx set, machine_mode req_mode)
 
     case CCZmode:
       if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode
-	  && req_mode != CCSRmode && req_mode != CCURmode)
+	  && req_mode != CCSRmode && req_mode != CCURmode
+	  && req_mode != CCZ1mode)
         return 0;
       break;
 
@@ -1762,11 +1764,31 @@ s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
 
 static rtx
 s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem,
-			    rtx cmp, rtx new_rtx)
+			    rtx cmp, rtx new_rtx, machine_mode ccmode)
 {
-  emit_insn (gen_atomic_compare_and_swapsi_internal (old, mem, cmp, new_rtx));
-  return s390_emit_compare (code, gen_rtx_REG (CCZ1mode, CC_REGNUM),
-			    const0_rtx);
+  rtx cc;
+
+  cc = gen_rtx_REG (ccmode, CC_REGNUM);
+  switch (GET_MODE (mem))
+    {
+    case SImode:
+      emit_insn (gen_atomic_compare_and_swapsi_internal (old, mem, cmp,
+							 new_rtx, cc));
+      break;
+    case DImode:
+      emit_insn (gen_atomic_compare_and_swapdi_internal (old, mem, cmp,
+							 new_rtx, cc));
+      break;
+    case TImode:
+	emit_insn (gen_atomic_compare_and_swapti_internal (old, mem, cmp,
+							   new_rtx, cc));
+      break;
+    case QImode:
+    case HImode:
+    default:
+      gcc_unreachable ();
+    }
+  return s390_emit_compare (code, cc, const0_rtx);
 }
 
 /* Emit a jump instruction to TARGET and return it.  If COND is
@@ -6723,7 +6745,7 @@ s390_two_part_insv (struct alignment_context *ac, rtx *seq1, rtx *seq2,
    the memory location, CMP the old value to compare MEM with and NEW_RTX the
    value to set if CMP == MEM.  */
 
-void
+static void
 s390_expand_cs_hqi (machine_mode mode, rtx btarget, rtx vtarget, rtx mem,
 		    rtx cmp, rtx new_rtx, bool is_weak)
 {
@@ -6770,7 +6792,7 @@ s390_expand_cs_hqi (machine_mode mode, rtx btarget, rtx vtarget, rtx mem,
   emit_insn (seq2);
   emit_insn (seq3);
 
-  cc = s390_emit_compare_and_swap (EQ, res, ac.memsi, cmpv, newv);
+  cc = s390_emit_compare_and_swap (EQ, res, ac.memsi, cmpv, newv, CCZ1mode);
   if (is_weak)
     emit_insn (gen_cstorecc4 (btarget, cc, XEXP (cc, 0), XEXP (cc, 1)));
   else
@@ -6799,6 +6821,138 @@ s390_expand_cs_hqi (machine_mode mode, rtx btarget, rtx vtarget, rtx mem,
 					      NULL_RTX, 1, OPTAB_DIRECT), 1);
 }
 
+/* Variant of s390_expand_cs for SI, DI and TI modes.  */
+static void
+s390_expand_cs_tdsi (machine_mode mode, rtx btarget, rtx vtarget, rtx mem,
+		     rtx cmp, rtx new_rtx, bool is_weak)
+{
+  rtx output = vtarget;
+  rtx_code_label *skip_cs_label = NULL;
+  bool do_const_opt = false;
+
+  if (!register_operand (output, mode))
+    output = gen_reg_rtx (mode);
+
+  /* If IS_WEAK is true and the INPUT value is a constant, compare the memory
+     with the constant first and skip the compare_and_swap because its very
+     expensive and likely to fail anyway.
+     Note 1: This is done only for IS_WEAK.  C11 allows optimizations that may
+     cause spurious in that case.
+     Note 2: It may be useful to do this also for non-constant INPUT.
+     Note 3: Currently only targets with "load on condition" are supported
+     (z196 and newer).  */
+
+  if (TARGET_Z196
+      && (mode == SImode || mode == DImode))
+    do_const_opt = (is_weak && CONST_INT_P (cmp));
+
+  if (do_const_opt)
+    {
+      const int very_unlikely = REG_BR_PROB_BASE / 100 - 1;
+      rtx cc = gen_rtx_REG (CCZmode, CC_REGNUM);
+
+      skip_cs_label = gen_label_rtx ();
+      emit_move_insn (output, mem);
+      emit_move_insn (btarget, const0_rtx);
+      emit_insn (gen_rtx_SET (cc, gen_rtx_COMPARE (CCZmode, output, cmp)));
+      s390_emit_jump (skip_cs_label, gen_rtx_NE (VOIDmode, cc, const0_rtx));
+      add_int_reg_note (get_last_insn (), REG_BR_PROB, very_unlikely);
+      /* If the jump is not taken, OUTPUT is the expected value.  */
+      cmp = output;
+      /* Reload newval to a register manually, *after* the compare and jump
+	 above.  Otherwise Reload might place it before the jump.  */
+    }
+  else
+    cmp = force_reg (mode, cmp);
+  new_rtx = force_reg (mode, new_rtx);
+  s390_emit_compare_and_swap (EQ, output, mem, cmp, new_rtx,
+			      (do_const_opt) ? CCZmode : CCZ1mode);
+  if (skip_cs_label != NULL)
+    emit_label (skip_cs_label);
+
+  /* We deliberately accept non-register operands in the predicate
+     to ensure the write back to the output operand happens *before*
+     the store-flags code below.  This makes it easier for combine
+     to merge the store-flags code with a potential test-and-branch
+     pattern following (immediately!) afterwards.  */
+  if (output != vtarget)
+    emit_move_insn (vtarget, output);
+
+  if (do_const_opt)
+    {
+      rtx cc, cond, ite;
+
+      /* Do not use gen_cstorecc4 here because it writes either 1 or 0, but
+	 btarget has already been initialized with 0 above.  */
+      cc = gen_rtx_REG (CCZmode, CC_REGNUM);
+      cond = gen_rtx_EQ (VOIDmode, cc, const0_rtx);
+      ite = gen_rtx_IF_THEN_ELSE (SImode, cond, const1_rtx, btarget);
+      emit_insn (gen_rtx_SET (btarget, ite));
+    }
+  else
+    {
+      rtx cc, cond;
+
+      cc = gen_rtx_REG (CCZ1mode, CC_REGNUM);
+      cond = gen_rtx_EQ (SImode, cc, const0_rtx);
+      emit_insn (gen_cstorecc4 (btarget, cond, cc, const0_rtx));
+    }
+}
+
+/* Expand an atomic compare and swap operation.  MEM is the memory location,
+   CMP the old value to compare MEM with and NEW_RTX the value to set if
+   CMP == MEM.  */
+
+void
+s390_expand_cs (machine_mode mode, rtx btarget, rtx vtarget, rtx mem,
+		rtx cmp, rtx new_rtx, bool is_weak)
+{
+  switch (mode)
+    {
+    case TImode:
+    case DImode:
+    case SImode:
+      s390_expand_cs_tdsi (mode, btarget, vtarget, mem, cmp, new_rtx, is_weak);
+      break;
+    case HImode:
+    case QImode:
+      s390_expand_cs_hqi (mode, btarget, vtarget, mem, cmp, new_rtx, is_weak);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Expand an atomic_exchange operation simulated with a compare-and-swap loop.
+   The memory location MEM is set to INPUT.  OUTPUT is set to the previous value
+   of MEM.  */
+
+void
+s390_expand_atomic_exchange_tdsi (rtx output, rtx mem, rtx input)
+{
+  machine_mode mode = GET_MODE (mem);
+  rtx_code_label *csloop;
+
+  if (TARGET_Z196
+      && (mode == DImode || mode == SImode)
+      && CONST_INT_P (input) && INTVAL (input) == 0)
+    {
+      emit_move_insn (output, const0_rtx);
+      if (mode == DImode)
+	emit_insn (gen_atomic_fetch_anddi (output, mem, const0_rtx, input));
+      else
+	emit_insn (gen_atomic_fetch_andsi (output, mem, const0_rtx, input));
+      return;
+    }
+
+  input = force_reg (mode, input);
+  emit_move_insn (output, mem);
+  csloop = gen_label_rtx ();
+  emit_label (csloop);
+  s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, output, mem, output,
+						      input, CCZ1mode));
+}
+
 /* Expand an atomic operation CODE of mode MODE.  MEM is the memory location
    and VAL the value to play with.  If AFTER is true then store the value
    MEM holds after the operation, if AFTER is false then store the value MEM
@@ -6878,7 +7032,8 @@ s390_expand_atomic (machine_mode mode, enum rtx_code code,
     }
 
   s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, cmp,
-						      ac.memsi, cmp, new_rtx));
+						      ac.memsi, cmp, new_rtx,
+						      CCZ1mode));
 
   /* Return the correct part of the bitfield.  */
   if (target)
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 59f189c..8a700ed 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -907,6 +907,21 @@
   [(set_attr "op_type" "RR<E>,RXY")
    (set_attr "z10prop" "z10_fr_E1,z10_fwd_A3") ])
 
+; Peephole to combine a load-and-test from volatile memory which combine does
+; not do.
+(define_peephole2
+  [(set (match_operand:GPR 0 "register_operand")
+	(match_operand:GPR 2 "memory_operand"))
+   (set (reg CC_REGNUM)
+	(compare (match_dup 0) (match_operand:GPR 1 "const0_operand")))]
+  "s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM
+   && GENERAL_REG_P (operands[0])
+   && satisfies_constraint_T (operands[2])"
+  [(parallel
+    [(set (reg:CCS CC_REGNUM)
+	  (compare:CCS (match_dup 2) (match_dup 1)))
+     (set (match_dup 0) (match_dup 2))])])
+
 ; ltr, lt, ltgr, ltg
 (define_insn "*tst<mode>_cconly_extimm"
   [(set (reg CC_REGNUM)
@@ -6518,13 +6533,30 @@
   [(parallel
     [(set (match_operand:SI 0 "register_operand" "")
 	  (match_operator:SI 1 "s390_eqne_operator"
-           [(match_operand:CCZ1 2 "register_operand")
+           [(match_operand 2 "cc_reg_operand")
 	    (match_operand 3 "const0_operand")]))
      (clobber (reg:CC CC_REGNUM))])]
   ""
-  "emit_insn (gen_sne (operands[0], operands[2]));
-   if (GET_CODE (operands[1]) == EQ)
-     emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
+  "machine_mode mode = GET_MODE (operands[2]);
+   if (TARGET_Z196)
+     {
+       rtx cond, ite;
+
+       if (GET_CODE (operands[1]) == NE)
+	 cond = gen_rtx_NE (VOIDmode, operands[2], const0_rtx);
+       else
+	 cond = gen_rtx_EQ (VOIDmode, operands[2], const0_rtx);
+       ite = gen_rtx_IF_THEN_ELSE (SImode, cond, const1_rtx, const0_rtx);
+       emit_insn (gen_rtx_SET (operands[0], ite));
+     }
+   else
+     {
+       if (mode != CCZ1mode)
+	 FAIL;
+       emit_insn (gen_sne (operands[0], operands[2]));
+       if (GET_CODE (operands[1]) == EQ)
+	 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
+     }
    DONE;")
 
 (define_insn_and_split "sne"
@@ -10198,83 +10230,56 @@
 
 (define_expand "atomic_compare_and_swap<mode>"
   [(match_operand:SI 0 "register_operand")	;; bool success output
-   (match_operand:DGPR 1 "nonimmediate_operand");; oldval output
-   (match_operand:DGPR 2 "memory_operand")	;; memory
-   (match_operand:DGPR 3 "register_operand")	;; expected intput
-   (match_operand:DGPR 4 "register_operand")	;; newval intput
+   (match_operand:DINT 1 "nonimmediate_operand");; oldval output
+   (match_operand:DINT 2 "s_operand")		;; memory
+   (match_operand:DINT 3 "general_operand")	;; expected intput
+   (match_operand:DINT 4 "general_operand")	;; newval intput
    (match_operand:SI 5 "const_int_operand")	;; is_weak
    (match_operand:SI 6 "const_int_operand")	;; success model
    (match_operand:SI 7 "const_int_operand")]	;; failure model
   ""
 {
-  rtx cc, cmp, output = operands[1];
-
-  if (!register_operand (output, <MODE>mode))
-    output = gen_reg_rtx (<MODE>mode);
-
-  if (MEM_ALIGN (operands[2]) < GET_MODE_BITSIZE (GET_MODE (operands[2])))
+  if (GET_MODE_BITSIZE (<MODE>mode) >= 16
+      && GET_MODE_BITSIZE (<MODE>mode) > MEM_ALIGN (operands[2]))
     FAIL;
 
-  emit_insn (gen_atomic_compare_and_swap<mode>_internal
-	     (output, operands[2], operands[3], operands[4]));
-
-  /* We deliberately accept non-register operands in the predicate
-     to ensure the write back to the output operand happens *before*
-     the store-flags code below.  This makes it easier for combine
-     to merge the store-flags code with a potential test-and-branch
-     pattern following (immediately!) afterwards.  */
-  if (output != operands[1])
-    emit_move_insn (operands[1], output);
-
-  cc = gen_rtx_REG (CCZ1mode, CC_REGNUM);
-  cmp = gen_rtx_EQ (SImode, cc, const0_rtx);
-  emit_insn (gen_cstorecc4 (operands[0], cmp, cc, const0_rtx));
-  DONE;
-})
-
-(define_expand "atomic_compare_and_swap<mode>"
-  [(match_operand:SI 0 "register_operand")	;; bool success output
-   (match_operand:HQI 1 "nonimmediate_operand")	;; oldval output
-   (match_operand:HQI 2 "memory_operand")	;; memory
-   (match_operand:HQI 3 "general_operand")	;; expected intput
-   (match_operand:HQI 4 "general_operand")	;; newval intput
-   (match_operand:SI 5 "const_int_operand")	;; is_weak
-   (match_operand:SI 6 "const_int_operand")	;; success model
-   (match_operand:SI 7 "const_int_operand")]	;; failure model
-  ""
-{
-  s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1], operands[2],
-		      operands[3], operands[4], INTVAL (operands[5]));
-  DONE;
-})
+  s390_expand_cs (<MODE>mode, operands[0], operands[1], operands[2],
+		  operands[3], operands[4], INTVAL (operands[5]));
+  DONE;})
 
 (define_expand "atomic_compare_and_swap<mode>_internal"
   [(parallel
      [(set (match_operand:DGPR 0 "register_operand")
-	   (match_operand:DGPR 1 "memory_operand"))
+	   (match_operand:DGPR 1 "s_operand"))
       (set (match_dup 1)
 	   (unspec_volatile:DGPR
 	     [(match_dup 1)
 	      (match_operand:DGPR 2 "register_operand")
 	      (match_operand:DGPR 3 "register_operand")]
 	     UNSPECV_CAS))
-      (set (reg:CCZ1 CC_REGNUM)
-	   (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
-  "")
+      (set (match_operand 4 "cc_reg_operand")
+	   (match_dup 5))])]
+  "GET_MODE (operands[4]) == CCZmode
+   || GET_MODE (operands[4]) == CCZ1mode"
+{
+  operands[5]
+    = gen_rtx_COMPARE (GET_MODE (operands[4]), operands[1], operands[2]);
+})
 
 ; cdsg, csg
 (define_insn "*atomic_compare_and_swap<mode>_1"
   [(set (match_operand:TDI 0 "register_operand" "=r")
-	(match_operand:TDI 1 "memory_operand" "+S"))
+	(match_operand:TDI 1 "s_operand" "+S"))
    (set (match_dup 1)
 	(unspec_volatile:TDI
 	  [(match_dup 1)
 	   (match_operand:TDI 2 "register_operand" "0")
 	   (match_operand:TDI 3 "register_operand" "r")]
 	  UNSPECV_CAS))
-   (set (reg:CCZ1 CC_REGNUM)
-	(compare:CCZ1 (match_dup 1) (match_dup 2)))]
-  "TARGET_ZARCH"
+   (set (reg CC_REGNUM)
+	(compare (match_dup 1) (match_dup 2)))]
+  "TARGET_ZARCH
+   && s390_match_ccmode (insn, CCZ1mode)"
   "c<td>sg\t%0,%3,%S1"
   [(set_attr "op_type" "RSY")
    (set_attr "type"   "sem")])
@@ -10282,16 +10287,17 @@
 ; cds, cdsy
 (define_insn "*atomic_compare_and_swapdi_2"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
-	(match_operand:DI 1 "memory_operand" "+Q,S"))
+	(match_operand:DI 1 "s_operand" "+Q,S"))
    (set (match_dup 1)
 	(unspec_volatile:DI
 	  [(match_dup 1)
 	   (match_operand:DI 2 "register_operand" "0,0")
 	   (match_operand:DI 3 "register_operand" "r,r")]
 	  UNSPECV_CAS))
-   (set (reg:CCZ1 CC_REGNUM)
-	(compare:CCZ1 (match_dup 1) (match_dup 2)))]
-  "!TARGET_ZARCH"
+   (set (reg CC_REGNUM)
+	(compare (match_dup 1) (match_dup 2)))]
+  "!TARGET_ZARCH
+   && s390_match_ccmode (insn, CCZ1mode)"
   "@
    cds\t%0,%3,%S1
    cdsy\t%0,%3,%S1"
@@ -10302,16 +10308,16 @@
 ; cs, csy
 (define_insn "*atomic_compare_and_swapsi_3"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
-	(match_operand:SI 1 "memory_operand" "+Q,S"))
+	(match_operand:SI 1 "s_operand" "+Q,S"))
    (set (match_dup 1)
 	(unspec_volatile:SI
 	  [(match_dup 1)
 	   (match_operand:SI 2 "register_operand" "0,0")
 	   (match_operand:SI 3 "register_operand" "r,r")]
 	  UNSPECV_CAS))
-   (set (reg:CCZ1 CC_REGNUM)
-	(compare:CCZ1 (match_dup 1) (match_dup 2)))]
-  ""
+   (set (reg CC_REGNUM)
+	(compare (match_dup 1) (match_dup 2)))]
+  "s390_match_ccmode (insn, CCZ1mode)"
   "@
    cs\t%0,%3,%S1
    csy\t%0,%3,%S1"
@@ -10398,15 +10404,25 @@
   DONE;
 })
 
+;; Pattern to implement atomic_exchange with a compare-and-swap loop.  The code
+;; generated by the middleend is not good.
 (define_expand "atomic_exchange<mode>"
-  [(match_operand:HQI 0 "register_operand")		;; val out
-   (match_operand:HQI 1 "memory_operand")		;; memory
-   (match_operand:HQI 2 "general_operand")		;; val in
+  [(match_operand:DINT 0 "register_operand")		;; val out
+   (match_operand:DINT 1 "s_operand")			;; memory
+   (match_operand:DINT 2 "general_operand")		;; val in
    (match_operand:SI 3 "const_int_operand")]		;; model
   ""
 {
-  s390_expand_atomic (<MODE>mode, SET, operands[0], operands[1],
-		      operands[2], false);
+  if (<MODE>mode != QImode
+      && MEM_ALIGN (operands[1]) < GET_MODE_BITSIZE (<MODE>mode))
+    FAIL;
+  if (<MODE>mode == HImode || <MODE>mode == QImode)
+    s390_expand_atomic (<MODE>mode, SET, operands[0], operands[1], operands[2],
+			false);
+  else if (<MODE>mode == SImode || TARGET_ZARCH)
+    s390_expand_atomic_exchange_tdsi (operands[0], operands[1], operands[2]);
+  else
+    FAIL;
   DONE;
 })
 
diff --git a/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.c b/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.c
new file mode 100644
index 0000000..5cc026d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.c
@@ -0,0 +1,84 @@
+/* Machine description pattern tests.  */
+
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-do run { target { s390_useable_hw } } } */
+
+#include <stdio.h>
+
+struct
+{
+#ifdef __s390xx__
+  __int128 dummy128;
+  __int128 mem128;
+#endif
+  long long dummy64;
+  long long mem64;
+  int dummy32;
+  int mem32;
+  short mem16l;
+  short mem16h;
+  char mem8ll;
+  char mem8lh;
+  char mem8hl;
+  char mem8hh;
+} mem_s;
+
+#define TYPE char
+#define FN(SUFFIX) f8 ## SUFFIX
+#define FNS(SUFFIX) "f8" #SUFFIX
+#include "atomic_compare_exchange-1.inc"
+
+#define TYPE short
+#define FN(SUFFIX) f16 ##SUFFIX
+#define FNS(SUFFIX) "f16" #SUFFIX
+#include "atomic_compare_exchange-1.inc"
+
+#define TYPE int
+#define FN(SUFFIX) f32 ## SUFFIX
+#define FNS(SUFFIX) "f32" #SUFFIX
+#include "atomic_compare_exchange-1.inc"
+
+#define TYPE long long
+#define FN(SUFFIX) f64 ## SUFFIX
+#define FNS(SUFFIX) "f64" #SUFFIX
+#include "atomic_compare_exchange-1.inc"
+
+#ifdef __s390xx__
+#define TYPE __int128
+#define FN(SUFFIX) f128 ## SUFFIX
+#define FNS(SUFFIX) "f128" #SUFFIX
+#include "atomic_compare_exchange-1.inc"
+#endif
+
+int main(void)
+{
+  int err_count = 0;
+  int i;
+
+  for (i = -1; i <= 2; i++)
+    {
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f8_validate(&mem_s.mem8ll, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f8_validate(&mem_s.mem8lh, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f8_validate(&mem_s.mem8hl, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f8_validate(&mem_s.mem8hh, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f16_validate(&mem_s.mem16l, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f16_validate(&mem_s.mem16h, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f32_validate(&mem_s.mem32, i, 1);
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f64_validate(&mem_s.mem64, i, 1);
+#ifdef __s390xx__
+      __builtin_memset(&mem_s, 0x99, sizeof(mem_s));
+      err_count += f128_validate(&mem_s.mem128, i, 1);
+#endif
+    }
+
+  return err_count;
+}
diff --git a/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.inc b/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.inc
new file mode 100644
index 0000000..199aaa3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/md/atomic_compare_exchange-1.inc
@@ -0,0 +1,336 @@
+/* -*-c-*- */
+
+#undef NEW
+#define NEW 3
+
+__attribute__ ((noinline))
+int FN(_bo)(TYPE *mem, TYPE *old_ret, TYPE old)
+{
+  *old_ret = old;
+  return __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN(_o)(TYPE *mem, TYPE *old_ret, TYPE old)
+{
+  *old_ret = old;
+  __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+  return;
+}
+
+__attribute__ ((noinline))
+int FN(_b)(TYPE *mem, TYPE old)
+{
+  return __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN()(TYPE *mem, TYPE old)
+{
+  __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+  return;
+}
+
+/* Const != 0 old value.  */
+__attribute__ ((noinline))
+int FN(_c1_bo)(TYPE *mem, TYPE *old_ret)
+{
+  *old_ret = 1;
+  return __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN(_c1_o)(TYPE *mem, TYPE *old_ret)
+{
+  *old_ret = 1;
+  __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+  return;
+}
+
+__attribute__ ((noinline))
+int FN(_c1_b)(TYPE *mem)
+{
+  TYPE old = 1;
+  return __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN(_c1)(TYPE *mem)
+{
+  TYPE old = 1;
+  __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+  return;
+}
+
+/* Const == 0 old value.  */
+__attribute__ ((noinline))
+int FN(_c0_bo)(TYPE *mem, TYPE *old_ret)
+{
+  *old_ret = 0;
+  return __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN(_c0_o)(TYPE *mem, TYPE *old_ret)
+{
+  *old_ret = 0;
+  __atomic_compare_exchange_n (mem, (void *)old_ret, NEW, 1, 2, 0);
+  return;
+}
+
+__attribute__ ((noinline))
+int FN(_c0_b)(TYPE *mem)
+{
+  TYPE old = 0;
+  return __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+}
+
+__attribute__ ((noinline))
+void FN(_c0)(TYPE *mem)
+{
+  TYPE old = 0;
+  __atomic_compare_exchange_n (mem, (void *)&old, NEW, 1, 2, 0);
+  return;
+}
+
+int FN(_validate_mem)(TYPE *mem, TYPE expected_mem)
+{
+  if (*mem != expected_mem)
+    {
+      fprintf(stderr, "  BAD: mem %d != expected mem %d\n",
+	      *mem, expected_mem);
+      return 1;
+    }
+
+  return 0;
+}
+
+int FN(_validate_rc)(int rc, int expected_rc)
+{
+  if (rc != expected_rc)
+    {
+      fprintf(stderr, "  BAD: rc %d != expected rc %d\n",
+	      rc, expected_rc);
+      return 1;
+    }
+
+  return 0;
+}
+
+int FN(_validate_old_ret)(int old_ret, int expected_old_ret)
+{
+  if (old_ret != expected_old_ret)
+    {
+      fprintf(stderr, "  BAD: old_ret %d != expected old_ret %d\n",
+	      old_ret, expected_old_ret);
+      return 1;
+    }
+
+  return 0;
+}
+
+int FN(_validate)(TYPE *mem, TYPE init_mem, TYPE old)
+{
+  int err_count = 0;
+  int rc;
+  TYPE expected_mem;
+  int expected_rc;
+  TYPE old_ret;
+  int failed;
+  const char *fname;
+
+  fprintf(stderr, "%s: init_mem %d @ %p\n", __FUNCTION__, init_mem, mem);
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_bo);
+    rc = FN(_bo)(mem, &old_ret, old);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS(_o);
+    FN(_o)(mem, &old_ret, old);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_b);
+    rc = FN(_b)(mem, old);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS();
+    FN()(mem, old);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_c1_bo);
+    rc = FN(_c1_bo)(mem, &old_ret);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS(_c1_o);
+    FN(_c1_o)(mem, &old_ret);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_c1_b);
+    rc = FN(_c1_b)(mem);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 1;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS(_c1);
+    FN(_c1)(mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 0;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_c0_bo);
+    rc = FN(_c0_bo)(mem, &old_ret);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 0;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS(_c0_o);
+    FN(_c0_o)(mem, &old_ret);
+    failed |= FN(_validate_old_ret)(old_ret, init_mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 0;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    expected_rc = (init_mem == old);
+    fname = FNS(_c0_b);
+    rc = FN(_c0_b)(mem);
+    failed |= FN(_validate_rc)(rc, expected_rc);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+  {
+    failed = 0;
+    old = 0;
+    *mem = init_mem;
+    expected_mem = (init_mem == old) ? NEW : *mem;
+    fname = FNS(_c0);
+    FN(_c0)(mem);
+    failed |= FN(_validate_mem)(mem, expected_mem);
+    if (failed)
+      {
+	fprintf(stderr, "  FAIL: %s: near line %d\n", fname, __LINE__ - 3);
+	err_count++;
+      }
+  }
+
+  return err_count;
+}
+
+#undef TYPE
+#undef MEM
+#undef FN
+#undef FNS
diff --git a/gcc/testsuite/gcc.target/s390/md/atomic_exchange-1.c b/gcc/testsuite/gcc.target/s390/md/atomic_exchange-1.c
new file mode 100644
index 0000000..f82b213
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/md/atomic_exchange-1.c
@@ -0,0 +1,309 @@
+/* Machine description pattern tests.  */
+
+/* { dg-do compile } */
+/* { dg-options "-lpthread -latomic" } */
+/* { dg-do run { target { s390_useable_hw } } } */
+
+/**/
+
+char
+ae_8_0 (char *lock)
+{
+  return __atomic_exchange_n (lock, 0, 2);
+}
+
+char
+ae_8_1 (char *lock)
+{
+  return __atomic_exchange_n (lock, 1, 2);
+}
+
+char g8;
+
+char
+ae_8_g_0 (void)
+{
+  return __atomic_exchange_n (&g8, 0, 2);
+}
+
+char
+ae_8_g_1 (void)
+{
+  return __atomic_exchange_n (&g8, 1, 2);
+}
+
+/**/
+
+short
+ae_16_0 (short *lock)
+{
+  return __atomic_exchange_n (lock, 0, 2);
+}
+
+short
+ae_16_1 (short *lock)
+{
+  return __atomic_exchange_n (lock, 1, 2);
+}
+
+short g16;
+
+short
+ae_16_g_0 (void)
+{
+  return __atomic_exchange_n (&g16, 0, 2);
+}
+
+short
+ae_16_g_1 (void)
+{
+  return __atomic_exchange_n (&g16, 1, 2);
+}
+
+/**/
+
+int
+ae_32_0 (int *lock)
+{
+  return __atomic_exchange_n (lock, 0, 2);
+}
+
+int
+ae_32_1 (int *lock)
+{
+  return __atomic_exchange_n (lock, 1, 2);
+}
+
+int g32;
+
+int
+ae_32_g_0 (void)
+{
+  return __atomic_exchange_n (&g32, 0, 2);
+}
+
+int
+ae_32_g_1 (void)
+{
+  return __atomic_exchange_n (&g32, 1, 2);
+}
+
+/**/
+
+long long
+ae_64_0 (long long *lock)
+{
+  return __atomic_exchange_n (lock, 0, 2);
+}
+
+long long
+ae_64_1 (long long *lock)
+{
+  return __atomic_exchange_n (lock, 1, 2);
+}
+
+long long g64;
+
+long long
+ ae_64_g_0 (void)
+{
+  return __atomic_exchange_n (&g64, 0, 2);
+}
+
+long long
+ae_64_g_1 (void)
+{
+  return __atomic_exchange_n (&g64, 1, 2);
+}
+
+/**/
+
+#ifdef __s390x__
+__int128
+ae_128_0 (__int128 *lock)
+{
+  return __atomic_exchange_n (lock, 0, 2);
+}
+
+__int128
+ae_128_1 (__int128 *lock)
+{
+  return __atomic_exchange_n (lock, 1, 2);
+}
+
+__int128 g128;
+
+__int128
+ae_128_g_0 (void)
+{
+  return __atomic_exchange_n (&g128, 0, 2);
+}
+
+__int128
+ae_128_g_1 (void)
+{
+  return __atomic_exchange_n (&g128, 1, 2);
+}
+
+#endif
+
+int main(void)
+{
+  int i;
+
+  for (i = 0; i <= 2; i++)
+    {
+      int oval = i;
+
+      {
+	char lock;
+	char rval;
+
+	lock = oval;
+	rval = ae_8_0 (&lock);
+	if (lock != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	lock = oval;
+	rval = ae_8_1 (&lock);
+	if (lock != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g8 = oval;
+	rval = ae_8_g_0 ();
+	if (g8 != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g8 = oval;
+	rval = ae_8_g_1 ();
+	if (g8 != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+      }
+      {
+	short lock;
+	short rval;
+
+	lock = oval;
+	rval = ae_16_0 (&lock);
+	if (lock != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	lock = oval;
+	rval = ae_16_1 (&lock);
+	if (lock != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g16 = oval;
+	rval = ae_16_g_0 ();
+	if (g16 != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g16 = oval;
+	rval = ae_16_g_1 ();
+	if (g16 != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+      }
+      {
+	int lock;
+	int rval;
+
+	lock = oval;
+	rval = ae_32_0 (&lock);
+	if (lock != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	lock = oval;
+	rval = ae_32_1 (&lock);
+	if (lock != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g32 = oval;
+	rval = ae_32_g_0 ();
+	if (g32 != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g32 = oval;
+	rval = ae_32_g_1 ();
+	if (g32 != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+      }
+      {
+	long long lock;
+	long long rval;
+
+	lock = oval;
+	rval = ae_64_0 (&lock);
+	if (lock != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	lock = oval;
+	rval = ae_64_1 (&lock);
+	if (lock != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g64 = oval;
+	rval = ae_64_g_0 ();
+	if (g64 != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g64 = oval;
+	rval = ae_64_g_1 ();
+	if (g64 != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+      }
+
+#ifdef __s390x__
+      {
+	__int128 lock;
+	__int128 rval;
+
+	lock = oval;
+	rval = ae_128_0 (&lock);
+	if (lock != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	lock = oval;
+	rval = ae_128_1 (&lock);
+	if (lock != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g128 = oval;
+	rval = ae_128_g_0 ();
+	if (g128 != 0)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+	g128 = oval;
+	rval = ae_128_g_1 ();
+	if (g128 != 1)
+	  __builtin_abort ();
+	if (rval != oval)
+	  __builtin_abort ();
+      }
+#endif
+    }
+
+  return 0;
+}
-- 
2.3.0


  parent reply	other threads:[~2017-04-07 14:14 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-27 20:50 Dominik Vogt
2017-03-29 15:22 ` [PATCH v2] " Dominik Vogt
2017-04-05 13:52 ` [PATCH] " Dominik Vogt
2017-04-05 15:25   ` Ulrich Weigand
2017-04-06  9:35   ` Dominik Vogt
2017-04-06 15:29     ` Ulrich Weigand
2017-04-06 15:34       ` Ulrich Weigand
2017-04-07 14:14   ` Dominik Vogt [this message]
2017-04-07 14:34     ` Ulrich Weigand
2017-04-07 15:37       ` Dominik Vogt
2017-04-07 17:22         ` Ulrich Weigand
2017-04-10  9:13           ` Dominik Vogt
2017-04-10  9:21             ` Dominik Vogt
2017-04-10 21:37               ` Ulrich Weigand
2017-04-11  8:11                 ` Andreas Krebbel
2017-04-11 14:21 ` [PATCH v5] " Dominik Vogt
2017-04-24 15:20   ` Ulrich Weigand
2017-04-25  8:04   ` Andreas Krebbel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170407141407.GA5569@linux.vnet.ibm.com \
    --to=vogt@linux.vnet.ibm.com \
    --cc=Ulrich.Weigand@de.ibm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=krebbel@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).