1;; Machine description for PowerPC synchronization instructions. 2;; Copyright (C) 2005-2019 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(define_insn "load_quadpti" 126 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 127 (unspec:PTI 128 [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))] 129 "TARGET_SYNC_TI 130 && !reg_mentioned_p (operands[0], operands[1])" 131 "lq %0,%1" 132 [(set_attr "type" "load")]) 133 134(define_expand "atomic_load<mode>" 135 [(set (match_operand:AINT 0 "register_operand") ;; output 136 (match_operand:AINT 1 "memory_operand")) ;; memory 137 (use (match_operand:SI 2 "const_int_operand"))] ;; model 138 "" 139{ 140 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 141 FAIL; 142 143 enum memmodel model = memmodel_base (INTVAL (operands[2])); 144 145 if (is_mm_seq_cst (model)) 146 emit_insn (gen_hwsync ()); 147 148 if (<MODE>mode != TImode) 149 emit_move_insn (operands[0], operands[1]); 150 else 151 { 152 rtx op0 = operands[0]; 153 rtx op1 = operands[1]; 154 rtx pti_reg = gen_reg_rtx (PTImode); 155 156 if (!quad_address_p (XEXP (op1, 0), TImode, false)) 157 { 158 rtx old_addr = XEXP (op1, 0); 159 rtx new_addr = force_reg (Pmode, old_addr); 160 operands[1] = op1 = replace_equiv_address (op1, new_addr); 161 } 162 163 emit_insn (gen_load_quadpti (pti_reg, op1)); 164 165 if (WORDS_BIG_ENDIAN) 166 emit_move_insn (op0, gen_lowpart (TImode, pti_reg)); 167 else 168 { 169 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti_reg)); 170 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti_reg)); 171 } 172 } 173 174 switch (model) 175 { 176 case MEMMODEL_RELAXED: 177 break; 178 case MEMMODEL_CONSUME: 179 case MEMMODEL_ACQUIRE: 180 case MEMMODEL_SEQ_CST: 181 emit_insn (gen_loadsync_<mode> (operands[0])); 182 break; 183 default: 184 gcc_unreachable (); 185 } 186 DONE; 187}) 188 189(define_insn "store_quadpti" 190 [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ") 191 (unspec:PTI 192 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))] 193 "TARGET_SYNC_TI" 194 "stq %1,%0" 195 [(set_attr "type" "store")]) 196 197(define_expand "atomic_store<mode>" 198 [(set (match_operand:AINT 0 "memory_operand") ;; memory 199 (match_operand:AINT 1 "register_operand")) ;; input 200 (use (match_operand:SI 2 "const_int_operand"))] ;; model 201 "" 202{ 203 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 204 FAIL; 205 206 enum memmodel model = memmodel_base (INTVAL (operands[2])); 207 switch (model) 208 { 209 case MEMMODEL_RELAXED: 210 break; 211 case MEMMODEL_RELEASE: 212 emit_insn (gen_lwsync ()); 213 break; 214 case MEMMODEL_SEQ_CST: 215 emit_insn (gen_hwsync ()); 216 break; 217 default: 218 gcc_unreachable (); 219 } 220 if (<MODE>mode != TImode) 221 emit_move_insn (operands[0], operands[1]); 222 else 223 { 224 rtx op0 = operands[0]; 225 rtx op1 = operands[1]; 226 rtx pti_reg = gen_reg_rtx (PTImode); 227 228 if (!quad_address_p (XEXP (op0, 0), TImode, false)) 229 { 230 rtx old_addr = XEXP (op0, 0); 231 rtx new_addr = force_reg (Pmode, old_addr); 232 operands[0] = op0 = replace_equiv_address (op0, new_addr); 233 } 234 235 if (WORDS_BIG_ENDIAN) 236 emit_move_insn (pti_reg, gen_lowpart (PTImode, op1)); 237 else 238 { 239 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op1)); 240 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op1)); 241 } 242 243 emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg)); 244 } 245 246 DONE; 247}) 248 249;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons 250;; other than the quad memory operations, which have special restrictions. 251;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased 252;; in and did not show up until power8. TImode atomic lqarx/stqcx. require 253;; special handling due to even/odd register requirements. 254(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI") 255 (HI "TARGET_SYNC_HI_QI") 256 SI 257 (DI "TARGET_POWERPC64")]) 258 259(define_insn "load_locked<mode>" 260 [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r") 261 (unspec_volatile:ATOMIC 262 [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))] 263 "" 264 "<larx> %0,%y1" 265 [(set_attr "type" "load_l")]) 266 267(define_insn "load_locked<QHI:mode>_si" 268 [(set (match_operand:SI 0 "int_reg_operand" "=r") 269 (unspec_volatile:SI 270 [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))] 271 "TARGET_SYNC_HI_QI" 272 "<QHI:larx> %0,%y1" 273 [(set_attr "type" "load_l")]) 274 275;; Use PTImode to get even/odd register pairs. 276;; Use a temporary register to force getting an even register for the 277;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra 278;; copy on big endian systems. 279 280;; On little endian systems where non-atomic quad word load/store instructions 281;; are not used, the address can be register+offset, so make sure the address 282;; is indexed or indirect before register allocation. 283 284(define_expand "load_lockedti" 285 [(use (match_operand:TI 0 "quad_int_reg_operand")) 286 (use (match_operand:TI 1 "memory_operand"))] 287 "TARGET_SYNC_TI" 288{ 289 rtx op0 = operands[0]; 290 rtx op1 = operands[1]; 291 rtx pti = gen_reg_rtx (PTImode); 292 293 if (!indexed_or_indirect_operand (op1, TImode)) 294 { 295 rtx old_addr = XEXP (op1, 0); 296 rtx new_addr = force_reg (Pmode, old_addr); 297 operands[1] = op1 = change_address (op1, TImode, new_addr); 298 } 299 300 emit_insn (gen_load_lockedpti (pti, op1)); 301 if (WORDS_BIG_ENDIAN) 302 emit_move_insn (op0, gen_lowpart (TImode, pti)); 303 else 304 { 305 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti)); 306 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti)); 307 } 308 DONE; 309}) 310 311(define_insn "load_lockedpti" 312 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 313 (unspec_volatile:PTI 314 [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))] 315 "TARGET_SYNC_TI 316 && !reg_mentioned_p (operands[0], operands[1]) 317 && quad_int_reg_operand (operands[0], PTImode)" 318 "lqarx %0,%y1" 319 [(set_attr "type" "load_l")]) 320 321(define_insn "store_conditional<mode>" 322 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 323 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 324 (set (match_operand:ATOMIC 1 "memory_operand" "=Z") 325 (match_operand:ATOMIC 2 "int_reg_operand" "r"))] 326 "" 327 "<stcx> %2,%y1" 328 [(set_attr "type" "store_c")]) 329 330;; Use a temporary register to force getting an even register for the 331;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra 332;; copy on big endian systems. 333 334;; On little endian systems where non-atomic quad word load/store instructions 335;; are not used, the address can be register+offset, so make sure the address 336;; is indexed or indirect before register allocation. 337 338(define_expand "store_conditionalti" 339 [(use (match_operand:CC 0 "cc_reg_operand")) 340 (use (match_operand:TI 1 "memory_operand")) 341 (use (match_operand:TI 2 "quad_int_reg_operand"))] 342 "TARGET_SYNC_TI" 343{ 344 rtx op0 = operands[0]; 345 rtx op1 = operands[1]; 346 rtx op2 = operands[2]; 347 rtx addr = XEXP (op1, 0); 348 rtx pti_mem; 349 rtx pti_reg; 350 351 if (!indexed_or_indirect_operand (op1, TImode)) 352 { 353 rtx new_addr = force_reg (Pmode, addr); 354 operands[1] = op1 = change_address (op1, TImode, new_addr); 355 addr = new_addr; 356 } 357 358 pti_mem = change_address (op1, PTImode, addr); 359 pti_reg = gen_reg_rtx (PTImode); 360 361 if (WORDS_BIG_ENDIAN) 362 emit_move_insn (pti_reg, gen_lowpart (PTImode, op2)); 363 else 364 { 365 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op2)); 366 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op2)); 367 } 368 369 emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg)); 370 DONE; 371}) 372 373(define_insn "store_conditionalpti" 374 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 375 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 376 (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z") 377 (match_operand:PTI 2 "quad_int_reg_operand" "r"))] 378 "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)" 379 "stqcx. %2,%y1" 380 [(set_attr "type" "store_c")]) 381 382(define_expand "atomic_compare_and_swap<mode>" 383 [(match_operand:SI 0 "int_reg_operand") ;; bool out 384 (match_operand:AINT 1 "int_reg_operand") ;; val out 385 (match_operand:AINT 2 "memory_operand") ;; memory 386 (match_operand:AINT 3 "reg_or_short_operand") ;; expected 387 (match_operand:AINT 4 "int_reg_operand") ;; desired 388 (match_operand:SI 5 "const_int_operand") ;; is_weak 389 (match_operand:SI 6 "const_int_operand") ;; model succ 390 (match_operand:SI 7 "const_int_operand")] ;; model fail 391 "" 392{ 393 rs6000_expand_atomic_compare_and_swap (operands); 394 DONE; 395}) 396 397(define_expand "atomic_exchange<mode>" 398 [(match_operand:AINT 0 "int_reg_operand") ;; output 399 (match_operand:AINT 1 "memory_operand") ;; memory 400 (match_operand:AINT 2 "int_reg_operand") ;; input 401 (match_operand:SI 3 "const_int_operand")] ;; model 402 "" 403{ 404 rs6000_expand_atomic_exchange (operands); 405 DONE; 406}) 407 408(define_expand "atomic_<fetchop_name><mode>" 409 [(match_operand:AINT 0 "memory_operand") ;; memory 410 (FETCHOP:AINT (match_dup 0) 411 (match_operand:AINT 1 "<fetchop_pred>")) ;; operand 412 (match_operand:SI 2 "const_int_operand")] ;; model 413 "" 414{ 415 rs6000_expand_atomic_op (<CODE>, operands[0], operands[1], 416 NULL_RTX, NULL_RTX, operands[2]); 417 DONE; 418}) 419 420(define_expand "atomic_nand<mode>" 421 [(match_operand:AINT 0 "memory_operand") ;; memory 422 (match_operand:AINT 1 "int_reg_operand") ;; operand 423 (match_operand:SI 2 "const_int_operand")] ;; model 424 "" 425{ 426 rs6000_expand_atomic_op (NOT, operands[0], operands[1], 427 NULL_RTX, NULL_RTX, operands[2]); 428 DONE; 429}) 430 431(define_expand "atomic_fetch_<fetchop_name><mode>" 432 [(match_operand:AINT 0 "int_reg_operand") ;; output 433 (match_operand:AINT 1 "memory_operand") ;; memory 434 (FETCHOP:AINT (match_dup 1) 435 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand 436 (match_operand:SI 3 "const_int_operand")] ;; model 437 "" 438{ 439 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 440 operands[0], NULL_RTX, operands[3]); 441 DONE; 442}) 443 444(define_expand "atomic_fetch_nand<mode>" 445 [(match_operand:AINT 0 "int_reg_operand") ;; output 446 (match_operand:AINT 1 "memory_operand") ;; memory 447 (match_operand:AINT 2 "int_reg_operand") ;; operand 448 (match_operand:SI 3 "const_int_operand")] ;; model 449 "" 450{ 451 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 452 operands[0], NULL_RTX, operands[3]); 453 DONE; 454}) 455 456(define_expand "atomic_<fetchop_name>_fetch<mode>" 457 [(match_operand:AINT 0 "int_reg_operand") ;; output 458 (match_operand:AINT 1 "memory_operand") ;; memory 459 (FETCHOP:AINT (match_dup 1) 460 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand 461 (match_operand:SI 3 "const_int_operand")] ;; model 462 "" 463{ 464 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 465 NULL_RTX, operands[0], operands[3]); 466 DONE; 467}) 468 469(define_expand "atomic_nand_fetch<mode>" 470 [(match_operand:AINT 0 "int_reg_operand") ;; output 471 (match_operand:AINT 1 "memory_operand") ;; memory 472 (match_operand:AINT 2 "int_reg_operand") ;; operand 473 (match_operand:SI 3 "const_int_operand")] ;; model 474 "" 475{ 476 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 477 NULL_RTX, operands[0], operands[3]); 478 DONE; 479}) 480