1;; Machine description for PowerPC synchronization instructions. 2;; Copyright (C) 2005-2020 Free Software Foundation, Inc. 3;; Contributed by Geoffrey Keating. 4 5;; This file is part of GCC. 6 7;; GCC is free software; you can redistribute it and/or modify it 8;; under the terms of the GNU General Public License as published 9;; by the Free Software Foundation; either version 3, or (at your 10;; option) any later version. 11 12;; GCC is distributed in the hope that it will be useful, but WITHOUT 13;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15;; License for more details. 16 17;; You should have received a copy of the GNU General Public License 18;; along with GCC; see the file COPYING3. If not see 19;; <http://www.gnu.org/licenses/>. 20 21(define_mode_attr larx [(QI "lbarx") 22 (HI "lharx") 23 (SI "lwarx") 24 (DI "ldarx") 25 (TI "lqarx")]) 26 27(define_mode_attr stcx [(QI "stbcx.") 28 (HI "sthcx.") 29 (SI "stwcx.") 30 (DI "stdcx.") 31 (TI "stqcx.")]) 32 33(define_code_iterator FETCHOP [plus minus ior xor and]) 34(define_code_attr fetchop_name 35 [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")]) 36(define_code_attr fetchop_pred 37 [(plus "add_operand") (minus "int_reg_operand") 38 (ior "logical_operand") (xor "logical_operand") (and "and_operand")]) 39 40(define_expand "mem_thread_fence" 41 [(match_operand:SI 0 "const_int_operand")] ;; model 42 "" 43{ 44 enum memmodel model = memmodel_base (INTVAL (operands[0])); 45 switch (model) 46 { 47 case MEMMODEL_RELAXED: 48 break; 49 case MEMMODEL_CONSUME: 50 case MEMMODEL_ACQUIRE: 51 case MEMMODEL_RELEASE: 52 case MEMMODEL_ACQ_REL: 53 emit_insn (gen_lwsync ()); 54 break; 55 case MEMMODEL_SEQ_CST: 56 emit_insn (gen_hwsync ()); 57 break; 58 default: 59 gcc_unreachable (); 60 } 61 DONE; 62}) 63 64(define_expand "hwsync" 65 [(set (match_dup 0) 66 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))] 67 "" 68{ 69 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); 70 MEM_VOLATILE_P (operands[0]) = 1; 71}) 72 73(define_insn "*hwsync" 74 [(set (match_operand:BLK 0 "" "") 75 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))] 76 "" 77 "sync" 78 [(set_attr "type" "sync")]) 79 80(define_expand "lwsync" 81 [(set (match_dup 0) 82 (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))] 83 "" 84{ 85 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); 86 MEM_VOLATILE_P (operands[0]) = 1; 87}) 88 89(define_insn "*lwsync" 90 [(set (match_operand:BLK 0 "" "") 91 (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))] 92 "" 93{ 94 if (TARGET_NO_LWSYNC) 95 return "sync"; 96 else 97 return "lwsync"; 98} 99 [(set_attr "type" "sync")]) 100 101(define_insn "isync" 102 [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)] 103 "" 104 "isync" 105 [(set_attr "type" "isync")]) 106 107;; Types that we should provide atomic instructions for. 108(define_mode_iterator AINT [QI 109 HI 110 SI 111 (DI "TARGET_POWERPC64") 112 (TI "TARGET_SYNC_TI")]) 113 114;; The control dependency used for load dependency described 115;; in B.2.3 of the Power ISA 2.06B. 116(define_insn "loadsync_<mode>" 117 [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")] 118 UNSPECV_ISYNC) 119 (clobber (match_scratch:CC 1 "=y"))] 120 "" 121 "cmpw %1,%0,%0\;bne- %1,$+4\;isync" 122 [(set_attr "type" "isync") 123 (set_attr "length" "12")]) 124 125;; If TARGET_PREFIXED, always use plq rather than lq. 126(define_insn "load_quadpti" 127 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 128 (unspec:PTI 129 [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))] 130 "TARGET_SYNC_TI 131 && !reg_mentioned_p (operands[0], operands[1])" 132 "lq %0,%1" 133 [(set_attr "type" "load") 134 (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED") 135 (const_string "yes") 136 (const_string "no")))]) 137 138;; Pattern load_quadpti will always use plq for atomic TImode if 139;; TARGET_PREFIXED. It has the correct doubleword ordering on either LE 140;; or BE, so we can just move the result into the output register and 141;; do not need to do the doubleword swap for LE. Also this avoids any 142;; confusion about whether the lq vs plq might be used based on whether 143;; op1 has PC-relative addressing. We could potentially allow BE to 144;; use lq because it doesn't have the doubleword ordering problem. 145(define_expand "atomic_load<mode>" 146 [(set (match_operand:AINT 0 "register_operand") ;; output 147 (match_operand:AINT 1 "memory_operand")) ;; memory 148 (use (match_operand:SI 2 "const_int_operand"))] ;; model 149 "" 150{ 151 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 152 FAIL; 153 154 enum memmodel model = memmodel_base (INTVAL (operands[2])); 155 156 if (is_mm_seq_cst (model)) 157 emit_insn (gen_hwsync ()); 158 159 if (<MODE>mode != TImode) 160 emit_move_insn (operands[0], operands[1]); 161 else 162 { 163 rtx op0 = operands[0]; 164 rtx op1 = operands[1]; 165 rtx pti_reg = gen_reg_rtx (PTImode); 166 167 if (!quad_address_p (XEXP (op1, 0), TImode, false)) 168 { 169 rtx old_addr = XEXP (op1, 0); 170 rtx new_addr = force_reg (Pmode, old_addr); 171 operands[1] = op1 = replace_equiv_address (op1, new_addr); 172 } 173 174 emit_insn (gen_load_quadpti (pti_reg, op1)); 175 176 if (WORDS_BIG_ENDIAN || TARGET_PREFIXED) 177 emit_move_insn (op0, gen_lowpart (TImode, pti_reg)); 178 else 179 { 180 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti_reg)); 181 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti_reg)); 182 } 183 } 184 185 switch (model) 186 { 187 case MEMMODEL_RELAXED: 188 break; 189 case MEMMODEL_CONSUME: 190 case MEMMODEL_ACQUIRE: 191 case MEMMODEL_SEQ_CST: 192 emit_insn (gen_loadsync_<mode> (operands[0])); 193 break; 194 default: 195 gcc_unreachable (); 196 } 197 DONE; 198}) 199 200;; If TARGET_PREFIXED, always use pstq rather than stq. 201(define_insn "store_quadpti" 202 [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ") 203 (unspec:PTI 204 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))] 205 "TARGET_SYNC_TI" 206 "stq %1,%0" 207 [(set_attr "type" "store") 208 (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED") 209 (const_string "yes") 210 (const_string "no")))]) 211 212;; Pattern store_quadpti will always use pstq if TARGET_PREFIXED, 213;; so the doubleword swap is never needed in that case. 214(define_expand "atomic_store<mode>" 215 [(set (match_operand:AINT 0 "memory_operand") ;; memory 216 (match_operand:AINT 1 "register_operand")) ;; input 217 (use (match_operand:SI 2 "const_int_operand"))] ;; model 218 "" 219{ 220 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 221 FAIL; 222 223 enum memmodel model = memmodel_base (INTVAL (operands[2])); 224 switch (model) 225 { 226 case MEMMODEL_RELAXED: 227 break; 228 case MEMMODEL_RELEASE: 229 emit_insn (gen_lwsync ()); 230 break; 231 case MEMMODEL_SEQ_CST: 232 emit_insn (gen_hwsync ()); 233 break; 234 default: 235 gcc_unreachable (); 236 } 237 if (<MODE>mode != TImode) 238 emit_move_insn (operands[0], operands[1]); 239 else 240 { 241 rtx op0 = operands[0]; 242 rtx op1 = operands[1]; 243 rtx pti_reg = gen_reg_rtx (PTImode); 244 245 if (!quad_address_p (XEXP (op0, 0), TImode, false)) 246 { 247 rtx old_addr = XEXP (op0, 0); 248 rtx new_addr = force_reg (Pmode, old_addr); 249 operands[0] = op0 = replace_equiv_address (op0, new_addr); 250 } 251 252 if (WORDS_BIG_ENDIAN || TARGET_PREFIXED) 253 emit_move_insn (pti_reg, gen_lowpart (PTImode, op1)); 254 else 255 { 256 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op1)); 257 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op1)); 258 } 259 260 emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg)); 261 } 262 263 DONE; 264}) 265 266;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons 267;; other than the quad memory operations, which have special restrictions. 268;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased 269;; in and did not show up until power8. TImode atomic lqarx/stqcx. require 270;; special handling due to even/odd register requirements. 271(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI") 272 (HI "TARGET_SYNC_HI_QI") 273 SI 274 (DI "TARGET_POWERPC64")]) 275 276(define_insn "load_locked<mode>" 277 [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r") 278 (unspec_volatile:ATOMIC 279 [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))] 280 "" 281 "<larx> %0,%y1" 282 [(set_attr "type" "load_l")]) 283 284(define_insn "load_locked<QHI:mode>_si" 285 [(set (match_operand:SI 0 "int_reg_operand" "=r") 286 (unspec_volatile:SI 287 [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))] 288 "TARGET_SYNC_HI_QI" 289 "<QHI:larx> %0,%y1" 290 [(set_attr "type" "load_l")]) 291 292;; Use PTImode to get even/odd register pairs. 293;; Use a temporary register to force getting an even register for the 294;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra 295;; copy on big endian systems. 296 297;; On little endian systems where non-atomic quad word load/store instructions 298;; are not used, the address can be register+offset, so make sure the address 299;; is indexed or indirect before register allocation. 300 301(define_expand "load_lockedti" 302 [(use (match_operand:TI 0 "quad_int_reg_operand")) 303 (use (match_operand:TI 1 "memory_operand"))] 304 "TARGET_SYNC_TI" 305{ 306 rtx op0 = operands[0]; 307 rtx op1 = operands[1]; 308 rtx pti = gen_reg_rtx (PTImode); 309 310 if (!indexed_or_indirect_operand (op1, TImode)) 311 { 312 rtx old_addr = XEXP (op1, 0); 313 rtx new_addr = force_reg (Pmode, old_addr); 314 operands[1] = op1 = change_address (op1, TImode, new_addr); 315 } 316 317 emit_insn (gen_load_lockedpti (pti, op1)); 318 if (WORDS_BIG_ENDIAN) 319 emit_move_insn (op0, gen_lowpart (TImode, pti)); 320 else 321 { 322 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti)); 323 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti)); 324 } 325 DONE; 326}) 327 328(define_insn "load_lockedpti" 329 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 330 (unspec_volatile:PTI 331 [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))] 332 "TARGET_SYNC_TI 333 && !reg_mentioned_p (operands[0], operands[1]) 334 && quad_int_reg_operand (operands[0], PTImode)" 335 "lqarx %0,%y1" 336 [(set_attr "type" "load_l")]) 337 338(define_insn "store_conditional<mode>" 339 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 340 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 341 (set (match_operand:ATOMIC 1 "memory_operand" "=Z") 342 (match_operand:ATOMIC 2 "int_reg_operand" "r"))] 343 "" 344 "<stcx> %2,%y1" 345 [(set_attr "type" "store_c")]) 346 347;; Use a temporary register to force getting an even register for the 348;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra 349;; copy on big endian systems. 350 351;; On little endian systems where non-atomic quad word load/store instructions 352;; are not used, the address can be register+offset, so make sure the address 353;; is indexed or indirect before register allocation. 354 355(define_expand "store_conditionalti" 356 [(use (match_operand:CC 0 "cc_reg_operand")) 357 (use (match_operand:TI 1 "memory_operand")) 358 (use (match_operand:TI 2 "quad_int_reg_operand"))] 359 "TARGET_SYNC_TI" 360{ 361 rtx op0 = operands[0]; 362 rtx op1 = operands[1]; 363 rtx op2 = operands[2]; 364 rtx addr = XEXP (op1, 0); 365 rtx pti_mem; 366 rtx pti_reg; 367 368 if (!indexed_or_indirect_operand (op1, TImode)) 369 { 370 rtx new_addr = force_reg (Pmode, addr); 371 operands[1] = op1 = change_address (op1, TImode, new_addr); 372 addr = new_addr; 373 } 374 375 pti_mem = change_address (op1, PTImode, addr); 376 pti_reg = gen_reg_rtx (PTImode); 377 378 if (WORDS_BIG_ENDIAN) 379 emit_move_insn (pti_reg, gen_lowpart (PTImode, op2)); 380 else 381 { 382 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op2)); 383 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op2)); 384 } 385 386 emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg)); 387 DONE; 388}) 389 390(define_insn "store_conditionalpti" 391 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 392 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 393 (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z") 394 (match_operand:PTI 2 "quad_int_reg_operand" "r"))] 395 "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)" 396 "stqcx. %2,%y1" 397 [(set_attr "type" "store_c")]) 398 399(define_expand "atomic_compare_and_swap<mode>" 400 [(match_operand:SI 0 "int_reg_operand") ;; bool out 401 (match_operand:AINT 1 "int_reg_operand") ;; val out 402 (match_operand:AINT 2 "memory_operand") ;; memory 403 (match_operand:AINT 3 "reg_or_short_operand") ;; expected 404 (match_operand:AINT 4 "int_reg_operand") ;; desired 405 (match_operand:SI 5 "const_int_operand") ;; is_weak 406 (match_operand:SI 6 "const_int_operand") ;; model succ 407 (match_operand:SI 7 "const_int_operand")] ;; model fail 408 "" 409{ 410 rs6000_expand_atomic_compare_and_swap (operands); 411 DONE; 412}) 413 414(define_expand "atomic_exchange<mode>" 415 [(match_operand:AINT 0 "int_reg_operand") ;; output 416 (match_operand:AINT 1 "memory_operand") ;; memory 417 (match_operand:AINT 2 "int_reg_operand") ;; input 418 (match_operand:SI 3 "const_int_operand")] ;; model 419 "" 420{ 421 rs6000_expand_atomic_exchange (operands); 422 DONE; 423}) 424 425(define_expand "atomic_<fetchop_name><mode>" 426 [(match_operand:AINT 0 "memory_operand") ;; memory 427 (FETCHOP:AINT (match_dup 0) 428 (match_operand:AINT 1 "<fetchop_pred>")) ;; operand 429 (match_operand:SI 2 "const_int_operand")] ;; model 430 "" 431{ 432 rs6000_expand_atomic_op (<CODE>, operands[0], operands[1], 433 NULL_RTX, NULL_RTX, operands[2]); 434 DONE; 435}) 436 437(define_expand "atomic_nand<mode>" 438 [(match_operand:AINT 0 "memory_operand") ;; memory 439 (match_operand:AINT 1 "int_reg_operand") ;; operand 440 (match_operand:SI 2 "const_int_operand")] ;; model 441 "" 442{ 443 rs6000_expand_atomic_op (NOT, operands[0], operands[1], 444 NULL_RTX, NULL_RTX, operands[2]); 445 DONE; 446}) 447 448(define_expand "atomic_fetch_<fetchop_name><mode>" 449 [(match_operand:AINT 0 "int_reg_operand") ;; output 450 (match_operand:AINT 1 "memory_operand") ;; memory 451 (FETCHOP:AINT (match_dup 1) 452 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand 453 (match_operand:SI 3 "const_int_operand")] ;; model 454 "" 455{ 456 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 457 operands[0], NULL_RTX, operands[3]); 458 DONE; 459}) 460 461(define_expand "atomic_fetch_nand<mode>" 462 [(match_operand:AINT 0 "int_reg_operand") ;; output 463 (match_operand:AINT 1 "memory_operand") ;; memory 464 (match_operand:AINT 2 "int_reg_operand") ;; operand 465 (match_operand:SI 3 "const_int_operand")] ;; model 466 "" 467{ 468 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 469 operands[0], NULL_RTX, operands[3]); 470 DONE; 471}) 472 473(define_expand "atomic_<fetchop_name>_fetch<mode>" 474 [(match_operand:AINT 0 "int_reg_operand") ;; output 475 (match_operand:AINT 1 "memory_operand") ;; memory 476 (FETCHOP:AINT (match_dup 1) 477 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand 478 (match_operand:SI 3 "const_int_operand")] ;; model 479 "" 480{ 481 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 482 NULL_RTX, operands[0], operands[3]); 483 DONE; 484}) 485 486(define_expand "atomic_nand_fetch<mode>" 487 [(match_operand:AINT 0 "int_reg_operand") ;; output 488 (match_operand:AINT 1 "memory_operand") ;; memory 489 (match_operand:AINT 2 "int_reg_operand") ;; operand 490 (match_operand:SI 3 "const_int_operand")] ;; model 491 "" 492{ 493 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 494 NULL_RTX, operands[0], operands[3]); 495 DONE; 496}) 497