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