This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[cond-optab] remove sync_compare_and_swap_cc optab


The sync_compare_and_swap_cc optab is present to support those
architectures where the CAS instruction touches the flag.  In this case
better code generation is possible.  Note that combine will not help in
this case because the CAS instruction has 2 sets (three with the CC set).

However, this is not needed; the CAS expander could look for a CC set in
the expansion of sync_compare_and_swap, and "somehow" use it to
synthesize a branch instruction.

The way to do so was anticipated in the cover letter for patch 1, in
which I mentioned a cbranchcc4 pattern.  This patch adds a cmpcc pattern
instead, but the idea is the same.  The advantage of doing so is that
the CAS expander can just pass the CC register down to the
emit_store_flag and emit_cmp_and_jump_insns machinery---the CAS
expanders were redoing the effort of emit_store_flag, basically:

  /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
     setcc instruction from the beginning.  We don't work too hard here,
     but it's nice to not be stupid about initial code gen either.  */

As a result, for example, -O0 code improves noticeably for s390 (not
that this matters much, as at -O1 and above if conversion does the same
job).

Note that for simplicity I decided to have only one cmpcc pattern
instead of one per MODE_CC mode (this required special casing of cmpcc
but only in a couple of places).  The machine description code is
supposed to know what it's doing, and it has a promise from the machine
independent code that the result will only be used for EQ and NE
comparisons.  For this reason, in patch 1 I actually had replaced a test
with an assertion in the s390 backend.

This patch was bootstrapped/regtested i686-pc-linux-gnu.  Furthermore, I
tried compiling the affected testcases on i686-pc-linux-gnu, s390-linux
and sparc-linux targets, both 32- and 64-bit.  There was no change in
assembly code for SPARC (as expected, since it does not have
sync_compare_and_swap_cc), minor register allocation changes on i686,
and minor register allocation changes at -O1 and above on s390 (at -O0
the code improved quite noticeably).

This will be resubmitted formally for 4.5, but reviews are welcome now too.

Paolo
2009-03-11  Paolo Bonzini  <bonzini@gnu.org>

	* config/i386/i386.md (cmpcc): New.
	* config/i386/sync.md (sync_compare_and_swap*): Set FLAGS_REG.
	(sync_compare_and_swap_cc*): Delete.

	* config/s390/s390.c (s390_emit_compare_and_swap): Adjust
	for changes in the machine description.
	* config/s390/s390.md (cmpcc): New.
	(sync_compare_and_swapqi, sync_compare_and_swaphi): Clobber
	CC_REGNUM, do not pretend it's set.
	(sync_compare_and_swap_cc*): Delete.
	* config/s390/predicates.md (cc_reg_operand): New.

	* expr.c (sync_compare_and_swap_cc): Delete.
	* optabs.h (sync_compare_and_swap_cc): Delete.
	* optabs.c (pprepare_cmp_insn): Ignore which specific CCmode
	is being used with can_compare_p.
	(emit_cmp_and_jump_insn_1): Likewise when looking in the optab.
	(find_cc_set): New.
	(expand_bool_compare_and_swap): Do not use sync_compare_and_swap_cc,
	look for a MODE_CC set instead.  Use emit_store_flag.
	(expand_compare_and_swap_loop): Likewise, with some additional
	complication to avoid a force_reg when useless.  Use
	emit_cmp_and_jump_insns.
	* genopinit.c (optabs): Delete sync_compare_and_swap_cc.
	* doc/md.texi (sync_compare_and_swap_cc): Merge with
	sync_compare_and_swap documentation.

Index: gcc/config/i386/i386.md
===================================================================
--- gcc/config/i386/i386.md	(branch cond-optab)
+++ gcc/config/i386/i386.md	(working copy)
@@ -1058,6 +1058,17 @@
   DONE;
 })
 
+(define_expand "cmpcc"
+  [(set (reg:CC FLAGS_REG)
+        (compare:CC (match_operand 0 "flags_reg_operand" "")
+                    (match_operand 1 "general_operand" "")))]
+  ""
+{
+  ix86_compare_op0 = operands[0];
+  ix86_compare_op1 = operands[1];
+  DONE;
+})
+
 ;; FP compares, step 1:
 ;; Set the FP condition codes.
 ;;
Index: gcc/config/i386/sync.md
===================================================================
--- gcc/config/i386/sync.md	(branch cond-optab)
+++ gcc/config/i386/sync.md	(working copy)
@@ -70,7 +70,11 @@
 	     (match_operand:CASMODE 2 "register_operand" "")
 	     (match_operand:CASMODE 3 "register_operand" "")]
 	    UNSPECV_CMPXCHG))
-     (clobber (reg:CC FLAGS_REG))])]
+   (set (reg:CCZ FLAGS_REG)
+        (compare:CCZ
+          (unspec_volatile:CASMODE
+            [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
+          (match_dup 2)))])]
   "TARGET_CMPXCHG"
 {
   if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
@@ -102,7 +106,11 @@
 	   (match_operand:IMODE 2 "register_operand" "a")
 	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
 	  UNSPECV_CMPXCHG))
-   (clobber (reg:CC FLAGS_REG))]
+   (set (reg:CCZ FLAGS_REG)
+        (compare:CCZ
+          (unspec_volatile:IMODE
+            [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
+          (match_dup 2)))]
   "TARGET_CMPXCHG"
   "lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
 
@@ -116,7 +124,12 @@
 	   (match_operand:<DCASHMODE> 3 "register_operand" "b")
 	   (match_operand:<DCASHMODE> 4 "register_operand" "c")]
 	  UNSPECV_CMPXCHG))
-   (clobber (reg:CC FLAGS_REG))]
+   (set (reg:CCZ FLAGS_REG)
+        (compare:CCZ
+          (unspec_volatile:DCASMODE
+            [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
+	    UNSPECV_CMPXCHG)
+          (match_dup 2)))]
   ""
   "lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
 
@@ -139,104 +152,12 @@
 	   (match_operand:SI 3 "register_operand" "SD")
 	   (match_operand:SI 4 "register_operand" "c")]
 	  UNSPECV_CMPXCHG))
-   (clobber (reg:CC FLAGS_REG))]
-  "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
-  "xchg{l}\t%%ebx, %3\;lock{%;| }cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3")
-
-(define_expand "sync_compare_and_swap_cc<mode>"
-  [(parallel
-    [(set (match_operand:CASMODE 0 "register_operand" "")
-	  (match_operand:CASMODE 1 "memory_operand" ""))
-     (set (match_dup 1)
-	  (unspec_volatile:CASMODE
-	    [(match_dup 1)
-	     (match_operand:CASMODE 2 "register_operand" "")
-	     (match_operand:CASMODE 3 "register_operand" "")]
-	    UNSPECV_CMPXCHG))
-     (set (match_dup 4)
-	  (compare:CCZ
-	    (unspec_volatile:CASMODE
-	      [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
-	    (match_dup 2)))])]
-  "TARGET_CMPXCHG"
-{
-  operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
-  ix86_compare_op0 = operands[4];
-  ix86_compare_op1 = const0_rtx;
-  if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
-    {
-      enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode;
-      rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0);
-      rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode,
-				      GET_MODE_SIZE (hmode));
-      low = force_reg (hmode, low);
-      high = force_reg (hmode, high);
-      if (<MODE>mode == DImode)
-	emit_insn (gen_sync_double_compare_and_swap_ccdi
-		   (operands[0], operands[1], operands[2], low, high));
-      else if (<MODE>mode == TImode)
-	emit_insn (gen_sync_double_compare_and_swap_ccti
-		   (operands[0], operands[1], operands[2], low, high));
-      else
-	gcc_unreachable ();
-      DONE;
-    }
-})
-
-(define_insn "*sync_compare_and_swap_cc<mode>"
-  [(set (match_operand:IMODE 0 "register_operand" "=a")
-	(match_operand:IMODE 1 "memory_operand" "+m"))
-   (set (match_dup 1)
-	(unspec_volatile:IMODE
-	  [(match_dup 1)
-	   (match_operand:IMODE 2 "register_operand" "a")
-	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
-	  UNSPECV_CMPXCHG))
-   (set (reg:CCZ FLAGS_REG)
-	(compare:CCZ
-	  (unspec_volatile:IMODE
-	    [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
-	  (match_dup 2)))]
-  "TARGET_CMPXCHG"
-  "lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
-
-(define_insn "sync_double_compare_and_swap_cc<mode>"
-  [(set (match_operand:DCASMODE 0 "register_operand" "=A")
-	(match_operand:DCASMODE 1 "memory_operand" "+m"))
-   (set (match_dup 1)
-	(unspec_volatile:DCASMODE
-	  [(match_dup 1)
-	   (match_operand:DCASMODE 2 "register_operand" "A")
-	   (match_operand:<DCASHMODE> 3 "register_operand" "b")
-	   (match_operand:<DCASHMODE> 4 "register_operand" "c")]
-	  UNSPECV_CMPXCHG))
    (set (reg:CCZ FLAGS_REG)
-	(compare:CCZ
-	  (unspec_volatile:DCASMODE
-	    [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
-	    UNSPECV_CMPXCHG)
-	  (match_dup 2)))]
-  ""
-  "lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
-
-;; See above for the explanation of using the constraint "SD" for
-;; operand 3.
-(define_insn "*sync_double_compare_and_swap_ccdi_pic"
-  [(set (match_operand:DI 0 "register_operand" "=A")
-	(match_operand:DI 1 "memory_operand" "+m"))
-   (set (match_dup 1)
-	(unspec_volatile:DI
-	  [(match_dup 1)
-	   (match_operand:DI 2 "register_operand" "A")
-	   (match_operand:SI 3 "register_operand" "SD")
-	   (match_operand:SI 4 "register_operand" "c")]
-	  UNSPECV_CMPXCHG))
-   (set (reg:CCZ FLAGS_REG)
-	(compare:CCZ
-	  (unspec_volatile:DI
-	    [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
-	    UNSPECV_CMPXCHG)
-	  (match_dup 2)))]
+        (compare:CCZ
+          (unspec_volatile:DI
+            [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
+            UNSPECV_CMPXCHG)
+          (match_dup 2)))]
   "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
   "xchg{l}\t%%ebx, %3\;lock{%;| }cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3")
 
Index: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c	(branch cond-optab)
+++ gcc/config/s390/s390.c	(working copy)
@@ -838,8 +838,8 @@ s390_emit_compare (enum rtx_code code, r
 static rtx
 s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new_rtx)
 {
-  emit_insn (gen_sync_compare_and_swap_ccsi (old, mem, cmp, new_rtx));
-  return s390_emit_compare (code, s390_compare_op0, s390_compare_op1);
+  emit_insn (gen_sync_compare_and_swapsi (old, mem, cmp, new_rtx));
+  return s390_emit_compare (code, gen_rtx_REG (CCZ1mode, CC_REGNUM), const0_rtx);
 }
 
 /* Emit a jump instruction to TARGET.  If COND is NULL_RTX, emit an
Index: gcc/config/s390/s390.md
===================================================================
--- gcc/config/s390/s390.md	(branch cond-optab)
+++ gcc/config/s390/s390.md	(working copy)
@@ -516,6 +516,16 @@
   DONE;
 })
 
+(define_expand "cmpcc"
+  [(set (reg:CC CC_REGNUM)
+        (compare:CC (match_operand 0 "cc_reg_operand" "")
+                    (match_operand 1 "general_operand" "")))]
+  ""
+{
+  s390_compare_op0 = operands[0];
+  s390_compare_op1 = operands[1];
+  DONE;
+})
 
 ; Test-under-Mask instructions
 
@@ -8243,32 +8253,11 @@
 	     (match_operand:HQI 2 "general_operand" "")
 	     (match_operand:HQI 3 "general_operand" "")]
 	    UNSPECV_CAS))
-     (set (reg:CCZ1 CC_REGNUM)
-	  (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
+     (clobber (reg:CC CC_REGNUM))])]
   ""
   "s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1],
 		       operands[2], operands[3]); DONE;")
 
-(define_expand "sync_compare_and_swap_cc<mode>"
-  [(parallel
-    [(set (match_operand:TDSI 0 "register_operand" "")
-	  (match_operand:TDSI 1 "memory_operand" ""))
-     (set (match_dup 1)
-	  (unspec_volatile:TDSI
-	    [(match_dup 1)
-	     (match_operand:TDSI 2 "register_operand" "")
-	     (match_operand:TDSI 3 "register_operand" "")]
-	    UNSPECV_CAS))
-     (set (match_dup 4)
-	  (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
-  ""
-{
-  /* Emulate compare.  */
-  operands[4] = gen_rtx_REG (CCZ1mode, CC_REGNUM);
-  s390_compare_op0 = operands[4];
-  s390_compare_op1 = const0_rtx;
-})
-
 ; cds, cdsg
 (define_insn "*sync_compare_and_swap<mode>"
   [(set (match_operand:DP 0 "register_operand" "=r")
Index: gcc/config/s390/predicates.md
===================================================================
--- gcc/config/s390/predicates.md	(branch cond-optab)
+++ gcc/config/s390/predicates.md	(working copy)
@@ -172,6 +172,11 @@
   return (s390_branch_condition_mask (op) >= 0);
 })
 
+;; Return true if op is the cc register.
+(define_predicate "cc_reg_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == CC_REGNUM")))
+
 (define_predicate "s390_signed_integer_comparison"
   (match_code "eq, ne, lt, gt, le, ge")
 {
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(branch cond-optab)
+++ gcc/optabs.c	(working copy)
@@ -4135,11 +4135,15 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 
   *px = x;
   *py = y;
-  if (can_compare_p (*pcomparison, mode, purpose))
+  if (GET_MODE_CLASS (mode) == MODE_CC)
+    {
+      gcc_assert (can_compare_p (*pcomparison, CCmode, purpose));
+      return;
+    }
+  else if (can_compare_p (*pcomparison, mode, purpose))
     return;
 
   /* Handle a lib call just for the mode we are using.  */
-
   libfunc = optab_libfunc (cmp_optab, mode);
   if (libfunc && !SCALAR_FLOAT_MODE_P (mode))
     {
@@ -4223,12 +4227,13 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, 
   /* Try combined insns first.  */
   do
     {
+      enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : wider_mode;
       enum insn_code icode;
       PUT_MODE (test, wider_mode);
 
       if (label)
 	{
-	  icode = optab_handler (cbranch_optab, wider_mode)->insn_code;
+	  icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
 
 	  if (icode != CODE_FOR_nothing
 	      && insn_data[icode].operand[0].predicate (test, wider_mode))
@@ -4241,7 +4246,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, 
 	}
 
       /* Handle some compares against zero.  */
-      icode = (int) optab_handler (tst_optab, wider_mode)->insn_code;
+      icode = (int) optab_handler (tst_optab, optab_mode)->insn_code;
       if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
 	{
 	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
@@ -4253,7 +4258,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, 
 
       /* Handle compares for which there is a directly suitable insn.  */
 
-      icode = (int) optab_handler (cmp_optab, wider_mode)->insn_code;
+      icode = (int) optab_handler (cmp_optab, optab_mode)->insn_code;
       if (icode != CODE_FOR_nothing)
 	{
 	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
@@ -6373,7 +6378,6 @@ init_optabs (void)
       sync_new_xor_optab[i] = CODE_FOR_nothing;
       sync_new_nand_optab[i] = CODE_FOR_nothing;
       sync_compare_and_swap[i] = CODE_FOR_nothing;
-      sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
       sync_lock_test_and_set[i] = CODE_FOR_nothing;
       sync_lock_release[i] = CODE_FOR_nothing;
 
@@ -6944,6 +6948,21 @@ expand_val_compare_and_swap (rtx mem, rt
   return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode);
 }
 
+/* Helper function to find the MODE_CC set in a sync_compare_and_swap
+   pattern.  */
+
+static void
+find_cc_set (rtx x, const_rtx pat, void *data)
+{
+  if (REG_P (x) && GET_MODE_CLASS (GET_MODE (x)) == MODE_CC
+      && GET_CODE (pat) == SET)
+    {
+      rtx *p_cc_reg = (rtx *) data;
+      gcc_assert (!*p_cc_reg);
+      *p_cc_reg = x;
+    }
+}
+
 /* Expand a compare-and-swap operation and store true into the result if
    the operation was successful and false otherwise.  Return the result.
    Unlike other routines, TARGET is not optional.  */
@@ -6953,84 +6972,45 @@ expand_bool_compare_and_swap (rtx mem, r
 {
   enum machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
-  rtx subtarget, label0, label1;
+  rtx subtarget, seq, cc_reg;
 
   /* If the target supports a compare-and-swap pattern that simultaneously
      sets some flag for success, then use it.  Otherwise use the regular
      compare-and-swap and follow that immediately with a compare insn.  */
-  icode = sync_compare_and_swap_cc[mode];
-  switch (icode)
-    {
-    default:
-      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
-						 NULL_RTX, icode);
-      if (subtarget != NULL_RTX)
-	break;
-
-      /* FALLTHRU */
-    case CODE_FOR_nothing:
-      icode = sync_compare_and_swap[mode];
-      if (icode == CODE_FOR_nothing)
-	return NULL_RTX;
-
-      /* Ensure that if old_val == mem, that we're not comparing
-	 against an old value.  */
-      if (MEM_P (old_val))
-	old_val = force_reg (mode, old_val);
+  icode = sync_compare_and_swap[mode];
+  if (icode == CODE_FOR_nothing)
+    return NULL_RTX;
 
+  do
+    {
+      start_sequence ();
       subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
-						 NULL_RTX, icode);
+					         NULL_RTX, icode);
+      cc_reg = NULL_RTX;
       if (subtarget == NULL_RTX)
-	return NULL_RTX;
-
-      emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true);
-    }
-
-  /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
-     setcc instruction from the beginning.  We don't work too hard here,
-     but it's nice to not be stupid about initial code gen either.  */
-  if (STORE_FLAG_VALUE == 1)
-    {
-      icode = setcc_gen_code[EQ];
-      if (icode != CODE_FOR_nothing)
 	{
-	  enum machine_mode cmode = insn_data[icode].operand[0].mode;
-	  rtx insn;
-
-	  subtarget = target;
-	  if (!insn_data[icode].operand[0].predicate (target, cmode))
-	    subtarget = gen_reg_rtx (cmode);
-
-	  insn = GEN_FCN (icode) (subtarget);
-	  if (insn)
-	    {
-	      emit_insn (insn);
-	      if (GET_MODE (target) != GET_MODE (subtarget))
-		{
-	          convert_move (target, subtarget, 1);
-		  subtarget = target;
-		}
-	      return subtarget;
-	    }
+	  end_sequence ();
+	  return NULL_RTX;
 	}
-    }
 
-  /* Without an appropriate setcc instruction, use a set of branches to
-     get 1 and 0 stored into target.  Presumably if the target has a
-     STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt.  */
-
-  label0 = gen_label_rtx ();
-  label1 = gen_label_rtx ();
-
-  emit_jump_insn (bcc_gen_fctn[EQ] (label0));
-  emit_move_insn (target, const0_rtx);
-  emit_jump_insn (gen_jump (label1));
-  emit_barrier ();
-  emit_label (label0);
-  emit_move_insn (target, const1_rtx);
-  emit_label (label1);
+      note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg);
+      seq = get_insns ();
+      end_sequence ();
 
-  return target;
+      /* We might be comparing against an old value.  Try again. :-(  */
+      if (!cc_reg && MEM_P (old_val))
+	{
+	  seq = NULL_RTX;
+	  old_val = force_reg (mode, old_val);
+        }
+    }
+  while (!seq);
+
+  emit_insn (seq);
+  if (cc_reg)
+    return emit_store_flag (target, EQ, cc_reg, const0_rtx, VOIDmode, 0, 1);
+  else
+    return emit_store_flag (target, EQ, subtarget, old_val, VOIDmode, 1, 1);
 }
 
 /* This is a helper function for the other atomic operations.  This function
@@ -7047,7 +7027,7 @@ expand_compare_and_swap_loop (rtx mem, r
 {
   enum machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
-  rtx label, cmp_reg, subtarget;
+  rtx label, cmp_reg, subtarget, cc_reg;
 
   /* The loop we want to generate looks like
 
@@ -7074,37 +7054,31 @@ expand_compare_and_swap_loop (rtx mem, r
   /* If the target supports a compare-and-swap pattern that simultaneously
      sets some flag for success, then use it.  Otherwise use the regular
      compare-and-swap and follow that immediately with a compare insn.  */
-  icode = sync_compare_and_swap_cc[mode];
-  switch (icode)
-    {
-    default:
-      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
-						 cmp_reg, icode);
-      if (subtarget != NULL_RTX)
-	{
-	  gcc_assert (subtarget == cmp_reg);
-	  break;
-	}
+  icode = sync_compare_and_swap[mode];
+  if (icode == CODE_FOR_nothing)
+    return false;
 
-      /* FALLTHRU */
-    case CODE_FOR_nothing:
-      icode = sync_compare_and_swap[mode];
-      if (icode == CODE_FOR_nothing)
-	return false;
+  subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
+					     cmp_reg, icode);
+  if (subtarget == NULL_RTX)
+    return false;
 
-      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
-						 cmp_reg, icode);
-      if (subtarget == NULL_RTX)
-	return false;
+  cc_reg = NULL_RTX;
+  note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg);
+  if (cc_reg)
+    {
+      cmp_reg = cc_reg;
+      old_reg = const0_rtx;
+    }
+  else
+    {
       if (subtarget != cmp_reg)
 	emit_move_insn (cmp_reg, subtarget);
-
-      emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
     }
 
   /* ??? Mark this jump predicted not taken?  */
-  emit_jump_insn (bcc_gen_fctn[NE] (label));
-
+  emit_cmp_and_jump_insns (cmp_reg, old_reg, NE, const0_rtx, GET_MODE (cmp_reg), 1,
+			   label);
   return true;
 }
 
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(branch cond-optab)
+++ gcc/expr.c	(working copy)
@@ -234,7 +234,6 @@ enum insn_code sync_new_and_optab[NUM_MA
 enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
 enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
 enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
-enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
 enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
 enum insn_code sync_lock_release[NUM_MACHINE_MODES];
 
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(branch cond-optab)
+++ gcc/doc/md.texi	(working copy)
@@ -5083,19 +5083,15 @@ memory operations before the atomic oper
 operation and all memory operations after the atomic operation occur
 after the atomic operation.
 
-@cindex @code{sync_compare_and_swap_cc@var{mode}} instruction pattern
-@item @samp{sync_compare_and_swap_cc@var{mode}}
-
-This pattern is just like @code{sync_compare_and_swap@var{mode}}, except
-it should act as if compare part of the compare-and-swap were issued via
-@code{cmp@var{m}}.  This comparison will only be used with @code{EQ} and
-@code{NE} branches and @code{setcc} operations.
-
-Some targets do expose the success or failure of the compare-and-swap
-operation via the status flags.  Ideally we wouldn't need a separate
-named pattern in order to take advantage of this, but the combine pass
-does not handle patterns with multiple sets, which is required by
-definition for @code{sync_compare_and_swap@var{mode}}.
+For targets where the success or failure of the compare-and-swap
+operation is available via the status flags, it is possible
+to avoid a separate compare operation and issue the subsequent
+setcc or branch immediately after the compare-and-swap.  To this
+end, GCC will look for a @code{MODE_CC} set in the output of
+@code{sync_compare_and_swap@var{mode}}; if the machine description
+includes such a set, the target should also define a special @code{cmpcc}
+instruction.  GCC will then be able to take the destination of the
+@code{MODE_CC} set and use it as the first operand of @code{cmpcc}.
 
 @cindex @code{sync_add@var{mode}} instruction pattern
 @cindex @code{sync_sub@var{mode}} instruction pattern
Index: gcc/genopinit.c
===================================================================
--- gcc/genopinit.c	(branch cond-optab)
+++ gcc/genopinit.c	(working copy)
@@ -234,7 +234,6 @@ static const char * const optabs[] =
   "sync_new_xor_optab[$A] = CODE_FOR_$(sync_new_xor$I$a$)",
   "sync_new_nand_optab[$A] = CODE_FOR_$(sync_new_nand$I$a$)",
   "sync_compare_and_swap[$A] = CODE_FOR_$(sync_compare_and_swap$I$a$)",
-  "sync_compare_and_swap_cc[$A] = CODE_FOR_$(sync_compare_and_swap_cc$I$a$)",
   "sync_lock_test_and_set[$A] = CODE_FOR_$(sync_lock_test_and_set$I$a$)",
   "sync_lock_release[$A] = CODE_FOR_$(sync_lock_release$I$a$)",
   "optab_handler (vec_set_optab, $A)->insn_code = CODE_FOR_$(vec_set$a$)",
Index: gcc/optabs.h
===================================================================
--- gcc/optabs.h	(branch cond-optab)
+++ gcc/optabs.h	(working copy)
@@ -670,7 +670,6 @@ extern enum insn_code sync_new_nand_opta
 
 /* Atomic compare and swap.  */
 extern enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
-extern enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
 
 /* Atomic exchange with acquire semantics.  */
 extern enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]