annotate gcc/config/cris/sync.md @ 111:04ced10e8804

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