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