]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/compare-elim.c
Update copyright years.
[thirdparty/gcc.git] / gcc / compare-elim.c
CommitLineData
e692f276 1/* Post-reload compare elimination.
7adcbafe 2 Copyright (C) 2010-2022 Free Software Foundation, Inc.
e692f276
RH
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20/* There is a set of targets whose general-purpose move or addition
21 instructions clobber the flags. These targets cannot split their
22 CBRANCH/CSTORE etc patterns before reload is complete, lest reload
23 itself insert these instructions in between the flags setter and user.
24 Because these targets cannot split the compare from the use, they
25 cannot make use of the comparison elimination offered by the combine pass.
26
27 This is a small pass intended to provide comparison elimination similar to
bd1cd0d0 28 what was available via NOTICE_UPDATE_CC for cc0 targets.
e692f276
RH
29
30 This pass assumes:
31
32 (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
33
34 (1) All comparison patterns are represented as
35
6c6a593d 36 [(set (reg:CC) (compare:CC (reg) (reg_or_immediate)))]
e692f276
RH
37
38 (2) All insn patterns that modify the flags are represented as
39
40 [(set (reg) (operation)
41 (clobber (reg:CC))]
42
43 (3) If an insn of form (2) can usefully set the flags, there is
44 another pattern of the form
45
4f0473fe
UB
46 [(set (reg:CCM) (compare:CCM (operation) (immediate)))
47 (set (reg) (operation)]
48
e692f276
RH
49 The mode CCM will be chosen as if by SELECT_CC_MODE.
50
51 Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
52 This could be handled as a future enhancement.
53*/
54
55#include "config.h"
56#include "system.h"
57#include "coretypes.h"
c7131fb2 58#include "backend.h"
957060b5 59#include "target.h"
e692f276 60#include "rtl.h"
c7131fb2 61#include "df.h"
4d0cdd0c 62#include "memmodel.h"
e692f276
RH
63#include "tm_p.h"
64#include "insn-config.h"
65#include "recog.h"
d7840b47 66#include "emit-rtl.h"
60393bbc 67#include "cfgrtl.h"
e692f276 68#include "tree-pass.h"
e692f276
RH
69#include "domwalk.h"
70
71\f
72/* These structures describe a comparison and how it is used. */
73
74/* The choice of maximum 3 uses comes from wanting to eliminate the two
75 duplicate compares from a three-way branch on the sign of a value.
76 This is also sufficient to eliminate the duplicate compare against the
77 high-part of a double-word comparison. */
78#define MAX_CMP_USE 3
79
80struct comparison_use
81{
82 /* The instruction in which the result of the compare is used. */
c566b828 83 rtx_insn *insn;
e692f276
RH
84 /* The location of the flags register within the use. */
85 rtx *loc;
86 /* The comparison code applied against the flags register. */
87 enum rtx_code code;
88};
89
90struct comparison
91{
92 /* The comparison instruction. */
c566b828 93 rtx_insn *insn;
e692f276
RH
94
95 /* The insn prior to the comparison insn that clobbers the flags. */
c566b828 96 rtx_insn *prev_clobber;
e692f276 97
efc04f78
JJ
98 /* The insn prior to the comparison insn that sets in_a REG. */
99 rtx_insn *in_a_setter;
100
e692f276
RH
101 /* The two values being compared. These will be either REGs or
102 constants. */
103 rtx in_a, in_b;
104
08281ce0
RH
105 /* The REG_EH_REGION of the comparison. */
106 rtx eh_note;
107
e692f276
RH
108 /* Information about how this comparison is used. */
109 struct comparison_use uses[MAX_CMP_USE];
110
111 /* The original CC_MODE for this comparison. */
ef4bddc2 112 machine_mode orig_mode;
e692f276
RH
113
114 /* The number of uses identified for this comparison. */
115 unsigned short n_uses;
116
117 /* True if not all uses of this comparison have been identified.
118 This can happen either for overflowing the array above, or if
119 the flags register is used in some unusual context. */
120 bool missing_uses;
121
122 /* True if its inputs are still valid at the end of the block. */
123 bool inputs_valid;
0ea52812
EB
124
125 /* Whether IN_A is wrapped in a NOT before being compared. */
126 bool not_in_a;
e692f276
RH
127};
128
526ceb68 129static vec<comparison *> all_compares;
e692f276 130
0ea52812
EB
131/* Return whether X is a NOT unary expression. */
132
133static bool
134is_not (rtx x)
135{
136 return GET_CODE (x) == NOT;
137}
138
139/* Strip a NOT unary expression around X, if any. */
140
141static rtx
142strip_not (rtx x)
143{
144 if (is_not (x))
145 return XEXP (x, 0);
146
147 return x;
148}
149
e692f276
RH
150/* Look for a "conforming" comparison, as defined above. If valid, return
151 the rtx for the COMPARE itself. */
152
153static rtx
c566b828 154conforming_compare (rtx_insn *insn)
e692f276
RH
155{
156 rtx set, src, dest;
157
158 set = single_set (insn);
159 if (set == NULL)
160 return NULL;
161
162 src = SET_SRC (set);
163 if (GET_CODE (src) != COMPARE)
164 return NULL;
165
166 dest = SET_DEST (set);
167 if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
168 return NULL;
169
0ea52812 170 if (!REG_P (strip_not (XEXP (src, 0))))
2c35bbe1
EB
171 return NULL;
172
173 if (CONSTANT_P (XEXP (src, 1)) || REG_P (XEXP (src, 1)))
e692f276
RH
174 return src;
175
2c35bbe1
EB
176 if (GET_CODE (XEXP (src, 1)) == UNSPEC)
177 {
178 for (int i = 0; i < XVECLEN (XEXP (src, 1), 0); i++)
179 if (!REG_P (XVECEXP (XEXP (src, 1), 0, i)))
180 return NULL;
181 return src;
182 }
183
e692f276
RH
184 return NULL;
185}
186
187/* Look for a pattern of the "correct" form for an insn with a flags clobber
188 for which we may be able to eliminate a compare later. We're not looking
189 to validate any inputs at this time, merely see that the basic shape is
190 correct. The term "arithmetic" may be somewhat misleading... */
191
192static bool
c566b828 193arithmetic_flags_clobber_p (rtx_insn *insn)
e692f276
RH
194{
195 rtx pat, x;
196
197 if (!NONJUMP_INSN_P (insn))
198 return false;
199 pat = PATTERN (insn);
93671519 200 if (asm_noperands (pat) >= 0)
e692f276
RH
201 return false;
202
203 if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
204 {
205 x = XVECEXP (pat, 0, 0);
206 if (GET_CODE (x) != SET)
207 return false;
208 x = SET_DEST (x);
209 if (!REG_P (x))
210 return false;
211
212 x = XVECEXP (pat, 0, 1);
213 if (GET_CODE (x) == CLOBBER)
214 {
215 x = XEXP (x, 0);
216 if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
217 return true;
218 }
219 }
220
221 return false;
222}
223
224/* Look for uses of FLAGS in INSN. If we find one we can analyze, record
225 it in CMP; otherwise indicate that we've missed a use. */
226
227static void
c566b828 228find_flags_uses_in_insn (struct comparison *cmp, rtx_insn *insn)
e692f276 229{
bfac633a 230 df_ref use;
e692f276
RH
231
232 /* If we've already lost track of uses, don't bother collecting more. */
233 if (cmp->missing_uses)
234 return;
235
236 /* Find a USE of the flags register. */
bfac633a 237 FOR_EACH_INSN_USE (use, insn)
e692f276
RH
238 if (DF_REF_REGNO (use) == targetm.flags_regnum)
239 {
240 rtx x, *loc;
241
242 /* If this is an unusual use, quit. */
243 if (DF_REF_TYPE (use) != DF_REF_REG_USE)
244 goto fail;
245
246 /* If we've run out of slots to record uses, quit. */
247 if (cmp->n_uses == MAX_CMP_USE)
248 goto fail;
249
250 /* Unfortunately the location of the flags register, while present
251 in the reference structure, doesn't help. We need to find the
252 comparison code that is outer to the actual flags use. */
253 loc = DF_REF_LOC (use);
254 x = PATTERN (insn);
255 if (GET_CODE (x) == PARALLEL)
256 x = XVECEXP (x, 0, 0);
257 x = SET_SRC (x);
258 if (GET_CODE (x) == IF_THEN_ELSE)
259 x = XEXP (x, 0);
260 if (COMPARISON_P (x)
261 && loc == &XEXP (x, 0)
262 && XEXP (x, 1) == const0_rtx)
263 {
264 /* We've found a use of the flags that we understand. */
265 struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
266 cuse->insn = insn;
267 cuse->loc = loc;
268 cuse->code = GET_CODE (x);
269 }
270 else
271 goto fail;
272 }
273 return;
274
275 fail:
276 /* We failed to recognize this use of the flags register. */
277 cmp->missing_uses = true;
278}
279
4d9192b5
TS
280class find_comparison_dom_walker : public dom_walker
281{
282public:
283 find_comparison_dom_walker (cdi_direction direction)
c3284718 284 : dom_walker (direction) {}
4d9192b5 285
3daacdcd 286 virtual edge before_dom_children (basic_block);
4d9192b5
TS
287};
288
6c6a593d
EB
289/* Return true if conforming COMPARE with EH_NOTE is redundant with comparison
290 CMP and can thus be eliminated. */
291
292static bool
293can_eliminate_compare (rtx compare, rtx eh_note, struct comparison *cmp)
294{
295 /* Take care that it's in the same EH region. */
296 if (cfun->can_throw_non_call_exceptions
297 && !rtx_equal_p (eh_note, cmp->eh_note))
298 return false;
299
300 /* Make sure the compare is redundant with the previous. */
0ea52812 301 if (!rtx_equal_p (strip_not (XEXP (compare, 0)), cmp->in_a)
6c6a593d
EB
302 || !rtx_equal_p (XEXP (compare, 1), cmp->in_b))
303 return false;
304
0ea52812
EB
305 if (is_not (XEXP (compare, 0)) != cmp->not_in_a)
306 return false;
307
6c6a593d 308 /* New mode must be compatible with the previous compare mode. */
b8506a8a 309 machine_mode new_mode
6c6a593d
EB
310 = targetm.cc_modes_compatible (GET_MODE (compare), cmp->orig_mode);
311
312 if (new_mode == VOIDmode)
313 return false;
314
315 if (cmp->orig_mode != new_mode)
316 {
317 /* Generate new comparison for substitution. */
318 rtx flags = gen_rtx_REG (new_mode, targetm.flags_regnum);
319 rtx x = gen_rtx_COMPARE (new_mode, cmp->in_a, cmp->in_b);
f7df4a84 320 x = gen_rtx_SET (flags, x);
6c6a593d
EB
321
322 if (!validate_change (cmp->insn, &PATTERN (cmp->insn), x, false))
323 return false;
324
325 cmp->orig_mode = new_mode;
326 }
327
328 return true;
329}
330
e692f276
RH
331/* Identify comparison instructions within BB. If the flags from the last
332 compare in the BB is live at the end of the block, install the compare
4d9192b5 333 in BB->AUX. Called via dom_walker.walk (). */
e692f276 334
3daacdcd 335edge
4d9192b5 336find_comparison_dom_walker::before_dom_children (basic_block bb)
e692f276 337{
efc04f78 338 rtx_insn *insn, *next;
08281ce0 339 bool need_purge = false;
efc04f78 340 rtx_insn *last_setter[FIRST_PSEUDO_REGISTER];
e692f276
RH
341
342 /* The last comparison that was made. Will be reset to NULL
343 once the flags are clobbered. */
efc04f78 344 struct comparison *last_cmp = NULL;
e692f276
RH
345
346 /* True iff the last comparison has not been clobbered, nor
347 have its inputs. Used to eliminate duplicate compares. */
efc04f78 348 bool last_cmp_valid = false;
e692f276
RH
349
350 /* The last insn that clobbered the flags, if that insn is of
351 a form that may be valid for eliminating a following compare.
352 To be reset to NULL once the flags are set otherwise. */
efc04f78 353 rtx_insn *last_clobber = NULL;
e692f276
RH
354
355 /* Propagate the last live comparison throughout the extended basic block. */
356 if (single_pred_p (bb))
357 {
358 last_cmp = (struct comparison *) single_pred (bb)->aux;
359 if (last_cmp)
360 last_cmp_valid = last_cmp->inputs_valid;
361 }
362
efc04f78 363 memset (last_setter, 0, sizeof (last_setter));
e692f276
RH
364 for (insn = BB_HEAD (bb); insn; insn = next)
365 {
366 rtx src;
367
c566b828 368 next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
e692f276
RH
369 if (!NONDEBUG_INSN_P (insn))
370 continue;
371
e692f276
RH
372 src = conforming_compare (insn);
373 if (src)
374 {
08281ce0 375 rtx eh_note = NULL;
28f7ff45 376
6c6a593d 377 if (cfun->can_throw_non_call_exceptions)
08281ce0 378 eh_note = find_reg_note (insn, REG_EH_REGION, NULL);
34c5f21a 379
6c6a593d
EB
380 if (last_cmp_valid && can_eliminate_compare (src, eh_note, last_cmp))
381 {
382 if (eh_note)
383 need_purge = true;
384 delete_insn (insn);
385 continue;
386 }
08281ce0 387
34c5f21a 388 last_cmp = XCNEW (struct comparison);
e692f276
RH
389 last_cmp->insn = insn;
390 last_cmp->prev_clobber = last_clobber;
0ea52812 391 last_cmp->in_a = strip_not (XEXP (src, 0));
e692f276 392 last_cmp->in_b = XEXP (src, 1);
0ea52812 393 last_cmp->not_in_a = is_not (XEXP (src, 0));
08281ce0 394 last_cmp->eh_note = eh_note;
6c6a593d 395 last_cmp->orig_mode = GET_MODE (src);
efc04f78
JJ
396 if (last_cmp->in_b == const0_rtx
397 && last_setter[REGNO (last_cmp->in_a)])
398 {
399 rtx set = single_set (last_setter[REGNO (last_cmp->in_a)]);
400 if (set && rtx_equal_p (SET_DEST (set), last_cmp->in_a))
401 last_cmp->in_a_setter = last_setter[REGNO (last_cmp->in_a)];
402 }
9771b263 403 all_compares.safe_push (last_cmp);
e692f276
RH
404
405 /* It's unusual, but be prepared for comparison patterns that
406 also clobber an input, or perhaps a scratch. */
407 last_clobber = NULL;
408 last_cmp_valid = true;
409 }
410
2c35bbe1 411 else
e692f276 412 {
2c35bbe1
EB
413 /* Notice if this instruction uses the flags register. */
414 if (last_cmp)
415 find_flags_uses_in_insn (last_cmp, insn);
e692f276 416
2c35bbe1 417 /* Notice if this instruction kills the flags register. */
efc04f78
JJ
418 df_ref def;
419 FOR_EACH_INSN_DEF (def, insn)
420 if (DF_REF_REGNO (def) == targetm.flags_regnum)
421 {
422 /* See if this insn could be the "clobber" that eliminates
423 a future comparison. */
424 last_clobber = (arithmetic_flags_clobber_p (insn)
425 ? insn : NULL);
426
427 /* In either case, the previous compare is no longer valid. */
428 last_cmp = NULL;
429 last_cmp_valid = false;
430 break;
431 }
2c35bbe1 432 }
e692f276 433
efc04f78
JJ
434 /* Notice if any of the inputs to the comparison have changed
435 and remember last insn that sets each register. */
436 df_ref def;
437 FOR_EACH_INSN_DEF (def, insn)
438 {
439 if (last_cmp_valid
440 && (DF_REF_REGNO (def) == REGNO (last_cmp->in_a)
441 || (REG_P (last_cmp->in_b)
442 && DF_REF_REGNO (def) == REGNO (last_cmp->in_b))))
443 last_cmp_valid = false;
444 last_setter[DF_REF_REGNO (def)] = insn;
445 }
e692f276
RH
446 }
447
e692f276
RH
448 /* Remember the live comparison for subsequent members of
449 the extended basic block. */
450 if (last_cmp)
451 {
452 bb->aux = last_cmp;
453 last_cmp->inputs_valid = last_cmp_valid;
454
455 /* Look to see if the flags register is live outgoing here, and
456 incoming to any successor not part of the extended basic block. */
53fbb724 457 if (bitmap_bit_p (df_get_live_out (bb), targetm.flags_regnum))
e692f276
RH
458 {
459 edge e;
460 edge_iterator ei;
461
462 FOR_EACH_EDGE (e, ei, bb->succs)
463 {
464 basic_block dest = e->dest;
6c6a593d 465 if (bitmap_bit_p (df_get_live_in (bb), targetm.flags_regnum)
e692f276
RH
466 && !single_pred_p (dest))
467 {
468 last_cmp->missing_uses = true;
469 break;
470 }
471 }
472 }
473 }
08281ce0
RH
474
475 /* If we deleted a compare with a REG_EH_REGION note, we may need to
476 remove EH edges. */
477 if (need_purge)
478 purge_dead_edges (bb);
3daacdcd
JL
479
480 return NULL;
e692f276
RH
481}
482
483/* Find all comparisons in the function. */
484
485static void
486find_comparisons (void)
487{
e692f276
RH
488 calculate_dominance_info (CDI_DOMINATORS);
489
4d9192b5
TS
490 find_comparison_dom_walker (CDI_DOMINATORS)
491 .walk (cfun->cfg->x_entry_block_ptr);
e692f276
RH
492
493 clear_aux_for_blocks ();
494 free_dominance_info (CDI_DOMINATORS);
495}
496
497/* Select an alternate CC_MODE for a comparison insn comparing A and B.
498 Note that inputs are almost certainly different than the IN_A and IN_B
499 stored in CMP -- we're called while attempting to eliminate the compare
500 after all. Return the new FLAGS rtx if successful, else return NULL.
501 Note that this function may start a change group. */
502
503static rtx
7fcaf152
AS
504maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
505 rtx b ATTRIBUTE_UNUSED)
e692f276 506{
ef4bddc2 507 machine_mode sel_mode;
e692f276
RH
508 const int n = cmp->n_uses;
509 rtx flags = NULL;
510
511#ifndef SELECT_CC_MODE
512 /* Minimize code differences when this target macro is undefined. */
513 return NULL;
514#define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
515#endif
516
517 /* If we don't have access to all of the uses, we can't validate. */
518 if (cmp->missing_uses || n == 0)
519 return NULL;
520
521 /* Find a new mode that works for all of the uses. Special case the
522 common case of exactly one use. */
523 if (n == 1)
524 {
525 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
526 if (sel_mode != cmp->orig_mode)
527 {
528 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
529 validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
530 }
531 }
532 else
533 {
534 int i;
535
536 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
537 for (i = 1; i < n; ++i)
538 {
6c6a593d 539 machine_mode new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
e692f276
RH
540 if (new_mode != sel_mode)
541 {
542 sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
543 if (sel_mode == VOIDmode)
544 return NULL;
545 }
546 }
6c6a593d 547
e692f276
RH
548 if (sel_mode != cmp->orig_mode)
549 {
550 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
551 for (i = 0; i < n; ++i)
552 validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
553 }
554 }
555
556 return flags;
557}
558
2c35bbe1
EB
559/* Return a register RTX holding the same value at START as REG at END, or
560 NULL_RTX if there is none. */
e692f276 561
2c35bbe1
EB
562static rtx
563equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
e692f276 564{
36449020 565 machine_mode orig_mode = GET_MODE (reg);
2c35bbe1 566 rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (end));
e692f276 567
2c35bbe1
EB
568 for (rtx_insn *insn = PREV_INSN (end);
569 insn != start;
e692f276
RH
570 insn = PREV_INSN (insn))
571 {
572 const int abnormal_flags
573 = (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
574 | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
575 | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
576 | DF_REF_PRE_POST_MODIFY);
bfac633a 577 df_ref def;
e692f276
RH
578
579 /* Note that the BB_HEAD is always either a note or a label, but in
d2d61a74 580 any case it means that REG is defined outside the block. */
e692f276 581 if (insn == bb_head)
2c35bbe1 582 return NULL_RTX;
e692f276
RH
583 if (NOTE_P (insn) || DEBUG_INSN_P (insn))
584 continue;
585
d2d61a74 586 /* Find a possible def of REG in INSN. */
bfac633a 587 FOR_EACH_INSN_DEF (def, insn)
2c35bbe1 588 if (DF_REF_REGNO (def) == REGNO (reg))
e692f276
RH
589 break;
590
d2d61a74 591 /* No definitions of REG; continue searching. */
e692f276
RH
592 if (def == NULL)
593 continue;
594
d2d61a74 595 /* Bail if this is not a totally normal set of REG. */
e692f276 596 if (DF_REF_IS_ARTIFICIAL (def))
2c35bbe1 597 return NULL_RTX;
e692f276 598 if (DF_REF_FLAGS (def) & abnormal_flags)
2c35bbe1 599 return NULL_RTX;
e692f276
RH
600
601 /* We've found an insn between the compare and the clobber that sets
d2d61a74 602 REG. Given that pass_cprop_hardreg has not yet run, we still find
e692f276 603 situations in which we can usefully look through a copy insn. */
2c35bbe1
EB
604 rtx x = single_set (insn);
605 if (x == NULL_RTX)
606 return NULL_RTX;
607 reg = SET_SRC (x);
608 if (!REG_P (reg))
609 return NULL_RTX;
610 }
611
36449020
UB
612 if (GET_MODE (reg) != orig_mode)
613 return NULL_RTX;
614
2c35bbe1
EB
615 return reg;
616}
617
d7840b47
KT
618/* Return true if it is okay to merge the comparison CMP_INSN with
619 the instruction ARITH_INSN. Both instructions are assumed to be in the
620 same basic block with ARITH_INSN appearing before CMP_INSN. This checks
621 that there are no uses or defs of the condition flags or control flow
622 changes between the two instructions. */
623
624static bool
625can_merge_compare_into_arith (rtx_insn *cmp_insn, rtx_insn *arith_insn)
626{
627 for (rtx_insn *insn = PREV_INSN (cmp_insn);
628 insn && insn != arith_insn;
629 insn = PREV_INSN (insn))
630 {
631 if (!NONDEBUG_INSN_P (insn))
632 continue;
633 /* Bail if there are jumps or calls in between. */
634 if (!NONJUMP_INSN_P (insn))
635 return false;
636
637 /* Bail on old-style asm statements because they lack
638 data flow information. */
639 if (GET_CODE (PATTERN (insn)) == ASM_INPUT)
640 return false;
641
642 df_ref ref;
643 /* Find a USE of the flags register. */
644 FOR_EACH_INSN_USE (ref, insn)
645 if (DF_REF_REGNO (ref) == targetm.flags_regnum)
646 return false;
647
648 /* Find a DEF of the flags register. */
649 FOR_EACH_INSN_DEF (ref, insn)
650 if (DF_REF_REGNO (ref) == targetm.flags_regnum)
651 return false;
652 }
653 return true;
654}
655
656/* Given two SET expressions, SET_A and SET_B determine whether they form
657 a recognizable pattern when emitted in parallel. Return that parallel
658 if so. Otherwise return NULL. */
659
660static rtx
661try_validate_parallel (rtx set_a, rtx set_b)
662{
efc04f78
JJ
663 rtx par = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
664 rtx_insn *insn = make_insn_raw (par);
d7840b47 665
efc04f78
JJ
666 if (insn_invalid_p (insn, false))
667 {
668 crtl->emit.x_cur_insn_uid--;
669 return NULL_RTX;
670 }
d7840b47 671
efc04f78
JJ
672 SET_PREV_INSN (insn) = NULL_RTX;
673 SET_NEXT_INSN (insn) = NULL_RTX;
674 INSN_LOCATION (insn) = 0;
675 return insn;
d7840b47
KT
676}
677
678/* For a comparison instruction described by CMP check if it compares a
679 register with zero i.e. it is of the form CC := CMP R1, 0.
680 If it is, find the instruction defining R1 (say I1) and try to create a
681 PARALLEL consisting of I1 and the comparison, representing a flag-setting
682 arithmetic instruction. Example:
683 I1: R1 := R2 + R3
684 <instructions that don't read the condition register>
685 I2: CC := CMP R1 0
686 I2 can be merged with I1 into:
efc04f78 687 I1: { CC := CMP (R2 + R3) 0 ; R1 := R2 + R3 }
d7840b47
KT
688 This catches cases where R1 is used between I1 and I2 and therefore
689 combine and other RTL optimisations will not try to propagate it into
690 I2. Return true if we succeeded in merging CMP. */
691
692static bool
693try_merge_compare (struct comparison *cmp)
694{
695 rtx_insn *cmp_insn = cmp->insn;
696
efc04f78 697 if (cmp->in_b != const0_rtx || cmp->in_a_setter == NULL)
d7840b47
KT
698 return false;
699 rtx in_a = cmp->in_a;
700 df_ref use;
701
702 FOR_EACH_INSN_USE (use, cmp_insn)
703 if (DF_REF_REGNO (use) == REGNO (in_a))
704 break;
705 if (!use)
706 return false;
707
efc04f78 708 rtx_insn *def_insn = cmp->in_a_setter;
d7840b47 709 rtx set = single_set (def_insn);
e9b8a628
JJ
710 if (!set)
711 return false;
d7840b47
KT
712
713 if (!can_merge_compare_into_arith (cmp_insn, def_insn))
714 return false;
715
716 rtx src = SET_SRC (set);
a3e87f07
PK
717
718 /* If the source uses addressing modes with side effects, we can't
719 do the merge because we'd end up with a PARALLEL that has two
720 instances of that side effect in it. */
721 if (side_effects_p (src))
722 return false;
723
d7840b47
KT
724 rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src)));
725 if (!flags)
726 {
727 /* We may already have a change group going through maybe_select_cc_mode.
728 Discard it properly. */
729 cancel_changes (0);
730 return false;
731 }
732
733 rtx flag_set
734 = gen_rtx_SET (flags, gen_rtx_COMPARE (GET_MODE (flags),
735 copy_rtx (src),
736 CONST0_RTX (GET_MODE (src))));
737 rtx arith_set = copy_rtx (PATTERN (def_insn));
738 rtx par = try_validate_parallel (flag_set, arith_set);
739 if (!par)
740 {
741 /* We may already have a change group going through maybe_select_cc_mode.
742 Discard it properly. */
743 cancel_changes (0);
744 return false;
745 }
746 if (!apply_change_group ())
747 return false;
748 emit_insn_after (par, def_insn);
749 delete_insn (def_insn);
750 delete_insn (cmp->insn);
751 return true;
752}
753
2c35bbe1
EB
754/* Attempt to replace a comparison with a prior arithmetic insn that can
755 compute the same flags value as the comparison itself. Return true if
756 successful, having made all rtl modifications necessary. */
757
758static bool
759try_eliminate_compare (struct comparison *cmp)
760{
d4920f40 761 rtx flags, in_a, in_b, cmp_a, cmp_b;
2c35bbe1 762
d7840b47
KT
763 if (try_merge_compare (cmp))
764 return true;
765
34311c5e 766 /* We must have found an interesting "clobber" preceding the compare. */
2c35bbe1
EB
767 if (cmp->prev_clobber == NULL)
768 return false;
769
770 /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
771 Given that this target requires this pass, we can assume that most
772 insns do clobber the flags, and so the distance between the compare
773 and the clobber is likely to be small. */
774 /* ??? This is one point at which one could argue that DF_REF_CHAIN would
775 be useful, but it is thought to be too heavy-weight a solution here. */
776 in_a = equivalent_reg_at_start (cmp->in_a, cmp->insn, cmp->prev_clobber);
777 if (!in_a)
778 return false;
779
780 /* Likewise for IN_B if need be. */
781 if (CONSTANT_P (cmp->in_b))
782 in_b = cmp->in_b;
783 else if (REG_P (cmp->in_b))
784 {
785 in_b = equivalent_reg_at_start (cmp->in_b, cmp->insn, cmp->prev_clobber);
786 if (!in_b)
e692f276
RH
787 return false;
788 }
2c35bbe1
EB
789 else if (GET_CODE (cmp->in_b) == UNSPEC)
790 {
791 const int len = XVECLEN (cmp->in_b, 0);
792 rtvec v = rtvec_alloc (len);
793 for (int i = 0; i < len; i++)
794 {
795 rtx r = equivalent_reg_at_start (XVECEXP (cmp->in_b, 0, i),
796 cmp->insn, cmp->prev_clobber);
797 if (!r)
798 return false;
799 RTVEC_ELT (v, i) = r;
800 }
801 in_b = gen_rtx_UNSPEC (GET_MODE (cmp->in_b), v, XINT (cmp->in_b, 1));
802 }
803 else
804 gcc_unreachable ();
e692f276
RH
805
806 /* We've reached PREV_CLOBBER without finding a modification of IN_A.
807 Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
808 recall that we've already validated the shape of PREV_CLOBBER. */
9b2ea071 809 rtx_insn *insn = cmp->prev_clobber;
4f0473fe
UB
810
811 rtx x = XVECEXP (PATTERN (insn), 0, 0);
ad1d9a50 812 if (rtx_equal_p (SET_DEST (x), in_a))
d4920f40 813 cmp_a = SET_SRC (x);
ad1d9a50
UB
814
815 /* Also check operations with implicit extensions, e.g.:
816 [(set (reg:DI)
2c35bbe1 817 (zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
ad1d9a50 818 (set (reg:CCZ flags)
2c35bbe1
EB
819 (compare:CCZ (plus:SI (reg:SI) (reg:SI))
820 (const_int 0)))] */
ad1d9a50
UB
821 else if (REG_P (SET_DEST (x))
822 && REG_P (in_a)
823 && REGNO (SET_DEST (x)) == REGNO (in_a)
824 && (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
825 || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
826 && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
d4920f40 827 cmp_a = XEXP (SET_SRC (x), 0);
2c35bbe1
EB
828
829 /* Also check fully redundant comparisons, e.g.:
830 [(set (reg:SI)
831 (minus:SI (reg:SI) (reg:SI))))
832 (set (reg:CC flags)
833 (compare:CC (reg:SI) (reg:SI)))] */
834 else if (REG_P (in_b)
835 && GET_CODE (SET_SRC (x)) == MINUS
836 && rtx_equal_p (XEXP (SET_SRC (x), 0), in_a)
837 && rtx_equal_p (XEXP (SET_SRC (x), 1), in_b))
d4920f40 838 cmp_a = in_a;
2c35bbe1 839
ad1d9a50 840 else
e692f276 841 return false;
ad1d9a50 842
a3e87f07
PK
843 /* If the source uses addressing modes with side effects, we can't
844 do the merge because we'd end up with a PARALLEL that has two
845 instances of that side effect in it. */
d4920f40
AO
846 if (side_effects_p (cmp_a))
847 return false;
848
849 if (in_a == in_b)
850 cmp_b = cmp_a;
851 else if (rtx_equal_p (SET_DEST (x), in_b))
852 cmp_b = SET_SRC (x);
853 else
854 cmp_b = in_b;
855 if (side_effects_p (cmp_b))
a3e87f07
PK
856 return false;
857
e692f276 858 /* Determine if we ought to use a different CC_MODE here. */
d4920f40 859 flags = maybe_select_cc_mode (cmp, cmp_a, cmp_b);
e692f276
RH
860 if (flags == NULL)
861 flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
862
863 /* Generate a new comparison for installation in the setter. */
0ea52812
EB
864 rtx y = cmp->not_in_a
865 ? gen_rtx_NOT (GET_MODE (cmp_a), copy_rtx (cmp_a))
866 : copy_rtx (cmp_a);
d4920f40 867 y = gen_rtx_COMPARE (GET_MODE (flags), y, copy_rtx (cmp_b));
4f0473fe
UB
868 y = gen_rtx_SET (flags, y);
869
870 /* Canonicalize instruction to:
871 [(set (reg:CCM) (compare:CCM (operation) (immediate)))
872 (set (reg) (operation)] */
e692f276 873
4f0473fe
UB
874 rtvec v = rtvec_alloc (2);
875 RTVEC_ELT (v, 0) = y;
876 RTVEC_ELT (v, 1) = x;
877
878 rtx pat = gen_rtx_PARALLEL (VOIDmode, v);
879
e692f276
RH
880 /* Succeed if the new instruction is valid. Note that we may have started
881 a change group within maybe_select_cc_mode, therefore we must continue. */
4f0473fe
UB
882 validate_change (insn, &PATTERN (insn), pat, true);
883
e692f276
RH
884 if (!apply_change_group ())
885 return false;
6c6a593d 886
e692f276
RH
887 /* Success. Delete the compare insn... */
888 delete_insn (cmp->insn);
889
890 /* ... and any notes that are now invalid due to multiple sets. */
891 x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
892 if (x)
893 remove_note (insn, x);
894 x = find_reg_note (insn, REG_EQUAL, NULL);
895 if (x)
896 remove_note (insn, x);
897 x = find_reg_note (insn, REG_EQUIV, NULL);
898 if (x)
899 remove_note (insn, x);
900
901 return true;
902}
903
904/* Main entry point to the pass. */
905
906static unsigned int
907execute_compare_elim_after_reload (void)
908{
6d43ec50 909 df_set_flags (DF_LR_RUN_DCE);
e692f276
RH
910 df_analyze ();
911
9771b263 912 gcc_checking_assert (!all_compares.exists ());
e692f276
RH
913
914 /* Locate all comparisons and their uses, and eliminate duplicates. */
915 find_comparisons ();
9771b263 916 if (all_compares.exists ())
e692f276
RH
917 {
918 struct comparison *cmp;
919 size_t i;
920
921 /* Eliminate comparisons that are redundant with flags computation. */
9771b263 922 FOR_EACH_VEC_ELT (all_compares, i, cmp)
e692f276
RH
923 {
924 try_eliminate_compare (cmp);
925 XDELETE (cmp);
926 }
927
9771b263 928 all_compares.release ();
e692f276
RH
929 }
930
931 return 0;
932}
933
17795822
TS
934namespace {
935
936const pass_data pass_data_compare_elim_after_reload =
e692f276 937{
27a4cd48
DM
938 RTL_PASS, /* type */
939 "cmpelim", /* name */
940 OPTGROUP_NONE, /* optinfo_flags */
27a4cd48
DM
941 TV_NONE, /* tv_id */
942 0, /* properties_required */
943 0, /* properties_provided */
944 0, /* properties_destroyed */
945 0, /* todo_flags_start */
3bea341f 946 ( TODO_df_finish | TODO_df_verify ), /* todo_flags_finish */
e692f276 947};
27a4cd48 948
17795822 949class pass_compare_elim_after_reload : public rtl_opt_pass
27a4cd48
DM
950{
951public:
c3284718
RS
952 pass_compare_elim_after_reload (gcc::context *ctxt)
953 : rtl_opt_pass (pass_data_compare_elim_after_reload, ctxt)
27a4cd48
DM
954 {}
955
956 /* opt_pass methods: */
1a3d085c
TS
957 virtual bool gate (function *)
958 {
959 /* Setting this target hook value is how a backend indicates the need. */
960 if (targetm.flags_regnum == INVALID_REGNUM)
961 return false;
962 return flag_compare_elim_after_reload;
963 }
964
be55bfe6
TS
965 virtual unsigned int execute (function *)
966 {
967 return execute_compare_elim_after_reload ();
968 }
27a4cd48
DM
969
970}; // class pass_compare_elim_after_reload
971
17795822
TS
972} // anon namespace
973
27a4cd48
DM
974rtl_opt_pass *
975make_pass_compare_elim_after_reload (gcc::context *ctxt)
976{
977 return new pass_compare_elim_after_reload (ctxt);
978}