1;; Machine description for PowerPC synchronization instructions. 2;; Copyright (C) 2005-2014 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 = (enum memmodel) 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 /* Some AIX assemblers don't accept lwsync, so we use a .long. */ 95 if (TARGET_NO_LWSYNC) 96 return "sync"; 97 else if (TARGET_LWSYNC_INSTRUCTION) 98 return "lwsync"; 99 else 100 return ".long 0x7c2004ac"; 101} 102 [(set_attr "type" "sync")]) 103 104(define_insn "isync" 105 [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)] 106 "" 107 "isync" 108 [(set_attr "type" "isync")]) 109 110;; Types that we should provide atomic instructions for. 111(define_mode_iterator AINT [QI 112 HI 113 SI 114 (DI "TARGET_POWERPC64") 115 (TI "TARGET_SYNC_TI")]) 116 117;; The control dependency used for load dependency described 118;; in B.2.3 of the Power ISA 2.06B. 119(define_insn "loadsync_<mode>" 120 [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")] 121 UNSPECV_ISYNC) 122 (clobber (match_scratch:CC 1 "=y"))] 123 "" 124 "cmpw %1,%0,%0\;bne- %1,$+4\;isync" 125 [(set_attr "type" "isync") 126 (set_attr "length" "12")]) 127 128(define_insn "load_quadpti" 129 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 130 (unspec:PTI 131 [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))] 132 "TARGET_SYNC_TI 133 && !reg_mentioned_p (operands[0], operands[1])" 134 "lq %0,%1" 135 [(set_attr "type" "load") 136 (set_attr "length" "4")]) 137 138(define_expand "atomic_load<mode>" 139 [(set (match_operand:AINT 0 "register_operand" "") ;; output 140 (match_operand:AINT 1 "memory_operand" "")) ;; memory 141 (use (match_operand:SI 2 "const_int_operand" ""))] ;; model 142 "" 143{ 144 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 145 FAIL; 146 147 enum memmodel model = (enum memmodel) INTVAL (operands[2]); 148 149 if (model == MEMMODEL_SEQ_CST) 150 emit_insn (gen_hwsync ()); 151 152 if (<MODE>mode != TImode) 153 emit_move_insn (operands[0], operands[1]); 154 else 155 { 156 rtx op0 = operands[0]; 157 rtx op1 = operands[1]; 158 rtx pti_reg = gen_reg_rtx (PTImode); 159 160 // Can't have indexed address for 'lq' 161 if (indexed_address (XEXP (op1, 0), TImode)) 162 { 163 rtx old_addr = XEXP (op1, 0); 164 rtx new_addr = force_reg (Pmode, old_addr); 165 operands[1] = op1 = replace_equiv_address (op1, new_addr); 166 } 167 168 emit_insn (gen_load_quadpti (pti_reg, op1)); 169 170 /* For 4.8 we need to do explicit dword copies, even in big endian mode, 171 unless we are using the LRA register allocator. The 4.9 register 172 allocator is smart enough to assign an even/odd pair. */ 173 if (WORDS_BIG_ENDIAN && rs6000_lra_flag) 174 emit_move_insn (op0, gen_lowpart (TImode, pti_reg)); 175 else 176 { 177 rtx op0_lo = gen_lowpart (DImode, op0); 178 rtx op0_hi = gen_highpart (DImode, op0); 179 rtx pti_lo = gen_lowpart (DImode, pti_reg); 180 rtx pti_hi = gen_highpart (DImode, pti_reg); 181 182 emit_insn (gen_rtx_CLOBBER (VOIDmode, op0)); 183 if (WORDS_BIG_ENDIAN) 184 { 185 emit_move_insn (op0_hi, pti_hi); 186 emit_move_insn (op0_lo, pti_lo); 187 } 188 else 189 { 190 emit_move_insn (op0_hi, pti_lo); 191 emit_move_insn (op0_lo, pti_hi); 192 } 193 } 194 } 195 196 switch (model) 197 { 198 case MEMMODEL_RELAXED: 199 break; 200 case MEMMODEL_CONSUME: 201 case MEMMODEL_ACQUIRE: 202 case MEMMODEL_SEQ_CST: 203 emit_insn (gen_loadsync_<mode> (operands[0])); 204 break; 205 default: 206 gcc_unreachable (); 207 } 208 DONE; 209}) 210 211(define_insn "store_quadpti" 212 [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ") 213 (unspec:PTI 214 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))] 215 "TARGET_SYNC_TI" 216 "stq %1,%0" 217 [(set_attr "type" "store") 218 (set_attr "length" "4")]) 219 220(define_expand "atomic_store<mode>" 221 [(set (match_operand:AINT 0 "memory_operand" "") ;; memory 222 (match_operand:AINT 1 "register_operand" "")) ;; input 223 (use (match_operand:SI 2 "const_int_operand" ""))] ;; model 224 "" 225{ 226 if (<MODE>mode == TImode && !TARGET_SYNC_TI) 227 FAIL; 228 229 enum memmodel model = (enum memmodel) INTVAL (operands[2]); 230 switch (model) 231 { 232 case MEMMODEL_RELAXED: 233 break; 234 case MEMMODEL_RELEASE: 235 emit_insn (gen_lwsync ()); 236 break; 237 case MEMMODEL_SEQ_CST: 238 emit_insn (gen_hwsync ()); 239 break; 240 default: 241 gcc_unreachable (); 242 } 243 if (<MODE>mode != TImode) 244 emit_move_insn (operands[0], operands[1]); 245 else 246 { 247 rtx op0 = operands[0]; 248 rtx op1 = operands[1]; 249 rtx pti_reg = gen_reg_rtx (PTImode); 250 251 // Can't have indexed address for 'stq' 252 if (indexed_address (XEXP (op0, 0), TImode)) 253 { 254 rtx old_addr = XEXP (op0, 0); 255 rtx new_addr = force_reg (Pmode, old_addr); 256 operands[0] = op0 = replace_equiv_address (op0, new_addr); 257 } 258 259 /* For 4.8 we need to do explicit dword copies, even in big endian mode, 260 unless we are using the LRA register allocator. The 4.9 register 261 allocator is smart enough to assign an even/odd pair. */ 262 if (WORDS_BIG_ENDIAN && rs6000_lra_flag) 263 emit_move_insn (pti_reg, gen_lowpart (PTImode, op1)); 264 else 265 { 266 rtx op1_lo = gen_lowpart (DImode, op1); 267 rtx op1_hi = gen_highpart (DImode, op1); 268 rtx pti_lo = gen_lowpart (DImode, pti_reg); 269 rtx pti_hi = gen_highpart (DImode, pti_reg); 270 271 emit_insn (gen_rtx_CLOBBER (VOIDmode, pti_reg)); 272 if (WORDS_BIG_ENDIAN) 273 { 274 emit_move_insn (pti_hi, op1_hi); 275 emit_move_insn (pti_lo, op1_lo); 276 } 277 else 278 { 279 emit_move_insn (pti_hi, op1_lo); 280 emit_move_insn (pti_lo, op1_hi); 281 } 282 } 283 284 emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg)); 285 } 286 287 DONE; 288}) 289 290;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons 291;; other than the quad memory operations, which have special restrictions. 292;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased 293;; in and did not show up until power8. TImode atomic lqarx/stqcx. require 294;; special handling due to even/odd register requirements. 295(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI") 296 (HI "TARGET_SYNC_HI_QI") 297 SI 298 (DI "TARGET_POWERPC64")]) 299 300(define_insn "load_locked<mode>" 301 [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r") 302 (unspec_volatile:ATOMIC 303 [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))] 304 "" 305 "<larx> %0,%y1" 306 [(set_attr "type" "load_l")]) 307 308(define_insn "load_locked<QHI:mode>_si" 309 [(set (match_operand:SI 0 "int_reg_operand" "=r") 310 (unspec_volatile:SI 311 [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))] 312 "TARGET_SYNC_HI_QI" 313 "<QHI:larx> %0,%y1" 314 [(set_attr "type" "load_l")]) 315 316;; Use PTImode to get even/odd register pairs. 317 318;; Use a temporary register to force getting an even register for the 319;; lqarx/stqcrx. instructions. Under AT 7.0, we need use an explicit copy, 320;; even in big endian mode, unless we are using the LRA register allocator. In 321;; GCC 4.9, the register allocator is smart enough to assign a even/odd 322;; register pair. 323 324;; On little endian systems where non-atomic quad word load/store instructions 325;; are not used, the address can be register+offset, so make sure the address 326;; is indexed or indirect before register allocation. 327 328(define_expand "load_lockedti" 329 [(use (match_operand:TI 0 "quad_int_reg_operand" "")) 330 (use (match_operand:TI 1 "memory_operand" ""))] 331 "TARGET_SYNC_TI" 332{ 333 rtx op0 = operands[0]; 334 rtx op1 = operands[1]; 335 rtx pti = gen_reg_rtx (PTImode); 336 337 if (!indexed_or_indirect_operand (op1, TImode)) 338 { 339 rtx old_addr = XEXP (op1, 0); 340 rtx new_addr = force_reg (Pmode, old_addr); 341 operands[1] = op1 = change_address (op1, TImode, new_addr); 342 } 343 344 emit_insn (gen_load_lockedpti (pti, op1)); 345 if (WORDS_BIG_ENDIAN && rs6000_lra_flag) 346 emit_move_insn (op0, gen_lowpart (TImode, pti)); 347 else 348 { 349 rtx op0_lo = gen_lowpart (DImode, op0); 350 rtx op0_hi = gen_highpart (DImode, op0); 351 rtx pti_lo = gen_lowpart (DImode, pti); 352 rtx pti_hi = gen_highpart (DImode, pti); 353 354 emit_insn (gen_rtx_CLOBBER (VOIDmode, op0)); 355 if (WORDS_BIG_ENDIAN) 356 { 357 emit_move_insn (op0_hi, pti_hi); 358 emit_move_insn (op0_lo, pti_lo); 359 } 360 else 361 { 362 emit_move_insn (op0_hi, pti_lo); 363 emit_move_insn (op0_lo, pti_hi); 364 } 365 } 366 DONE; 367}) 368 369(define_insn "load_lockedpti" 370 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r") 371 (unspec_volatile:PTI 372 [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))] 373 "TARGET_SYNC_TI 374 && !reg_mentioned_p (operands[0], operands[1]) 375 && quad_int_reg_operand (operands[0], PTImode)" 376 "lqarx %0,%y1" 377 [(set_attr "type" "load_l")]) 378 379(define_insn "store_conditional<mode>" 380 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 381 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 382 (set (match_operand:ATOMIC 1 "memory_operand" "=Z") 383 (match_operand:ATOMIC 2 "int_reg_operand" "r"))] 384 "" 385 "<stcx> %2,%y1" 386 [(set_attr "type" "store_c")]) 387 388;; Use a temporary register to force getting an even register for the 389;; lqarx/stqcrx. instructions. Under AT 7.0, we need use an explicit copy, 390;; even in big endian mode. In GCC 4.9, the register allocator is smart enough 391;; to assign a even/odd register pair. 392 393;; On little endian systems where non-atomic quad word load/store instructions 394;; are not used, the address can be register+offset, so make sure the address 395;; is indexed or indirect before register allocation. 396 397(define_expand "store_conditionalti" 398 [(use (match_operand:CC 0 "cc_reg_operand" "")) 399 (use (match_operand:TI 1 "memory_operand" "")) 400 (use (match_operand:TI 2 "quad_int_reg_operand" ""))] 401 "TARGET_SYNC_TI" 402{ 403 rtx op0 = operands[0]; 404 rtx op1 = operands[1]; 405 rtx op2 = operands[2]; 406 rtx addr = XEXP (op1, 0); 407 rtx pti_mem; 408 rtx pti_reg; 409 410 if (!indexed_or_indirect_operand (op1, TImode)) 411 { 412 rtx new_addr = force_reg (Pmode, addr); 413 operands[1] = op1 = change_address (op1, TImode, new_addr); 414 addr = new_addr; 415 } 416 417 pti_mem = change_address (op1, PTImode, addr); 418 pti_reg = gen_reg_rtx (PTImode); 419 420 if (WORDS_BIG_ENDIAN && rs6000_lra_flag) 421 emit_move_insn (pti_reg, gen_lowpart (PTImode, op2)); 422 else 423 { 424 rtx op2_lo = gen_lowpart (DImode, op2); 425 rtx op2_hi = gen_highpart (DImode, op2); 426 rtx pti_lo = gen_lowpart (DImode, pti_reg); 427 rtx pti_hi = gen_highpart (DImode, pti_reg); 428 429 emit_insn (gen_rtx_CLOBBER (VOIDmode, op0)); 430 if (WORDS_BIG_ENDIAN) 431 { 432 emit_move_insn (pti_hi, op2_hi); 433 emit_move_insn (pti_lo, op2_lo); 434 } 435 else 436 { 437 emit_move_insn (pti_hi, op2_lo); 438 emit_move_insn (pti_lo, op2_hi); 439 } 440 } 441 442 emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg)); 443 DONE; 444}) 445 446(define_insn "store_conditionalpti" 447 [(set (match_operand:CC 0 "cc_reg_operand" "=x") 448 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC)) 449 (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z") 450 (match_operand:PTI 2 "quad_int_reg_operand" "r"))] 451 "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)" 452 "stqcx. %2,%y1" 453 [(set_attr "type" "store_c")]) 454 455(define_expand "atomic_compare_and_swap<mode>" 456 [(match_operand:SI 0 "int_reg_operand" "") ;; bool out 457 (match_operand:AINT 1 "int_reg_operand" "") ;; val out 458 (match_operand:AINT 2 "memory_operand" "") ;; memory 459 (match_operand:AINT 3 "reg_or_short_operand" "") ;; expected 460 (match_operand:AINT 4 "int_reg_operand" "") ;; desired 461 (match_operand:SI 5 "const_int_operand" "") ;; is_weak 462 (match_operand:SI 6 "const_int_operand" "") ;; model succ 463 (match_operand:SI 7 "const_int_operand" "")] ;; model fail 464 "" 465{ 466 rs6000_expand_atomic_compare_and_swap (operands); 467 DONE; 468}) 469 470(define_expand "atomic_exchange<mode>" 471 [(match_operand:AINT 0 "int_reg_operand" "") ;; output 472 (match_operand:AINT 1 "memory_operand" "") ;; memory 473 (match_operand:AINT 2 "int_reg_operand" "") ;; input 474 (match_operand:SI 3 "const_int_operand" "")] ;; model 475 "" 476{ 477 rs6000_expand_atomic_exchange (operands); 478 DONE; 479}) 480 481(define_expand "atomic_<fetchop_name><mode>" 482 [(match_operand:AINT 0 "memory_operand" "") ;; memory 483 (FETCHOP:AINT (match_dup 0) 484 (match_operand:AINT 1 "<fetchop_pred>" "")) ;; operand 485 (match_operand:SI 2 "const_int_operand" "")] ;; model 486 "" 487{ 488 rs6000_expand_atomic_op (<CODE>, operands[0], operands[1], 489 NULL_RTX, NULL_RTX, operands[2]); 490 DONE; 491}) 492 493(define_expand "atomic_nand<mode>" 494 [(match_operand:AINT 0 "memory_operand" "") ;; memory 495 (match_operand:AINT 1 "int_reg_operand" "") ;; operand 496 (match_operand:SI 2 "const_int_operand" "")] ;; model 497 "" 498{ 499 rs6000_expand_atomic_op (NOT, operands[0], operands[1], 500 NULL_RTX, NULL_RTX, operands[2]); 501 DONE; 502}) 503 504(define_expand "atomic_fetch_<fetchop_name><mode>" 505 [(match_operand:AINT 0 "int_reg_operand" "") ;; output 506 (match_operand:AINT 1 "memory_operand" "") ;; memory 507 (FETCHOP:AINT (match_dup 1) 508 (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand 509 (match_operand:SI 3 "const_int_operand" "")] ;; model 510 "" 511{ 512 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 513 operands[0], NULL_RTX, operands[3]); 514 DONE; 515}) 516 517(define_expand "atomic_fetch_nand<mode>" 518 [(match_operand:AINT 0 "int_reg_operand" "") ;; output 519 (match_operand:AINT 1 "memory_operand" "") ;; memory 520 (match_operand:AINT 2 "int_reg_operand" "") ;; operand 521 (match_operand:SI 3 "const_int_operand" "")] ;; model 522 "" 523{ 524 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 525 operands[0], NULL_RTX, operands[3]); 526 DONE; 527}) 528 529(define_expand "atomic_<fetchop_name>_fetch<mode>" 530 [(match_operand:AINT 0 "int_reg_operand" "") ;; output 531 (match_operand:AINT 1 "memory_operand" "") ;; memory 532 (FETCHOP:AINT (match_dup 1) 533 (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand 534 (match_operand:SI 3 "const_int_operand" "")] ;; model 535 "" 536{ 537 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2], 538 NULL_RTX, operands[0], operands[3]); 539 DONE; 540}) 541 542(define_expand "atomic_nand_fetch<mode>" 543 [(match_operand:AINT 0 "int_reg_operand" "") ;; output 544 (match_operand:AINT 1 "memory_operand" "") ;; memory 545 (match_operand:AINT 2 "int_reg_operand" "") ;; operand 546 (match_operand:SI 3 "const_int_operand" "")] ;; model 547 "" 548{ 549 rs6000_expand_atomic_op (NOT, operands[1], operands[2], 550 NULL_RTX, operands[0], operands[3]); 551 DONE; 552}) 553