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