Add assember CFI directives to millicode division and remainder routines.
[official-gcc.git] / gcc / config / arm / sync.md
blob7626bf3c443285dc63b4c4367b11a879a99c93c6
1 ;; Machine description for ARM processor synchronization primitives.
2 ;; Copyright (C) 2010-2023 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     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")])
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")])
117 ;; An LDRD instruction usable by the atomic_loaddi expander on LPAE targets
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")])
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).
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"
140   memmodel model = memmodel_from_int (INTVAL (operands[2]));
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]));
152       DONE;
153     }
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]));
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);
169   DONE;
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>"
183   arm_expand_compare_and_swap (operands);
184   DONE;
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")        ;; bool out
191         (unspec_volatile:CCSI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
192    (set (match_operand:SI 1 "s_register_operand" "=&r,&l,&l*h") ;; val out
193         (zero_extend:SI
194           (match_operand:NARROW 2 "mem_noofs_operand" "+Ua,Ua,Ua")))    ;; memory
195    (set (match_dup 2)
196         (unspec_volatile:NARROW
197           [(match_operand:SI 3 "arm_add_operand" "rIL,lILJ*h,*r")       ;; expected
198            (match_operand:NARROW 4 "s_register_operand" "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"))]
204   "<NARROW: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")])
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")])
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")        ;; bool out
223         (unspec_volatile:CCSI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
224    (set (match_operand:SIDI 1 "s_register_operand" "=&r,&l,&l*h")       ;; val out
225         (match_operand:SIDI 2 "mem_noofs_operand" "+Ua,Ua,Ua")) ;; memory
226    (set (match_dup 2)
227         (unspec_volatile:SIDI
228           [(match_operand:SIDI 3 "<SIDI:cas_cmp_operand>" "<SIDI:cas_cmp_str>,lILJ*h,*r") ;; expect
229            (match_operand:SIDI 4 "s_register_operand" "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"))]
235   "<SIDI: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")])
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")])
266 ;; The following mode and code attribute are defined here because they are
267 ;; specific to atomics and are not needed anywhere else.
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")])
275 (define_mode_attr atomic_op_str
276   [(QI "rn") (HI "rn") (SI "rn") (DI "r")])
278 (define_code_attr thumb1_atomic_op_str
279   [(ior "l,l") (xor "l,l") (and "l,l") (plus "lIJL,r") (minus "lPd,lPd")])
281 (define_code_attr thumb1_atomic_newop_str
282   [(ior "&l,&l") (xor "&l,&l") (and "&l,&l") (plus "&l,&r") (minus "&l,&l")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])
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")])