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