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]

atomic memory operation builtins, i686


Here's the i686 portion.


r~


        * config/i386/i386.c (x86_cmpxchg, x86_xadd): New.
        (ix86_compare_emitted): New.
        (ix86_expand_compare): Use ix86_compare_emitted if set.
        (ix86_expand_setcc): Only emit REG_EQUAL if both ix86_compare_op0
        and ix86_compare_op0 are set.
        * config/i386/i386.h (x86_cmpxchg, x86_xadd): Declare.
        (TARGET_CMPXCHG, TARGET_XADD): New.
        (ix86_compare_emitted): Declare.
        * config/i386/i386.md: Include sync.md
        (UNSPECV_CMPXCHG_1, UNSPECV_CMPXCHG_2): New.
        (UNSPECV_XCHG, UNSPECV_LOCK): New.
        * config/i386/sync.md: New file.

Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.810
diff -u -p -d -r1.810 i386.c
--- config/i386/i386.c	14 Apr 2005 17:45:57 -0000	1.810
+++ config/i386/i386.c	14 Apr 2005 23:39:34 -0000
@@ -584,6 +584,10 @@ const int x86_ext_80387_constants = m_K6
 const int x86_four_jump_limit = m_PPRO | m_ATHLON_K8 | m_PENT4 | m_NOCONA;
 const int x86_schedule = m_PPRO | m_ATHLON_K8 | m_K6 | m_PENT;
 const int x86_use_bt = m_ATHLON_K8;
+/* Compare and exchange was added for 80486.  */
+const int x86_cmpxchg = ~m_386;
+/* Exchange and add was added for 80486.  */
+const int x86_xadd = ~m_386;
 
 /* In case the average insn count for single function invocation is
    lower than this constant, emit fast (but longer) prologue and
@@ -727,6 +731,7 @@ int const svr4_dbx_register_map[FIRST_PS
 
 rtx ix86_compare_op0 = NULL_RTX;
 rtx ix86_compare_op1 = NULL_RTX;
+rtx ix86_compare_emitted = NULL_RTX;
 
 #define MAX_386_STACK_LOCALS 3
 /* Size of the register save area.  */
@@ -9049,7 +9054,12 @@ ix86_expand_compare (enum rtx_code code,
   if (bypass_test)
     *bypass_test = NULL_RTX;
 
-  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+  if (ix86_compare_emitted)
+    {
+      ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_emitted, const0_rtx);
+      ix86_compare_emitted = NULL_RTX;
+    }
+  else if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
     ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
 				  second_test, bypass_test);
   else
@@ -9378,10 +9388,13 @@ ix86_expand_setcc (enum rtx_code code, r
     }
 
   /* Attach a REG_EQUAL note describing the comparison result.  */
-  equiv = simplify_gen_relational (code, QImode,
-				   GET_MODE (ix86_compare_op0),
-				   ix86_compare_op0, ix86_compare_op1);
-  set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
+  if (ix86_compare_op0 && ix86_compare_op1)
+    {
+      equiv = simplify_gen_relational (code, QImode,
+				       GET_MODE (ix86_compare_op0),
+				       ix86_compare_op0, ix86_compare_op1);
+      set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
+    }
 
   return 1; /* DONE */
 }
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.427
diff -u -p -d -r1.427 i386.h
--- config/i386/i386.h	12 Apr 2005 01:46:38 -0000	1.427
+++ config/i386/i386.h	14 Apr 2005 23:39:35 -0000
@@ -253,6 +253,7 @@ extern const int x86_sse_typeless_stores
 extern const int x86_use_ffreep;
 extern const int x86_inter_unit_moves, x86_schedule;
 extern const int x86_use_bt;
+extern const int x86_cmpxchg, x86_xadd;
 extern int x86_prefetch_sse;
 
 #define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK)
@@ -333,6 +334,9 @@ extern int x86_prefetch_sse;
 #define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
 #define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN)
 
+#define TARGET_CMPXCHG (x86_cmpxchg & (1 << ix86_arch))
+#define TARGET_XADD (x86_xadd & (1 << ix86_arch))
+
 /* WARNING: Do not mark empty strings for translation, as calling
             gettext on an empty string does NOT return an empty
             string.  */
@@ -2463,6 +2467,7 @@ extern enum reg_class const regclass_map
 
 extern rtx ix86_compare_op0;	/* operand 0 for comparisons */
 extern rtx ix86_compare_op1;	/* operand 1 for comparisons */
+extern rtx ix86_compare_emitted;
 
 /* To properly truncate FP values into integers, we need to set i387 control
    word.  We can't emit proper mode switching code before reload, as spills
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.629
diff -u -p -d -r1.629 i386.md
--- config/i386/i386.md	14 Apr 2005 11:31:04 -0000	1.629
+++ config/i386/i386.md	14 Apr 2005 23:39:43 -0000
@@ -151,6 +151,10 @@
    (UNSPECV_ALIGN		7)
    (UNSPECV_MONITOR		8)
    (UNSPECV_MWAIT		9)
+   (UNSPECV_CMPXCHG_1		10)
+   (UNSPECV_CMPXCHG_2		11)
+   (UNSPECV_XCHG		12)
+   (UNSPECV_LOCK		13)
   ])
 
 ;; Registers by name.
@@ -19757,3 +19761,4 @@
 
 (include "sse.md")
 (include "mmx.md")
+(include "sync.md")
Index: config/i386/sync.md
===================================================================
RCS file: config/i386/sync.md
diff -N config/i386/sync.md
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ config/i386/sync.md	14 Apr 2005 23:39:43 -0000
@@ -0,0 +1,158 @@
+;; GCC machine description for i386 synchronization instructions.
+;; Copyright (C) 2005
+;; Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+(define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")])
+(define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
+(define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")])
+(define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")])
+
+;; ??? It would be possible to use cmpxchg8b on pentium for DImode
+;; changes.  It's complicated because the insn uses ecx:ebx as the
+;; new value; note that the registers are reversed from the order
+;; that they'd be in with (reg:DI 2 ecx).  Similarly for TImode 
+;; data in 64-bit mode.
+
+(define_insn "sync_compare_and_swap<mode>"
+  [(set (match_operand:IMODE 0 "register_operand" "=a")
+	(unspec_volatile:IMODE
+	  [(match_operand:IMODE 1 "memory_operand" "+m")
+	   (match_operand:IMODE 2 "register_operand" "a")
+	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
+	  UNSPECV_CMPXCHG_1))
+   (set (match_dup 1)
+	(unspec_volatile:IMODE
+	  [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_CMPXCHG"
+  "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
+
+(define_expand "sync_compare_and_swap_cc<mode>"
+  [(parallel
+    [(set (match_operand:IMODE 0 "register_operand" "")
+	  (unspec_volatile:IMODE
+	    [(match_operand:IMODE 1 "memory_operand" "")
+	     (match_operand:IMODE 2 "register_operand" "")
+	     (match_operand:IMODE 3 "register_operand" "")]
+	    UNSPECV_CMPXCHG_1))
+     (set (match_dup 1)
+	  (unspec_volatile:IMODE
+	    [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
+     (set (match_dup 4)
+	  (compare:CCZ
+	    (unspec_volatile:IMODE
+	      [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_1)
+	    (match_dup 3)))])]
+  "TARGET_CMPXCHG"
+{
+  operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
+  ix86_compare_op0 = operands[3];
+  ix86_compare_op1 = NULL;
+  ix86_compare_emitted = operands[4];
+})
+
+(define_insn "*sync_compare_and_swap_cc<mode>"
+  [(set (match_operand:IMODE 0 "register_operand" "=a")
+	(unspec_volatile:IMODE
+	  [(match_operand:IMODE 1 "memory_operand" "+m")
+	   (match_operand:IMODE 2 "register_operand" "a")
+	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
+	  UNSPECV_CMPXCHG_1))
+   (set (match_dup 1)
+	(unspec_volatile:IMODE
+	  [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
+   (set (reg:CCZ FLAGS_REG)
+	(compare:CCZ
+	  (unspec_volatile:IMODE
+	    [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_1)
+	  (match_dup 3)))]
+  "TARGET_CMPXCHG"
+  "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
+
+(define_insn "sync_old_add<mode>"
+  [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
+	(unspec_volatile:IMODE
+	  [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
+   (set (match_dup 1)
+	(plus:IMODE (match_dup 1)
+		    (match_operand:IMODE 2 "register_operand" "0")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_XADD"
+  "lock\;xadd{<modesuffix>}\t{%0, %1|%1, %0}")
+
+;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
+(define_insn "sync_lock_test_and_set<mode>"
+  [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
+	(unspec_volatile:IMODE
+	  [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
+   (set (match_dup 1)
+	(match_operand:IMODE 2 "register_operand" "0"))]
+  ""
+  "xchg{<modesuffix>}\t{%1, %0|%0, %1}")
+
+(define_insn "sync_add<mode>"
+  [(set (match_operand:IMODE 0 "memory_operand" "=m")
+	(unspec_volatile:IMODE
+	  [(plus:IMODE (match_dup 0)
+	     (match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
+	  UNSPECV_LOCK))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "lock\;add{<modesuffix>}\t{%1, %0|%0, %1}")
+
+(define_insn "sync_sub<mode>"
+  [(set (match_operand:IMODE 0 "memory_operand" "=m")
+	(unspec_volatile:IMODE
+	  [(minus:IMODE (match_dup 0)
+	     (match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
+	  UNSPECV_LOCK))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "lock\;sub{<modesuffix>}\t{%1, %0|%0, %1}")
+
+(define_insn "sync_ior<mode>"
+  [(set (match_operand:IMODE 0 "memory_operand" "=m")
+	(unspec_volatile:IMODE
+	  [(ior:IMODE (match_dup 0)
+	     (match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
+	  UNSPECV_LOCK))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "lock\;or{<modesuffix>}\t{%1, %0|%0, %1}")
+
+(define_insn "sync_and<mode>"
+  [(set (match_operand:IMODE 0 "memory_operand" "=m")
+	(unspec_volatile:IMODE
+	  [(and:IMODE (match_dup 0)
+	     (match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
+	  UNSPECV_LOCK))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "lock\;and{<modesuffix>}\t{%1, %0|%0, %1}")
+
+(define_insn "sync_xor<mode>"
+  [(set (match_operand:IMODE 0 "memory_operand" "=m")
+	(unspec_volatile:IMODE
+	  [(xor:IMODE (match_dup 0)
+	     (match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
+	  UNSPECV_LOCK))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "lock\;xor{<modesuffix>}\t{%1, %0|%0, %1}")


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