]>
Commit | Line | Data |
---|---|---|
21ed4444 | 1 | ;; GCC machine description for CRIS atomic memory sequences. |
a945c346 | 2 | ;; Copyright (C) 2012-2024 Free Software Foundation, Inc. |
21ed4444 HPN |
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 | ;; The CRIS atomic support yields code in three flavors, depending on | |
21 | ;; the CPU for which code is generated: | |
22 | ;; | |
23 | ;; - Plain old CRIS v0 (..v8) | |
24 | ;; - CRIS v10 (as used in ETRAX 100 LX) | |
21ed4444 | 25 | ;; |
d0780379 | 26 | ;; The second alternative is of LL/SC type. It may |
21ed4444 | 27 | ;; fail for other reasons; an exception, a cache miss or a bus request |
d0780379 | 28 | ;; from other parts of the system. See the chapter on integral read-write |
21ed4444 | 29 | ;; operations, chapter 1.13 in "ETRAX 100LX Programmers Manual", |
d0780379 | 30 | ;; <http://www.axis.com/files/tech_notes/etrax_100lx_prog_man-050519.pdf>. |
21ed4444 HPN |
31 | ;; Note that the datum being stored has to be contained fully within a |
32 | ;; cache-line to be integral. A failure to store the data integrally | |
33 | ;; will be flagged, but the store may still have happened in part, | |
34 | ;; which translates most usefully into the data having to be | |
35 | ;; "naturally aligned" to work. Natural alignment is verified in the | |
36 | ;; generated code and will by default cause for unaligned pointers a | |
37 | ;; "break 8" to be executed or optionally a call to abort(). Beware | |
38 | ;; that options -m16bit and -m8bit may cause data to be unaligned | |
39 | ;; where it was otherwise aligned. Data has a better chance of being | |
40 | ;; aligned if it is declared with e.g. __attribute__ ((__align__ (4))). | |
41 | ;; | |
42 | ;; The "plain old v0..v8 flavor" just assumes there's a single CPU in | |
43 | ;; the system, that no other parts of the system have access to memory | |
44 | ;; used for atomic accesses and since there's no user mode without | |
45 | ;; access to interrupt flags (another assumption), it just turns off | |
46 | ;; interrupts while doing the access. Here, alignment is neither | |
47 | ;; required nor asserted. | |
48 | ||
49 | (define_c_enum "" | |
50 | [ | |
51 | CRIS_UNSPEC_ATOMIC_OP | |
52 | CRIS_UNSPEC_ATOMIC_SWAP_MEM | |
53 | CRIS_UNSPEC_ATOMIC_SWAP_BOOL | |
54 | ]) | |
55 | ||
56 | (define_constants [(CRIS_CCR_INTERRUPT_BIT 5)]) | |
57 | ||
58 | ;; We use "mult" as a placeholder for "nand" (which does not have a | |
59 | ;; separate binary rtx operation) so we can use an iterator in the | |
60 | ;; define_expand and define_insn and avoid having a separate | |
61 | ;; mostly-identical copy. You will see the "mult" operator in rtl | |
62 | ;; dumps, but it shouldn't matter as its use has one of its operands | |
63 | ;; inside an unspec_volatile. | |
64 | ||
65 | (define_code_iterator atomic_op [plus minus ior and xor mult]) | |
66 | ||
67 | (define_code_attr atomic_op_name | |
68 | [(plus "add") (minus "sub") (and "and") (ior "or") (xor "xor") (mult "nand")]) | |
69 | ||
24ddb79c HPN |
70 | ;; The operator nonatomic-operand can be memory, constant or register |
71 | ;; for all but xor. We can't use memory or addressing modes with | |
72 | ;; side-effects though, so just use registers and literal constants. | |
73 | (define_code_attr atomic_op_op_cnstr | |
74 | [(plus "ri") (minus "ri") (and "ri") (ior "ri") (xor "r") (mult "ri")]) | |
75 | ||
76 | (define_code_attr atomic_op_op_pred | |
77 | [(plus "nonmemory_operand") (minus "nonmemory_operand") | |
78 | (and "nonmemory_operand") (ior "nonmemory_operand") | |
79 | (xor "register_operand") (mult "nonmemory_operand")]) | |
80 | ||
21ed4444 | 81 | ;; Pairs of these are used to insert the "not" after the "and" for nand. |
24ddb79c HPN |
82 | (define_code_attr atomic_op_mnem_pre_op2 ;; Upper-case only to simplify testing. |
83 | [(plus "%P2") (minus "Sub.d %2") (and "And%q2 %2") (ior "Or%q2 %2") (xor "Xor %2") | |
84 | (mult "aNd%q2 %2")]) | |
85 | ||
21ed4444 HPN |
86 | (define_code_attr atomic_op_mnem_post_op3 |
87 | [(plus "") (minus "") (and "") (ior "") (xor "") (mult "not %3\;")]) | |
88 | ||
24ddb79c HPN |
89 | ;; For SImode, emit "q" for operands -31..31. |
90 | (define_mode_attr qm3 [(SI "%q3") (HI ".w") (QI ".b")]) | |
91 | ||
21ed4444 HPN |
92 | (define_expand "atomic_fetch_<atomic_op_name><mode>" |
93 | [(match_operand:BWD 0 "register_operand") | |
94 | (match_operand:BWD 1 "memory_operand") | |
24ddb79c | 95 | (match_operand:BWD 2 "<atomic_op_op_pred>") |
21ed4444 HPN |
96 | (match_operand 3) |
97 | (atomic_op:BWD (match_dup 0) (match_dup 1))] | |
64e544ef | 98 | "<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS" |
21ed4444 | 99 | { |
2f352e3d HPN |
100 | enum memmodel mmodel = (enum memmodel) INTVAL (operands[3]); |
101 | ||
21ed4444 HPN |
102 | if (<MODE>mode != QImode && TARGET_TRAP_UNALIGNED_ATOMIC) |
103 | cris_emit_trap_for_misalignment (operands[1]); | |
104 | ||
fdb6272c HPN |
105 | if (need_atomic_barrier_p (mmodel, true)) |
106 | expand_mem_thread_fence (mmodel); | |
107 | ||
21ed4444 HPN |
108 | emit_insn (gen_cris_atomic_fetch_<atomic_op_name><mode>_1 (operands[0], |
109 | operands[1], | |
110 | operands[2])); | |
fdb6272c HPN |
111 | if (need_atomic_barrier_p (mmodel, false)) |
112 | expand_mem_thread_fence (mmodel); | |
113 | ||
21ed4444 HPN |
114 | DONE; |
115 | }) | |
116 | ||
117 | (define_insn "cris_atomic_fetch_<atomic_op_name><mode>_1" | |
118 | [(set (match_operand:BWD 1 "memory_operand" "+Q") | |
119 | (atomic_op:BWD | |
120 | (unspec_volatile:BWD [(match_dup 1)] CRIS_UNSPEC_ATOMIC_OP) | |
24ddb79c HPN |
121 | ;; FIXME: improve constants more for plus, minus, and, ior. |
122 | ;; FIXME: handle memory operands without side-effects. | |
123 | (match_operand:BWD 2 "<atomic_op_op_pred>" "<atomic_op_op_cnstr>"))) | |
21ed4444 HPN |
124 | (set (match_operand:BWD 0 "register_operand" "=&r") |
125 | (match_dup 1)) | |
fb062a8b HPN |
126 | (clobber (match_scratch:SI 3 "=&r")) |
127 | (clobber (reg:CC CRIS_CC0_REGNUM))] | |
dec4306f | 128 | "<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS" |
21ed4444 HPN |
129 | { |
130 | /* Can't be too sure; better ICE if this happens. */ | |
1e98f060 HPN |
131 | gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]) |
132 | && !reg_overlap_mentioned_p (operands[0], operands[2]) | |
133 | && !reg_overlap_mentioned_p (operands[0], operands[3]) | |
134 | && !reg_overlap_mentioned_p (operands[1], operands[3]) | |
135 | && !reg_overlap_mentioned_p (operands[2], operands[3])); | |
21ed4444 | 136 | |
d0780379 | 137 | if (cris_cpu_version == 10) |
21ed4444 HPN |
138 | return |
139 | "clearf\n" | |
140 | ".Lsync.%=:\;" | |
141 | "move<m> %1,%0\;" | |
142 | "move.d %0,%3\;" | |
24ddb79c | 143 | "<atomic_op_mnem_pre_op2>,%3\;<atomic_op_mnem_post_op3>" |
21ed4444 HPN |
144 | "ax\;" |
145 | "move<m> %3,%1\;" | |
146 | "bwf .Lsync.%=\;" | |
147 | "clearf"; | |
148 | else | |
149 | { | |
150 | /* This one is for CRIS versions without load-locked-store-conditional | |
151 | machinery; assume single-core-non-shared-memory without user | |
152 | mode/supervisor mode distinction, and just disable interrupts | |
153 | while performing the operation. | |
154 | Rather than making this pattern more complex by freeing another | |
155 | register or stack position to save condition codes (the value | |
156 | of the interrupt-enabled bit), we check whether interrupts were | |
157 | enabled before we disabled them and branch to a version | |
158 | with/without afterwards re-enabling them. */ | |
159 | rtx ops[5]; | |
160 | ||
161 | /* We have no available macro to stringify CRIS_CCR_INTERRUPT_BIT. */ | |
162 | memcpy (ops, operands, sizeof(ops)); | |
163 | ops[4] = GEN_INT (CRIS_CCR_INTERRUPT_BIT); | |
164 | ||
165 | output_asm_insn ("move $ccr,%3\;" | |
166 | "di\;" | |
167 | "move<m> %1,%0\;" | |
168 | "btstq %4,%3", | |
169 | ops); | |
170 | return | |
171 | "bmi .Lsync.irqon.%=\;" | |
172 | "move.d %0,%3\;" | |
173 | ||
24ddb79c | 174 | "<atomic_op_mnem_pre_op2>,%3\;<atomic_op_mnem_post_op3>" |
21ed4444 HPN |
175 | "ba .Lsync.irqoff.%=\;" |
176 | "move<m> %3,%1\n" | |
177 | ||
178 | ".Lsync.irqon.%=:\;" | |
24ddb79c | 179 | "<atomic_op_mnem_pre_op2>,%3\;<atomic_op_mnem_post_op3>" |
21ed4444 HPN |
180 | "move<m> %3,%1\;" |
181 | "ei\n" | |
182 | ".Lsync.irqoff.%=:"; | |
183 | } | |
184 | }) | |
185 | ||
186 | ;; This pattern is more-or-less assumed to always exist if any of the | |
187 | ;; other atomic patterns exist (see e.g. comment at the | |
e53b6e56 | 188 | ;; can_compare_and_swap_p call in omp-low.cc, 4.8 era). We'd slightly |
21ed4444 HPN |
189 | ;; prefer atomic_exchange<mode> over this, but having both would be |
190 | ;; redundant. | |
1cdea33b | 191 | ;; FIXME: handle memory without side-effects for operand[3]. |
21ed4444 HPN |
192 | (define_expand "atomic_compare_and_swap<mode>" |
193 | [(match_operand:SI 0 "register_operand") | |
194 | (match_operand:BWD 1 "register_operand") | |
195 | (match_operand:BWD 2 "memory_operand") | |
1cdea33b | 196 | (match_operand:BWD 3 "nonmemory_operand") |
21ed4444 HPN |
197 | (match_operand:BWD 4 "register_operand") |
198 | (match_operand 5) | |
199 | (match_operand 6) | |
200 | (match_operand 7)] | |
dec4306f | 201 | "<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS" |
21ed4444 | 202 | { |
2f352e3d HPN |
203 | enum memmodel mmodel = (enum memmodel) INTVAL (operands[6]); |
204 | ||
21ed4444 HPN |
205 | if (<MODE>mode != QImode && TARGET_TRAP_UNALIGNED_ATOMIC) |
206 | cris_emit_trap_for_misalignment (operands[2]); | |
207 | ||
fdb6272c HPN |
208 | if (need_atomic_barrier_p (mmodel, true)) |
209 | expand_mem_thread_fence (mmodel); | |
210 | ||
21ed4444 HPN |
211 | emit_insn (gen_cris_atomic_compare_and_swap<mode>_1 (operands[0], |
212 | operands[1], | |
213 | operands[2], | |
214 | operands[3], | |
215 | operands[4])); | |
fdb6272c HPN |
216 | if (need_atomic_barrier_p (mmodel, false)) |
217 | expand_mem_thread_fence (mmodel); | |
218 | ||
21ed4444 HPN |
219 | DONE; |
220 | }) | |
221 | ||
222 | (define_insn "cris_atomic_compare_and_swap<mode>_1" | |
223 | [(set (match_operand:SI 0 "register_operand" "=&r") | |
224 | (unspec_volatile:SI | |
225 | [(match_operand:BWD 2 "memory_operand" "+Q") | |
1cdea33b | 226 | (match_operand:BWD 3 "nonmemory_operand" "ri")] |
21ed4444 HPN |
227 | CRIS_UNSPEC_ATOMIC_SWAP_BOOL)) |
228 | (set (match_operand:BWD 1 "register_operand" "=&r") (match_dup 2)) | |
229 | (set (match_dup 2) | |
230 | (unspec_volatile:BWD | |
231 | [(match_dup 2) | |
232 | (match_dup 3) | |
233 | (match_operand:BWD 4 "register_operand" "r")] | |
fb062a8b HPN |
234 | CRIS_UNSPEC_ATOMIC_SWAP_MEM)) |
235 | (clobber (reg:CC CRIS_CC0_REGNUM))] | |
dec4306f | 236 | "<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS" |
21ed4444 | 237 | { |
d0780379 | 238 | if (cris_cpu_version == 10) |
21ed4444 | 239 | return |
24ddb79c HPN |
240 | "\n.Lsync.repeat.%=:\;" |
241 | "clearf\;" | |
21ed4444 | 242 | "move<m> %2,%1\;" |
24ddb79c | 243 | "cmp<qm3> %3,%1\;" |
21ed4444 | 244 | "bne .Lsync.after.%=\;" |
21ed4444 | 245 | "ax\;" |
24ddb79c | 246 | |
21ed4444 | 247 | "move<m> %4,%2\;" |
24ddb79c HPN |
248 | "bwf .Lsync.repeat.%=\n" |
249 | ".Lsync.after.%=:\;" | |
250 | "seq %0"; | |
21ed4444 HPN |
251 | else |
252 | { | |
253 | /* This one is for CRIS versions without load-locked-store-conditional | |
254 | machinery; assume single-core-non-shared-memory without user | |
255 | mode/supervisor mode distinction, and just disable interrupts | |
256 | while performing the operation. | |
257 | Rather than making this pattern more complex by freeing another | |
258 | register or stack position to save condition codes (the value | |
259 | of the interrupt-enabled bit), we check whether interrupts were | |
260 | enabled before we disabled them and branch to a version | |
261 | with/without afterwards re-enabling them. */ | |
262 | rtx ops[4]; | |
263 | ||
264 | /* We have no available macro to stringify CRIS_CCR_INTERRUPT_BIT. */ | |
265 | memcpy (ops, operands, sizeof(ops)); | |
266 | ops[3] = GEN_INT (CRIS_CCR_INTERRUPT_BIT); | |
267 | ||
268 | output_asm_insn ("move $ccr,%0\;" | |
269 | "di\;" | |
270 | "move<m> %2,%1\;" | |
271 | "btstq %3,%0", | |
272 | ops); | |
273 | return | |
274 | "bmi .Lsync.irqon.%=\;" | |
275 | "nop\;" | |
276 | ||
24ddb79c | 277 | "cmp<qm3> %3,%1\;" |
21ed4444 HPN |
278 | "bne .Lsync.after.%=\;" |
279 | "seq %0\;" | |
280 | "ba .Lsync.after.%=\;" | |
281 | "move<m> %4,%2\n" | |
282 | ||
283 | ".Lsync.irqon.%=:\;" | |
24ddb79c | 284 | "cmp<qm3> %3,%1\;" |
21ed4444 HPN |
285 | "bne .Lsync.after.%=\;" |
286 | "seq %0\;" | |
287 | "move<m> %4,%2\;" | |
288 | "ei\n" | |
289 | ".Lsync.after.%=:"; | |
290 | } | |
291 | }) |