sync.md (atomic_compare_and_swap<dwi>_doubleword): If possible, add .cfi directives...
[gcc.git] / gcc / config / i386 / sync.md
1 ;; GCC machine description for i386 synchronization instructions.
2 ;; Copyright (C) 2005-2013 Free Software Foundation, Inc.
3 ;;
4 ;; This file is part of GCC.
5 ;;
6 ;; GCC is free software; you can redistribute it and/or modify
7 ;; it under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation; either version 3, or (at your option)
9 ;; any later version.
10 ;;
11 ;; GCC is distributed in the hope that it will be useful,
12 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;; GNU General Public License for more details.
15 ;;
16 ;; You should have received a copy of the GNU General Public License
17 ;; along with GCC; see the file COPYING3. If not see
18 ;; <http://www.gnu.org/licenses/>.
19
20 (define_c_enum "unspec" [
21 UNSPEC_LFENCE
22 UNSPEC_SFENCE
23 UNSPEC_MFENCE
24 UNSPEC_MOVA ; For __atomic support
25 UNSPEC_LDA
26 UNSPEC_STA
27 ])
28
29 (define_c_enum "unspecv" [
30 UNSPECV_CMPXCHG
31 UNSPECV_XCHG
32 UNSPECV_LOCK
33 ])
34
35 (define_expand "sse2_lfence"
36 [(set (match_dup 0)
37 (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))]
38 "TARGET_SSE2"
39 {
40 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
41 MEM_VOLATILE_P (operands[0]) = 1;
42 })
43
44 (define_insn "*sse2_lfence"
45 [(set (match_operand:BLK 0)
46 (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))]
47 "TARGET_SSE2"
48 "lfence"
49 [(set_attr "type" "sse")
50 (set_attr "length_address" "0")
51 (set_attr "atom_sse_attr" "lfence")
52 (set_attr "memory" "unknown")])
53
54 (define_expand "sse_sfence"
55 [(set (match_dup 0)
56 (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))]
57 "TARGET_SSE || TARGET_3DNOW_A"
58 {
59 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
60 MEM_VOLATILE_P (operands[0]) = 1;
61 })
62
63 (define_insn "*sse_sfence"
64 [(set (match_operand:BLK 0)
65 (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))]
66 "TARGET_SSE || TARGET_3DNOW_A"
67 "sfence"
68 [(set_attr "type" "sse")
69 (set_attr "length_address" "0")
70 (set_attr "atom_sse_attr" "fence")
71 (set_attr "memory" "unknown")])
72
73 (define_expand "sse2_mfence"
74 [(set (match_dup 0)
75 (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))]
76 "TARGET_SSE2"
77 {
78 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
79 MEM_VOLATILE_P (operands[0]) = 1;
80 })
81
82 (define_insn "mfence_sse2"
83 [(set (match_operand:BLK 0)
84 (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))]
85 "TARGET_64BIT || TARGET_SSE2"
86 "mfence"
87 [(set_attr "type" "sse")
88 (set_attr "length_address" "0")
89 (set_attr "atom_sse_attr" "fence")
90 (set_attr "memory" "unknown")])
91
92 (define_insn "mfence_nosse"
93 [(set (match_operand:BLK 0)
94 (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))
95 (clobber (reg:CC FLAGS_REG))]
96 "!(TARGET_64BIT || TARGET_SSE2)"
97 "lock{%;} or{l}\t{$0, (%%esp)|DWORD PTR [esp], 0}"
98 [(set_attr "memory" "unknown")])
99
100 (define_expand "mem_thread_fence"
101 [(match_operand:SI 0 "const_int_operand")] ;; model
102 ""
103 {
104 enum memmodel model = (enum memmodel) (INTVAL (operands[0]) & MEMMODEL_MASK);
105
106 /* Unless this is a SEQ_CST fence, the i386 memory model is strong
107 enough not to require barriers of any kind. */
108 if (model == MEMMODEL_SEQ_CST)
109 {
110 rtx (*mfence_insn)(rtx);
111 rtx mem;
112
113 if (TARGET_64BIT || TARGET_SSE2)
114 mfence_insn = gen_mfence_sse2;
115 else
116 mfence_insn = gen_mfence_nosse;
117
118 mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
119 MEM_VOLATILE_P (mem) = 1;
120
121 emit_insn (mfence_insn (mem));
122 }
123 DONE;
124 })
125
126 ;; ??? From volume 3 section 8.1.1 Guaranteed Atomic Operations,
127 ;; Only beginning at Pentium family processors do we get any guarantee of
128 ;; atomicity in aligned 64-bit quantities. Beginning at P6, we get a
129 ;; guarantee for 64-bit accesses that do not cross a cacheline boundary.
130 ;;
131 ;; Note that the TARGET_CMPXCHG8B test below is a stand-in for "Pentium".
132 ;;
133 ;; Importantly, *no* processor makes atomicity guarantees for larger
134 ;; accesses. In particular, there's no way to perform an atomic TImode
135 ;; move, despite the apparent applicability of MOVDQA et al.
136
137 (define_mode_iterator ATOMIC
138 [QI HI SI
139 (DI "TARGET_64BIT || (TARGET_CMPXCHG8B && (TARGET_80387 || TARGET_SSE))")
140 ])
141
142 (define_expand "atomic_load<mode>"
143 [(set (match_operand:ATOMIC 0 "register_operand")
144 (unspec:ATOMIC [(match_operand:ATOMIC 1 "memory_operand")
145 (match_operand:SI 2 "const_int_operand")]
146 UNSPEC_MOVA))]
147 ""
148 {
149 /* For DImode on 32-bit, we can use the FPU to perform the load. */
150 if (<MODE>mode == DImode && !TARGET_64BIT)
151 emit_insn (gen_atomic_loaddi_fpu
152 (operands[0], operands[1],
153 assign_386_stack_local (DImode, SLOT_TEMP)));
154 else
155 emit_move_insn (operands[0], operands[1]);
156 DONE;
157 })
158
159 (define_insn_and_split "atomic_loaddi_fpu"
160 [(set (match_operand:DI 0 "nonimmediate_operand" "=x,m,?r")
161 (unspec:DI [(match_operand:DI 1 "memory_operand" "m,m,m")]
162 UNSPEC_MOVA))
163 (clobber (match_operand:DI 2 "memory_operand" "=X,X,m"))
164 (clobber (match_scratch:DF 3 "=X,xf,xf"))]
165 "!TARGET_64BIT && (TARGET_80387 || TARGET_SSE)"
166 "#"
167 "&& reload_completed"
168 [(const_int 0)]
169 {
170 rtx dst = operands[0], src = operands[1];
171 rtx mem = operands[2], tmp = operands[3];
172
173 if (SSE_REG_P (dst))
174 emit_move_insn (dst, src);
175 else
176 {
177 if (MEM_P (dst))
178 mem = dst;
179
180 if (STACK_REG_P (tmp))
181 {
182 emit_insn (gen_loaddi_via_fpu (tmp, src));
183 emit_insn (gen_storedi_via_fpu (mem, tmp));
184 }
185 else
186 {
187 adjust_reg_mode (tmp, DImode);
188 emit_move_insn (tmp, src);
189 emit_move_insn (mem, tmp);
190 }
191
192 if (mem != dst)
193 emit_move_insn (dst, mem);
194 }
195 DONE;
196 })
197
198 (define_expand "atomic_store<mode>"
199 [(set (match_operand:ATOMIC 0 "memory_operand")
200 (unspec:ATOMIC [(match_operand:ATOMIC 1 "register_operand")
201 (match_operand:SI 2 "const_int_operand")]
202 UNSPEC_MOVA))]
203 ""
204 {
205 enum memmodel model = (enum memmodel) (INTVAL (operands[2]) & MEMMODEL_MASK);
206
207 if (<MODE>mode == DImode && !TARGET_64BIT)
208 {
209 /* For DImode on 32-bit, we can use the FPU to perform the store. */
210 /* Note that while we could perform a cmpxchg8b loop, that turns
211 out to be significantly larger than this plus a barrier. */
212 emit_insn (gen_atomic_storedi_fpu
213 (operands[0], operands[1],
214 assign_386_stack_local (DImode, SLOT_TEMP)));
215 }
216 else
217 {
218 /* For seq-cst stores, when we lack MFENCE, use XCHG. */
219 if (model == MEMMODEL_SEQ_CST && !(TARGET_64BIT || TARGET_SSE2))
220 {
221 emit_insn (gen_atomic_exchange<mode> (gen_reg_rtx (<MODE>mode),
222 operands[0], operands[1],
223 operands[2]));
224 DONE;
225 }
226
227 /* Otherwise use a store. */
228 emit_insn (gen_atomic_store<mode>_1 (operands[0], operands[1],
229 operands[2]));
230 }
231 /* ... followed by an MFENCE, if required. */
232 if (model == MEMMODEL_SEQ_CST)
233 emit_insn (gen_mem_thread_fence (operands[2]));
234 DONE;
235 })
236
237 (define_insn "atomic_store<mode>_1"
238 [(set (match_operand:SWI 0 "memory_operand" "=m")
239 (unspec:SWI [(match_operand:SWI 1 "<nonmemory_operand>" "<r><i>")
240 (match_operand:SI 2 "const_int_operand")]
241 UNSPEC_MOVA))]
242 ""
243 "%K2mov{<imodesuffix>}\t{%1, %0|%0, %1}")
244
245 (define_insn_and_split "atomic_storedi_fpu"
246 [(set (match_operand:DI 0 "memory_operand" "=m,m,m")
247 (unspec:DI [(match_operand:DI 1 "register_operand" "x,m,?r")]
248 UNSPEC_MOVA))
249 (clobber (match_operand:DI 2 "memory_operand" "=X,X,m"))
250 (clobber (match_scratch:DF 3 "=X,xf,xf"))]
251 "!TARGET_64BIT && (TARGET_80387 || TARGET_SSE)"
252 "#"
253 "&& reload_completed"
254 [(const_int 0)]
255 {
256 rtx dst = operands[0], src = operands[1];
257 rtx mem = operands[2], tmp = operands[3];
258
259 if (!SSE_REG_P (src))
260 {
261 if (REG_P (src))
262 {
263 emit_move_insn (mem, src);
264 src = mem;
265 }
266
267 if (STACK_REG_P (tmp))
268 {
269 emit_insn (gen_loaddi_via_fpu (tmp, src));
270 emit_insn (gen_storedi_via_fpu (dst, tmp));
271 DONE;
272 }
273 else
274 {
275 adjust_reg_mode (tmp, DImode);
276 emit_move_insn (tmp, mem);
277 src = tmp;
278 }
279 }
280 emit_move_insn (dst, src);
281 DONE;
282 })
283
284 ;; ??? You'd think that we'd be able to perform this via FLOAT + FIX_TRUNC
285 ;; operations. But the fix_trunc patterns want way more setup than we want
286 ;; to provide. Note that the scratch is DFmode instead of XFmode in order
287 ;; to make it easy to allocate a scratch in either SSE or FP_REGs above.
288
289 (define_insn "loaddi_via_fpu"
290 [(set (match_operand:DF 0 "register_operand" "=f")
291 (unspec:DF [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_LDA))]
292 "TARGET_80387"
293 "fild%Z1\t%1"
294 [(set_attr "type" "fmov")
295 (set_attr "mode" "DF")
296 (set_attr "fp_int_src" "true")])
297
298 (define_insn "storedi_via_fpu"
299 [(set (match_operand:DI 0 "memory_operand" "=m")
300 (unspec:DI [(match_operand:DF 1 "register_operand" "f")] UNSPEC_STA))]
301 "TARGET_80387"
302 {
303 gcc_assert (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != NULL_RTX);
304
305 return "fistp%Z0\t%0";
306 }
307 [(set_attr "type" "fmov")
308 (set_attr "mode" "DI")])
309
310 (define_expand "atomic_compare_and_swap<mode>"
311 [(match_operand:QI 0 "register_operand") ;; bool success output
312 (match_operand:SWI124 1 "register_operand") ;; oldval output
313 (match_operand:SWI124 2 "memory_operand") ;; memory
314 (match_operand:SWI124 3 "register_operand") ;; expected input
315 (match_operand:SWI124 4 "register_operand") ;; newval input
316 (match_operand:SI 5 "const_int_operand") ;; is_weak
317 (match_operand:SI 6 "const_int_operand") ;; success model
318 (match_operand:SI 7 "const_int_operand")] ;; failure model
319 "TARGET_CMPXCHG"
320 {
321 emit_insn
322 (gen_atomic_compare_and_swap<mode>_1
323 (operands[1], operands[2], operands[3], operands[4], operands[6]));
324 ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG),
325 const0_rtx);
326 DONE;
327 })
328
329 (define_mode_iterator CASMODE
330 [(DI "TARGET_64BIT || TARGET_CMPXCHG8B")
331 (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
332 (define_mode_attr CASHMODE [(DI "SI") (TI "DI")])
333
334 (define_expand "atomic_compare_and_swap<mode>"
335 [(match_operand:QI 0 "register_operand") ;; bool success output
336 (match_operand:CASMODE 1 "register_operand") ;; oldval output
337 (match_operand:CASMODE 2 "memory_operand") ;; memory
338 (match_operand:CASMODE 3 "register_operand") ;; expected input
339 (match_operand:CASMODE 4 "register_operand") ;; newval input
340 (match_operand:SI 5 "const_int_operand") ;; is_weak
341 (match_operand:SI 6 "const_int_operand") ;; success model
342 (match_operand:SI 7 "const_int_operand")] ;; failure model
343 "TARGET_CMPXCHG"
344 {
345 if (<MODE>mode == DImode && TARGET_64BIT)
346 {
347 emit_insn
348 (gen_atomic_compare_and_swapdi_1
349 (operands[1], operands[2], operands[3], operands[4], operands[6]));
350 }
351 else
352 {
353 enum machine_mode hmode = <CASHMODE>mode;
354 rtx lo_o, lo_e, lo_n, hi_o, hi_e, hi_n, mem;
355
356 lo_o = operands[1];
357 mem = operands[2];
358 lo_e = operands[3];
359 lo_n = operands[4];
360 hi_o = gen_highpart (hmode, lo_o);
361 hi_e = gen_highpart (hmode, lo_e);
362 hi_n = gen_highpart (hmode, lo_n);
363 lo_o = gen_lowpart (hmode, lo_o);
364 lo_e = gen_lowpart (hmode, lo_e);
365 lo_n = gen_lowpart (hmode, lo_n);
366
367 if (!cmpxchg8b_pic_memory_operand (mem, <MODE>mode))
368 mem = replace_equiv_address (mem, force_reg (Pmode, XEXP (mem, 0)));
369
370 emit_insn
371 (gen_atomic_compare_and_swap<mode>_doubleword
372 (lo_o, hi_o, mem, lo_e, hi_e, lo_n, hi_n, operands[6]));
373 }
374
375 ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG),
376 const0_rtx);
377 DONE;
378 })
379
380 (define_insn "atomic_compare_and_swap<mode>_1"
381 [(set (match_operand:SWI 0 "register_operand" "=a")
382 (unspec_volatile:SWI
383 [(match_operand:SWI 1 "memory_operand" "+m")
384 (match_operand:SWI 2 "register_operand" "0")
385 (match_operand:SWI 3 "register_operand" "<r>")
386 (match_operand:SI 4 "const_int_operand")]
387 UNSPECV_CMPXCHG))
388 (set (match_dup 1)
389 (unspec_volatile:SWI [(const_int 0)] UNSPECV_CMPXCHG))
390 (set (reg:CCZ FLAGS_REG)
391 (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))]
392 "TARGET_CMPXCHG"
393 "lock{%;} %K4cmpxchg{<imodesuffix>}\t{%3, %1|%1, %3}")
394
395 ;; For double-word compare and swap, we are obliged to play tricks with
396 ;; the input newval (op5:op6) because the Intel register numbering does
397 ;; not match the gcc register numbering, so the pair must be CX:BX.
398 ;; That said, in order to take advantage of possible lower-subreg opts,
399 ;; treat all of the integral operands in the same way.
400
401 ;; Operands 5 and 6 really need to be different registers, which in
402 ;; this case means op5 must not be ecx. If op5 and op6 are the same
403 ;; (like when the input is -1LL) GCC might chose to allocate op5 to ecx,
404 ;; like op6. This breaks, as the xchg will move the PIC register
405 ;; contents to %ecx then --> boom.
406
407 (define_mode_attr doublemodesuffix [(SI "8") (DI "16")])
408 (define_mode_attr regprefix [(SI "e") (DI "r")])
409
410 (define_insn "atomic_compare_and_swap<dwi>_doubleword"
411 [(set (match_operand:DWIH 0 "register_operand" "=a,a")
412 (unspec_volatile:DWIH
413 [(match_operand:<DWI> 2 "cmpxchg8b_pic_memory_operand" "+m,m")
414 (match_operand:DWIH 3 "register_operand" "0,0")
415 (match_operand:DWIH 4 "register_operand" "1,1")
416 (match_operand:DWIH 5 "register_operand" "b,!*r")
417 (match_operand:DWIH 6 "register_operand" "c,c")
418 (match_operand:SI 7 "const_int_operand")]
419 UNSPECV_CMPXCHG))
420 (set (match_operand:DWIH 1 "register_operand" "=d,d")
421 (unspec_volatile:DWIH [(const_int 0)] UNSPECV_CMPXCHG))
422 (set (match_dup 2)
423 (unspec_volatile:<DWI> [(const_int 0)] UNSPECV_CMPXCHG))
424 (set (reg:CCZ FLAGS_REG)
425 (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))
426 (clobber (match_scratch:DWIH 8 "=X,&5"))]
427 "TARGET_CMPXCHG<doublemodesuffix>B"
428 {
429 bool swap = REGNO (operands[5]) != BX_REG;
430 const char *xchg = "xchg{<imodesuffix>}\t%%<regprefix>bx, %5";
431
432 if (swap)
433 {
434 output_asm_insn (xchg, operands);
435 if (ix86_emit_cfi ())
436 {
437 output_asm_insn (".cfi_remember_state", operands);
438 output_asm_insn (".cfi_register\t%%<regprefix>bx, %5", operands);
439 }
440 }
441 output_asm_insn ("lock{%;} %K7cmpxchg<doublemodesuffix>b\t%2", operands);
442 if (swap)
443 {
444 output_asm_insn (xchg, operands);
445 if (ix86_emit_cfi ())
446 output_asm_insn (".cfi_restore_state", operands);
447 }
448
449 return "";
450 })
451
452 ;; For operand 2 nonmemory_operand predicate is used instead of
453 ;; register_operand to allow combiner to better optimize atomic
454 ;; additions of constants.
455 (define_insn "atomic_fetch_add<mode>"
456 [(set (match_operand:SWI 0 "register_operand" "=<r>")
457 (unspec_volatile:SWI
458 [(match_operand:SWI 1 "memory_operand" "+m")
459 (match_operand:SI 3 "const_int_operand")] ;; model
460 UNSPECV_XCHG))
461 (set (match_dup 1)
462 (plus:SWI (match_dup 1)
463 (match_operand:SWI 2 "nonmemory_operand" "0")))
464 (clobber (reg:CC FLAGS_REG))]
465 "TARGET_XADD"
466 "lock{%;} %K3xadd{<imodesuffix>}\t{%0, %1|%1, %0}")
467
468 ;; This peephole2 and following insn optimize
469 ;; __sync_fetch_and_add (x, -N) == N into just lock {add,sub,inc,dec}
470 ;; followed by testing of flags instead of lock xadd and comparisons.
471 (define_peephole2
472 [(set (match_operand:SWI 0 "register_operand")
473 (match_operand:SWI 2 "const_int_operand"))
474 (parallel [(set (match_dup 0)
475 (unspec_volatile:SWI
476 [(match_operand:SWI 1 "memory_operand")
477 (match_operand:SI 4 "const_int_operand")]
478 UNSPECV_XCHG))
479 (set (match_dup 1)
480 (plus:SWI (match_dup 1)
481 (match_dup 0)))
482 (clobber (reg:CC FLAGS_REG))])
483 (set (reg:CCZ FLAGS_REG)
484 (compare:CCZ (match_dup 0)
485 (match_operand:SWI 3 "const_int_operand")))]
486 "peep2_reg_dead_p (3, operands[0])
487 && (unsigned HOST_WIDE_INT) INTVAL (operands[2])
488 == -(unsigned HOST_WIDE_INT) INTVAL (operands[3])
489 && !reg_overlap_mentioned_p (operands[0], operands[1])"
490 [(parallel [(set (reg:CCZ FLAGS_REG)
491 (compare:CCZ
492 (unspec_volatile:SWI [(match_dup 1) (match_dup 4)]
493 UNSPECV_XCHG)
494 (match_dup 3)))
495 (set (match_dup 1)
496 (plus:SWI (match_dup 1)
497 (match_dup 2)))])])
498
499 (define_insn "*atomic_fetch_add_cmp<mode>"
500 [(set (reg:CCZ FLAGS_REG)
501 (compare:CCZ
502 (unspec_volatile:SWI
503 [(match_operand:SWI 0 "memory_operand" "+m")
504 (match_operand:SI 3 "const_int_operand")] ;; model
505 UNSPECV_XCHG)
506 (match_operand:SWI 2 "const_int_operand" "i")))
507 (set (match_dup 0)
508 (plus:SWI (match_dup 0)
509 (match_operand:SWI 1 "const_int_operand" "i")))]
510 "(unsigned HOST_WIDE_INT) INTVAL (operands[1])
511 == -(unsigned HOST_WIDE_INT) INTVAL (operands[2])"
512 {
513 if (incdec_operand (operands[1], <MODE>mode))
514 {
515 if (operands[1] == const1_rtx)
516 return "lock{%;} %K3inc{<imodesuffix>}\t%0";
517 else
518 {
519 gcc_assert (operands[1] == constm1_rtx);
520 return "lock{%;} %K3dec{<imodesuffix>}\t%0";
521 }
522 }
523
524 if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
525 return "lock{%;} %K3sub{<imodesuffix>}\t{%1, %0|%0, %1}";
526
527 return "lock{%;} %K3add{<imodesuffix>}\t{%1, %0|%0, %1}";
528 })
529
530 ;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
531 ;; In addition, it is always a full barrier, so we can ignore the memory model.
532 (define_insn "atomic_exchange<mode>"
533 [(set (match_operand:SWI 0 "register_operand" "=<r>") ;; output
534 (unspec_volatile:SWI
535 [(match_operand:SWI 1 "memory_operand" "+m") ;; memory
536 (match_operand:SI 3 "const_int_operand")] ;; model
537 UNSPECV_XCHG))
538 (set (match_dup 1)
539 (match_operand:SWI 2 "register_operand" "0"))] ;; input
540 ""
541 "%K3xchg{<imodesuffix>}\t{%1, %0|%0, %1}")
542
543 (define_insn "atomic_add<mode>"
544 [(set (match_operand:SWI 0 "memory_operand" "+m")
545 (unspec_volatile:SWI
546 [(plus:SWI (match_dup 0)
547 (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
548 (match_operand:SI 2 "const_int_operand")] ;; model
549 UNSPECV_LOCK))
550 (clobber (reg:CC FLAGS_REG))]
551 ""
552 {
553 if (incdec_operand (operands[1], <MODE>mode))
554 {
555 if (operands[1] == const1_rtx)
556 return "lock{%;} %K2inc{<imodesuffix>}\t%0";
557 else
558 {
559 gcc_assert (operands[1] == constm1_rtx);
560 return "lock{%;} %K2dec{<imodesuffix>}\t%0";
561 }
562 }
563
564 if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
565 return "lock{%;} %K2sub{<imodesuffix>}\t{%1, %0|%0, %1}";
566
567 return "lock{%;} %K2add{<imodesuffix>}\t{%1, %0|%0, %1}";
568 })
569
570 (define_insn "atomic_sub<mode>"
571 [(set (match_operand:SWI 0 "memory_operand" "+m")
572 (unspec_volatile:SWI
573 [(minus:SWI (match_dup 0)
574 (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
575 (match_operand:SI 2 "const_int_operand")] ;; model
576 UNSPECV_LOCK))
577 (clobber (reg:CC FLAGS_REG))]
578 ""
579 {
580 if (incdec_operand (operands[1], <MODE>mode))
581 {
582 if (operands[1] == const1_rtx)
583 return "lock{%;} %K2dec{<imodesuffix>}\t%0";
584 else
585 {
586 gcc_assert (operands[1] == constm1_rtx);
587 return "lock{%;} %K2inc{<imodesuffix>}\t%0";
588 }
589 }
590
591 if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
592 return "lock{%;} %K2add{<imodesuffix>}\t{%1, %0|%0, %1}";
593
594 return "lock{%;} %K2sub{<imodesuffix>}\t{%1, %0|%0, %1}";
595 })
596
597 (define_insn "atomic_<logic><mode>"
598 [(set (match_operand:SWI 0 "memory_operand" "+m")
599 (unspec_volatile:SWI
600 [(any_logic:SWI (match_dup 0)
601 (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
602 (match_operand:SI 2 "const_int_operand")] ;; model
603 UNSPECV_LOCK))
604 (clobber (reg:CC FLAGS_REG))]
605 ""
606 "lock{%;} %K2<logic>{<imodesuffix>}\t{%1, %0|%0, %1}")