]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/arm/aarch-common.c
Update copyright years in gcc/
[thirdparty/gcc.git] / gcc / config / arm / aarch-common.c
1 /* Dependency checks for instruction scheduling, shared between ARM and
2 AARCH64.
3
4 Copyright (C) 1991-2014 Free Software Foundation, Inc.
5 Contributed by ARM Ltd.
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 3, or (at your
12 option) any later version.
13
14 GCC is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
22
23
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "tm_p.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "c-family/c-common.h"
32 #include "rtl.h"
33
34 typedef struct
35 {
36 rtx_code search_code;
37 rtx search_result;
38 bool find_any_shift;
39 } search_term;
40
41 /* Return TRUE if X is either an arithmetic shift left, or
42 is a multiplication by a power of two. */
43 bool
44 arm_rtx_shift_left_p (rtx x)
45 {
46 enum rtx_code code = GET_CODE (x);
47
48 if (code == MULT && CONST_INT_P (XEXP (x, 1))
49 && exact_log2 (INTVAL (XEXP (x, 1))) > 0)
50 return true;
51
52 if (code == ASHIFT)
53 return true;
54
55 return false;
56 }
57
58 static rtx_code shift_rtx_codes[] =
59 { ASHIFT, ROTATE, ASHIFTRT, LSHIFTRT,
60 ROTATERT, ZERO_EXTEND, SIGN_EXTEND };
61
62 /* Callback function for arm_find_sub_rtx_with_code.
63 DATA is safe to treat as a SEARCH_TERM, ST. This will
64 hold a SEARCH_CODE. PATTERN is checked to see if it is an
65 RTX with that code. If it is, write SEARCH_RESULT in ST
66 and return 1. Otherwise, or if we have been passed a NULL_RTX
67 return 0. If ST.FIND_ANY_SHIFT then we are interested in
68 anything which can reasonably be described as a SHIFT RTX. */
69 static int
70 arm_find_sub_rtx_with_search_term (rtx *pattern, void *data)
71 {
72 search_term *st = (search_term *) data;
73 rtx_code pattern_code;
74 int found = 0;
75
76 gcc_assert (pattern);
77 gcc_assert (st);
78
79 /* Poorly formed patterns can really ruin our day. */
80 if (*pattern == NULL_RTX)
81 return 0;
82
83 pattern_code = GET_CODE (*pattern);
84
85 if (st->find_any_shift)
86 {
87 unsigned i = 0;
88
89 /* Left shifts might have been canonicalized to a MULT of some
90 power of two. Make sure we catch them. */
91 if (arm_rtx_shift_left_p (*pattern))
92 found = 1;
93 else
94 for (i = 0; i < ARRAY_SIZE (shift_rtx_codes); i++)
95 if (pattern_code == shift_rtx_codes[i])
96 found = 1;
97 }
98
99 if (pattern_code == st->search_code)
100 found = 1;
101
102 if (found)
103 st->search_result = *pattern;
104
105 return found;
106 }
107
108 /* Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE. */
109 static rtx
110 arm_find_sub_rtx_with_code (rtx pattern, rtx_code code, bool find_any_shift)
111 {
112 search_term st;
113 int result = 0;
114
115 gcc_assert (pattern != NULL_RTX);
116 st.search_code = code;
117 st.search_result = NULL_RTX;
118 st.find_any_shift = find_any_shift;
119 result = for_each_rtx (&pattern, arm_find_sub_rtx_with_search_term, &st);
120 if (result)
121 return st.search_result;
122 else
123 return NULL_RTX;
124 }
125
126 /* Traverse PATTERN looking for any sub-rtx which looks like a shift. */
127 static rtx
128 arm_find_shift_sub_rtx (rtx pattern)
129 {
130 return arm_find_sub_rtx_with_code (pattern, ASHIFT, true);
131 }
132
133 /* PRODUCER and CONSUMER are two potentially dependant RTX. PRODUCER
134 (possibly) contains a SET which will provide a result we can access
135 using the SET_DEST macro. We will place the RTX which would be
136 written by PRODUCER in SET_SOURCE.
137 Similarly, CONSUMER (possibly) contains a SET which has an operand
138 we can access using SET_SRC. We place this operand in
139 SET_DESTINATION.
140
141 Return nonzero if we found the SET RTX we expected. */
142 static int
143 arm_get_set_operands (rtx producer, rtx consumer,
144 rtx *set_source, rtx *set_destination)
145 {
146 rtx set_producer = arm_find_sub_rtx_with_code (producer, SET, false);
147 rtx set_consumer = arm_find_sub_rtx_with_code (consumer, SET, false);
148
149 if (set_producer && set_consumer)
150 {
151 *set_source = SET_DEST (set_producer);
152 *set_destination = SET_SRC (set_consumer);
153 return 1;
154 }
155 return 0;
156 }
157
158 /* Return nonzero if the CONSUMER instruction (a load) does need
159 PRODUCER's value to calculate the address. */
160 int
161 arm_early_load_addr_dep (rtx producer, rtx consumer)
162 {
163 rtx value, addr;
164
165 if (!arm_get_set_operands (producer, consumer, &value, &addr))
166 return 0;
167
168 return reg_overlap_mentioned_p (value, addr);
169 }
170
171 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
172 have an early register shift value or amount dependency on the
173 result of PRODUCER. */
174 int
175 arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
176 {
177 rtx value, op;
178 rtx early_op;
179
180 if (!arm_get_set_operands (producer, consumer, &value, &op))
181 return 0;
182
183 if ((early_op = arm_find_shift_sub_rtx (op)))
184 {
185 if (REG_P (early_op))
186 early_op = op;
187
188 return !reg_overlap_mentioned_p (value, early_op);
189 }
190
191 return 0;
192 }
193
194 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
195 have an early register shift value dependency on the result of
196 PRODUCER. */
197 int
198 arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
199 {
200 rtx value, op;
201 rtx early_op;
202
203 if (!arm_get_set_operands (producer, consumer, &value, &op))
204 return 0;
205
206 if ((early_op = arm_find_shift_sub_rtx (op)))
207 /* We want to check the value being shifted. */
208 if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
209 return 1;
210
211 return 0;
212 }
213
214 /* Return nonzero if the CONSUMER (a mul or mac op) does not
215 have an early register mult dependency on the result of
216 PRODUCER. */
217 int
218 arm_no_early_mul_dep (rtx producer, rtx consumer)
219 {
220 rtx value, op;
221
222 if (!arm_get_set_operands (producer, consumer, &value, &op))
223 return 0;
224
225 if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
226 {
227 if (GET_CODE (XEXP (op, 0)) == MULT)
228 return !reg_overlap_mentioned_p (value, XEXP (op, 0));
229 else
230 return !reg_overlap_mentioned_p (value, XEXP (op, 1));
231 }
232
233 return 0;
234 }
235
236 /* Return nonzero if the CONSUMER instruction (a store) does not need
237 PRODUCER's value to calculate the address. */
238
239 int
240 arm_no_early_store_addr_dep (rtx producer, rtx consumer)
241 {
242 rtx value = arm_find_sub_rtx_with_code (producer, SET, false);
243 rtx addr = arm_find_sub_rtx_with_code (consumer, SET, false);
244
245 if (value)
246 value = SET_DEST (value);
247
248 if (addr)
249 addr = SET_DEST (addr);
250
251 if (!value || !addr)
252 return 0;
253
254 return !reg_overlap_mentioned_p (value, addr);
255 }
256
257 /* Return nonzero if the CONSUMER instruction (a store) does need
258 PRODUCER's value to calculate the address. */
259
260 int
261 arm_early_store_addr_dep (rtx producer, rtx consumer)
262 {
263 return !arm_no_early_store_addr_dep (producer, consumer);
264 }
265
266 /* Return non-zero iff the consumer (a multiply-accumulate or a
267 multiple-subtract instruction) has an accumulator dependency on the
268 result of the producer and no other dependency on that result. It
269 does not check if the producer is multiply-accumulate instruction. */
270 int
271 arm_mac_accumulator_is_result (rtx producer, rtx consumer)
272 {
273 rtx result;
274 rtx op0, op1, acc;
275
276 producer = PATTERN (producer);
277 consumer = PATTERN (consumer);
278
279 if (GET_CODE (producer) == COND_EXEC)
280 producer = COND_EXEC_CODE (producer);
281 if (GET_CODE (consumer) == COND_EXEC)
282 consumer = COND_EXEC_CODE (consumer);
283
284 if (GET_CODE (producer) != SET)
285 return 0;
286
287 result = XEXP (producer, 0);
288
289 if (GET_CODE (consumer) != SET)
290 return 0;
291
292 /* Check that the consumer is of the form
293 (set (...) (plus (mult ...) (...)))
294 or
295 (set (...) (minus (...) (mult ...))). */
296 if (GET_CODE (XEXP (consumer, 1)) == PLUS)
297 {
298 if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT)
299 return 0;
300
301 op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0);
302 op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1);
303 acc = XEXP (XEXP (consumer, 1), 1);
304 }
305 else if (GET_CODE (XEXP (consumer, 1)) == MINUS)
306 {
307 if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT)
308 return 0;
309
310 op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0);
311 op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1);
312 acc = XEXP (XEXP (consumer, 1), 0);
313 }
314 else
315 return 0;
316
317 return (reg_overlap_mentioned_p (result, acc)
318 && !reg_overlap_mentioned_p (result, op0)
319 && !reg_overlap_mentioned_p (result, op1));
320 }
321
322 /* Return non-zero if the consumer (a multiply-accumulate instruction)
323 has an accumulator dependency on the result of the producer (a
324 multiplication instruction) and no other dependency on that result. */
325 int
326 arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
327 {
328 rtx mul = PATTERN (producer);
329 rtx mac = PATTERN (consumer);
330 rtx mul_result;
331 rtx mac_op0, mac_op1, mac_acc;
332
333 if (GET_CODE (mul) == COND_EXEC)
334 mul = COND_EXEC_CODE (mul);
335 if (GET_CODE (mac) == COND_EXEC)
336 mac = COND_EXEC_CODE (mac);
337
338 /* Check that mul is of the form (set (...) (mult ...))
339 and mla is of the form (set (...) (plus (mult ...) (...))). */
340 if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
341 || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
342 || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
343 return 0;
344
345 mul_result = XEXP (mul, 0);
346 mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
347 mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
348 mac_acc = XEXP (XEXP (mac, 1), 1);
349
350 return (reg_overlap_mentioned_p (mul_result, mac_acc)
351 && !reg_overlap_mentioned_p (mul_result, mac_op0)
352 && !reg_overlap_mentioned_p (mul_result, mac_op1));
353 }