OSDN Git Service

853686b4ab2a4dc6d38a21f2cae8200724f9b5d6
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / sync.md
1 ;; GCC machine description for i386 synchronization instructions.
2 ;; Copyright (C) 2005, 2006, 2007
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 3, 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 COPYING3.  If not see
19 ;; <http://www.gnu.org/licenses/>.
20
21 (define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")])
22 (define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
23 (define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")])
24 (define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")])
25
26 (define_mode_macro CASMODE [QI HI SI (DI "TARGET_64BIT || TARGET_CMPXCHG8B")
27                            (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
28 (define_mode_macro DCASMODE
29   [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic")
30    (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
31 (define_mode_attr doublemodesuffix [(DI "8") (TI "16")])
32 (define_mode_attr DCASHMODE [(DI "SI") (TI "DI")])
33
34 ;; ??? It would be possible to use cmpxchg8b on pentium for DImode
35 ;; changes.  It's complicated because the insn uses ecx:ebx as the
36 ;; new value; note that the registers are reversed from the order
37 ;; that they'd be in with (reg:DI 2 ecx).  Similarly for TImode 
38 ;; data in 64-bit mode.
39
40 (define_expand "sync_compare_and_swap<mode>"
41   [(parallel
42     [(set (match_operand:CASMODE 0 "register_operand" "")
43           (match_operand:CASMODE 1 "memory_operand" ""))
44      (set (match_dup 1)
45           (unspec_volatile:CASMODE
46             [(match_dup 1)
47              (match_operand:CASMODE 2 "register_operand" "")
48              (match_operand:CASMODE 3 "register_operand" "")]
49             UNSPECV_CMPXCHG_1))
50      (clobber (reg:CC FLAGS_REG))])]
51   "TARGET_CMPXCHG"
52 {
53   if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
54     {
55       enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode;
56       rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0);
57       rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode,
58                                       GET_MODE_SIZE (hmode));
59       low = force_reg (hmode, low);
60       high = force_reg (hmode, high);
61       if (<MODE>mode == DImode)
62         emit_insn (gen_sync_double_compare_and_swapdi
63                    (operands[0], operands[1], operands[2], low, high));
64       else if (<MODE>mode == TImode)
65         emit_insn (gen_sync_double_compare_and_swapti
66                    (operands[0], operands[1], operands[2], low, high));
67       else
68         gcc_unreachable ();
69       DONE;
70     }
71 })
72
73 (define_insn "*sync_compare_and_swap<mode>"
74   [(set (match_operand:IMODE 0 "register_operand" "=a")
75         (match_operand:IMODE 1 "memory_operand" "+m"))
76    (set (match_dup 1)
77         (unspec_volatile:IMODE
78           [(match_dup 1)
79            (match_operand:IMODE 2 "register_operand" "a")
80            (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
81           UNSPECV_CMPXCHG_1))
82    (clobber (reg:CC FLAGS_REG))]
83   "TARGET_CMPXCHG"
84   "lock{\;| }cmpxchg{<modesuffix>\t%3, %1| %1, %3}")
85
86 (define_insn "sync_double_compare_and_swap<mode>"
87   [(set (match_operand:DCASMODE 0 "register_operand" "=A")
88         (match_operand:DCASMODE 1 "memory_operand" "+m"))
89    (set (match_dup 1)
90         (unspec_volatile:DCASMODE
91           [(match_dup 1)
92            (match_operand:DCASMODE 2 "register_operand" "A")
93            (match_operand:<DCASHMODE> 3 "register_operand" "b")
94            (match_operand:<DCASHMODE> 4 "register_operand" "c")]
95           UNSPECV_CMPXCHG_1))
96    (clobber (reg:CC FLAGS_REG))]
97   ""
98   "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1")
99
100 ;; Theoretically we'd like to use constraint "r" (any reg) for operand
101 ;; 3, but that includes ecx.  If operand 3 and 4 are the same (like when
102 ;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like
103 ;; operand 4.  This breaks, as the xchg will move the PIC register contents
104 ;; to %ecx then --> boom.  Operands 3 and 4 really need to be different
105 ;; registers, which in this case means operand 3 must not be ecx.
106 ;; Instead of playing tricks with fake early clobbers or the like we
107 ;; just enumerate all regs possible here, which (as this is !TARGET_64BIT)
108 ;; are just esi and edi.
109 (define_insn "*sync_double_compare_and_swapdi_pic"
110   [(set (match_operand:DI 0 "register_operand" "=A")
111         (match_operand:DI 1 "memory_operand" "+m"))
112    (set (match_dup 1)
113         (unspec_volatile:DI
114           [(match_dup 1)
115            (match_operand:DI 2 "register_operand" "A")
116            (match_operand:SI 3 "register_operand" "SD")
117            (match_operand:SI 4 "register_operand" "c")]
118           UNSPECV_CMPXCHG_1))
119    (clobber (reg:CC FLAGS_REG))]
120   "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
121   "xchg{l}\t%%ebx, %3\;lock{\;| }cmpxchg8b{\t| }%1\;xchg{l}\t%%ebx, %3")
122
123 (define_expand "sync_compare_and_swap_cc<mode>"
124   [(parallel
125     [(set (match_operand:CASMODE 0 "register_operand" "")
126           (match_operand:CASMODE 1 "memory_operand" ""))
127      (set (match_dup 1)
128           (unspec_volatile:CASMODE
129             [(match_dup 1)
130              (match_operand:CASMODE 2 "register_operand" "")
131              (match_operand:CASMODE 3 "register_operand" "")]
132             UNSPECV_CMPXCHG_1))
133      (set (match_dup 4)
134           (compare:CCZ
135             (unspec_volatile:CASMODE
136               [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
137             (match_dup 2)))])]
138   "TARGET_CMPXCHG"
139 {
140   operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
141   ix86_compare_op0 = operands[3];
142   ix86_compare_op1 = NULL;
143   ix86_compare_emitted = operands[4];
144   if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
145     {
146       enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode;
147       rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0);
148       rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode,
149                                       GET_MODE_SIZE (hmode));
150       low = force_reg (hmode, low);
151       high = force_reg (hmode, high);
152       if (<MODE>mode == DImode)
153         emit_insn (gen_sync_double_compare_and_swap_ccdi
154                    (operands[0], operands[1], operands[2], low, high));
155       else if (<MODE>mode == TImode)
156         emit_insn (gen_sync_double_compare_and_swap_ccti
157                    (operands[0], operands[1], operands[2], low, high));
158       else
159         gcc_unreachable ();
160       DONE;
161     }
162 })
163
164 (define_insn "*sync_compare_and_swap_cc<mode>"
165   [(set (match_operand:IMODE 0 "register_operand" "=a")
166         (match_operand:IMODE 1 "memory_operand" "+m"))
167    (set (match_dup 1)
168         (unspec_volatile:IMODE
169           [(match_dup 1)
170            (match_operand:IMODE 2 "register_operand" "a")
171            (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
172           UNSPECV_CMPXCHG_1))
173    (set (reg:CCZ FLAGS_REG)
174         (compare:CCZ
175           (unspec_volatile:IMODE
176             [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
177           (match_dup 2)))]
178   "TARGET_CMPXCHG"
179   "lock{\;| }cmpxchg{<modesuffix>\t%3, %1| %1, %3}")
180
181 (define_insn "sync_double_compare_and_swap_cc<mode>"
182   [(set (match_operand:DCASMODE 0 "register_operand" "=A")
183         (match_operand:DCASMODE 1 "memory_operand" "+m"))
184    (set (match_dup 1)
185         (unspec_volatile:DCASMODE
186           [(match_dup 1)
187            (match_operand:DCASMODE 2 "register_operand" "A")
188            (match_operand:<DCASHMODE> 3 "register_operand" "b")
189            (match_operand:<DCASHMODE> 4 "register_operand" "c")]
190           UNSPECV_CMPXCHG_1))
191    (set (reg:CCZ FLAGS_REG)
192         (compare:CCZ
193           (unspec_volatile:DCASMODE
194             [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
195             UNSPECV_CMPXCHG_2)
196           (match_dup 2)))]
197   ""
198   "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1")
199
200 ;; See above for the explanation of using the constraint "SD" for
201 ;; operand 3.
202 (define_insn "*sync_double_compare_and_swap_ccdi_pic"
203   [(set (match_operand:DI 0 "register_operand" "=A")
204         (match_operand:DI 1 "memory_operand" "+m"))
205    (set (match_dup 1)
206         (unspec_volatile:DI
207           [(match_dup 1)
208            (match_operand:DI 2 "register_operand" "A")
209            (match_operand:SI 3 "register_operand" "SD")
210            (match_operand:SI 4 "register_operand" "c")]
211           UNSPECV_CMPXCHG_1))
212    (set (reg:CCZ FLAGS_REG)
213         (compare:CCZ
214           (unspec_volatile:DI
215             [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
216             UNSPECV_CMPXCHG_2)
217           (match_dup 2)))]
218   "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
219   "xchg{l}\t%%ebx, %3\;lock{\;| }cmpxchg8b{\t| }%1\;xchg{l}\t%%ebx, %3")
220
221 (define_insn "sync_old_add<mode>"
222   [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
223         (unspec_volatile:IMODE
224           [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
225    (set (match_dup 1)
226         (plus:IMODE (match_dup 1)
227                     (match_operand:IMODE 2 "register_operand" "0")))
228    (clobber (reg:CC FLAGS_REG))]
229   "TARGET_XADD"
230   "lock{\;| }xadd{<modesuffix>\t%0, %1| %1, %0}")
231
232 ;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
233 (define_insn "sync_lock_test_and_set<mode>"
234   [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
235         (unspec_volatile:IMODE
236           [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
237    (set (match_dup 1)
238         (match_operand:IMODE 2 "register_operand" "0"))]
239   ""
240   "xchg{<modesuffix>}\t{%1, %0|%0, %1}")
241
242 (define_insn "sync_add<mode>"
243   [(set (match_operand:IMODE 0 "memory_operand" "+m")
244         (unspec_volatile:IMODE
245           [(plus:IMODE (match_dup 0)
246              (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
247           UNSPECV_LOCK))
248    (clobber (reg:CC FLAGS_REG))]
249   ""
250 {
251   if (TARGET_USE_INCDEC)
252     {
253       if (operands[1] == const1_rtx)
254         return "lock{\;| }inc{<modesuffix>\t| }%0";
255       if (operands[1] == constm1_rtx)
256         return "lock{\;| }dec{<modesuffix>\t| }%0";
257     }
258
259   return "lock{\;| }add{<modesuffix>\t%1, %0| %0, %1}";
260 })
261
262 (define_insn "sync_sub<mode>"
263   [(set (match_operand:IMODE 0 "memory_operand" "+m")
264         (unspec_volatile:IMODE
265           [(minus:IMODE (match_dup 0)
266              (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
267           UNSPECV_LOCK))
268    (clobber (reg:CC FLAGS_REG))]
269   ""
270 {
271   if (TARGET_USE_INCDEC)
272     {
273       if (operands[1] == const1_rtx)
274         return "lock{\;| }dec{<modesuffix>\t| }%0";
275       if (operands[1] == constm1_rtx)
276         return "lock{\;| }inc{<modesuffix>\t| }%0";
277     }
278
279   return "lock{\;| }sub{<modesuffix>\t%1, %0| %0, %1}";
280 })
281
282 (define_insn "sync_ior<mode>"
283   [(set (match_operand:IMODE 0 "memory_operand" "+m")
284         (unspec_volatile:IMODE
285           [(ior:IMODE (match_dup 0)
286              (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
287           UNSPECV_LOCK))
288    (clobber (reg:CC FLAGS_REG))]
289   ""
290   "lock{\;| }or{<modesuffix>\t%1, %0| %0, %1}")
291
292 (define_insn "sync_and<mode>"
293   [(set (match_operand:IMODE 0 "memory_operand" "+m")
294         (unspec_volatile:IMODE
295           [(and:IMODE (match_dup 0)
296              (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
297           UNSPECV_LOCK))
298    (clobber (reg:CC FLAGS_REG))]
299   ""
300   "lock{\;| }and{<modesuffix>\t%1, %0| %0, %1}")
301
302 (define_insn "sync_xor<mode>"
303   [(set (match_operand:IMODE 0 "memory_operand" "+m")
304         (unspec_volatile:IMODE
305           [(xor:IMODE (match_dup 0)
306              (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))]
307           UNSPECV_LOCK))
308    (clobber (reg:CC FLAGS_REG))]
309   ""
310   "lock{\;| }xor{<modesuffix>\t%1, %0| %0, %1}")