1 ;; GCC machine description for i386 synchronization instructions.
2 ;; Copyright (C) 2005, 2006, 2007
3 ;; Free Software Foundation, Inc.
5 ;; This file is part of GCC.
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)
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 ;; ??? 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.
40 (define_expand "sync_compare_and_swap<mode>"
42 [(set (match_operand:CASMODE 0 "register_operand" "")
43 (match_operand:CASMODE 1 "memory_operand" ""))
45 (unspec_volatile:CASMODE
47 (match_operand:CASMODE 2 "register_operand" "")
48 (match_operand:CASMODE 3 "register_operand" "")]
50 (clobber (reg:CC FLAGS_REG))])]
53 if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
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));
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"))
77 (unspec_volatile:IMODE
79 (match_operand:IMODE 2 "register_operand" "a")
80 (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
82 (clobber (reg:CC FLAGS_REG))]
84 "lock{%;| } cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
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"))
90 (unspec_volatile:DCASMODE
92 (match_operand:DCASMODE 2 "register_operand" "A")
93 (match_operand:<DCASHMODE> 3 "register_operand" "b")
94 (match_operand:<DCASHMODE> 4 "register_operand" "c")]
96 (clobber (reg:CC FLAGS_REG))]
98 "lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
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"))
115 (match_operand:DI 2 "register_operand" "A")
116 (match_operand:SI 3 "register_operand" "SD")
117 (match_operand:SI 4 "register_operand" "c")]
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")
123 (define_expand "sync_compare_and_swap_cc<mode>"
125 [(set (match_operand:CASMODE 0 "register_operand" "")
126 (match_operand:CASMODE 1 "memory_operand" ""))
128 (unspec_volatile:CASMODE
130 (match_operand:CASMODE 2 "register_operand" "")
131 (match_operand:CASMODE 3 "register_operand" "")]
135 (unspec_volatile:CASMODE
136 [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
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)
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));
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"))
168 (unspec_volatile:IMODE
170 (match_operand:IMODE 2 "register_operand" "a")
171 (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
173 (set (reg:CCZ FLAGS_REG)
175 (unspec_volatile:IMODE
176 [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2)
179 "lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
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"))
185 (unspec_volatile:DCASMODE
187 (match_operand:DCASMODE 2 "register_operand" "A")
188 (match_operand:<DCASHMODE> 3 "register_operand" "b")
189 (match_operand:<DCASHMODE> 4 "register_operand" "c")]
191 (set (reg:CCZ FLAGS_REG)
193 (unspec_volatile:DCASMODE
194 [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
198 "lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
200 ;; See above for the explanation of using the constraint "SD" for
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"))
208 (match_operand:DI 2 "register_operand" "A")
209 (match_operand:SI 3 "register_operand" "SD")
210 (match_operand:SI 4 "register_operand" "c")]
212 (set (reg:CCZ FLAGS_REG)
215 [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
218 "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
219 "xchg{l}\t%%ebx, %3\;lock{%;| }cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3")
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))
226 (plus:IMODE (match_dup 1)
227 (match_operand:IMODE 2 "register_operand" "0")))
228 (clobber (reg:CC FLAGS_REG))]
230 "lock{%;| }xadd{<modesuffix>}\t{%0, %1|%1, %0}")
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))
238 (match_operand:IMODE 2 "register_operand" "0"))]
240 "xchg{<modesuffix>}\t{%1, %0|%0, %1}")
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>"))]
248 (clobber (reg:CC FLAGS_REG))]
251 if (TARGET_USE_INCDEC)
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";
259 return "lock{%;| }add{<modesuffix>}\t{%1, %0|%0, %1}";
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>"))]
268 (clobber (reg:CC FLAGS_REG))]
271 if (TARGET_USE_INCDEC)
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";
279 return "lock{%;| }sub{<modesuffix>}\t{%1, %0|%0, %1}";
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>"))]
288 (clobber (reg:CC FLAGS_REG))]
290 "lock{%;| }or{<modesuffix>}\t{%1, %0|%0, %1}")
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>"))]
298 (clobber (reg:CC FLAGS_REG))]
300 "lock{%;| }and{<modesuffix>}\t{%1, %0|%0, %1}")
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>"))]
308 (clobber (reg:CC FLAGS_REG))]
310 "lock{%;| }xor{<modesuffix>}\t{%1, %0|%0, %1}")