1;; GCC machine description for i386 synchronization instructions.
2;; Copyright (C) 2005
3;; Free Software Foundation, Inc.
4;;
5;; This file is part of GCC.
6;;
7;; GCC is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11;;
12;; GCC is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16;;
17;; You should have received a copy of the GNU General Public License
18;; along with GCC; see the file COPYING.  If not, write to
19;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20;; Boston, MA 02110-1301, USA.
21
22(define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")])
23(define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
24(define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")])
25(define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")])
26
27;; ??? It would be possible to use cmpxchg8b on pentium for DImode
28;; changes.  It's complicated because the insn uses ecx:ebx as the
29;; new value; note that the registers are reversed from the order
30;; that they'd be in with (reg:DI 2 ecx).  Similarly for TImode 
31;; data in 64-bit mode.
32
33(define_insn "sync_compare_and_swap<mode>"
34  [(set (match_operand:IMODE 0 "register_operand" "=a")
35	(match_operand:IMODE 1 "memory_operand" "+m"))
36   (set (match_dup 1)
37	(unspec_volatile:IMODE
38	  [(match_dup 1)
39	   (match_operand:IMODE 2 "register_operand" "a")
40	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
41	  UNSPECV_CMPXCHG_1))
42   (clobber (reg:CC FLAGS_REG))]
43  "TARGET_CMPXCHG"
44  "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
45
46(define_expand "sync_compare_and_swap_cc<mode>"
47  [(parallel
48    [(set (match_operand:IMODE 0 "register_operand" "")
49	  (match_operand:IMODE 1 "memory_operand" ""))
50     (set (match_dup 1)
51	  (unspec_volatile:IMODE
52	    [(match_dup 1)
53	     (match_operand:IMODE 2 "register_operand" "")
54	     (match_operand:IMODE 3 "register_operand" "")]
55	    UNSPECV_CMPXCHG_1))
56     (set (match_dup 4)
57	  (compare:CCZ
58	    (unspec_volatile:IMODE
59	      [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
60	    (match_dup 2)))])]
61  "TARGET_CMPXCHG"
62{
63  operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
64  ix86_compare_op0 = operands[3];
65  ix86_compare_op1 = NULL;
66  ix86_compare_emitted = operands[4];
67})
68
69(define_insn "*sync_compare_and_swap_cc<mode>"
70  [(set (match_operand:IMODE 0 "register_operand" "=a")
71	(match_operand:IMODE 1 "memory_operand" "+m"))
72   (set (match_dup 1)
73	(unspec_volatile:IMODE
74	  [(match_dup 1)
75	   (match_operand:IMODE 2 "register_operand" "a")
76	   (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
77	  UNSPECV_CMPXCHG_1))
78   (set (reg:CCZ FLAGS_REG)
79	(compare:CCZ
80	  (unspec_volatile:IMODE
81	    [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
82	  (match_dup 2)))]
83  "TARGET_CMPXCHG"
84  "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
85
86(define_insn "sync_old_add<mode>"
87  [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
88	(unspec_volatile:IMODE
89	  [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
90   (set (match_dup 1)
91	(plus:IMODE (match_dup 1)
92		    (match_operand:IMODE 2 "register_operand" "0")))
93   (clobber (reg:CC FLAGS_REG))]
94  "TARGET_XADD"
95  "lock\;xadd{<modesuffix>}\t{%0, %1|%1, %0}")
96
97;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
98(define_insn "sync_lock_test_and_set<mode>"
99  [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
100	(unspec_volatile:IMODE
101	  [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
102   (set (match_dup 1)
103	(match_operand:IMODE 2 "register_operand" "0"))]
104  ""
105  "xchg{<modesuffix>}\t{%1, %0|%0, %1}")
106
107(define_insn "sync_add<mode>"
108  [(set (match_operand:IMODE 0 "memory_operand" "=m")
109	(unspec_volatile:IMODE
110	  [(plus:IMODE (match_dup 0)
111	     (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
112	  UNSPECV_LOCK))
113   (clobber (reg:CC FLAGS_REG))]
114  ""
115  "lock\;add{<modesuffix>}\t{%1, %0|%0, %1}")
116
117(define_insn "sync_sub<mode>"
118  [(set (match_operand:IMODE 0 "memory_operand" "=m")
119	(unspec_volatile:IMODE
120	  [(minus:IMODE (match_dup 0)
121	     (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
122	  UNSPECV_LOCK))
123   (clobber (reg:CC FLAGS_REG))]
124  ""
125  "lock\;sub{<modesuffix>}\t{%1, %0|%0, %1}")
126
127(define_insn "sync_ior<mode>"
128  [(set (match_operand:IMODE 0 "memory_operand" "=m")
129	(unspec_volatile:IMODE
130	  [(ior:IMODE (match_dup 0)
131	     (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
132	  UNSPECV_LOCK))
133   (clobber (reg:CC FLAGS_REG))]
134  ""
135  "lock\;or{<modesuffix>}\t{%1, %0|%0, %1}")
136
137(define_insn "sync_and<mode>"
138  [(set (match_operand:IMODE 0 "memory_operand" "=m")
139	(unspec_volatile:IMODE
140	  [(and:IMODE (match_dup 0)
141	     (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
142	  UNSPECV_LOCK))
143   (clobber (reg:CC FLAGS_REG))]
144  ""
145  "lock\;and{<modesuffix>}\t{%1, %0|%0, %1}")
146
147(define_insn "sync_xor<mode>"
148  [(set (match_operand:IMODE 0 "memory_operand" "=m")
149	(unspec_volatile:IMODE
150	  [(xor:IMODE (match_dup 0)
151	     (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
152	  UNSPECV_LOCK))
153   (clobber (reg:CC FLAGS_REG))]
154  ""
155  "lock\;xor{<modesuffix>}\t{%1, %0|%0, %1}")
156