1;; GCC machine description for i386 synchronization instructions.
2;; Copyright (C) 2005-2014 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}")
607