]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/arm/aarch-common.c
[arm] Early split addvdi4
[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-2019 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 #define IN_TARGET_CODE 1
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "rtl.h"
31 #include "rtl-iter.h"
32 #include "memmodel.h"
33
34 /* Return TRUE if X is either an arithmetic shift left, or
35 is a multiplication by a power of two. */
36 bool
37 arm_rtx_shift_left_p (rtx x)
38 {
39 enum rtx_code code = GET_CODE (x);
40
41 if (code == MULT && CONST_INT_P (XEXP (x, 1))
42 && exact_log2 (INTVAL (XEXP (x, 1))) > 0)
43 return true;
44
45 if (code == ASHIFT)
46 return true;
47
48 return false;
49 }
50
51 static rtx_code shift_rtx_codes[] =
52 { ASHIFT, ROTATE, ASHIFTRT, LSHIFTRT,
53 ROTATERT, ZERO_EXTEND, SIGN_EXTEND };
54
55 /* Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE.
56 If FIND_ANY_SHIFT then we are interested in anything which can
57 reasonably be described as a SHIFT RTX. */
58 static rtx
59 arm_find_sub_rtx_with_code (rtx pattern, rtx_code code, bool find_any_shift)
60 {
61 subrtx_var_iterator::array_type array;
62 FOR_EACH_SUBRTX_VAR (iter, array, pattern, NONCONST)
63 {
64 rtx x = *iter;
65 if (find_any_shift)
66 {
67 /* Left shifts might have been canonicalized to a MULT of some
68 power of two. Make sure we catch them. */
69 if (arm_rtx_shift_left_p (x))
70 return x;
71 else
72 for (unsigned int i = 0; i < ARRAY_SIZE (shift_rtx_codes); i++)
73 if (GET_CODE (x) == shift_rtx_codes[i])
74 return x;
75 }
76
77 if (GET_CODE (x) == code)
78 return x;
79 }
80 return NULL_RTX;
81 }
82
83 /* Traverse PATTERN looking for any sub-rtx which looks like a shift. */
84 static rtx
85 arm_find_shift_sub_rtx (rtx pattern)
86 {
87 return arm_find_sub_rtx_with_code (pattern, ASHIFT, true);
88 }
89
90 /* PRODUCER and CONSUMER are two potentially dependant RTX. PRODUCER
91 (possibly) contains a SET which will provide a result we can access
92 using the SET_DEST macro. We will place the RTX which would be
93 written by PRODUCER in SET_SOURCE.
94 Similarly, CONSUMER (possibly) contains a SET which has an operand
95 we can access using SET_SRC. We place this operand in
96 SET_DESTINATION.
97
98 Return nonzero if we found the SET RTX we expected. */
99 static int
100 arm_get_set_operands (rtx producer, rtx consumer,
101 rtx *set_source, rtx *set_destination)
102 {
103 rtx set_producer = arm_find_sub_rtx_with_code (PATTERN (producer),
104 SET, false);
105 rtx set_consumer = arm_find_sub_rtx_with_code (PATTERN (consumer),
106 SET, false);
107
108 if (set_producer && set_consumer)
109 {
110 *set_source = SET_DEST (set_producer);
111 *set_destination = SET_SRC (set_consumer);
112 return 1;
113 }
114 return 0;
115 }
116
117 bool
118 aarch_rev16_shright_mask_imm_p (rtx val, machine_mode mode)
119 {
120 return CONST_INT_P (val)
121 && INTVAL (val)
122 == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff),
123 mode);
124 }
125
126 bool
127 aarch_rev16_shleft_mask_imm_p (rtx val, machine_mode mode)
128 {
129 return CONST_INT_P (val)
130 && INTVAL (val)
131 == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff00),
132 mode);
133 }
134
135
136 static bool
137 aarch_rev16_p_1 (rtx lhs, rtx rhs, machine_mode mode)
138 {
139 if (GET_CODE (lhs) == AND
140 && GET_CODE (XEXP (lhs, 0)) == ASHIFT
141 && CONST_INT_P (XEXP (XEXP (lhs, 0), 1))
142 && INTVAL (XEXP (XEXP (lhs, 0), 1)) == 8
143 && REG_P (XEXP (XEXP (lhs, 0), 0))
144 && CONST_INT_P (XEXP (lhs, 1))
145 && GET_CODE (rhs) == AND
146 && GET_CODE (XEXP (rhs, 0)) == LSHIFTRT
147 && REG_P (XEXP (XEXP (rhs, 0), 0))
148 && CONST_INT_P (XEXP (XEXP (rhs, 0), 1))
149 && INTVAL (XEXP (XEXP (rhs, 0), 1)) == 8
150 && CONST_INT_P (XEXP (rhs, 1))
151 && REGNO (XEXP (XEXP (rhs, 0), 0)) == REGNO (XEXP (XEXP (lhs, 0), 0)))
152
153 {
154 rtx lhs_mask = XEXP (lhs, 1);
155 rtx rhs_mask = XEXP (rhs, 1);
156
157 return aarch_rev16_shright_mask_imm_p (rhs_mask, mode)
158 && aarch_rev16_shleft_mask_imm_p (lhs_mask, mode);
159 }
160
161 return false;
162 }
163
164 /* Recognise a sequence of bitwise operations corresponding to a rev16 operation.
165 These will be of the form:
166 ((x >> 8) & 0x00ff00ff)
167 | ((x << 8) & 0xff00ff00)
168 for SImode and with similar but wider bitmasks for DImode.
169 The two sub-expressions of the IOR can appear on either side so check both
170 permutations with the help of aarch_rev16_p_1 above. */
171
172 bool
173 aarch_rev16_p (rtx x)
174 {
175 rtx left_sub_rtx, right_sub_rtx;
176 bool is_rev = false;
177
178 if (GET_CODE (x) != IOR)
179 return false;
180
181 left_sub_rtx = XEXP (x, 0);
182 right_sub_rtx = XEXP (x, 1);
183
184 /* There are no canonicalisation rules for the position of the two shifts
185 involved in a rev, so try both permutations. */
186 is_rev = aarch_rev16_p_1 (left_sub_rtx, right_sub_rtx, GET_MODE (x));
187
188 if (!is_rev)
189 is_rev = aarch_rev16_p_1 (right_sub_rtx, left_sub_rtx, GET_MODE (x));
190
191 return is_rev;
192 }
193
194 /* Return non-zero if the RTX representing a memory model is a memory model
195 that needs acquire semantics. */
196 bool
197 aarch_mm_needs_acquire (rtx const_int)
198 {
199 enum memmodel model = memmodel_from_int (INTVAL (const_int));
200 return !(is_mm_relaxed (model)
201 || is_mm_consume (model)
202 || is_mm_release (model));
203 }
204
205 /* Return non-zero if the RTX representing a memory model is a memory model
206 that needs release semantics. */
207 bool
208 aarch_mm_needs_release (rtx const_int)
209 {
210 enum memmodel model = memmodel_from_int (INTVAL (const_int));
211 return !(is_mm_relaxed (model)
212 || is_mm_consume (model)
213 || is_mm_acquire (model));
214 }
215
216 /* Return nonzero if the CONSUMER instruction (a load) does need
217 PRODUCER's value to calculate the address. */
218 int
219 arm_early_load_addr_dep (rtx producer, rtx consumer)
220 {
221 rtx value, addr;
222
223 if (!arm_get_set_operands (producer, consumer, &value, &addr))
224 return 0;
225
226 return reg_overlap_mentioned_p (value, addr);
227 }
228
229 /* Return nonzero if the CONSUMER instruction (a load) does need
230 a Pmode PRODUCER's value to calculate the address. */
231
232 int
233 arm_early_load_addr_dep_ptr (rtx producer, rtx consumer)
234 {
235 rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
236 rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
237
238 if (!value || !addr || !MEM_P (SET_SRC (value)))
239 return 0;
240
241 value = SET_DEST (value);
242 addr = SET_SRC (addr);
243
244 return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
245 }
246
247 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
248 have an early register shift value or amount dependency on the
249 result of PRODUCER. */
250 int
251 arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
252 {
253 rtx value, op;
254 rtx early_op;
255
256 if (!arm_get_set_operands (producer, consumer, &value, &op))
257 return 0;
258
259 if ((early_op = arm_find_shift_sub_rtx (op)))
260 return !reg_overlap_mentioned_p (value, early_op);
261
262 return 0;
263 }
264
265 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
266 have an early register shift value dependency on the result of
267 PRODUCER. */
268 int
269 arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
270 {
271 rtx value, op;
272 rtx early_op;
273
274 if (!arm_get_set_operands (producer, consumer, &value, &op))
275 return 0;
276
277 if ((early_op = arm_find_shift_sub_rtx (op)))
278 /* We want to check the value being shifted. */
279 if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
280 return 1;
281
282 return 0;
283 }
284
285 /* Return nonzero if the CONSUMER (a mul or mac op) does not
286 have an early register mult dependency on the result of
287 PRODUCER. */
288 int
289 arm_no_early_mul_dep (rtx producer, rtx consumer)
290 {
291 rtx value, op;
292
293 if (!arm_get_set_operands (producer, consumer, &value, &op))
294 return 0;
295
296 if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
297 {
298 if (GET_CODE (XEXP (op, 0)) == MULT)
299 return !reg_overlap_mentioned_p (value, XEXP (op, 0));
300 else
301 return !reg_overlap_mentioned_p (value, XEXP (op, 1));
302 }
303
304 return 0;
305 }
306
307 /* Return nonzero if the CONSUMER instruction (a store) does not need
308 PRODUCER's value to calculate the address. */
309
310 int
311 arm_no_early_store_addr_dep (rtx producer, rtx consumer)
312 {
313 rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
314 rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
315
316 if (value)
317 value = SET_DEST (value);
318
319 if (addr)
320 addr = SET_DEST (addr);
321
322 if (!value || !addr)
323 return 0;
324
325 return !reg_overlap_mentioned_p (value, addr);
326 }
327
328 /* Return nonzero if the CONSUMER instruction (a store) does need
329 PRODUCER's value to calculate the address. */
330
331 int
332 arm_early_store_addr_dep (rtx producer, rtx consumer)
333 {
334 return !arm_no_early_store_addr_dep (producer, consumer);
335 }
336
337 /* Return nonzero if the CONSUMER instruction (a store) does need
338 a Pmode PRODUCER's value to calculate the address. */
339
340 int
341 arm_early_store_addr_dep_ptr (rtx producer, rtx consumer)
342 {
343 rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
344 rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
345
346 if (!value || !addr || !MEM_P (SET_SRC (value)))
347 return 0;
348
349 value = SET_DEST (value);
350 addr = SET_DEST (addr);
351
352 return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
353 }
354
355 /* Return non-zero iff the consumer (a multiply-accumulate or a
356 multiple-subtract instruction) has an accumulator dependency on the
357 result of the producer and no other dependency on that result. It
358 does not check if the producer is multiply-accumulate instruction. */
359 int
360 arm_mac_accumulator_is_result (rtx producer, rtx consumer)
361 {
362 rtx result;
363 rtx op0, op1, acc;
364
365 producer = PATTERN (producer);
366 consumer = PATTERN (consumer);
367
368 if (GET_CODE (producer) == COND_EXEC)
369 producer = COND_EXEC_CODE (producer);
370 if (GET_CODE (consumer) == COND_EXEC)
371 consumer = COND_EXEC_CODE (consumer);
372
373 if (GET_CODE (producer) != SET)
374 return 0;
375
376 result = XEXP (producer, 0);
377
378 if (GET_CODE (consumer) != SET)
379 return 0;
380
381 /* Check that the consumer is of the form
382 (set (...) (plus (mult ...) (...)))
383 or
384 (set (...) (minus (...) (mult ...))). */
385 if (GET_CODE (XEXP (consumer, 1)) == PLUS)
386 {
387 if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT)
388 return 0;
389
390 op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0);
391 op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1);
392 acc = XEXP (XEXP (consumer, 1), 1);
393 }
394 else if (GET_CODE (XEXP (consumer, 1)) == MINUS)
395 {
396 if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT)
397 return 0;
398
399 op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0);
400 op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1);
401 acc = XEXP (XEXP (consumer, 1), 0);
402 }
403 else
404 return 0;
405
406 return (reg_overlap_mentioned_p (result, acc)
407 && !reg_overlap_mentioned_p (result, op0)
408 && !reg_overlap_mentioned_p (result, op1));
409 }
410
411 /* Return non-zero if the destination of PRODUCER feeds the accumulator
412 operand of an MLA-like operation. */
413
414 int
415 aarch_accumulator_forwarding (rtx_insn *producer, rtx_insn *consumer)
416 {
417 rtx producer_set = single_set (producer);
418 rtx consumer_set = single_set (consumer);
419
420 /* We are looking for a SET feeding a SET. */
421 if (!producer_set || !consumer_set)
422 return 0;
423
424 rtx dest = SET_DEST (producer_set);
425 rtx mla = SET_SRC (consumer_set);
426
427 /* We're looking for a register SET. */
428 if (!REG_P (dest))
429 return 0;
430
431 rtx accumulator;
432
433 /* Strip a zero_extend. */
434 if (GET_CODE (mla) == ZERO_EXTEND)
435 mla = XEXP (mla, 0);
436
437 switch (GET_CODE (mla))
438 {
439 case PLUS:
440 /* Possibly an MADD. */
441 if (GET_CODE (XEXP (mla, 0)) == MULT)
442 accumulator = XEXP (mla, 1);
443 else
444 return 0;
445 break;
446 case MINUS:
447 /* Possibly an MSUB. */
448 if (GET_CODE (XEXP (mla, 1)) == MULT)
449 accumulator = XEXP (mla, 0);
450 else
451 return 0;
452 break;
453 case FMA:
454 {
455 /* Possibly an FMADD/FMSUB/FNMADD/FNMSUB. */
456 if (REG_P (XEXP (mla, 1))
457 && REG_P (XEXP (mla, 2))
458 && (REG_P (XEXP (mla, 0))
459 || GET_CODE (XEXP (mla, 0)) == NEG))
460
461 {
462 /* FMADD/FMSUB. */
463 accumulator = XEXP (mla, 2);
464 }
465 else if (REG_P (XEXP (mla, 1))
466 && GET_CODE (XEXP (mla, 2)) == NEG
467 && (REG_P (XEXP (mla, 0))
468 || GET_CODE (XEXP (mla, 0)) == NEG))
469 {
470 /* FNMADD/FNMSUB. */
471 accumulator = XEXP (XEXP (mla, 2), 0);
472 }
473 else
474 return 0;
475 break;
476 }
477 default:
478 /* Not an MLA-like operation. */
479 return 0;
480 }
481
482 if (GET_CODE (accumulator) == SUBREG)
483 accumulator = SUBREG_REG (accumulator);
484
485 if (!REG_P (accumulator))
486 return 0;
487
488 return (REGNO (dest) == REGNO (accumulator));
489 }
490
491 /* Return non-zero if the consumer (a multiply-accumulate instruction)
492 has an accumulator dependency on the result of the producer (a
493 multiplication instruction) and no other dependency on that result. */
494 int
495 arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
496 {
497 rtx mul = PATTERN (producer);
498 rtx mac = PATTERN (consumer);
499 rtx mul_result;
500 rtx mac_op0, mac_op1, mac_acc;
501
502 if (GET_CODE (mul) == COND_EXEC)
503 mul = COND_EXEC_CODE (mul);
504 if (GET_CODE (mac) == COND_EXEC)
505 mac = COND_EXEC_CODE (mac);
506
507 /* Check that mul is of the form (set (...) (mult ...))
508 and mla is of the form (set (...) (plus (mult ...) (...))). */
509 if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
510 || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
511 || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
512 return 0;
513
514 mul_result = XEXP (mul, 0);
515 mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
516 mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
517 mac_acc = XEXP (XEXP (mac, 1), 1);
518
519 return (reg_overlap_mentioned_p (mul_result, mac_acc)
520 && !reg_overlap_mentioned_p (mul_result, mac_op0)
521 && !reg_overlap_mentioned_p (mul_result, mac_op1));
522 }