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