1;; GCC machine description for IA-64 synchronization instructions. 2;; Copyright (C) 2005-2020 Free Software Foundation, Inc. 3;; 4;; This file is part of GCC. 5;; 6;; GCC is free software; you can redistribute it and/or modify 7;; it under the terms of the GNU General Public License as published by 8;; the Free Software Foundation; either version 3, or (at your option) 9;; any later version. 10;; 11;; GCC is distributed in the hope that it will be useful, 12;; but WITHOUT ANY WARRANTY; without even the implied warranty of 13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14;; GNU General Public License for more details. 15;; 16;; You should have received a copy of the GNU General Public License 17;; along with GCC; see the file COPYING3. If not see 18;; <http://www.gnu.org/licenses/>. 19 20;; Conversion to C++11 memory model based on 21;; http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html 22 23(define_mode_iterator IMODE [QI HI SI DI]) 24(define_mode_iterator I124MODE [QI HI SI]) 25(define_mode_iterator I48MODE [SI DI]) 26(define_mode_attr modesuffix [(QI "1") (HI "2") (SI "4") (DI "8")]) 27 28(define_code_iterator FETCHOP [plus minus ior xor and]) 29(define_code_attr fetchop_name 30 [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")]) 31 32(define_expand "mem_thread_fence" 33 [(match_operand:SI 0 "const_int_operand" "")] ;; model 34 "" 35{ 36 if (is_mm_seq_cst (memmodel_from_int (INTVAL (operands[0])))) 37 emit_insn (gen_memory_barrier ()); 38 DONE; 39}) 40 41(define_expand "memory_barrier" 42 [(set (match_dup 0) 43 (unspec:BLK [(match_dup 0)] UNSPEC_MF))] 44 "" 45{ 46 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); 47 MEM_VOLATILE_P (operands[0]) = 1; 48}) 49 50(define_insn "*memory_barrier" 51 [(set (match_operand:BLK 0 "" "") 52 (unspec:BLK [(match_dup 0)] UNSPEC_MF))] 53 "" 54 "mf" 55 [(set_attr "itanium_class" "syst_m")]) 56 57(define_expand "atomic_load<mode>" 58 [(match_operand:IMODE 0 "gr_register_operand" "") ;; output 59 (match_operand:IMODE 1 "memory_operand" "") ;; memory 60 (match_operand:SI 2 "const_int_operand" "")] ;; model 61 "" 62{ 63 enum memmodel model = memmodel_from_int (INTVAL (operands[2])); 64 65 /* Unless the memory model is relaxed, we want to emit ld.acq, which 66 will happen automatically for volatile memories. */ 67 gcc_assert (is_mm_relaxed (model) || MEM_VOLATILE_P (operands[1])); 68 emit_move_insn (operands[0], operands[1]); 69 DONE; 70}) 71 72(define_expand "atomic_store<mode>" 73 [(match_operand:IMODE 0 "memory_operand" "") ;; memory 74 (match_operand:IMODE 1 "gr_reg_or_0_operand" "") ;; input 75 (match_operand:SI 2 "const_int_operand" "")] ;; model 76 "" 77{ 78 enum memmodel model = memmodel_from_int (INTVAL (operands[2])); 79 80 /* Unless the memory model is relaxed, we want to emit st.rel, which 81 will happen automatically for volatile memories. */ 82 gcc_assert (is_mm_relaxed (model) || MEM_VOLATILE_P (operands[0])); 83 emit_move_insn (operands[0], operands[1]); 84 85 /* Sequentially consistent stores need a subsequent MF. See 86 http://www.decadent.org.uk/pipermail/cpp-threads/2008-December/001952.html 87 for a discussion of why a MF is needed here, but not for atomic_load. */ 88 if (is_mm_seq_cst (model)) 89 emit_insn (gen_memory_barrier ()); 90 DONE; 91}) 92 93(define_expand "atomic_compare_and_swap<mode>" 94 [(match_operand:DI 0 "gr_register_operand" "") ;; bool out 95 (match_operand:IMODE 1 "gr_register_operand" "") ;; val out 96 (match_operand:IMODE 2 "not_postinc_memory_operand" "") ;; memory 97 (match_operand:IMODE 3 "gr_register_operand" "") ;; expected 98 (match_operand:IMODE 4 "gr_reg_or_0_operand" "") ;; desired 99 (match_operand:SI 5 "const_int_operand" "") ;; is_weak 100 (match_operand:SI 6 "const_int_operand" "") ;; succ model 101 (match_operand:SI 7 "const_int_operand" "")] ;; fail model 102 "" 103{ 104 /* No need to distinquish __sync from __atomic, so get base value. */ 105 enum memmodel model = memmodel_base (INTVAL (operands[6])); 106 rtx ccv = gen_rtx_REG (DImode, AR_CCV_REGNUM); 107 rtx dval, eval; 108 109 eval = gen_reg_rtx (DImode); 110 convert_move (eval, operands[3], 1); 111 emit_move_insn (ccv, eval); 112 113 if (<MODE>mode == DImode) 114 dval = operands[1]; 115 else 116 dval = gen_reg_rtx (DImode); 117 118 switch (model) 119 { 120 case MEMMODEL_RELAXED: 121 case MEMMODEL_ACQUIRE: 122 case MEMMODEL_CONSUME: 123 emit_insn (gen_cmpxchg_acq_<mode> (dval, operands[2], ccv, operands[4])); 124 break; 125 case MEMMODEL_RELEASE: 126 emit_insn (gen_cmpxchg_rel_<mode> (dval, operands[2], ccv, operands[4])); 127 break; 128 case MEMMODEL_ACQ_REL: 129 case MEMMODEL_SEQ_CST: 130 emit_insn (gen_cmpxchg_rel_<mode> (dval, operands[2], ccv, operands[4])); 131 emit_insn (gen_memory_barrier ()); 132 break; 133 default: 134 gcc_unreachable (); 135 } 136 137 if (<MODE>mode != DImode) 138 emit_move_insn (operands[1], gen_lowpart (<MODE>mode, dval)); 139 140 emit_insn (gen_cstoredi4 (operands[0], gen_rtx_EQ (DImode, dval, eval), 141 dval, eval)); 142 DONE; 143}) 144 145(define_insn "cmpxchg_acq_<mode>" 146 [(set (match_operand:DI 0 "gr_register_operand" "=r") 147 (zero_extend:DI 148 (match_operand:I124MODE 1 "not_postinc_memory_operand" "+S"))) 149 (set (match_dup 1) 150 (unspec:I124MODE 151 [(match_dup 1) 152 (match_operand:DI 2 "ar_ccv_reg_operand" "") 153 (match_operand:I124MODE 3 "gr_reg_or_0_operand" "rO")] 154 UNSPEC_CMPXCHG_ACQ))] 155 "" 156 "cmpxchg<modesuffix>.acq %0 = %1, %r3, %2" 157 [(set_attr "itanium_class" "sem")]) 158 159(define_insn "cmpxchg_rel_<mode>" 160 [(set (match_operand:DI 0 "gr_register_operand" "=r") 161 (zero_extend:DI 162 (match_operand:I124MODE 1 "not_postinc_memory_operand" "+S"))) 163 (set (match_dup 1) 164 (unspec:I124MODE 165 [(match_dup 1) 166 (match_operand:DI 2 "ar_ccv_reg_operand" "") 167 (match_operand:I124MODE 3 "gr_reg_or_0_operand" "rO")] 168 UNSPEC_CMPXCHG_REL))] 169 "" 170 "cmpxchg<modesuffix>.rel %0 = %1, %r3, %2" 171 [(set_attr "itanium_class" "sem")]) 172 173(define_insn "cmpxchg_acq_di" 174 [(set (match_operand:DI 0 "gr_register_operand" "=r") 175 (match_operand:DI 1 "not_postinc_memory_operand" "+S")) 176 (set (match_dup 1) 177 (unspec:DI [(match_dup 1) 178 (match_operand:DI 2 "ar_ccv_reg_operand" "") 179 (match_operand:DI 3 "gr_reg_or_0_operand" "rO")] 180 UNSPEC_CMPXCHG_ACQ))] 181 "" 182 "cmpxchg8.acq %0 = %1, %r3, %2" 183 [(set_attr "itanium_class" "sem")]) 184 185(define_insn "cmpxchg_rel_di" 186 [(set (match_operand:DI 0 "gr_register_operand" "=r") 187 (match_operand:DI 1 "not_postinc_memory_operand" "+S")) 188 (set (match_dup 1) 189 (unspec:DI [(match_dup 1) 190 (match_operand:DI 2 "ar_ccv_reg_operand" "") 191 (match_operand:DI 3 "gr_reg_or_0_operand" "rO")] 192 UNSPEC_CMPXCHG_REL))] 193 "" 194 "cmpxchg8.rel %0 = %1, %r3, %2" 195 [(set_attr "itanium_class" "sem")]) 196 197(define_expand "atomic_exchange<mode>" 198 [(match_operand:IMODE 0 "gr_register_operand" "") ;; output 199 (match_operand:IMODE 1 "not_postinc_memory_operand" "") ;; memory 200 (match_operand:IMODE 2 "gr_reg_or_0_operand" "") ;; input 201 (match_operand:SI 3 "const_int_operand" "")] ;; succ model 202 "" 203{ 204 /* No need to distinquish __sync from __atomic, so get base value. */ 205 enum memmodel model = memmodel_base (INTVAL (operands[3])); 206 207 switch (model) 208 { 209 case MEMMODEL_RELAXED: 210 case MEMMODEL_ACQUIRE: 211 case MEMMODEL_CONSUME: 212 break; 213 case MEMMODEL_RELEASE: 214 case MEMMODEL_ACQ_REL: 215 case MEMMODEL_SEQ_CST: 216 emit_insn (gen_memory_barrier ()); 217 break; 218 default: 219 gcc_unreachable (); 220 } 221 emit_insn (gen_xchg_acq_<mode> (operands[0], operands[1], operands[2])); 222 DONE; 223}) 224 225;; Note that XCHG is always memory model acquire. 226(define_insn "xchg_acq_<mode>" 227 [(set (match_operand:IMODE 0 "gr_register_operand" "=r") 228 (match_operand:IMODE 1 "not_postinc_memory_operand" "+S")) 229 (set (match_dup 1) 230 (match_operand:IMODE 2 "gr_reg_or_0_operand" "rO"))] 231 "" 232 "xchg<modesuffix> %0 = %1, %r2" 233 [(set_attr "itanium_class" "sem")]) 234 235(define_expand "atomic_<fetchop_name><mode>" 236 [(set (match_operand:IMODE 0 "memory_operand" "") 237 (FETCHOP:IMODE (match_dup 0) 238 (match_operand:IMODE 1 "nonmemory_operand" ""))) 239 (use (match_operand:SI 2 "const_int_operand" ""))] 240 "" 241{ 242 ia64_expand_atomic_op (<CODE>, operands[0], operands[1], NULL, NULL, 243 (enum memmodel) INTVAL (operands[2])); 244 DONE; 245}) 246 247(define_expand "atomic_nand<mode>" 248 [(set (match_operand:IMODE 0 "memory_operand" "") 249 (not:IMODE 250 (and:IMODE (match_dup 0) 251 (match_operand:IMODE 1 "nonmemory_operand" "")))) 252 (use (match_operand:SI 2 "const_int_operand" ""))] 253 "" 254{ 255 ia64_expand_atomic_op (NOT, operands[0], operands[1], NULL, NULL, 256 (enum memmodel) INTVAL (operands[2])); 257 DONE; 258}) 259 260(define_expand "atomic_fetch_<fetchop_name><mode>" 261 [(set (match_operand:IMODE 0 "gr_register_operand" "") 262 (FETCHOP:IMODE 263 (match_operand:IMODE 1 "memory_operand" "") 264 (match_operand:IMODE 2 "nonmemory_operand" ""))) 265 (use (match_operand:SI 3 "const_int_operand" ""))] 266 "" 267{ 268 ia64_expand_atomic_op (<CODE>, operands[1], operands[2], operands[0], NULL, 269 (enum memmodel) INTVAL (operands[3])); 270 DONE; 271}) 272 273(define_expand "atomic_fetch_nand<mode>" 274 [(set (match_operand:IMODE 0 "gr_register_operand" "") 275 (not:IMODE 276 (and:IMODE (match_operand:IMODE 1 "memory_operand" "") 277 (match_operand:IMODE 2 "nonmemory_operand" "")))) 278 (use (match_operand:SI 3 "const_int_operand" ""))] 279 "" 280{ 281 ia64_expand_atomic_op (NOT, operands[1], operands[2], operands[0], NULL, 282 (enum memmodel) INTVAL (operands[3])); 283 DONE; 284}) 285 286(define_expand "atomic_<fetchop_name>_fetch<mode>" 287 [(set (match_operand:IMODE 0 "gr_register_operand" "") 288 (FETCHOP:IMODE 289 (match_operand:IMODE 1 "memory_operand" "") 290 (match_operand:IMODE 2 "nonmemory_operand" ""))) 291 (use (match_operand:SI 3 "const_int_operand" ""))] 292 "" 293{ 294 ia64_expand_atomic_op (<CODE>, operands[1], operands[2], NULL, operands[0], 295 (enum memmodel) INTVAL (operands[3])); 296 DONE; 297}) 298 299(define_expand "atomic_nand_fetch<mode>" 300 [(set (match_operand:IMODE 0 "gr_register_operand" "") 301 (not:IMODE 302 (and:IMODE (match_operand:IMODE 1 "memory_operand" "") 303 (match_operand:IMODE 2 "nonmemory_operand" "")))) 304 (use (match_operand:SI 3 "const_int_operand" ""))] 305 "" 306{ 307 ia64_expand_atomic_op (NOT, operands[1], operands[2], NULL, operands[0], 308 (enum memmodel) INTVAL (operands[3])); 309 DONE; 310}) 311 312(define_insn "fetchadd_acq_<mode>" 313 [(set (match_operand:I48MODE 0 "gr_register_operand" "=r") 314 (match_operand:I48MODE 1 "not_postinc_memory_operand" "+S")) 315 (set (match_dup 1) 316 (unspec:I48MODE [(match_dup 1) 317 (match_operand:I48MODE 2 "fetchadd_operand" "n")] 318 UNSPEC_FETCHADD_ACQ))] 319 "" 320 "fetchadd<modesuffix>.acq %0 = %1, %2" 321 [(set_attr "itanium_class" "sem")]) 322 323(define_insn "fetchadd_rel_<mode>" 324 [(set (match_operand:I48MODE 0 "gr_register_operand" "=r") 325 (match_operand:I48MODE 1 "not_postinc_memory_operand" "+S")) 326 (set (match_dup 1) 327 (unspec:I48MODE [(match_dup 1) 328 (match_operand:I48MODE 2 "fetchadd_operand" "n")] 329 UNSPEC_FETCHADD_REL))] 330 "" 331 "fetchadd<modesuffix>.rel %0 = %1, %2" 332 [(set_attr "itanium_class" "sem")]) 333