1;; GCC machine description for Tilera TILE-Gx synchronization 2;; instructions. 3;; Copyright (C) 2011-2016 Free Software Foundation, Inc. 4;; Contributed by Walter Lee (walt@tilera.com) 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 10;; by the Free Software Foundation; either version 3, or (at your 11;; option) any later version. 12;; 13;; GCC is distributed in the hope that it will be useful, but WITHOUT 14;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16;; 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_code_iterator fetchop [plus ior and]) 23(define_code_attr fetchop_name [(plus "add") (ior "or") (and "and")]) 24 25(define_insn "mtspr_cmpexch<mode>" 26 [(set (reg:I48MODE TILEGX_CMPEXCH_REG) 27 (unspec_volatile:I48MODE 28 [(match_operand:I48MODE 0 "reg_or_0_operand" "rO")] 29 UNSPEC_SPR_MOVE))] 30 "" 31 "mtspr\tCMPEXCH_VALUE, %r0" 32 [(set_attr "type" "X1")]) 33 34 35(define_expand "atomic_compare_and_swap<mode>" 36 [(match_operand:DI 0 "register_operand" "") ;; bool output 37 (match_operand:I48MODE 1 "register_operand" "") ;; val output 38 (match_operand:I48MODE 2 "nonautoincmem_operand" "") ;; memory 39 (match_operand:I48MODE 3 "reg_or_0_operand" "") ;; expected value 40 (match_operand:I48MODE 4 "reg_or_0_operand" "") ;; desired value 41 (match_operand:SI 5 "const_int_operand" "") ;; is_weak 42 (match_operand:SI 6 "const_int_operand" "") ;; mod_s 43 (match_operand:SI 7 "const_int_operand" "")] ;; mod_f 44 "" 45{ 46 enum memmodel mod_s = (enum memmodel) INTVAL (operands[6]); 47 48 if (operands[3] != const0_rtx) 49 operands[3] = force_reg (<MODE>mode, operands[3]); 50 if (operands[4] != const0_rtx) 51 operands[4] = force_reg (<MODE>mode, operands[4]); 52 53 tilegx_pre_atomic_barrier (mod_s); 54 emit_insn (gen_mtspr_cmpexch<mode> (operands[3])); 55 emit_insn (gen_atomic_compare_and_swap_bare<mode> (operands[1], operands[2], 56 operands[4])); 57 tilegx_post_atomic_barrier (mod_s); 58 emit_insn (gen_insn_cmpeq_<mode>di (operands[0], operands[1], operands[3])); 59 DONE; 60}) 61 62 63(define_insn "atomic_compare_and_swap_bare<mode>" 64 [(set (match_operand:I48MODE 0 "register_operand" "=r") 65 (match_operand:I48MODE 1 "nonautoincmem_operand" "+U")) 66 (set (match_dup 1) 67 (unspec_volatile:I48MODE 68 [(match_dup 1) 69 (reg:I48MODE TILEGX_CMPEXCH_REG) 70 (match_operand:I48MODE 2 "reg_or_0_operand" "rO")] 71 UNSPEC_CMPXCHG))] 72 "" 73 "cmpexch<four_if_si>\t%0, %1, %r2" 74 [(set_attr "type" "X1_remote")]) 75 76 77(define_expand "atomic_exchange<mode>" 78 [(match_operand:I48MODE 0 "register_operand" "") ;; result 79 (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory 80 (match_operand:I48MODE 2 "reg_or_0_operand" "") ;; input 81 (match_operand:SI 3 "const_int_operand" "")] ;; model 82 "" 83{ 84 enum memmodel model = (enum memmodel) INTVAL (operands[3]); 85 86 tilegx_pre_atomic_barrier (model); 87 emit_insn (gen_atomic_exchange_bare<mode> (operands[0], operands[1], 88 operands[2])); 89 tilegx_post_atomic_barrier (model); 90 DONE; 91}) 92 93 94(define_insn "atomic_exchange_bare<mode>" 95 [(set (match_operand:I48MODE 0 "register_operand" "=r") 96 (match_operand:I48MODE 1 "nonautoincmem_operand" "+U")) 97 (set (match_dup 1) 98 (unspec_volatile:I48MODE 99 [(match_operand:I48MODE 2 "reg_or_0_operand" "rO")] 100 UNSPEC_XCHG))] 101 "" 102 "exch<four_if_si>\t%0, %1, %r2" 103 [(set_attr "type" "X1_remote")]) 104 105 106(define_expand "atomic_fetch_<fetchop_name><mode>" 107 [(match_operand:I48MODE 0 "register_operand" "") ;; result 108 (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory 109 (unspec_volatile:I48MODE 110 [(fetchop:I48MODE 111 (match_dup 1) 112 (match_operand:I48MODE 2 "reg_or_0_operand" ""))] ;; value 113 UNSPEC_ATOMIC) 114 (match_operand:SI 3 "const_int_operand" "")] ;; model 115 "" 116{ 117 enum memmodel model = (enum memmodel) INTVAL (operands[3]); 118 119 tilegx_pre_atomic_barrier (model); 120 emit_insn (gen_atomic_fetch_<fetchop_name>_bare<mode> (operands[0], 121 operands[1], 122 operands[2])); 123 tilegx_post_atomic_barrier (model); 124 DONE; 125}) 126 127 128(define_insn "atomic_fetch_<fetchop_name>_bare<mode>" 129 [(set (match_operand:I48MODE 0 "register_operand" "=r") 130 (match_operand:I48MODE 1 "nonautoincmem_operand" "+U")) 131 (set (match_dup 1) 132 (unspec_volatile:I48MODE 133 [(fetchop:I48MODE 134 (match_dup 1) 135 (match_operand:I48MODE 2 "reg_or_0_operand" "rO"))] 136 UNSPEC_ATOMIC))] 137 "" 138 "fetch<fetchop_name><four_if_si>\t%0, %1, %r2" 139 [(set_attr "type" "X1_remote")]) 140 141 142(define_expand "atomic_fetch_sub<mode>" 143 [(match_operand:I48MODE 0 "register_operand" "") ;; result 144 (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory 145 (unspec_volatile:I48MODE 146 [(minus:I48MODE 147 (match_dup 1) 148 (match_operand:I48MODE 2 "reg_or_0_operand" ""))] ;; value 149 UNSPEC_ATOMIC) 150 (match_operand:SI 3 "const_int_operand" "")] ;; model 151 "" 152{ 153 rtx addend; 154 enum memmodel model = (enum memmodel) INTVAL (operands[3]); 155 156 if (operands[2] != const0_rtx) 157 { 158 addend = gen_reg_rtx (<MODE>mode); 159 emit_move_insn (addend, 160 gen_rtx_MINUS (<MODE>mode, const0_rtx, operands[2])); 161 } 162 else 163 addend = operands[2]; 164 165 tilegx_pre_atomic_barrier (model); 166 emit_insn (gen_atomic_fetch_add_bare<mode> (operands[0], 167 operands[1], 168 addend)); 169 tilegx_post_atomic_barrier (model); 170 DONE; 171}) 172 173 174(define_expand "atomic_test_and_set" 175 [(match_operand:QI 0 "register_operand" "") ;; bool output 176 (match_operand:QI 1 "nonautoincmem_operand" "+U") ;; memory 177 (match_operand:SI 2 "const_int_operand" "")] ;; model 178 "" 179{ 180 rtx addr, aligned_addr, aligned_mem, offset, word, shmt, tmp; 181 rtx result = operands[0]; 182 rtx mem = operands[1]; 183 enum memmodel model = (enum memmodel) INTVAL (operands[2]); 184 185 addr = force_reg (Pmode, XEXP (mem, 0)); 186 187 aligned_addr = gen_reg_rtx (Pmode); 188 emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, GEN_INT (-8))); 189 190 aligned_mem = change_address (mem, DImode, aligned_addr); 191 set_mem_alias_set (aligned_mem, 0); 192 193 tmp = gen_reg_rtx (Pmode); 194 if (BYTES_BIG_ENDIAN) 195 { 196 emit_move_insn (gen_lowpart (DImode, tmp), 197 gen_rtx_NOT (DImode, gen_lowpart (DImode, addr))); 198 } 199 else 200 { 201 tmp = addr; 202 } 203 204 offset = gen_reg_rtx (DImode); 205 emit_move_insn (offset, gen_rtx_AND (DImode, gen_lowpart (DImode, tmp), 206 GEN_INT (7))); 207 208 tmp = gen_reg_rtx (DImode); 209 emit_move_insn (tmp, GEN_INT (1)); 210 211 shmt = gen_reg_rtx (DImode); 212 emit_move_insn (shmt, gen_rtx_ASHIFT (DImode, offset, GEN_INT (3))); 213 214 word = gen_reg_rtx (DImode); 215 emit_move_insn (word, gen_rtx_ASHIFT (DImode, tmp, 216 gen_lowpart (SImode, shmt))); 217 218 tmp = gen_reg_rtx (DImode); 219 tilegx_pre_atomic_barrier (model); 220 emit_insn (gen_atomic_fetch_or_baredi (tmp, aligned_mem, word)); 221 tilegx_post_atomic_barrier (model); 222 223 emit_move_insn (gen_lowpart (DImode, result), 224 gen_rtx_LSHIFTRT (DImode, tmp, 225 gen_lowpart (SImode, shmt))); 226 DONE; 227}) 228