]>
Commit | Line | Data |
---|---|---|
7cede643 DD |
1 | ;; Machine Description for MIPS based processor synchronization |
2 | ;; instructions. | |
d1e082c2 | 3 | ;; Copyright (C) 2007-2013 Free Software Foundation, Inc. |
7cede643 DD |
4 | |
5 | ;; This file is part of GCC. | |
6 | ||
7 | ;; GCC is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 3, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GCC is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public 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 | ||
24609606 RS |
21 | (define_c_enum "unspec" [ |
22 | UNSPEC_COMPARE_AND_SWAP | |
23 | UNSPEC_COMPARE_AND_SWAP_12 | |
24 | UNSPEC_SYNC_OLD_OP | |
25 | UNSPEC_SYNC_NEW_OP | |
26 | UNSPEC_SYNC_NEW_OP_12 | |
27 | UNSPEC_SYNC_OLD_OP_12 | |
28 | UNSPEC_SYNC_EXCHANGE | |
29 | UNSPEC_SYNC_EXCHANGE_12 | |
30 | UNSPEC_MEMORY_BARRIER | |
01c196ea TV |
31 | UNSPEC_ATOMIC_COMPARE_AND_SWAP |
32 | UNSPEC_ATOMIC_EXCHANGE | |
33 | UNSPEC_ATOMIC_FETCH_OP | |
24609606 RS |
34 | ]) |
35 | ||
7cede643 DD |
36 | ;; Atomic fetch bitwise operations. |
37 | (define_code_iterator fetchop_bit [ior xor and]) | |
38 | ||
39 | ;; Atomic HI and QI operations | |
40 | (define_code_iterator atomic_hiqi_op [plus minus ior xor and]) | |
41 | ||
42 | ;; Atomic memory operations. | |
43 | ||
1a8c13b3 UB |
44 | (define_expand "memory_barrier" |
45 | [(set (match_dup 0) | |
46 | (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] | |
47 | "GENERATE_SYNC" | |
48 | { | |
49 | operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); | |
50 | MEM_VOLATILE_P (operands[0]) = 1; | |
51 | }) | |
52 | ||
4f24c6d6 | 53 | (define_insn "*memory_barrier" |
1a8c13b3 UB |
54 | [(set (match_operand:BLK 0 "" "") |
55 | (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] | |
7cede643 | 56 | "GENERATE_SYNC" |
6f5a62e9 | 57 | { return mips_output_sync (); }) |
7cede643 | 58 | |
01c196ea | 59 | ;; Can be removed in favor of atomic_compare_and_swap below. |
7cede643 DD |
60 | (define_insn "sync_compare_and_swap<mode>" |
61 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 62 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
63 | (set (match_dup 1) |
64 | (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ") | |
65 | (match_operand:GPR 3 "arith_operand" "I,d")] | |
66 | UNSPEC_COMPARE_AND_SWAP))] | |
67 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
68 | { return mips_output_sync_loop (insn, operands); } |
69 | [(set_attr "sync_insn1" "li,move") | |
70 | (set_attr "sync_oldval" "0") | |
71 | (set_attr "sync_mem" "1") | |
72 | (set_attr "sync_required_oldval" "2") | |
73 | (set_attr "sync_insn1_op2" "3")]) | |
7cede643 DD |
74 | |
75 | (define_expand "sync_compare_and_swap<mode>" | |
76 | [(match_operand:SHORT 0 "register_operand") | |
77 | (match_operand:SHORT 1 "memory_operand") | |
78 | (match_operand:SHORT 2 "general_operand") | |
79 | (match_operand:SHORT 3 "general_operand")] | |
80 | "GENERATE_LL_SC" | |
81 | { | |
82 | union mips_gen_fn_ptrs generator; | |
83 | generator.fn_6 = gen_compare_and_swap_12; | |
84 | mips_expand_atomic_qihi (generator, | |
85 | operands[0], operands[1], operands[2], operands[3]); | |
86 | DONE; | |
87 | }) | |
88 | ||
89 | ;; Helper insn for mips_expand_atomic_qihi. | |
90 | (define_insn "compare_and_swap_12" | |
91 | [(set (match_operand:SI 0 "register_operand" "=&d,&d") | |
22c4c869 | 92 | (match_operand:SI 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
93 | (set (match_dup 1) |
94 | (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d") | |
95 | (match_operand:SI 3 "register_operand" "d,d") | |
96 | (match_operand:SI 4 "reg_or_0_operand" "dJ,dJ") | |
97 | (match_operand:SI 5 "reg_or_0_operand" "d,J")] | |
98 | UNSPEC_COMPARE_AND_SWAP_12))] | |
99 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
100 | { return mips_output_sync_loop (insn, operands); } |
101 | [(set_attr "sync_oldval" "0") | |
102 | (set_attr "sync_mem" "1") | |
103 | (set_attr "sync_inclusive_mask" "2") | |
104 | (set_attr "sync_exclusive_mask" "3") | |
105 | (set_attr "sync_required_oldval" "4") | |
106 | (set_attr "sync_insn1_op2" "5")]) | |
7cede643 DD |
107 | |
108 | (define_insn "sync_add<mode>" | |
22c4c869 | 109 | [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR") |
7cede643 DD |
110 | (unspec_volatile:GPR |
111 | [(plus:GPR (match_dup 0) | |
112 | (match_operand:GPR 1 "arith_operand" "I,d"))] | |
113 | UNSPEC_SYNC_OLD_OP))] | |
114 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
115 | { return mips_output_sync_loop (insn, operands); } |
116 | [(set_attr "sync_insn1" "addiu,addu") | |
117 | (set_attr "sync_mem" "0") | |
118 | (set_attr "sync_insn1_op2" "1")]) | |
7cede643 DD |
119 | |
120 | (define_expand "sync_<optab><mode>" | |
121 | [(set (match_operand:SHORT 0 "memory_operand") | |
122 | (unspec_volatile:SHORT | |
123 | [(atomic_hiqi_op:SHORT (match_dup 0) | |
124 | (match_operand:SHORT 1 "general_operand"))] | |
125 | UNSPEC_SYNC_OLD_OP))] | |
126 | "GENERATE_LL_SC" | |
127 | { | |
128 | union mips_gen_fn_ptrs generator; | |
129 | generator.fn_4 = gen_sync_<optab>_12; | |
130 | mips_expand_atomic_qihi (generator, | |
131 | NULL, operands[0], operands[1], NULL); | |
132 | DONE; | |
133 | }) | |
134 | ||
135 | ;; Helper insn for sync_<optab><mode> | |
136 | (define_insn "sync_<optab>_12" | |
22c4c869 | 137 | [(set (match_operand:SI 0 "memory_operand" "+ZR") |
7cede643 DD |
138 | (unspec_volatile:SI |
139 | [(match_operand:SI 1 "register_operand" "d") | |
140 | (match_operand:SI 2 "register_operand" "d") | |
141 | (atomic_hiqi_op:SI (match_dup 0) | |
31045a25 | 142 | (match_operand:SI 3 "reg_or_0_operand" "dJ"))] |
7cede643 DD |
143 | UNSPEC_SYNC_OLD_OP_12)) |
144 | (clobber (match_scratch:SI 4 "=&d"))] | |
145 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
146 | { return mips_output_sync_loop (insn, operands); } |
147 | [(set_attr "sync_insn1" "<insn>") | |
148 | (set_attr "sync_insn2" "and") | |
149 | (set_attr "sync_mem" "0") | |
150 | (set_attr "sync_inclusive_mask" "1") | |
151 | (set_attr "sync_exclusive_mask" "2") | |
152 | (set_attr "sync_insn1_op2" "3") | |
153 | (set_attr "sync_oldval" "4") | |
154 | (set_attr "sync_newval" "4")]) | |
7cede643 DD |
155 | |
156 | (define_expand "sync_old_<optab><mode>" | |
157 | [(parallel [ | |
158 | (set (match_operand:SHORT 0 "register_operand") | |
159 | (match_operand:SHORT 1 "memory_operand")) | |
160 | (set (match_dup 1) | |
161 | (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT | |
162 | (match_dup 1) | |
163 | (match_operand:SHORT 2 "general_operand"))] | |
164 | UNSPEC_SYNC_OLD_OP))])] | |
165 | "GENERATE_LL_SC" | |
166 | { | |
167 | union mips_gen_fn_ptrs generator; | |
168 | generator.fn_5 = gen_sync_old_<optab>_12; | |
169 | mips_expand_atomic_qihi (generator, | |
170 | operands[0], operands[1], operands[2], NULL); | |
171 | DONE; | |
172 | }) | |
173 | ||
174 | ;; Helper insn for sync_old_<optab><mode> | |
175 | (define_insn "sync_old_<optab>_12" | |
176 | [(set (match_operand:SI 0 "register_operand" "=&d") | |
22c4c869 | 177 | (match_operand:SI 1 "memory_operand" "+ZR")) |
7cede643 DD |
178 | (set (match_dup 1) |
179 | (unspec_volatile:SI | |
180 | [(match_operand:SI 2 "register_operand" "d") | |
181 | (match_operand:SI 3 "register_operand" "d") | |
182 | (atomic_hiqi_op:SI (match_dup 0) | |
31045a25 | 183 | (match_operand:SI 4 "reg_or_0_operand" "dJ"))] |
7cede643 DD |
184 | UNSPEC_SYNC_OLD_OP_12)) |
185 | (clobber (match_scratch:SI 5 "=&d"))] | |
186 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
187 | { return mips_output_sync_loop (insn, operands); } |
188 | [(set_attr "sync_insn1" "<insn>") | |
189 | (set_attr "sync_insn2" "and") | |
190 | (set_attr "sync_oldval" "0") | |
191 | (set_attr "sync_mem" "1") | |
192 | (set_attr "sync_inclusive_mask" "2") | |
193 | (set_attr "sync_exclusive_mask" "3") | |
194 | (set_attr "sync_insn1_op2" "4") | |
195 | (set_attr "sync_newval" "5")]) | |
7cede643 DD |
196 | |
197 | (define_expand "sync_new_<optab><mode>" | |
198 | [(parallel [ | |
199 | (set (match_operand:SHORT 0 "register_operand") | |
200 | (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT | |
201 | (match_operand:SHORT 1 "memory_operand") | |
202 | (match_operand:SHORT 2 "general_operand"))] | |
203 | UNSPEC_SYNC_NEW_OP)) | |
204 | (set (match_dup 1) | |
205 | (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] | |
206 | UNSPEC_SYNC_NEW_OP))])] | |
207 | "GENERATE_LL_SC" | |
208 | { | |
209 | union mips_gen_fn_ptrs generator; | |
210 | generator.fn_5 = gen_sync_new_<optab>_12; | |
211 | mips_expand_atomic_qihi (generator, | |
212 | operands[0], operands[1], operands[2], NULL); | |
213 | DONE; | |
214 | }) | |
215 | ||
216 | ;; Helper insn for sync_new_<optab><mode> | |
217 | (define_insn "sync_new_<optab>_12" | |
218 | [(set (match_operand:SI 0 "register_operand" "=&d") | |
219 | (unspec_volatile:SI | |
22c4c869 | 220 | [(match_operand:SI 1 "memory_operand" "+ZR") |
7cede643 DD |
221 | (match_operand:SI 2 "register_operand" "d") |
222 | (match_operand:SI 3 "register_operand" "d") | |
223 | (atomic_hiqi_op:SI (match_dup 0) | |
31045a25 | 224 | (match_operand:SI 4 "reg_or_0_operand" "dJ"))] |
7cede643 DD |
225 | UNSPEC_SYNC_NEW_OP_12)) |
226 | (set (match_dup 1) | |
227 | (unspec_volatile:SI | |
228 | [(match_dup 1) | |
229 | (match_dup 2) | |
230 | (match_dup 3) | |
231 | (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] | |
232 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
233 | { return mips_output_sync_loop (insn, operands); } |
234 | [(set_attr "sync_insn1" "<insn>") | |
235 | (set_attr "sync_insn2" "and") | |
236 | (set_attr "sync_oldval" "0") | |
237 | (set_attr "sync_newval" "0") | |
238 | (set_attr "sync_mem" "1") | |
239 | (set_attr "sync_inclusive_mask" "2") | |
240 | (set_attr "sync_exclusive_mask" "3") | |
241 | (set_attr "sync_insn1_op2" "4")]) | |
7cede643 DD |
242 | |
243 | (define_expand "sync_nand<mode>" | |
244 | [(set (match_operand:SHORT 0 "memory_operand") | |
245 | (unspec_volatile:SHORT | |
246 | [(match_dup 0) | |
247 | (match_operand:SHORT 1 "general_operand")] | |
248 | UNSPEC_SYNC_OLD_OP))] | |
249 | "GENERATE_LL_SC" | |
250 | { | |
251 | union mips_gen_fn_ptrs generator; | |
252 | generator.fn_4 = gen_sync_nand_12; | |
253 | mips_expand_atomic_qihi (generator, | |
254 | NULL, operands[0], operands[1], NULL); | |
255 | DONE; | |
256 | }) | |
257 | ||
258 | ;; Helper insn for sync_nand<mode> | |
259 | (define_insn "sync_nand_12" | |
22c4c869 | 260 | [(set (match_operand:SI 0 "memory_operand" "+ZR") |
7cede643 DD |
261 | (unspec_volatile:SI |
262 | [(match_operand:SI 1 "register_operand" "d") | |
263 | (match_operand:SI 2 "register_operand" "d") | |
264 | (match_dup 0) | |
31045a25 | 265 | (match_operand:SI 3 "reg_or_0_operand" "dJ")] |
7cede643 DD |
266 | UNSPEC_SYNC_OLD_OP_12)) |
267 | (clobber (match_scratch:SI 4 "=&d"))] | |
268 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
269 | { return mips_output_sync_loop (insn, operands); } |
270 | [(set_attr "sync_insn1" "and") | |
271 | (set_attr "sync_insn2" "xor") | |
272 | (set_attr "sync_mem" "0") | |
273 | (set_attr "sync_inclusive_mask" "1") | |
274 | (set_attr "sync_exclusive_mask" "2") | |
275 | (set_attr "sync_insn1_op2" "3") | |
276 | (set_attr "sync_oldval" "4") | |
277 | (set_attr "sync_newval" "4")]) | |
7cede643 DD |
278 | |
279 | (define_expand "sync_old_nand<mode>" | |
280 | [(parallel [ | |
281 | (set (match_operand:SHORT 0 "register_operand") | |
282 | (match_operand:SHORT 1 "memory_operand")) | |
283 | (set (match_dup 1) | |
284 | (unspec_volatile:SHORT [(match_dup 1) | |
285 | (match_operand:SHORT 2 "general_operand")] | |
286 | UNSPEC_SYNC_OLD_OP))])] | |
287 | "GENERATE_LL_SC" | |
288 | { | |
289 | union mips_gen_fn_ptrs generator; | |
290 | generator.fn_5 = gen_sync_old_nand_12; | |
291 | mips_expand_atomic_qihi (generator, | |
292 | operands[0], operands[1], operands[2], NULL); | |
293 | DONE; | |
294 | }) | |
295 | ||
296 | ;; Helper insn for sync_old_nand<mode> | |
297 | (define_insn "sync_old_nand_12" | |
298 | [(set (match_operand:SI 0 "register_operand" "=&d") | |
22c4c869 | 299 | (match_operand:SI 1 "memory_operand" "+ZR")) |
7cede643 DD |
300 | (set (match_dup 1) |
301 | (unspec_volatile:SI | |
302 | [(match_operand:SI 2 "register_operand" "d") | |
303 | (match_operand:SI 3 "register_operand" "d") | |
31045a25 | 304 | (match_operand:SI 4 "reg_or_0_operand" "dJ")] |
7cede643 DD |
305 | UNSPEC_SYNC_OLD_OP_12)) |
306 | (clobber (match_scratch:SI 5 "=&d"))] | |
307 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
308 | { return mips_output_sync_loop (insn, operands); } |
309 | [(set_attr "sync_insn1" "and") | |
310 | (set_attr "sync_insn2" "xor") | |
311 | (set_attr "sync_oldval" "0") | |
312 | (set_attr "sync_mem" "1") | |
313 | (set_attr "sync_inclusive_mask" "2") | |
314 | (set_attr "sync_exclusive_mask" "3") | |
315 | (set_attr "sync_insn1_op2" "4") | |
316 | (set_attr "sync_newval" "5")]) | |
7cede643 DD |
317 | |
318 | (define_expand "sync_new_nand<mode>" | |
319 | [(parallel [ | |
320 | (set (match_operand:SHORT 0 "register_operand") | |
321 | (unspec_volatile:SHORT [(match_operand:SHORT 1 "memory_operand") | |
322 | (match_operand:SHORT 2 "general_operand")] | |
323 | UNSPEC_SYNC_NEW_OP)) | |
324 | (set (match_dup 1) | |
325 | (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] | |
326 | UNSPEC_SYNC_NEW_OP))])] | |
327 | "GENERATE_LL_SC" | |
328 | { | |
329 | union mips_gen_fn_ptrs generator; | |
330 | generator.fn_5 = gen_sync_new_nand_12; | |
331 | mips_expand_atomic_qihi (generator, | |
332 | operands[0], operands[1], operands[2], NULL); | |
333 | DONE; | |
334 | }) | |
335 | ||
336 | ;; Helper insn for sync_new_nand<mode> | |
337 | (define_insn "sync_new_nand_12" | |
338 | [(set (match_operand:SI 0 "register_operand" "=&d") | |
339 | (unspec_volatile:SI | |
22c4c869 | 340 | [(match_operand:SI 1 "memory_operand" "+ZR") |
7cede643 DD |
341 | (match_operand:SI 2 "register_operand" "d") |
342 | (match_operand:SI 3 "register_operand" "d") | |
31045a25 | 343 | (match_operand:SI 4 "reg_or_0_operand" "dJ")] |
7cede643 DD |
344 | UNSPEC_SYNC_NEW_OP_12)) |
345 | (set (match_dup 1) | |
346 | (unspec_volatile:SI | |
347 | [(match_dup 1) | |
348 | (match_dup 2) | |
349 | (match_dup 3) | |
350 | (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] | |
351 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
352 | { return mips_output_sync_loop (insn, operands); } |
353 | [(set_attr "sync_insn1" "and") | |
354 | (set_attr "sync_insn2" "xor") | |
355 | (set_attr "sync_oldval" "0") | |
356 | (set_attr "sync_newval" "0") | |
357 | (set_attr "sync_mem" "1") | |
358 | (set_attr "sync_inclusive_mask" "2") | |
359 | (set_attr "sync_exclusive_mask" "3") | |
360 | (set_attr "sync_insn1_op2" "4")]) | |
7cede643 DD |
361 | |
362 | (define_insn "sync_sub<mode>" | |
22c4c869 | 363 | [(set (match_operand:GPR 0 "memory_operand" "+ZR") |
7cede643 DD |
364 | (unspec_volatile:GPR |
365 | [(minus:GPR (match_dup 0) | |
6f5a62e9 | 366 | (match_operand:GPR 1 "register_operand" "d"))] |
7cede643 DD |
367 | UNSPEC_SYNC_OLD_OP))] |
368 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
369 | { return mips_output_sync_loop (insn, operands); } |
370 | [(set_attr "sync_insn1" "subu") | |
371 | (set_attr "sync_mem" "0") | |
372 | (set_attr "sync_insn1_op2" "1")]) | |
7cede643 | 373 | |
01c196ea | 374 | ;; Can be removed in favor of atomic_fetch_add below. |
7cede643 DD |
375 | (define_insn "sync_old_add<mode>" |
376 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 377 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
378 | (set (match_dup 1) |
379 | (unspec_volatile:GPR | |
380 | [(plus:GPR (match_dup 1) | |
381 | (match_operand:GPR 2 "arith_operand" "I,d"))] | |
382 | UNSPEC_SYNC_OLD_OP))] | |
383 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
384 | { return mips_output_sync_loop (insn, operands); } |
385 | [(set_attr "sync_insn1" "addiu,addu") | |
386 | (set_attr "sync_oldval" "0") | |
387 | (set_attr "sync_mem" "1") | |
388 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
389 | |
390 | (define_insn "sync_old_sub<mode>" | |
391 | [(set (match_operand:GPR 0 "register_operand" "=&d") | |
22c4c869 | 392 | (match_operand:GPR 1 "memory_operand" "+ZR")) |
7cede643 DD |
393 | (set (match_dup 1) |
394 | (unspec_volatile:GPR | |
395 | [(minus:GPR (match_dup 1) | |
396 | (match_operand:GPR 2 "register_operand" "d"))] | |
397 | UNSPEC_SYNC_OLD_OP))] | |
398 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
399 | { return mips_output_sync_loop (insn, operands); } |
400 | [(set_attr "sync_insn1" "subu") | |
401 | (set_attr "sync_oldval" "0") | |
402 | (set_attr "sync_mem" "1") | |
403 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
404 | |
405 | (define_insn "sync_new_add<mode>" | |
406 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 407 | (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR") |
7cede643 DD |
408 | (match_operand:GPR 2 "arith_operand" "I,d"))) |
409 | (set (match_dup 1) | |
410 | (unspec_volatile:GPR | |
411 | [(plus:GPR (match_dup 1) (match_dup 2))] | |
412 | UNSPEC_SYNC_NEW_OP))] | |
413 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
414 | { return mips_output_sync_loop (insn, operands); } |
415 | [(set_attr "sync_insn1" "addiu,addu") | |
416 | (set_attr "sync_oldval" "0") | |
417 | (set_attr "sync_newval" "0") | |
418 | (set_attr "sync_mem" "1") | |
419 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
420 | |
421 | (define_insn "sync_new_sub<mode>" | |
422 | [(set (match_operand:GPR 0 "register_operand" "=&d") | |
22c4c869 | 423 | (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR") |
7cede643 DD |
424 | (match_operand:GPR 2 "register_operand" "d"))) |
425 | (set (match_dup 1) | |
426 | (unspec_volatile:GPR | |
427 | [(minus:GPR (match_dup 1) (match_dup 2))] | |
428 | UNSPEC_SYNC_NEW_OP))] | |
429 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
430 | { return mips_output_sync_loop (insn, operands); } |
431 | [(set_attr "sync_insn1" "subu") | |
432 | (set_attr "sync_oldval" "0") | |
433 | (set_attr "sync_newval" "0") | |
434 | (set_attr "sync_mem" "1") | |
435 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
436 | |
437 | (define_insn "sync_<optab><mode>" | |
22c4c869 | 438 | [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR") |
7cede643 DD |
439 | (unspec_volatile:GPR |
440 | [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d") | |
441 | (match_dup 0))] | |
442 | UNSPEC_SYNC_OLD_OP))] | |
443 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
444 | { return mips_output_sync_loop (insn, operands); } |
445 | [(set_attr "sync_insn1" "<immediate_insn>,<insn>") | |
446 | (set_attr "sync_mem" "0") | |
447 | (set_attr "sync_insn1_op2" "1")]) | |
7cede643 DD |
448 | |
449 | (define_insn "sync_old_<optab><mode>" | |
450 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 451 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
452 | (set (match_dup 1) |
453 | (unspec_volatile:GPR | |
454 | [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d") | |
455 | (match_dup 1))] | |
456 | UNSPEC_SYNC_OLD_OP))] | |
457 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
458 | { return mips_output_sync_loop (insn, operands); } |
459 | [(set_attr "sync_insn1" "<immediate_insn>,<insn>") | |
460 | (set_attr "sync_oldval" "0") | |
461 | (set_attr "sync_mem" "1") | |
462 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
463 | |
464 | (define_insn "sync_new_<optab><mode>" | |
465 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 466 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
467 | (set (match_dup 1) |
468 | (unspec_volatile:GPR | |
469 | [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d") | |
470 | (match_dup 1))] | |
471 | UNSPEC_SYNC_NEW_OP))] | |
472 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
473 | { return mips_output_sync_loop (insn, operands); } |
474 | [(set_attr "sync_insn1" "<immediate_insn>,<insn>") | |
475 | (set_attr "sync_oldval" "0") | |
476 | (set_attr "sync_newval" "0") | |
477 | (set_attr "sync_mem" "1") | |
478 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
479 | |
480 | (define_insn "sync_nand<mode>" | |
22c4c869 | 481 | [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR") |
7cede643 DD |
482 | (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")] |
483 | UNSPEC_SYNC_OLD_OP))] | |
484 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
485 | { return mips_output_sync_loop (insn, operands); } |
486 | [(set_attr "sync_insn1" "andi,and") | |
487 | (set_attr "sync_insn2" "not") | |
488 | (set_attr "sync_mem" "0") | |
489 | (set_attr "sync_insn1_op2" "1")]) | |
7cede643 DD |
490 | |
491 | (define_insn "sync_old_nand<mode>" | |
492 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 493 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
494 | (set (match_dup 1) |
495 | (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] | |
496 | UNSPEC_SYNC_OLD_OP))] | |
497 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
498 | { return mips_output_sync_loop (insn, operands); } |
499 | [(set_attr "sync_insn1" "andi,and") | |
500 | (set_attr "sync_insn2" "not") | |
501 | (set_attr "sync_oldval" "0") | |
502 | (set_attr "sync_mem" "1") | |
503 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
504 | |
505 | (define_insn "sync_new_nand<mode>" | |
506 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 507 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
508 | (set (match_dup 1) |
509 | (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] | |
510 | UNSPEC_SYNC_NEW_OP))] | |
511 | "GENERATE_LL_SC" | |
6f5a62e9 RS |
512 | { return mips_output_sync_loop (insn, operands); } |
513 | [(set_attr "sync_insn1" "andi,and") | |
514 | (set_attr "sync_insn2" "not") | |
515 | (set_attr "sync_oldval" "0") | |
516 | (set_attr "sync_newval" "0") | |
517 | (set_attr "sync_mem" "1") | |
518 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
519 | |
520 | (define_insn "sync_lock_test_and_set<mode>" | |
521 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 522 | (match_operand:GPR 1 "memory_operand" "+ZR,ZR")) |
7cede643 DD |
523 | (set (match_dup 1) |
524 | (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")] | |
525 | UNSPEC_SYNC_EXCHANGE))] | |
526 | "GENERATE_LL_SC" | |
6f5a62e9 | 527 | { return mips_output_sync_loop (insn, operands); } |
01c196ea | 528 | [(set_attr "sync_memmodel" "11") |
6f5a62e9 RS |
529 | (set_attr "sync_insn1" "li,move") |
530 | (set_attr "sync_oldval" "0") | |
531 | (set_attr "sync_mem" "1") | |
532 | (set_attr "sync_insn1_op2" "2")]) | |
7cede643 DD |
533 | |
534 | (define_expand "sync_lock_test_and_set<mode>" | |
535 | [(match_operand:SHORT 0 "register_operand") | |
536 | (match_operand:SHORT 1 "memory_operand") | |
537 | (match_operand:SHORT 2 "general_operand")] | |
538 | "GENERATE_LL_SC" | |
539 | { | |
540 | union mips_gen_fn_ptrs generator; | |
541 | generator.fn_5 = gen_test_and_set_12; | |
542 | mips_expand_atomic_qihi (generator, | |
543 | operands[0], operands[1], operands[2], NULL); | |
544 | DONE; | |
545 | }) | |
546 | ||
547 | (define_insn "test_and_set_12" | |
6f5a62e9 | 548 | [(set (match_operand:SI 0 "register_operand" "=&d") |
22c4c869 | 549 | (match_operand:SI 1 "memory_operand" "+ZR")) |
7cede643 | 550 | (set (match_dup 1) |
6f5a62e9 RS |
551 | (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d") |
552 | (match_operand:SI 3 "register_operand" "d") | |
31045a25 | 553 | (match_operand:SI 4 "reg_or_0_operand" "dJ")] |
7cede643 DD |
554 | UNSPEC_SYNC_EXCHANGE_12))] |
555 | "GENERATE_LL_SC" | |
6f5a62e9 | 556 | { return mips_output_sync_loop (insn, operands); } |
01c196ea | 557 | [(set_attr "sync_memmodel" "11") |
6f5a62e9 RS |
558 | (set_attr "sync_oldval" "0") |
559 | (set_attr "sync_mem" "1") | |
560 | ;; Unused, but needed to give the number of operands expected by | |
561 | ;; the expander. | |
562 | (set_attr "sync_inclusive_mask" "2") | |
563 | (set_attr "sync_exclusive_mask" "3") | |
564 | (set_attr "sync_insn1_op2" "4")]) | |
01c196ea TV |
565 | |
566 | (define_insn "atomic_compare_and_swap<mode>" | |
567 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
568 | ;; Logically this unspec is an "eq" operator, but we need to obscure | |
569 | ;; reads and writes from/to memory with an unspec to prevent | |
570 | ;; optimizations on shared memory locations. Otherwise, comparison in | |
571 | ;; { mem = 2; if (atomic_cmp_swap(mem,...) == 2) ...; } | |
572 | ;; would be optimized away. In addition to that we need to use | |
573 | ;; unspec_volatile, not just plain unspec -- for the sake of other | |
574 | ;; threads -- to make sure we don't remove the entirety of the pattern | |
575 | ;; just because current thread doesn't observe any effect from it. | |
576 | ;; TODO: the obscuring unspec can be relaxed for permissive memory | |
577 | ;; models. | |
578 | ;; Same applies to other atomic_* patterns. | |
22c4c869 | 579 | (unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR") |
01c196ea TV |
580 | (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")] |
581 | UNSPEC_ATOMIC_COMPARE_AND_SWAP)) | |
582 | (set (match_operand:GPR 1 "register_operand" "=&d,&d") | |
583 | (unspec_volatile:GPR [(match_dup 2)] | |
584 | UNSPEC_ATOMIC_COMPARE_AND_SWAP)) | |
585 | (set (match_dup 2) | |
586 | (unspec_volatile:GPR [(match_dup 2) | |
587 | (match_dup 3) | |
588 | (match_operand:GPR 4 "arith_operand" "I,d")] | |
589 | UNSPEC_ATOMIC_COMPARE_AND_SWAP)) | |
590 | (unspec_volatile:GPR [(match_operand:SI 5 "const_int_operand") | |
591 | (match_operand:SI 6 "const_int_operand") | |
592 | (match_operand:SI 7 "const_int_operand")] | |
593 | UNSPEC_ATOMIC_COMPARE_AND_SWAP)] | |
594 | "GENERATE_LL_SC" | |
595 | { return mips_output_sync_loop (insn, operands); } | |
596 | [(set_attr "sync_insn1" "li,move") | |
597 | (set_attr "sync_oldval" "1") | |
598 | (set_attr "sync_cmp" "0") | |
599 | (set_attr "sync_mem" "2") | |
600 | (set_attr "sync_required_oldval" "3") | |
601 | (set_attr "sync_insn1_op2" "4") | |
602 | (set_attr "sync_memmodel" "6")]) | |
603 | ||
604 | (define_expand "atomic_exchange<mode>" | |
605 | [(match_operand:GPR 0 "register_operand") | |
606 | (match_operand:GPR 1 "memory_operand") | |
607 | (match_operand:GPR 2 "arith_operand") | |
608 | (match_operand:SI 3 "const_int_operand")] | |
6399761a | 609 | "GENERATE_LL_SC || ISA_HAS_SWAP" |
01c196ea | 610 | { |
6399761a TV |
611 | if (ISA_HAS_SWAP) |
612 | { | |
613 | if (!mem_noofs_operand (operands[1], <MODE>mode)) | |
614 | { | |
615 | rtx addr; | |
616 | ||
617 | addr = force_reg (Pmode, XEXP (operands[1], 0)); | |
618 | operands[1] = replace_equiv_address (operands[1], addr); | |
619 | } | |
620 | operands[2] = force_reg (<MODE>mode, operands[2]); | |
621 | emit_insn (gen_atomic_exchange<mode>_swap (operands[0], operands[1], | |
622 | operands[2])); | |
623 | } | |
624 | else | |
01c196ea TV |
625 | emit_insn (gen_atomic_exchange<mode>_llsc (operands[0], operands[1], |
626 | operands[2], operands[3])); | |
627 | DONE; | |
628 | }) | |
629 | ||
630 | (define_insn "atomic_exchange<mode>_llsc" | |
631 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 632 | (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")] |
01c196ea TV |
633 | UNSPEC_ATOMIC_EXCHANGE)) |
634 | (set (match_dup 1) | |
635 | (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")] | |
636 | UNSPEC_ATOMIC_EXCHANGE)) | |
637 | (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")] | |
638 | UNSPEC_ATOMIC_EXCHANGE)] | |
6399761a | 639 | "GENERATE_LL_SC && !ISA_HAS_SWAP" |
01c196ea TV |
640 | { return mips_output_sync_loop (insn, operands); } |
641 | [(set_attr "sync_insn1" "li,move") | |
642 | (set_attr "sync_oldval" "0") | |
643 | (set_attr "sync_mem" "1") | |
644 | (set_attr "sync_insn1_op2" "2") | |
645 | (set_attr "sync_memmodel" "3")]) | |
646 | ||
6399761a TV |
647 | ;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one. |
648 | (define_insn "atomic_exchange<mode>_swap" | |
649 | [(set (match_operand:GPR 0 "register_operand" "=d") | |
650 | (unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")] | |
651 | UNSPEC_ATOMIC_EXCHANGE)) | |
652 | (set (match_dup 1) | |
653 | (unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "0")] | |
654 | UNSPEC_ATOMIC_EXCHANGE))] | |
655 | "ISA_HAS_SWAP" | |
3088716e MK |
656 | "swap<size>\t%0,%b1" |
657 | [(set_attr "type" "atomic")]) | |
6399761a | 658 | |
01c196ea TV |
659 | (define_expand "atomic_fetch_add<mode>" |
660 | [(match_operand:GPR 0 "register_operand") | |
661 | (match_operand:GPR 1 "memory_operand") | |
662 | (match_operand:GPR 2 "arith_operand") | |
663 | (match_operand:SI 3 "const_int_operand")] | |
6399761a | 664 | "GENERATE_LL_SC || ISA_HAS_LDADD" |
01c196ea | 665 | { |
6399761a TV |
666 | if (ISA_HAS_LDADD) |
667 | { | |
668 | if (!mem_noofs_operand (operands[1], <MODE>mode)) | |
669 | { | |
670 | rtx addr; | |
671 | ||
672 | addr = force_reg (Pmode, XEXP (operands[1], 0)); | |
673 | operands[1] = replace_equiv_address (operands[1], addr); | |
674 | } | |
675 | operands[2] = force_reg (<MODE>mode, operands[2]); | |
676 | emit_insn (gen_atomic_fetch_add<mode>_ldadd (operands[0], operands[1], | |
677 | operands[2])); | |
678 | } | |
679 | else | |
01c196ea TV |
680 | emit_insn (gen_atomic_fetch_add<mode>_llsc (operands[0], operands[1], |
681 | operands[2], operands[3])); | |
682 | DONE; | |
683 | }) | |
684 | ||
685 | (define_insn "atomic_fetch_add<mode>_llsc" | |
686 | [(set (match_operand:GPR 0 "register_operand" "=&d,&d") | |
22c4c869 | 687 | (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")] |
01c196ea TV |
688 | UNSPEC_ATOMIC_FETCH_OP)) |
689 | (set (match_dup 1) | |
690 | (unspec_volatile:GPR | |
691 | [(plus:GPR (match_dup 1) | |
692 | (match_operand:GPR 2 "arith_operand" "I,d"))] | |
693 | UNSPEC_ATOMIC_FETCH_OP)) | |
694 | (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")] | |
695 | UNSPEC_ATOMIC_FETCH_OP)] | |
6399761a | 696 | "GENERATE_LL_SC && !ISA_HAS_LDADD" |
01c196ea TV |
697 | { return mips_output_sync_loop (insn, operands); } |
698 | [(set_attr "sync_insn1" "addiu,addu") | |
699 | (set_attr "sync_oldval" "0") | |
700 | (set_attr "sync_mem" "1") | |
701 | (set_attr "sync_insn1_op2" "2") | |
702 | (set_attr "sync_memmodel" "3")]) | |
6399761a TV |
703 | |
704 | ;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one. | |
705 | (define_insn "atomic_fetch_add<mode>_ldadd" | |
706 | [(set (match_operand:GPR 0 "register_operand" "=d") | |
707 | (unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")] | |
708 | UNSPEC_ATOMIC_FETCH_OP)) | |
709 | (set (match_dup 1) | |
710 | (unspec_volatile:GPR | |
711 | [(plus:GPR (match_dup 1) | |
712 | (match_operand:GPR 2 "register_operand" "0"))] | |
713 | UNSPEC_ATOMIC_FETCH_OP))] | |
714 | "ISA_HAS_LDADD" | |
3088716e MK |
715 | "ldadd<size>\t%0,%b1" |
716 | [(set_attr "type" "atomic")]) |