* x86-tune-sched.c (ix86_adjust_cost): Fix Zen support.
[official-gcc.git] / gcc / config / i386 / sync.md
blob29b82f86d43a07f128082d292ba726c59192b5bb
1 ;; GCC machine description for i386 synchronization instructions.
2 ;; Copyright (C) 2005-2017 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.
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.
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/>.
20 (define_c_enum "unspec" [
21   UNSPEC_LFENCE
22   UNSPEC_SFENCE
23   UNSPEC_MFENCE
25   UNSPEC_FILD_ATOMIC
26   UNSPEC_FIST_ATOMIC
28   UNSPEC_LDX_ATOMIC
29   UNSPEC_STX_ATOMIC
31   ;; __atomic support
32   UNSPEC_LDA
33   UNSPEC_STA
36 (define_c_enum "unspecv" [
37   UNSPECV_CMPXCHG
38   UNSPECV_XCHG
39   UNSPECV_LOCK
42 (define_expand "sse2_lfence"
43   [(set (match_dup 0)
44         (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))]
45   "TARGET_SSE2"
47   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
48   MEM_VOLATILE_P (operands[0]) = 1;
51 (define_insn "*sse2_lfence"
52   [(set (match_operand:BLK 0)
53         (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))]
54   "TARGET_SSE2"
55   "lfence"
56   [(set_attr "type" "sse")
57    (set_attr "length_address" "0")
58    (set_attr "atom_sse_attr" "lfence")
59    (set_attr "memory" "unknown")])
61 (define_expand "sse_sfence"
62   [(set (match_dup 0)
63         (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))]
64   "TARGET_SSE || TARGET_3DNOW_A"
66   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
67   MEM_VOLATILE_P (operands[0]) = 1;
70 (define_insn "*sse_sfence"
71   [(set (match_operand:BLK 0)
72         (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))]
73   "TARGET_SSE || TARGET_3DNOW_A"
74   "sfence"
75   [(set_attr "type" "sse")
76    (set_attr "length_address" "0")
77    (set_attr "atom_sse_attr" "fence")
78    (set_attr "memory" "unknown")])
80 (define_expand "sse2_mfence"
81   [(set (match_dup 0)
82         (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))]
83   "TARGET_SSE2"
85   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
86   MEM_VOLATILE_P (operands[0]) = 1;
89 (define_insn "mfence_sse2"
90   [(set (match_operand:BLK 0)
91         (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))]
92   "TARGET_64BIT || TARGET_SSE2"
93   "mfence"
94   [(set_attr "type" "sse")
95    (set_attr "length_address" "0")
96    (set_attr "atom_sse_attr" "fence")
97    (set_attr "memory" "unknown")])
99 (define_insn "mfence_nosse"
100   [(set (match_operand:BLK 0)
101         (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))
102    (clobber (reg:CC FLAGS_REG))]
103   "!(TARGET_64BIT || TARGET_SSE2)"
104   "lock{%;} or{l}\t{$0, (%%esp)|DWORD PTR [esp], 0}"
105   [(set_attr "memory" "unknown")])
107 (define_expand "mem_thread_fence"
108   [(match_operand:SI 0 "const_int_operand")]            ;; model
109   ""
111   enum memmodel model = memmodel_from_int (INTVAL (operands[0]));
113   /* Unless this is a SEQ_CST fence, the i386 memory model is strong
114      enough not to require barriers of any kind.  */
115   if (is_mm_seq_cst (model))
116     {
117       rtx (*mfence_insn)(rtx);
118       rtx mem;
120       if (TARGET_64BIT || TARGET_SSE2)
121         mfence_insn = gen_mfence_sse2;
122       else
123         mfence_insn = gen_mfence_nosse;
125       mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
126       MEM_VOLATILE_P (mem) = 1;
128       emit_insn (mfence_insn (mem));
129     }
130   DONE;
133 ;; ??? From volume 3 section 8.1.1 Guaranteed Atomic Operations,
134 ;; Only beginning at Pentium family processors do we get any guarantee of
135 ;; atomicity in aligned 64-bit quantities.  Beginning at P6, we get a
136 ;; guarantee for 64-bit accesses that do not cross a cacheline boundary.
138 ;; Note that the TARGET_CMPXCHG8B test below is a stand-in for "Pentium".
140 ;; Importantly, *no* processor makes atomicity guarantees for larger
141 ;; accesses.  In particular, there's no way to perform an atomic TImode
142 ;; move, despite the apparent applicability of MOVDQA et al.
144 (define_mode_iterator ATOMIC
145    [QI HI SI
146     (DI "TARGET_64BIT || (TARGET_CMPXCHG8B && (TARGET_80387 || TARGET_SSE))")
147    ])
149 (define_expand "atomic_load<mode>"
150   [(set (match_operand:ATOMIC 0 "nonimmediate_operand")
151         (unspec:ATOMIC [(match_operand:ATOMIC 1 "memory_operand")
152                         (match_operand:SI 2 "const_int_operand")]
153                        UNSPEC_LDA))]
154   ""
156   /* For DImode on 32-bit, we can use the FPU to perform the load.  */
157   if (<MODE>mode == DImode && !TARGET_64BIT)
158     emit_insn (gen_atomic_loaddi_fpu
159                (operands[0], operands[1],
160                 assign_386_stack_local (DImode, SLOT_TEMP)));
161   else
162     {
163       rtx dst = operands[0];
165       if (MEM_P (dst))
166         dst = gen_reg_rtx (<MODE>mode);
168       emit_move_insn (dst, operands[1]);
170       /* Fix up the destination if needed.  */
171       if (dst != operands[0])
172         emit_move_insn (operands[0], dst);
173     }
174   DONE;
177 (define_insn_and_split "atomic_loaddi_fpu"
178   [(set (match_operand:DI 0 "nonimmediate_operand" "=x,m,?r")
179         (unspec:DI [(match_operand:DI 1 "memory_operand" "m,m,m")]
180                    UNSPEC_LDA))
181    (clobber (match_operand:DI 2 "memory_operand" "=X,X,m"))
182    (clobber (match_scratch:DF 3 "=X,xf,xf"))]
183   "!TARGET_64BIT && (TARGET_80387 || TARGET_SSE)"
184   "#"
185   "&& reload_completed"
186   [(const_int 0)]
188   rtx dst = operands[0], src = operands[1];
189   rtx mem = operands[2], tmp = operands[3];
191   if (SSE_REG_P (dst))
192     emit_move_insn (dst, src);
193   else
194     {
195       if (MEM_P (dst))
196         mem = dst;
198       if (STACK_REG_P (tmp))
199         {
200           emit_insn (gen_loaddi_via_fpu (tmp, src));
201           emit_insn (gen_storedi_via_fpu (mem, tmp));
202         }
203       else
204         {
205           emit_insn (gen_loaddi_via_sse (tmp, src));
206           emit_insn (gen_storedi_via_sse (mem, tmp));
207         }
209       if (mem != dst)
210         emit_move_insn (dst, mem);
211     }
212   DONE;
215 (define_peephole2
216   [(set (match_operand:DF 0 "fp_register_operand")
217         (unspec:DF [(match_operand:DI 1 "memory_operand")]
218                    UNSPEC_FILD_ATOMIC))
219    (set (match_operand:DI 2 "memory_operand")
220         (unspec:DI [(match_dup 0)]
221                    UNSPEC_FIST_ATOMIC))
222    (set (match_operand:DF 3 "fp_register_operand")
223         (match_operand:DF 4 "memory_operand"))]
224   "!TARGET_64BIT
225    && peep2_reg_dead_p (2, operands[0])
226    && rtx_equal_p (operands[4], adjust_address_nv (operands[2], DFmode, 0))"
227   [(set (match_dup 3) (match_dup 5))]
228   "operands[5] = gen_lowpart (DFmode, operands[1]);")
230 (define_peephole2
231   [(set (match_operand:DF 0 "sse_reg_operand")
232         (unspec:DF [(match_operand:DI 1 "memory_operand")]
233                    UNSPEC_LDX_ATOMIC))
234    (set (match_operand:DI 2 "memory_operand")
235         (unspec:DI [(match_dup 0)]
236                    UNSPEC_STX_ATOMIC))
237    (set (match_operand:DF 3 "fp_register_operand")
238         (match_operand:DF 4 "memory_operand"))]
239   "!TARGET_64BIT
240    && peep2_reg_dead_p (2, operands[0])
241    && rtx_equal_p (operands[4], adjust_address_nv (operands[2], DFmode, 0))"
242   [(set (match_dup 3) (match_dup 5))]
243   "operands[5] = gen_lowpart (DFmode, operands[1]);")
245 (define_expand "atomic_store<mode>"
246   [(set (match_operand:ATOMIC 0 "memory_operand")
247         (unspec:ATOMIC [(match_operand:ATOMIC 1 "nonimmediate_operand")
248                         (match_operand:SI 2 "const_int_operand")]
249                        UNSPEC_STA))]
250   ""
252   enum memmodel model = memmodel_from_int (INTVAL (operands[2]));
254   if (<MODE>mode == DImode && !TARGET_64BIT)
255     {
256       /* For DImode on 32-bit, we can use the FPU to perform the store.  */
257       /* Note that while we could perform a cmpxchg8b loop, that turns
258          out to be significantly larger than this plus a barrier.  */
259       emit_insn (gen_atomic_storedi_fpu
260                  (operands[0], operands[1],
261                   assign_386_stack_local (DImode, SLOT_TEMP)));
262     }
263   else
264     {
265       operands[1] = force_reg (<MODE>mode, operands[1]);
267       /* For seq-cst stores, when we lack MFENCE, use XCHG.  */
268       if (is_mm_seq_cst (model) && !(TARGET_64BIT || TARGET_SSE2))
269         {
270           emit_insn (gen_atomic_exchange<mode> (gen_reg_rtx (<MODE>mode),
271                                                 operands[0], operands[1],
272                                                 operands[2]));
273           DONE;
274         }
276       /* Otherwise use a store.  */
277       emit_insn (gen_atomic_store<mode>_1 (operands[0], operands[1],
278                                            operands[2]));
279     }
280   /* ... followed by an MFENCE, if required.  */
281   if (is_mm_seq_cst (model))
282     emit_insn (gen_mem_thread_fence (operands[2]));
283   DONE;
286 (define_insn "atomic_store<mode>_1"
287   [(set (match_operand:SWI 0 "memory_operand" "=m")
288         (unspec:SWI [(match_operand:SWI 1 "<nonmemory_operand>" "<r><i>")
289                      (match_operand:SI 2 "const_int_operand")]
290                     UNSPEC_STA))]
291   ""
292   "%K2mov{<imodesuffix>}\t{%1, %0|%0, %1}")
294 (define_insn_and_split "atomic_storedi_fpu"
295   [(set (match_operand:DI 0 "memory_operand" "=m,m,m")
296         (unspec:DI [(match_operand:DI 1 "nonimmediate_operand" "x,m,?r")]
297                    UNSPEC_STA))
298    (clobber (match_operand:DI 2 "memory_operand" "=X,X,m"))
299    (clobber (match_scratch:DF 3 "=X,xf,xf"))]
300   "!TARGET_64BIT && (TARGET_80387 || TARGET_SSE)"
301   "#"
302   "&& reload_completed"
303   [(const_int 0)]
305   rtx dst = operands[0], src = operands[1];
306   rtx mem = operands[2], tmp = operands[3];
308   if (SSE_REG_P (src))
309     emit_move_insn (dst, src);
310   else
311     {
312       if (REG_P (src))
313         {
314           emit_move_insn (mem, src);
315           src = mem;
316         }
318       if (STACK_REG_P (tmp))
319         {
320           emit_insn (gen_loaddi_via_fpu (tmp, src));
321           emit_insn (gen_storedi_via_fpu (dst, tmp));
322         }
323       else
324         {
325           emit_insn (gen_loaddi_via_sse (tmp, src));
326           emit_insn (gen_storedi_via_sse (dst, tmp));
327         }
328     }
329   DONE;
332 (define_peephole2
333   [(set (match_operand:DF 0 "memory_operand")
334         (match_operand:DF 1 "fp_register_operand"))
335    (set (match_operand:DF 2 "fp_register_operand")
336         (unspec:DF [(match_operand:DI 3 "memory_operand")]
337                    UNSPEC_FILD_ATOMIC))
338    (set (match_operand:DI 4 "memory_operand")
339         (unspec:DI [(match_dup 2)]
340                    UNSPEC_FIST_ATOMIC))]
341   "!TARGET_64BIT
342    && peep2_reg_dead_p (3, operands[2])
343    && rtx_equal_p (operands[0], adjust_address_nv (operands[3], DFmode, 0))"
344   [(set (match_dup 5) (match_dup 1))]
345   "operands[5] = gen_lowpart (DFmode, operands[4]);")
347 (define_peephole2
348   [(set (match_operand:DF 0 "memory_operand")
349         (match_operand:DF 1 "fp_register_operand"))
350    (set (match_operand:DF 2 "sse_reg_operand")
351         (unspec:DF [(match_operand:DI 3 "memory_operand")]
352                    UNSPEC_LDX_ATOMIC))
353    (set (match_operand:DI 4 "memory_operand")
354         (unspec:DI [(match_dup 2)]
355                    UNSPEC_STX_ATOMIC))]
356   "!TARGET_64BIT
357    && peep2_reg_dead_p (3, operands[2])
358    && rtx_equal_p (operands[0], adjust_address_nv (operands[3], DFmode, 0))"
359   [(set (match_dup 5) (match_dup 1))]
360   "operands[5] = gen_lowpart (DFmode, operands[4]);")
362 ;; ??? You'd think that we'd be able to perform this via FLOAT + FIX_TRUNC
363 ;; operations.  But the fix_trunc patterns want way more setup than we want
364 ;; to provide.  Note that the scratch is DFmode instead of XFmode in order
365 ;; to make it easy to allocate a scratch in either SSE or FP_REGs above.
367 (define_insn "loaddi_via_fpu"
368   [(set (match_operand:DF 0 "register_operand" "=f")
369         (unspec:DF [(match_operand:DI 1 "memory_operand" "m")]
370                    UNSPEC_FILD_ATOMIC))]
371   "TARGET_80387"
372   "fild%Z1\t%1"
373   [(set_attr "type" "fmov")
374    (set_attr "mode" "DF")
375    (set_attr "fp_int_src" "true")])
377 (define_insn "storedi_via_fpu"
378   [(set (match_operand:DI 0 "memory_operand" "=m")
379         (unspec:DI [(match_operand:DF 1 "register_operand" "f")]
380                    UNSPEC_FIST_ATOMIC))]
381   "TARGET_80387"
383   gcc_assert (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != NULL_RTX);
385   return "fistp%Z0\t%0";
387   [(set_attr "type" "fmov")
388    (set_attr "mode" "DI")])
390 (define_insn "loaddi_via_sse"
391   [(set (match_operand:DF 0 "register_operand" "=x")
392         (unspec:DF [(match_operand:DI 1 "memory_operand" "m")]
393                    UNSPEC_LDX_ATOMIC))]
394   "TARGET_SSE"
396   if (TARGET_SSE2)
397     return "%vmovq\t{%1, %0|%0, %1}";
398   return "movlps\t{%1, %0|%0, %1}";
400   [(set_attr "type" "ssemov")
401    (set_attr "mode" "DI")])
403 (define_insn "storedi_via_sse"
404   [(set (match_operand:DI 0 "memory_operand" "=m")
405         (unspec:DI [(match_operand:DF 1 "register_operand" "x")]
406                    UNSPEC_STX_ATOMIC))]
407   "TARGET_SSE"
409   if (TARGET_SSE2)
410     return "%vmovq\t{%1, %0|%0, %1}";
411   return "movlps\t{%1, %0|%0, %1}";
413   [(set_attr "type" "ssemov")
414    (set_attr "mode" "DI")])
416 (define_expand "atomic_compare_and_swap<mode>"
417   [(match_operand:QI 0 "register_operand")      ;; bool success output
418    (match_operand:SWI124 1 "register_operand")  ;; oldval output
419    (match_operand:SWI124 2 "memory_operand")    ;; memory
420    (match_operand:SWI124 3 "register_operand")  ;; expected input
421    (match_operand:SWI124 4 "register_operand")  ;; newval input
422    (match_operand:SI 5 "const_int_operand")     ;; is_weak
423    (match_operand:SI 6 "const_int_operand")     ;; success model
424    (match_operand:SI 7 "const_int_operand")]    ;; failure model
425   "TARGET_CMPXCHG"
427   emit_insn
428    (gen_atomic_compare_and_swap<mode>_1
429     (operands[1], operands[2], operands[3], operands[4], operands[6]));
430   ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG),
431                      const0_rtx);
432   DONE;
435 (define_mode_iterator CASMODE
436   [(DI "TARGET_64BIT || TARGET_CMPXCHG8B")
437    (TI "TARGET_64BIT && TARGET_CMPXCHG16B")])
438 (define_mode_attr CASHMODE [(DI "SI") (TI "DI")])
440 (define_expand "atomic_compare_and_swap<mode>"
441   [(match_operand:QI 0 "register_operand")      ;; bool success output
442    (match_operand:CASMODE 1 "register_operand") ;; oldval output
443    (match_operand:CASMODE 2 "memory_operand")   ;; memory
444    (match_operand:CASMODE 3 "register_operand") ;; expected input
445    (match_operand:CASMODE 4 "register_operand") ;; newval input
446    (match_operand:SI 5 "const_int_operand")     ;; is_weak
447    (match_operand:SI 6 "const_int_operand")     ;; success model
448    (match_operand:SI 7 "const_int_operand")]    ;; failure model
449   "TARGET_CMPXCHG"
451   if (<MODE>mode == DImode && TARGET_64BIT)
452     {
453       emit_insn
454        (gen_atomic_compare_and_swapdi_1
455         (operands[1], operands[2], operands[3], operands[4], operands[6]));
456     }
457   else
458     {
459       machine_mode hmode = <CASHMODE>mode;
461       emit_insn
462        (gen_atomic_compare_and_swap<mode>_doubleword
463         (operands[1], operands[2], operands[3],
464          gen_lowpart (hmode, operands[4]), gen_highpart (hmode, operands[4]),
465          operands[6]));
466     }
468   ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG),
469                      const0_rtx);
470   DONE;
473 ;; For double-word compare and swap, we are obliged to play tricks with
474 ;; the input newval (op3:op4) because the Intel register numbering does
475 ;; not match the gcc register numbering, so the pair must be CX:BX.
477 (define_mode_attr doublemodesuffix [(SI "8") (DI "16")])
479 (define_insn "atomic_compare_and_swap<dwi>_doubleword"
480   [(set (match_operand:<DWI> 0 "register_operand" "=A")
481         (unspec_volatile:<DWI>
482           [(match_operand:<DWI> 1 "memory_operand" "+m")
483            (match_operand:<DWI> 2 "register_operand" "0")
484            (match_operand:DWIH 3 "register_operand" "b")
485            (match_operand:DWIH 4 "register_operand" "c")
486            (match_operand:SI 5 "const_int_operand")]
487           UNSPECV_CMPXCHG))
488    (set (match_dup 1)
489         (unspec_volatile:<DWI> [(const_int 0)] UNSPECV_CMPXCHG))
490    (set (reg:CCZ FLAGS_REG)
491         (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))]
492   "TARGET_CMPXCHG<doublemodesuffix>B"
493   "lock{%;} %K5cmpxchg<doublemodesuffix>b\t%1")
495 (define_insn "atomic_compare_and_swap<mode>_1"
496   [(set (match_operand:SWI 0 "register_operand" "=a")
497         (unspec_volatile:SWI
498           [(match_operand:SWI 1 "memory_operand" "+m")
499            (match_operand:SWI 2 "register_operand" "0")
500            (match_operand:SWI 3 "register_operand" "<r>")
501            (match_operand:SI 4 "const_int_operand")]
502           UNSPECV_CMPXCHG))
503    (set (match_dup 1)
504         (unspec_volatile:SWI [(const_int 0)] UNSPECV_CMPXCHG))
505    (set (reg:CCZ FLAGS_REG)
506         (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))]
507   "TARGET_CMPXCHG"
508   "lock{%;} %K4cmpxchg{<imodesuffix>}\t{%3, %1|%1, %3}")
510 ;; For operand 2 nonmemory_operand predicate is used instead of
511 ;; register_operand to allow combiner to better optimize atomic
512 ;; additions of constants.
513 (define_insn "atomic_fetch_add<mode>"
514   [(set (match_operand:SWI 0 "register_operand" "=<r>")
515         (unspec_volatile:SWI
516           [(match_operand:SWI 1 "memory_operand" "+m")
517            (match_operand:SI 3 "const_int_operand")]            ;; model
518           UNSPECV_XCHG))
519    (set (match_dup 1)
520         (plus:SWI (match_dup 1)
521                   (match_operand:SWI 2 "nonmemory_operand" "0")))
522    (clobber (reg:CC FLAGS_REG))]
523   "TARGET_XADD"
524   "lock{%;} %K3xadd{<imodesuffix>}\t{%0, %1|%1, %0}")
526 ;; This peephole2 and following insn optimize
527 ;; __sync_fetch_and_add (x, -N) == N into just lock {add,sub,inc,dec}
528 ;; followed by testing of flags instead of lock xadd and comparisons.
529 (define_peephole2
530   [(set (match_operand:SWI 0 "register_operand")
531         (match_operand:SWI 2 "const_int_operand"))
532    (parallel [(set (match_dup 0)
533                    (unspec_volatile:SWI
534                      [(match_operand:SWI 1 "memory_operand")
535                       (match_operand:SI 4 "const_int_operand")]
536                      UNSPECV_XCHG))
537               (set (match_dup 1)
538                    (plus:SWI (match_dup 1)
539                              (match_dup 0)))
540               (clobber (reg:CC FLAGS_REG))])
541    (set (reg:CCZ FLAGS_REG)
542         (compare:CCZ (match_dup 0)
543                      (match_operand:SWI 3 "const_int_operand")))]
544   "peep2_reg_dead_p (3, operands[0])
545    && (unsigned HOST_WIDE_INT) INTVAL (operands[2])
546       == -(unsigned HOST_WIDE_INT) INTVAL (operands[3])
547    && !reg_overlap_mentioned_p (operands[0], operands[1])"
548   [(parallel [(set (reg:CCZ FLAGS_REG)
549                    (compare:CCZ
550                      (unspec_volatile:SWI [(match_dup 1) (match_dup 4)]
551                                           UNSPECV_XCHG)
552                      (match_dup 3)))
553               (set (match_dup 1)
554                    (plus:SWI (match_dup 1)
555                              (match_dup 2)))])])
557 ;; Likewise, but for the -Os special case of *mov<mode>_or.
558 (define_peephole2
559   [(parallel [(set (match_operand:SWI 0 "register_operand")
560                    (match_operand:SWI 2 "constm1_operand"))
561               (clobber (reg:CC FLAGS_REG))])
562    (parallel [(set (match_dup 0)
563                    (unspec_volatile:SWI
564                      [(match_operand:SWI 1 "memory_operand")
565                       (match_operand:SI 4 "const_int_operand")]
566                      UNSPECV_XCHG))
567               (set (match_dup 1)
568                    (plus:SWI (match_dup 1)
569                              (match_dup 0)))
570               (clobber (reg:CC FLAGS_REG))])
571    (set (reg:CCZ FLAGS_REG)
572         (compare:CCZ (match_dup 0)
573                      (match_operand:SWI 3 "const_int_operand")))]
574   "peep2_reg_dead_p (3, operands[0])
575    && (unsigned HOST_WIDE_INT) INTVAL (operands[2])
576       == -(unsigned HOST_WIDE_INT) INTVAL (operands[3])
577    && !reg_overlap_mentioned_p (operands[0], operands[1])"
578   [(parallel [(set (reg:CCZ FLAGS_REG)
579                    (compare:CCZ
580                      (unspec_volatile:SWI [(match_dup 1) (match_dup 4)]
581                                           UNSPECV_XCHG)
582                      (match_dup 3)))
583               (set (match_dup 1)
584                    (plus:SWI (match_dup 1)
585                              (match_dup 2)))])])
587 (define_insn "*atomic_fetch_add_cmp<mode>"
588   [(set (reg:CCZ FLAGS_REG)
589         (compare:CCZ
590           (unspec_volatile:SWI
591             [(match_operand:SWI 0 "memory_operand" "+m")
592              (match_operand:SI 3 "const_int_operand")]          ;; model
593             UNSPECV_XCHG)
594           (match_operand:SWI 2 "const_int_operand" "i")))
595    (set (match_dup 0)
596         (plus:SWI (match_dup 0)
597                   (match_operand:SWI 1 "const_int_operand" "i")))]
598   "(unsigned HOST_WIDE_INT) INTVAL (operands[1])
599    == -(unsigned HOST_WIDE_INT) INTVAL (operands[2])"
601   if (incdec_operand (operands[1], <MODE>mode))
602     {
603       if (operands[1] == const1_rtx)
604         return "lock{%;} %K3inc{<imodesuffix>}\t%0";
605       else
606         {
607           gcc_assert (operands[1] == constm1_rtx);
608           return "lock{%;} %K3dec{<imodesuffix>}\t%0";
609         }
610     }
612   if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
613     return "lock{%;} %K3sub{<imodesuffix>}\t{%1, %0|%0, %1}";
615   return "lock{%;} %K3add{<imodesuffix>}\t{%1, %0|%0, %1}";
618 ;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
619 ;; In addition, it is always a full barrier, so we can ignore the memory model.
620 (define_insn "atomic_exchange<mode>"
621   [(set (match_operand:SWI 0 "register_operand" "=<r>")         ;; output
622         (unspec_volatile:SWI
623           [(match_operand:SWI 1 "memory_operand" "+m")          ;; memory
624            (match_operand:SI 3 "const_int_operand")]            ;; model
625           UNSPECV_XCHG))
626    (set (match_dup 1)
627         (match_operand:SWI 2 "register_operand" "0"))]          ;; input
628   ""
629   "%K3xchg{<imodesuffix>}\t{%1, %0|%0, %1}")
631 (define_insn "atomic_add<mode>"
632   [(set (match_operand:SWI 0 "memory_operand" "+m")
633         (unspec_volatile:SWI
634           [(plus:SWI (match_dup 0)
635                      (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
636            (match_operand:SI 2 "const_int_operand")]            ;; model
637           UNSPECV_LOCK))
638    (clobber (reg:CC FLAGS_REG))]
639   ""
641   if (incdec_operand (operands[1], <MODE>mode))
642     {
643       if (operands[1] == const1_rtx)
644         return "lock{%;} %K2inc{<imodesuffix>}\t%0";
645       else
646         {
647           gcc_assert (operands[1] == constm1_rtx);
648           return "lock{%;} %K2dec{<imodesuffix>}\t%0";
649         }
650     }
652   if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
653     return "lock{%;} %K2sub{<imodesuffix>}\t{%1, %0|%0, %1}";
655   return "lock{%;} %K2add{<imodesuffix>}\t{%1, %0|%0, %1}";
658 (define_insn "atomic_sub<mode>"
659   [(set (match_operand:SWI 0 "memory_operand" "+m")
660         (unspec_volatile:SWI
661           [(minus:SWI (match_dup 0)
662                       (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
663            (match_operand:SI 2 "const_int_operand")]            ;; model
664           UNSPECV_LOCK))
665    (clobber (reg:CC FLAGS_REG))]
666   ""
668   if (incdec_operand (operands[1], <MODE>mode))
669     {
670       if (operands[1] == const1_rtx)
671         return "lock{%;} %K2dec{<imodesuffix>}\t%0";
672       else
673         {
674           gcc_assert (operands[1] == constm1_rtx);
675           return "lock{%;} %K2inc{<imodesuffix>}\t%0";
676         }
677     }
679   if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
680     return "lock{%;} %K2add{<imodesuffix>}\t{%1, %0|%0, %1}";
682   return "lock{%;} %K2sub{<imodesuffix>}\t{%1, %0|%0, %1}";
685 (define_insn "atomic_<logic><mode>"
686   [(set (match_operand:SWI 0 "memory_operand" "+m")
687         (unspec_volatile:SWI
688           [(any_logic:SWI (match_dup 0)
689                           (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
690            (match_operand:SI 2 "const_int_operand")]            ;; model
691           UNSPECV_LOCK))
692    (clobber (reg:CC FLAGS_REG))]
693   ""
694   "lock{%;} %K2<logic>{<imodesuffix>}\t{%1, %0|%0, %1}")
696 (define_expand "atomic_bit_test_and_set<mode>"
697   [(match_operand:SWI248 0 "register_operand")
698    (match_operand:SWI248 1 "memory_operand")
699    (match_operand:SWI248 2 "nonmemory_operand")
700    (match_operand:SI 3 "const_int_operand") ;; model
701    (match_operand:SI 4 "const_int_operand")]
702   ""
704   emit_insn (gen_atomic_bit_test_and_set<mode>_1 (operands[1], operands[2],
705                                                   operands[3]));
706   rtx tem = gen_reg_rtx (QImode);
707   ix86_expand_setcc (tem, EQ, gen_rtx_REG (CCCmode, FLAGS_REG), const0_rtx);
708   rtx result = convert_modes (<MODE>mode, QImode, tem, 1);
709   if (operands[4] == const0_rtx)
710     result = expand_simple_binop (<MODE>mode, ASHIFT, result,
711                                   operands[2], operands[0], 0, OPTAB_DIRECT);
712   if (result != operands[0])
713     emit_move_insn (operands[0], result);
714   DONE;
717 (define_insn "atomic_bit_test_and_set<mode>_1"
718   [(set (reg:CCC FLAGS_REG)
719         (compare:CCC
720           (unspec_volatile:SWI248
721             [(match_operand:SWI248 0 "memory_operand" "+m")
722              (match_operand:SI 2 "const_int_operand")]          ;; model
723             UNSPECV_XCHG)
724           (const_int 0)))
725    (set (zero_extract:SWI248 (match_dup 0)
726                              (const_int 1)
727                              (match_operand:SWI248 1 "nonmemory_operand" "rN"))
728         (const_int 1))]
729   ""
730   "lock{%;} %K2bts{<imodesuffix>}\t{%1, %0|%0, %1}")
732 (define_expand "atomic_bit_test_and_complement<mode>"
733   [(match_operand:SWI248 0 "register_operand")
734    (match_operand:SWI248 1 "memory_operand")
735    (match_operand:SWI248 2 "nonmemory_operand")
736    (match_operand:SI 3 "const_int_operand") ;; model
737    (match_operand:SI 4 "const_int_operand")]
738   ""
740   emit_insn (gen_atomic_bit_test_and_complement<mode>_1 (operands[1],
741                                                          operands[2],
742                                                          operands[3]));
743   rtx tem = gen_reg_rtx (QImode);
744   ix86_expand_setcc (tem, EQ, gen_rtx_REG (CCCmode, FLAGS_REG), const0_rtx);
745   rtx result = convert_modes (<MODE>mode, QImode, tem, 1);
746   if (operands[4] == const0_rtx)
747     result = expand_simple_binop (<MODE>mode, ASHIFT, result,
748                                   operands[2], operands[0], 0, OPTAB_DIRECT);
749   if (result != operands[0])
750     emit_move_insn (operands[0], result);
751   DONE;
754 (define_insn "atomic_bit_test_and_complement<mode>_1"
755   [(set (reg:CCC FLAGS_REG)
756         (compare:CCC
757           (unspec_volatile:SWI248
758             [(match_operand:SWI248 0 "memory_operand" "+m")
759              (match_operand:SI 2 "const_int_operand")]          ;; model
760             UNSPECV_XCHG)
761           (const_int 0)))
762    (set (zero_extract:SWI248 (match_dup 0)
763                              (const_int 1)
764                              (match_operand:SWI248 1 "nonmemory_operand" "rN"))
765         (not:SWI248 (zero_extract:SWI248 (match_dup 0)
766                                          (const_int 1)
767                                          (match_dup 1))))]
768   ""
769   "lock{%;} %K2btc{<imodesuffix>}\t{%1, %0|%0, %1}")
771 (define_expand "atomic_bit_test_and_reset<mode>"
772   [(match_operand:SWI248 0 "register_operand")
773    (match_operand:SWI248 1 "memory_operand")
774    (match_operand:SWI248 2 "nonmemory_operand")
775    (match_operand:SI 3 "const_int_operand") ;; model
776    (match_operand:SI 4 "const_int_operand")]
777   ""
779   emit_insn (gen_atomic_bit_test_and_reset<mode>_1 (operands[1], operands[2],
780                                                     operands[3]));
781   rtx tem = gen_reg_rtx (QImode);
782   ix86_expand_setcc (tem, EQ, gen_rtx_REG (CCCmode, FLAGS_REG), const0_rtx);
783   rtx result = convert_modes (<MODE>mode, QImode, tem, 1);
784   if (operands[4] == const0_rtx)
785     result = expand_simple_binop (<MODE>mode, ASHIFT, result,
786                                   operands[2], operands[0], 0, OPTAB_DIRECT);
787   if (result != operands[0])
788     emit_move_insn (operands[0], result);
789   DONE;
792 (define_insn "atomic_bit_test_and_reset<mode>_1"
793   [(set (reg:CCC FLAGS_REG)
794         (compare:CCC
795           (unspec_volatile:SWI248
796             [(match_operand:SWI248 0 "memory_operand" "+m")
797              (match_operand:SI 2 "const_int_operand")]          ;; model
798             UNSPECV_XCHG)
799           (const_int 0)))
800    (set (zero_extract:SWI248 (match_dup 0)
801                              (const_int 1)
802                              (match_operand:SWI248 1 "nonmemory_operand" "rN"))
803         (const_int 0))]
804   ""
805   "lock{%;} %K2btr{<imodesuffix>}\t{%1, %0|%0, %1}")