1;; Machine description for ARM processor synchronization primitives.
2;; Copyright (C) 2010-2019 Free Software Foundation, Inc.
3;; Written by Marcus Shawcroft (marcus.shawcroft@arm.com)
4;; 64bit Atomics by Dave Gilbert (david.gilbert@linaro.org)
5;;
6;; This file is part of GCC.
7;;
8;; GCC is free software; you can redistribute it and/or modify it
9;; under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 3, or (at your option)
11;; any later version.
12;;
13;; GCC is distributed in the hope that it will be useful, but
14;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16;; General Public License for more details.
17;;
18;; You should have received a copy of the GNU General Public License
19;; along with GCC; see the file COPYING3.  If not see
20;; <http://www.gnu.org/licenses/>.  */
21
22(define_mode_attr sync_predtab
23  [(QI "TARGET_HAVE_LDREXBH && TARGET_HAVE_MEMORY_BARRIER")
24   (HI "TARGET_HAVE_LDREXBH && TARGET_HAVE_MEMORY_BARRIER")
25   (SI "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER")
26   (DI "TARGET_HAVE_LDREXD && ARM_DOUBLEWORD_ALIGN
27	&& TARGET_HAVE_MEMORY_BARRIER")])
28
29(define_code_iterator syncop [plus minus ior xor and])
30
31(define_code_attr sync_optab
32  [(ior "or") (xor "xor") (and "and") (plus "add") (minus "sub")])
33
34(define_mode_attr sync_sfx
35  [(QI "b") (HI "h") (SI "") (DI "d")])
36
37(define_expand "memory_barrier"
38  [(set (match_dup 0)
39	(unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
40  "TARGET_HAVE_MEMORY_BARRIER"
41{
42  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
43  MEM_VOLATILE_P (operands[0]) = 1;
44})
45
46(define_insn "*memory_barrier"
47  [(set (match_operand:BLK 0 "" "")
48	(unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
49  "TARGET_HAVE_MEMORY_BARRIER"
50  {
51    if (TARGET_HAVE_DMB)
52      {
53	return "dmb\\tish";
54      }
55
56    if (TARGET_HAVE_DMB_MCR)
57      return "mcr\\tp15, 0, r0, c7, c10, 5";
58
59    gcc_unreachable ();
60  }
61  [(set_attr "length" "4")
62   (set_attr "conds" "unconditional")
63   (set_attr "predicable" "no")])
64
65(define_insn "atomic_load<mode>"
66  [(set (match_operand:QHSI 0 "register_operand" "=r,r,l")
67    (unspec_volatile:QHSI
68      [(match_operand:QHSI 1 "arm_sync_memory_operand" "Q,Q,Q")
69       (match_operand:SI 2 "const_int_operand" "n,Pf,n")]	;; model
70      VUNSPEC_LDA))]
71  "TARGET_HAVE_LDACQ"
72  {
73    if (aarch_mm_needs_acquire (operands[2]))
74      {
75	if (TARGET_THUMB1)
76	  return "lda<sync_sfx>\t%0, %1";
77	else
78	  return "lda<sync_sfx>%?\t%0, %1";
79      }
80    else
81      {
82	if (TARGET_THUMB1)
83	  return "ldr<sync_sfx>\t%0, %1";
84	else
85	  return "ldr<sync_sfx>%?\t%0, %1";
86      }
87  }
88  [(set_attr "arch" "32,v8mb,any")
89   (set_attr "predicable" "yes")])
90
91(define_insn "atomic_store<mode>"
92  [(set (match_operand:QHSI 0 "memory_operand" "=Q,Q,Q")
93    (unspec_volatile:QHSI
94      [(match_operand:QHSI 1 "general_operand" "r,r,l")
95       (match_operand:SI 2 "const_int_operand" "n,Pf,n")]	;; model
96      VUNSPEC_STL))]
97  "TARGET_HAVE_LDACQ"
98  {
99    if (aarch_mm_needs_release (operands[2]))
100      {
101	if (TARGET_THUMB1)
102	  return "stl<sync_sfx>\t%1, %0";
103	else
104	  return "stl<sync_sfx>%?\t%1, %0";
105      }
106    else
107      {
108	if (TARGET_THUMB1)
109	  return "str<sync_sfx>\t%1, %0";
110	else
111	  return "str<sync_sfx>%?\t%1, %0";
112      }
113  }
114  [(set_attr "arch" "32,v8mb,any")
115   (set_attr "predicable" "yes")])
116
117;; An LDRD instruction usable by the atomic_loaddi expander on LPAE targets
118
119(define_insn "arm_atomic_loaddi2_ldrd"
120  [(set (match_operand:DI 0 "register_operand" "=r")
121	(unspec_volatile:DI
122	  [(match_operand:DI 1 "arm_sync_memory_operand" "Q")]
123	    VUNSPEC_LDRD_ATOMIC))]
124  "ARM_DOUBLEWORD_ALIGN && TARGET_HAVE_LPAE"
125  "ldrd%?\t%0, %H0, %C1"
126  [(set_attr "predicable" "yes")])
127
128;; There are three ways to expand this depending on the architecture
129;; features available.  As for the barriers, a load needs a barrier
130;; after it on all non-relaxed memory models except when the load
131;; has acquire semantics (for ARMv8-A).
132
133(define_expand "atomic_loaddi"
134  [(match_operand:DI 0 "s_register_operand")		;; val out
135   (match_operand:DI 1 "mem_noofs_operand")		;; memory
136   (match_operand:SI 2 "const_int_operand")]		;; model
137  "(TARGET_HAVE_LDREXD || TARGET_HAVE_LPAE || TARGET_HAVE_LDACQEXD)
138   && ARM_DOUBLEWORD_ALIGN"
139{
140  memmodel model = memmodel_from_int (INTVAL (operands[2]));
141
142  /* For ARMv8-A we can use an LDAEXD to atomically load two 32-bit registers
143     when acquire or stronger semantics are needed.  When the relaxed model is
144     used this can be relaxed to a normal LDRD.  */
145  if (TARGET_HAVE_LDACQEXD)
146    {
147      if (is_mm_relaxed (model))
148	emit_insn (gen_arm_atomic_loaddi2_ldrd (operands[0], operands[1]));
149      else
150	emit_insn (gen_arm_load_acquire_exclusivedi (operands[0], operands[1]));
151
152      DONE;
153    }
154
155  /* On LPAE targets LDRD and STRD accesses to 64-bit aligned
156     locations are 64-bit single-copy atomic.  We still need barriers in the
157     appropriate places to implement the ordering constraints.  */
158  if (TARGET_HAVE_LPAE)
159    emit_insn (gen_arm_atomic_loaddi2_ldrd (operands[0], operands[1]));
160  else
161    emit_insn (gen_arm_load_exclusivedi (operands[0], operands[1]));
162
163
164  /* All non-relaxed models need a barrier after the load when load-acquire
165     instructions are not available.  */
166  if (!is_mm_relaxed (model))
167    expand_mem_thread_fence (model);
168
169  DONE;
170})
171
172(define_expand "atomic_compare_and_swap<mode>"
173  [(match_operand:SI 0 "s_register_operand" "")		;; bool out
174   (match_operand:QHSD 1 "s_register_operand" "")	;; val out
175   (match_operand:QHSD 2 "mem_noofs_operand" "")	;; memory
176   (match_operand:QHSD 3 "general_operand" "")		;; expected
177   (match_operand:QHSD 4 "s_register_operand" "")	;; desired
178   (match_operand:SI 5 "const_int_operand")		;; is_weak
179   (match_operand:SI 6 "const_int_operand")		;; mod_s
180   (match_operand:SI 7 "const_int_operand")]		;; mod_f
181  "<sync_predtab>"
182{
183  arm_expand_compare_and_swap (operands);
184  DONE;
185})
186
187;; Constraints of this pattern must be at least as strict as those of the
188;; cbranchsi operations in thumb1.md and aim to be as permissive.
189(define_insn_and_split "@atomic_compare_and_swap<CCSI:arch><NARROW:mode>_1"
190  [(set (match_operand:CCSI 0 "cc_register_operand" "=&c,&l,&l,&l")	;; bool out
191	(unspec_volatile:CCSI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
192   (set (match_operand:SI 1 "s_register_operand" "=&r,&l,&0,&l*h")	;; val out
193	(zero_extend:SI
194	  (match_operand:NARROW 2 "mem_noofs_operand" "+Ua,Ua,Ua,Ua")))	;; memory
195   (set (match_dup 2)
196	(unspec_volatile:NARROW
197	  [(match_operand:SI 3 "arm_add_operand" "rIL,lIL*h,J,*r")	;; expected
198	   (match_operand:NARROW 4 "s_register_operand" "r,r,r,r")	;; desired
199	   (match_operand:SI 5 "const_int_operand")		;; is_weak
200	   (match_operand:SI 6 "const_int_operand")		;; mod_s
201	   (match_operand:SI 7 "const_int_operand")]		;; mod_f
202	  VUNSPEC_ATOMIC_CAS))
203   (clobber (match_scratch:SI 8 "=&r,X,X,X"))]
204  "<sync_predtab>"
205  "#"
206  "&& reload_completed"
207  [(const_int 0)]
208  {
209    arm_split_compare_and_swap (operands);
210    DONE;
211  }
212  [(set_attr "arch" "32,v8mb,v8mb,v8mb")])
213
214(define_mode_attr cas_cmp_operand
215  [(SI "arm_add_operand") (DI "cmpdi_operand")])
216(define_mode_attr cas_cmp_str
217  [(SI "rIL") (DI "rDi")])
218
219;; Constraints of this pattern must be at least as strict as those of the
220;; cbranchsi operations in thumb1.md and aim to be as permissive.
221(define_insn_and_split "@atomic_compare_and_swap<CCSI:arch><SIDI:mode>_1"
222  [(set (match_operand:CCSI 0 "cc_register_operand" "=&c,&l,&l,&l")	;; bool out
223	(unspec_volatile:CCSI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
224   (set (match_operand:SIDI 1 "s_register_operand" "=&r,&l,&0,&l*h")	;; val out
225	(match_operand:SIDI 2 "mem_noofs_operand" "+Ua,Ua,Ua,Ua"))	;; memory
226   (set (match_dup 2)
227	(unspec_volatile:SIDI
228	  [(match_operand:SIDI 3 "<cas_cmp_operand>" "<cas_cmp_str>,lIL*h,J,*r") ;; expect
229	   (match_operand:SIDI 4 "s_register_operand" "r,r,r,r")	;; desired
230	   (match_operand:SI 5 "const_int_operand")		;; is_weak
231	   (match_operand:SI 6 "const_int_operand")		;; mod_s
232	   (match_operand:SI 7 "const_int_operand")]		;; mod_f
233	  VUNSPEC_ATOMIC_CAS))
234   (clobber (match_scratch:SI 8 "=&r,X,X,X"))]
235  "<sync_predtab>"
236  "#"
237  "&& reload_completed"
238  [(const_int 0)]
239  {
240    arm_split_compare_and_swap (operands);
241    DONE;
242  }
243  [(set_attr "arch" "32,v8mb,v8mb,v8mb")])
244
245(define_insn_and_split "atomic_exchange<mode>"
246  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&r")	;; output
247	(match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua"))	;; memory
248   (set (match_dup 1)
249	(unspec_volatile:QHSD
250	  [(match_operand:QHSD 2 "s_register_operand" "r,r")	;; input
251	   (match_operand:SI 3 "const_int_operand" "")]		;; model
252	  VUNSPEC_ATOMIC_XCHG))
253   (clobber (reg:CC CC_REGNUM))
254   (clobber (match_scratch:SI 4 "=&r,&l"))]
255  "<sync_predtab>"
256  "#"
257  "&& reload_completed"
258  [(const_int 0)]
259  {
260    arm_split_atomic_op (SET, operands[0], NULL, operands[1],
261			 operands[2], operands[3], operands[4]);
262    DONE;
263  }
264  [(set_attr "arch" "32,v8mb")])
265
266;; The following mode and code attribute are defined here because they are
267;; specific to atomics and are not needed anywhere else.
268
269(define_mode_attr atomic_op_operand
270  [(QI "reg_or_int_operand")
271   (HI "reg_or_int_operand")
272   (SI "reg_or_int_operand")
273   (DI "s_register_operand")])
274
275(define_mode_attr atomic_op_str
276  [(QI "rn") (HI "rn") (SI "rn") (DI "r")])
277
278(define_code_attr thumb1_atomic_op_str
279  [(ior "l,l") (xor "l,l") (and "l,l") (plus "lIJL,r") (minus "lPd,lPd")])
280
281(define_code_attr thumb1_atomic_newop_str
282  [(ior "&l,&l") (xor "&l,&l") (and "&l,&l") (plus "&l,&r") (minus "&l,&l")])
283
284;; Constraints of this pattern must be at least as strict as those of the non
285;; atomic operations in thumb1.md and aim to be as permissive.
286(define_insn_and_split "atomic_<sync_optab><mode>"
287  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua,Ua,Ua")
288	(unspec_volatile:QHSD
289	  [(syncop:QHSD (match_dup 0)
290	     (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_op_str>"))
291	   (match_operand:SI 2 "const_int_operand")]		;; model
292	  VUNSPEC_ATOMIC_OP))
293   (clobber (reg:CC CC_REGNUM))
294   (clobber (match_scratch:QHSD 3 "=&r,<thumb1_atomic_newop_str>"))
295   (clobber (match_scratch:SI 4 "=&r,&l,&l"))]
296  "<sync_predtab>"
297  "#"
298  "&& reload_completed"
299  [(const_int 0)]
300  {
301    arm_split_atomic_op (<CODE>, NULL, operands[3], operands[0],
302			 operands[1], operands[2], operands[4]);
303    DONE;
304  }
305  [(set_attr "arch" "32,v8mb,v8mb")])
306
307;; Constraints of this pattern must be at least as strict as those of the non
308;; atomic NANDs in thumb1.md and aim to be as permissive.
309(define_insn_and_split "atomic_nand<mode>"
310  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua,Ua")
311	(unspec_volatile:QHSD
312	  [(not:QHSD
313	     (and:QHSD (match_dup 0)
314	       (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>,l")))
315	   (match_operand:SI 2 "const_int_operand")]		;; model
316	  VUNSPEC_ATOMIC_OP))
317   (clobber (reg:CC CC_REGNUM))
318   (clobber (match_scratch:QHSD 3 "=&r,&l"))
319   (clobber (match_scratch:SI 4 "=&r,&l"))]
320  "<sync_predtab>"
321  "#"
322  "&& reload_completed"
323  [(const_int 0)]
324  {
325    arm_split_atomic_op (NOT, NULL, operands[3], operands[0],
326			 operands[1], operands[2], operands[4]);
327    DONE;
328  }
329  [(set_attr "arch" "32,v8mb")])
330
331;; 3 alternatives are needed to represent constraints after split from
332;; thumb1_addsi3: (i) case where operand1 and destination can be in different
333;; registers, (ii) case where they are in the same low register and (iii) case
334;; when they are in the same register without restriction on the register.  We
335;; disparage slightly alternatives that require copying the old value into the
336;; register for the new value (see bind_old_new in arm_split_atomic_op).
337(define_code_attr thumb1_atomic_fetch_op_str
338  [(ior "l,l,l") (xor "l,l,l") (and "l,l,l") (plus "lL,?IJ,?r") (minus "lPd,lPd,lPd")])
339
340(define_code_attr thumb1_atomic_fetch_newop_str
341  [(ior "&l,&l,&l") (xor "&l,&l,&l") (and "&l,&l,&l") (plus "&l,&l,&r") (minus "&l,&l,&l")])
342
343(define_code_attr thumb1_atomic_fetch_oldop_str
344  [(ior "&r,&r,&r") (xor "&r,&r,&r") (and "&r,&r,&r") (plus "&l,&r,&r") (minus "&l,&l,&l")])
345
346;; Constraints of this pattern must be at least as strict as those of the non
347;; atomic operations in thumb1.md and aim to be as permissive.
348(define_insn_and_split "atomic_fetch_<sync_optab><mode>"
349  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,<thumb1_atomic_fetch_oldop_str>")
350	(match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua,Ua,Ua"))
351   (set (match_dup 1)
352	(unspec_volatile:QHSD
353	  [(syncop:QHSD (match_dup 1)
354	     (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_fetch_op_str>"))
355	   (match_operand:SI 3 "const_int_operand")]		;; model
356	  VUNSPEC_ATOMIC_OP))
357   (clobber (reg:CC CC_REGNUM))
358   (clobber (match_scratch:QHSD 4 "=&r,<thumb1_atomic_fetch_newop_str>"))
359   (clobber (match_scratch:SI 5 "=&r,&l,&l,&l"))]
360  "<sync_predtab>"
361  "#"
362  "&& reload_completed"
363  [(const_int 0)]
364  {
365    arm_split_atomic_op (<CODE>, operands[0], operands[4], operands[1],
366			 operands[2], operands[3], operands[5]);
367    DONE;
368  }
369  [(set_attr "arch" "32,v8mb,v8mb,v8mb")])
370
371;; Constraints of this pattern must be at least as strict as those of the non
372;; atomic NANDs in thumb1.md and aim to be as permissive.
373(define_insn_and_split "atomic_fetch_nand<mode>"
374  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&r")
375	(match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua"))
376   (set (match_dup 1)
377	(unspec_volatile:QHSD
378	  [(not:QHSD
379	     (and:QHSD (match_dup 1)
380	       (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,l")))
381	   (match_operand:SI 3 "const_int_operand")]		;; model
382	  VUNSPEC_ATOMIC_OP))
383   (clobber (reg:CC CC_REGNUM))
384   (clobber (match_scratch:QHSD 4 "=&r,&l"))
385   (clobber (match_scratch:SI 5 "=&r,&l"))]
386  "<sync_predtab>"
387  "#"
388  "&& reload_completed"
389  [(const_int 0)]
390  {
391    arm_split_atomic_op (NOT, operands[0], operands[4], operands[1],
392			 operands[2], operands[3], operands[5]);
393    DONE;
394  }
395  [(set_attr "arch" "32,v8mb")])
396
397;; Constraints of this pattern must be at least as strict as those of the non
398;; atomic operations in thumb1.md and aim to be as permissive.
399(define_insn_and_split "atomic_<sync_optab>_fetch<mode>"
400  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,<thumb1_atomic_newop_str>")
401	(syncop:QHSD
402	  (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua,Ua")
403	  (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_op_str>")))
404   (set (match_dup 1)
405	(unspec_volatile:QHSD
406	  [(match_dup 1) (match_dup 2)
407	   (match_operand:SI 3 "const_int_operand")]		;; model
408	  VUNSPEC_ATOMIC_OP))
409   (clobber (reg:CC CC_REGNUM))
410   (clobber (match_scratch:SI 4 "=&r,&l,&l"))]
411  "<sync_predtab>"
412  "#"
413  "&& reload_completed"
414  [(const_int 0)]
415  {
416    arm_split_atomic_op (<CODE>, NULL, operands[0], operands[1],
417			 operands[2], operands[3], operands[4]);
418    DONE;
419  }
420  [(set_attr "arch" "32,v8mb,v8mb")])
421
422;; Constraints of this pattern must be at least as strict as those of the non
423;; atomic NANDs in thumb1.md and aim to be as permissive.
424(define_insn_and_split "atomic_nand_fetch<mode>"
425  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&l")
426	(not:QHSD
427	  (and:QHSD
428	    (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua")
429	    (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,l"))))
430   (set (match_dup 1)
431	(unspec_volatile:QHSD
432	  [(match_dup 1) (match_dup 2)
433	   (match_operand:SI 3 "const_int_operand")]		;; model
434	  VUNSPEC_ATOMIC_OP))
435   (clobber (reg:CC CC_REGNUM))
436   (clobber (match_scratch:SI 4 "=&r,&l"))]
437  "<sync_predtab>"
438  "#"
439  "&& reload_completed"
440  [(const_int 0)]
441  {
442    arm_split_atomic_op (NOT, NULL, operands[0], operands[1],
443			 operands[2], operands[3], operands[4]);
444    DONE;
445  }
446  [(set_attr "arch" "32,v8mb")])
447
448(define_insn "arm_load_exclusive<mode>"
449  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
450        (zero_extend:SI
451	  (unspec_volatile:NARROW
452	    [(match_operand:NARROW 1 "mem_noofs_operand" "Ua,Ua")]
453	    VUNSPEC_LL)))]
454  "TARGET_HAVE_LDREXBH"
455  "@
456   ldrex<sync_sfx>%?\t%0, %C1
457   ldrex<sync_sfx>\t%0, %C1"
458  [(set_attr "arch" "32,v8mb")
459   (set_attr "predicable" "yes")])
460
461(define_insn "arm_load_acquire_exclusive<mode>"
462  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
463        (zero_extend:SI
464	  (unspec_volatile:NARROW
465	    [(match_operand:NARROW 1 "mem_noofs_operand" "Ua,Ua")]
466	    VUNSPEC_LAX)))]
467  "TARGET_HAVE_LDACQ"
468  "@
469   ldaex<sync_sfx>%?\\t%0, %C1
470   ldaex<sync_sfx>\\t%0, %C1"
471  [(set_attr "arch" "32,v8mb")
472   (set_attr "predicable" "yes")])
473
474(define_insn "arm_load_exclusivesi"
475  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
476	(unspec_volatile:SI
477	  [(match_operand:SI 1 "mem_noofs_operand" "Ua,Ua")]
478	  VUNSPEC_LL))]
479  "TARGET_HAVE_LDREX"
480  "@
481   ldrex%?\t%0, %C1
482   ldrex\t%0, %C1"
483  [(set_attr "arch" "32,v8mb")
484   (set_attr "predicable" "yes")])
485
486(define_insn "arm_load_acquire_exclusivesi"
487  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
488	(unspec_volatile:SI
489	  [(match_operand:SI 1 "mem_noofs_operand" "Ua,Ua")]
490	  VUNSPEC_LAX))]
491  "TARGET_HAVE_LDACQ"
492  "@
493   ldaex%?\t%0, %C1
494   ldaex\t%0, %C1"
495  [(set_attr "arch" "32,v8mb")
496   (set_attr "predicable" "yes")])
497
498(define_insn "arm_load_exclusivedi"
499  [(set (match_operand:DI 0 "s_register_operand" "=r")
500	(unspec_volatile:DI
501	  [(match_operand:DI 1 "mem_noofs_operand" "Ua")]
502	  VUNSPEC_LL))]
503  "TARGET_HAVE_LDREXD"
504  "ldrexd%?\t%0, %H0, %C1"
505  [(set_attr "predicable" "yes")])
506
507(define_insn "arm_load_acquire_exclusivedi"
508  [(set (match_operand:DI 0 "s_register_operand" "=r")
509	(unspec_volatile:DI
510	  [(match_operand:DI 1 "mem_noofs_operand" "Ua")]
511	  VUNSPEC_LAX))]
512  "TARGET_HAVE_LDACQEXD && ARM_DOUBLEWORD_ALIGN"
513  "ldaexd%?\t%0, %H0, %C1"
514  [(set_attr "predicable" "yes")])
515
516(define_insn "arm_store_exclusive<mode>"
517  [(set (match_operand:SI 0 "s_register_operand" "=&r")
518	(unspec_volatile:SI [(const_int 0)] VUNSPEC_SC))
519   (set (match_operand:QHSD 1 "mem_noofs_operand" "=Ua")
520	(unspec_volatile:QHSD
521	  [(match_operand:QHSD 2 "s_register_operand" "r")]
522	  VUNSPEC_SC))]
523  "<sync_predtab>"
524  {
525    if (<MODE>mode == DImode)
526      {
527	/* The restrictions on target registers in ARM mode are that the two
528	   registers are consecutive and the first one is even; Thumb is
529	   actually more flexible, but DI should give us this anyway.
530	   Note that the 1st register always gets the
531	   lowest word in memory.  */
532	gcc_assert ((REGNO (operands[2]) & 1) == 0 || TARGET_THUMB2);
533	return "strexd%?\t%0, %2, %H2, %C1";
534      }
535    if (TARGET_THUMB1)
536      return "strex<sync_sfx>\t%0, %2, %C1";
537    else
538      return "strex<sync_sfx>%?\t%0, %2, %C1";
539  }
540  [(set_attr "predicable" "yes")])
541
542(define_insn "arm_store_release_exclusivedi"
543  [(set (match_operand:SI 0 "s_register_operand" "=&r")
544	(unspec_volatile:SI [(const_int 0)] VUNSPEC_SLX))
545   (set (match_operand:DI 1 "mem_noofs_operand" "=Ua")
546	(unspec_volatile:DI
547	  [(match_operand:DI 2 "s_register_operand" "r")]
548	  VUNSPEC_SLX))]
549  "TARGET_HAVE_LDACQEXD && ARM_DOUBLEWORD_ALIGN"
550  {
551    /* See comment in arm_store_exclusive<mode> above.  */
552    gcc_assert ((REGNO (operands[2]) & 1) == 0 || TARGET_THUMB2);
553    return "stlexd%?\t%0, %2, %H2, %C1";
554  }
555  [(set_attr "predicable" "yes")])
556
557(define_insn "arm_store_release_exclusive<mode>"
558  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
559	(unspec_volatile:SI [(const_int 0)] VUNSPEC_SLX))
560   (set (match_operand:QHSI 1 "mem_noofs_operand" "=Ua,Ua")
561	(unspec_volatile:QHSI
562	  [(match_operand:QHSI 2 "s_register_operand" "r,r")]
563	  VUNSPEC_SLX))]
564  "TARGET_HAVE_LDACQ"
565  "@
566   stlex<sync_sfx>%?\t%0, %2, %C1
567   stlex<sync_sfx>\t%0, %2, %C1"
568  [(set_attr "arch" "32,v8mb")
569   (set_attr "predicable" "yes")])
570