]>
Commit | Line | Data |
---|---|---|
dd552284 WL |
1 | ;; GCC machine description for Tilera TILE-Gx synchronization |
2 | ;; instructions. | |
a5544970 | 3 | ;; Copyright (C) 2011-2019 Free Software Foundation, Inc. |
dd552284 WL |
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" | |
9b0370aa | 74 | [(set_attr "type" "X1_remote")]) |
dd552284 WL |
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" | |
9b0370aa | 103 | [(set_attr "type" "X1_remote")]) |
dd552284 WL |
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])); | |
7eb0f141 | 123 | tilegx_post_atomic_barrier (model); |
dd552284 WL |
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" | |
9b0370aa | 139 | [(set_attr "type" "X1_remote")]) |
dd552284 WL |
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 | { | |
6bb0e248 | 153 | rtx addend; |
dd552284 WL |
154 | enum memmodel model = (enum memmodel) INTVAL (operands[3]); |
155 | ||
156 | if (operands[2] != const0_rtx) | |
6bb0e248 WL |
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]; | |
dd552284 WL |
164 | |
165 | tilegx_pre_atomic_barrier (model); | |
166 | emit_insn (gen_atomic_fetch_add_bare<mode> (operands[0], | |
167 | operands[1], | |
6bb0e248 | 168 | addend)); |
2bcf3c5c | 169 | tilegx_post_atomic_barrier (model); |
dd552284 WL |
170 | DONE; |
171 | }) | |
327a1118 WL |
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 | { | |
341c653c | 180 | rtx addr, aligned_addr, aligned_mem, offset, word, shmt, tmp; |
327a1118 WL |
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 | ||
341c653c WL |
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 | ||
327a1118 | 204 | offset = gen_reg_rtx (DImode); |
341c653c | 205 | emit_move_insn (offset, gen_rtx_AND (DImode, gen_lowpart (DImode, tmp), |
327a1118 WL |
206 | GEN_INT (7))); |
207 | ||
341c653c WL |
208 | tmp = gen_reg_rtx (DImode); |
209 | emit_move_insn (tmp, GEN_INT (1)); | |
327a1118 WL |
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); | |
341c653c | 215 | emit_move_insn (word, gen_rtx_ASHIFT (DImode, tmp, |
327a1118 WL |
216 | gen_lowpart (SImode, shmt))); |
217 | ||
341c653c | 218 | tmp = gen_reg_rtx (DImode); |
327a1118 | 219 | tilegx_pre_atomic_barrier (model); |
341c653c | 220 | emit_insn (gen_atomic_fetch_or_baredi (tmp, aligned_mem, word)); |
327a1118 WL |
221 | tilegx_post_atomic_barrier (model); |
222 | ||
223 | emit_move_insn (gen_lowpart (DImode, result), | |
341c653c | 224 | gen_rtx_LSHIFTRT (DImode, tmp, |
327a1118 WL |
225 | gen_lowpart (SImode, shmt))); |
226 | DONE; | |
227 | }) |