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