OSDN Git Service

2010-04-06 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / sync.md
1 ;; GCC machine description for i386 synchronization instructions.
2 ;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
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_iterator CASMODE
22   [QI HI SI (DI "TARGET_64BIT || TARGET_CMPXCHG8B")
23             (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
24 (define_mode_iterator DCASMODE
25   [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic")
26    (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
27 (define_mode_attr doublemodesuffix [(DI "8") (TI "16")])
28 (define_mode_attr DCASHMODE [(DI "SI") (TI "DI")])
29
30 (define_expand "memory_barrier"
31   [(set (match_dup 0)
32         (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))]
33   ""
34 {
35   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
36   MEM_VOLATILE_P (operands[0]) = 1;
37
38   if (!(TARGET_64BIT || TARGET_SSE2))
39     {
40       emit_insn (gen_memory_barrier_nosse (operands[0]));
41       DONE;
42     }
43 })
44
45 (define_insn "memory_barrier_nosse"
46   [(set (match_operand:BLK 0 "" "")
47         (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))
48    (clobber (reg:CC FLAGS_REG))]
49   "!(TARGET_64BIT || TARGET_SSE2)"
50   "lock{%;} or{l}\t{$0, (%%esp)|DWORD PTR [esp], 0}"
51   [(set_attr "memory" "unknown")])
52
53 ;; ??? It would be possible to use cmpxchg8b on pentium for DImode
54 ;; changes.  It's complicated because the insn uses ecx:ebx as the
55 ;; new value; note that the registers are reversed from the order
56 ;; that they'd be in with (reg:DI 2 ecx).  Similarly for TImode
57 ;; data in 64-bit mode.
58
59 (define_expand "sync_compare_and_swap<mode>"
60   [(parallel
61     [(set (match_operand:CASMODE 0 "register_operand" "")
62           (match_operand:CASMODE 1 "memory_operand" ""))
63      (set (match_dup 1)
64           (unspec_volatile:CASMODE
65             [(match_dup 1)
66              (match_operand:CASMODE 2 "register_operand" "")
67              (match_operand:CASMODE 3 "register_operand" "")]
68             UNSPECV_CMPXCHG))
69    (set (reg:CCZ FLAGS_REG)
70         (compare:CCZ
71           (unspec_volatile:CASMODE
72             [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
73           (match_dup 2)))])]
74   "TARGET_CMPXCHG"
75 {
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         {
86           if (flag_pic && !cmpxchg8b_pic_memory_operand (operands[1], DImode))
87             operands[1] = replace_equiv_address (operands[1],
88                                                  force_reg (Pmode,
89                                                             XEXP (operands[1],
90                                                                   0)));
91           emit_insn (gen_sync_double_compare_and_swapdi
92                      (operands[0], operands[1], operands[2], low, high));
93         }
94       else if (<MODE>mode == TImode)
95         emit_insn (gen_sync_double_compare_and_swapti
96                    (operands[0], operands[1], operands[2], low, high));
97       else
98         gcc_unreachable ();
99       DONE;
100     }
101 })
102
103 (define_insn "*sync_compare_and_swap<mode>"
104   [(set (match_operand:SWI 0 "register_operand" "=a")
105         (match_operand:SWI 1 "memory_operand" "+m"))
106    (set (match_dup 1)
107         (unspec_volatile:SWI
108           [(match_dup 1)
109            (match_operand:SWI 2 "register_operand" "a")
110            (match_operand:SWI 3 "register_operand" "<r>")]
111           UNSPECV_CMPXCHG))
112    (set (reg:CCZ FLAGS_REG)
113         (compare:CCZ
114           (unspec_volatile:SWI
115             [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
116           (match_dup 2)))]
117   "TARGET_CMPXCHG"
118   "lock{%;} cmpxchg{<imodesuffix>}\t{%3, %1|%1, %3}")
119
120 (define_insn "sync_double_compare_and_swap<mode>"
121   [(set (match_operand:DCASMODE 0 "register_operand" "=A")
122         (match_operand:DCASMODE 1 "memory_operand" "+m"))
123    (set (match_dup 1)
124         (unspec_volatile:DCASMODE
125           [(match_dup 1)
126            (match_operand:DCASMODE 2 "register_operand" "A")
127            (match_operand:<DCASHMODE> 3 "register_operand" "b")
128            (match_operand:<DCASHMODE> 4 "register_operand" "c")]
129           UNSPECV_CMPXCHG))
130    (set (reg:CCZ FLAGS_REG)
131         (compare:CCZ
132           (unspec_volatile:DCASMODE
133             [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
134             UNSPECV_CMPXCHG)
135           (match_dup 2)))]
136   ""
137   "lock{%;} cmpxchg<doublemodesuffix>b\t%1")
138
139 ;; Theoretically we'd like to use constraint "r" (any reg) for operand
140 ;; 3, but that includes ecx.  If operand 3 and 4 are the same (like when
141 ;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like
142 ;; operand 4.  This breaks, as the xchg will move the PIC register contents
143 ;; to %ecx then --> boom.  Operands 3 and 4 really need to be different
144 ;; registers, which in this case means operand 3 must not be ecx.
145 ;; Instead of playing tricks with fake early clobbers or the like we
146 ;; just enumerate all regs possible here, which (as this is !TARGET_64BIT)
147 ;; are just esi and edi.
148 (define_insn "*sync_double_compare_and_swapdi_pic"
149   [(set (match_operand:DI 0 "register_operand" "=A")
150         (match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m"))
151    (set (match_dup 1)
152         (unspec_volatile:DI
153           [(match_dup 1)
154            (match_operand:DI 2 "register_operand" "A")
155            (match_operand:SI 3 "register_operand" "SD")
156            (match_operand:SI 4 "register_operand" "c")]
157           UNSPECV_CMPXCHG))
158    (set (reg:CCZ FLAGS_REG)
159         (compare:CCZ
160           (unspec_volatile:DI
161             [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
162             UNSPECV_CMPXCHG)
163           (match_dup 2)))]
164   "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
165   "xchg{l}\t%%ebx, %3\;lock{%;} cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3")
166
167 (define_insn "sync_old_add<mode>"
168   [(set (match_operand:SWI 0 "register_operand" "=<r>")
169         (unspec_volatile:SWI
170           [(match_operand:SWI 1 "memory_operand" "+m")] UNSPECV_XCHG))
171    (set (match_dup 1)
172         (plus:SWI (match_dup 1)
173                   (match_operand:SWI 2 "register_operand" "0")))
174    (clobber (reg:CC FLAGS_REG))]
175   "TARGET_XADD"
176   "lock{%;} xadd{<imodesuffix>}\t{%0, %1|%1, %0}")
177
178 ;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
179 (define_insn "sync_lock_test_and_set<mode>"
180   [(set (match_operand:SWI 0 "register_operand" "=<r>")
181         (unspec_volatile:SWI
182           [(match_operand:SWI 1 "memory_operand" "+m")] UNSPECV_XCHG))
183    (set (match_dup 1)
184         (match_operand:SWI 2 "register_operand" "0"))]
185   ""
186   "xchg{<imodesuffix>}\t{%1, %0|%0, %1}")
187
188 (define_insn "sync_add<mode>"
189   [(set (match_operand:SWI 0 "memory_operand" "+m")
190         (unspec_volatile:SWI
191           [(plus:SWI (match_dup 0)
192                      (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))]
193           UNSPECV_LOCK))
194    (clobber (reg:CC FLAGS_REG))]
195   ""
196 {
197   if (TARGET_USE_INCDEC)
198     {
199       if (operands[1] == const1_rtx)
200         return "lock{%;} inc{<imodesuffix>}\t%0";
201       if (operands[1] == constm1_rtx)
202         return "lock{%;} dec{<imodesuffix>}\t%0";
203     }
204
205   if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
206     return "lock{%;} sub{<imodesuffix>}\t{%1, %0|%0, %1}";
207
208   return "lock{%;} add{<imodesuffix>}\t{%1, %0|%0, %1}";
209 })
210
211 (define_insn "sync_sub<mode>"
212   [(set (match_operand:SWI 0 "memory_operand" "+m")
213         (unspec_volatile:SWI
214           [(minus:SWI (match_dup 0)
215                       (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))]
216           UNSPECV_LOCK))
217    (clobber (reg:CC FLAGS_REG))]
218   ""
219 {
220   if (TARGET_USE_INCDEC)
221     {
222       if (operands[1] == const1_rtx)
223         return "lock{%;} dec{<imodesuffix>}\t%0";
224       if (operands[1] == constm1_rtx)
225         return "lock{%;} inc{<imodesuffix>}\t%0";
226     }
227
228   return "lock{%;} sub{<imodesuffix>}\t{%1, %0|%0, %1}";
229 })
230
231 (define_insn "sync_<code><mode>"
232   [(set (match_operand:SWI 0 "memory_operand" "+m")
233         (unspec_volatile:SWI
234           [(any_logic:SWI (match_dup 0)
235                           (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))]
236           UNSPECV_LOCK))
237    (clobber (reg:CC FLAGS_REG))]
238   ""
239   "lock{%;} <logic>{<imodesuffix>}\t{%1, %0|%0, %1}")