re PR libstdc++/43622 (Incomplete C++ library support for __float128)
[official-gcc.git] / gcc / compare-elim.c
blobd4c0e6884c157cc84c6685b74f4cf14003df47ed
1 /* Post-reload compare elimination.
2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
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.
27 This is a small pass intended to provide comparison elimination similar to
28 what is available via NOTICE_UPDATE_CC for cc0 targets. This should help
29 encourage cc0 targets to convert to an explicit post-reload representation
30 of the flags.
32 This pass assumes:
34 (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
36 (1) All comparison patterns are represented as
38 [(set (reg:CC) (compare:CC (reg) (immediate)))]
40 (2) All insn patterns that modify the flags are represented as
42 [(set (reg) (operation)
43 (clobber (reg:CC))]
45 (3) If an insn of form (2) can usefully set the flags, there is
46 another pattern of the form
48 [(set (reg) (operation)
49 (set (reg:CCM) (compare:CCM (operation) (immediate)))]
51 The mode CCM will be chosen as if by SELECT_CC_MODE.
53 Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
54 This could be handled as a future enhancement.
57 #include "config.h"
58 #include "system.h"
59 #include "coretypes.h"
60 #include "tm.h"
61 #include "rtl.h"
62 #include "tm_p.h"
63 #include "insn-config.h"
64 #include "recog.h"
65 #include "flags.h"
66 #include "predict.h"
67 #include "vec.h"
68 #include "hashtab.h"
69 #include "hash-set.h"
70 #include "machmode.h"
71 #include "hard-reg-set.h"
72 #include "input.h"
73 #include "function.h"
74 #include "dominance.h"
75 #include "cfg.h"
76 #include "cfgrtl.h"
77 #include "basic-block.h"
78 #include "tree-pass.h"
79 #include "target.h"
80 #include "df.h"
81 #include "domwalk.h"
84 /* These structures describe a comparison and how it is used. */
86 /* The choice of maximum 3 uses comes from wanting to eliminate the two
87 duplicate compares from a three-way branch on the sign of a value.
88 This is also sufficient to eliminate the duplicate compare against the
89 high-part of a double-word comparison. */
90 #define MAX_CMP_USE 3
92 struct comparison_use
94 /* The instruction in which the result of the compare is used. */
95 rtx_insn *insn;
96 /* The location of the flags register within the use. */
97 rtx *loc;
98 /* The comparison code applied against the flags register. */
99 enum rtx_code code;
102 struct comparison
104 /* The comparison instruction. */
105 rtx_insn *insn;
107 /* The insn prior to the comparison insn that clobbers the flags. */
108 rtx_insn *prev_clobber;
110 /* The two values being compared. These will be either REGs or
111 constants. */
112 rtx in_a, in_b;
114 /* The REG_EH_REGION of the comparison. */
115 rtx eh_note;
117 /* Information about how this comparison is used. */
118 struct comparison_use uses[MAX_CMP_USE];
120 /* The original CC_MODE for this comparison. */
121 machine_mode orig_mode;
123 /* The number of uses identified for this comparison. */
124 unsigned short n_uses;
126 /* True if not all uses of this comparison have been identified.
127 This can happen either for overflowing the array above, or if
128 the flags register is used in some unusual context. */
129 bool missing_uses;
131 /* True if its inputs are still valid at the end of the block. */
132 bool inputs_valid;
135 typedef struct comparison *comparison_struct_p;
137 static vec<comparison_struct_p> all_compares;
139 /* Look for a "conforming" comparison, as defined above. If valid, return
140 the rtx for the COMPARE itself. */
142 static rtx
143 conforming_compare (rtx_insn *insn)
145 rtx set, src, dest;
147 set = single_set (insn);
148 if (set == NULL)
149 return NULL;
151 src = SET_SRC (set);
152 if (GET_CODE (src) != COMPARE)
153 return NULL;
155 dest = SET_DEST (set);
156 if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
157 return NULL;
159 if (REG_P (XEXP (src, 0))
160 && REG_P (XEXP (src, 0))
161 && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
162 return src;
164 return NULL;
167 /* Look for a pattern of the "correct" form for an insn with a flags clobber
168 for which we may be able to eliminate a compare later. We're not looking
169 to validate any inputs at this time, merely see that the basic shape is
170 correct. The term "arithmetic" may be somewhat misleading... */
172 static bool
173 arithmetic_flags_clobber_p (rtx_insn *insn)
175 rtx pat, x;
177 if (!NONJUMP_INSN_P (insn))
178 return false;
179 pat = PATTERN (insn);
180 if (extract_asm_operands (pat))
181 return false;
183 if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
185 x = XVECEXP (pat, 0, 0);
186 if (GET_CODE (x) != SET)
187 return false;
188 x = SET_DEST (x);
189 if (!REG_P (x))
190 return false;
192 x = XVECEXP (pat, 0, 1);
193 if (GET_CODE (x) == CLOBBER)
195 x = XEXP (x, 0);
196 if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
197 return true;
201 return false;
204 /* Look for uses of FLAGS in INSN. If we find one we can analyze, record
205 it in CMP; otherwise indicate that we've missed a use. */
207 static void
208 find_flags_uses_in_insn (struct comparison *cmp, rtx_insn *insn)
210 df_ref use;
212 /* If we've already lost track of uses, don't bother collecting more. */
213 if (cmp->missing_uses)
214 return;
216 /* Find a USE of the flags register. */
217 FOR_EACH_INSN_USE (use, insn)
218 if (DF_REF_REGNO (use) == targetm.flags_regnum)
220 rtx x, *loc;
222 /* If this is an unusual use, quit. */
223 if (DF_REF_TYPE (use) != DF_REF_REG_USE)
224 goto fail;
226 /* If we've run out of slots to record uses, quit. */
227 if (cmp->n_uses == MAX_CMP_USE)
228 goto fail;
230 /* Unfortunately the location of the flags register, while present
231 in the reference structure, doesn't help. We need to find the
232 comparison code that is outer to the actual flags use. */
233 loc = DF_REF_LOC (use);
234 x = PATTERN (insn);
235 if (GET_CODE (x) == PARALLEL)
236 x = XVECEXP (x, 0, 0);
237 x = SET_SRC (x);
238 if (GET_CODE (x) == IF_THEN_ELSE)
239 x = XEXP (x, 0);
240 if (COMPARISON_P (x)
241 && loc == &XEXP (x, 0)
242 && XEXP (x, 1) == const0_rtx)
244 /* We've found a use of the flags that we understand. */
245 struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
246 cuse->insn = insn;
247 cuse->loc = loc;
248 cuse->code = GET_CODE (x);
250 else
251 goto fail;
253 return;
255 fail:
256 /* We failed to recognize this use of the flags register. */
257 cmp->missing_uses = true;
260 class find_comparison_dom_walker : public dom_walker
262 public:
263 find_comparison_dom_walker (cdi_direction direction)
264 : dom_walker (direction) {}
266 virtual void before_dom_children (basic_block);
269 /* Identify comparison instructions within BB. If the flags from the last
270 compare in the BB is live at the end of the block, install the compare
271 in BB->AUX. Called via dom_walker.walk (). */
273 void
274 find_comparison_dom_walker::before_dom_children (basic_block bb)
276 struct comparison *last_cmp;
277 rtx_insn *insn, *next, *last_clobber;
278 bool last_cmp_valid;
279 bool need_purge = false;
280 bitmap killed;
282 killed = BITMAP_ALLOC (NULL);
284 /* The last comparison that was made. Will be reset to NULL
285 once the flags are clobbered. */
286 last_cmp = NULL;
288 /* True iff the last comparison has not been clobbered, nor
289 have its inputs. Used to eliminate duplicate compares. */
290 last_cmp_valid = false;
292 /* The last insn that clobbered the flags, if that insn is of
293 a form that may be valid for eliminating a following compare.
294 To be reset to NULL once the flags are set otherwise. */
295 last_clobber = NULL;
297 /* Propagate the last live comparison throughout the extended basic block. */
298 if (single_pred_p (bb))
300 last_cmp = (struct comparison *) single_pred (bb)->aux;
301 if (last_cmp)
302 last_cmp_valid = last_cmp->inputs_valid;
305 for (insn = BB_HEAD (bb); insn; insn = next)
307 rtx src;
309 next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
310 if (!NONDEBUG_INSN_P (insn))
311 continue;
313 /* Compute the set of registers modified by this instruction. */
314 bitmap_clear (killed);
315 df_simulate_find_defs (insn, killed);
317 src = conforming_compare (insn);
318 if (src)
320 machine_mode src_mode = GET_MODE (src);
321 rtx eh_note = NULL;
323 if (flag_non_call_exceptions)
324 eh_note = find_reg_note (insn, REG_EH_REGION, NULL);
326 if (!last_cmp_valid)
327 goto dont_delete;
329 /* Take care that it's in the same EH region. */
330 if (flag_non_call_exceptions
331 && !rtx_equal_p (eh_note, last_cmp->eh_note))
332 goto dont_delete;
334 /* Make sure the compare is redundant with the previous. */
335 if (!rtx_equal_p (last_cmp->in_a, XEXP (src, 0))
336 || !rtx_equal_p (last_cmp->in_b, XEXP (src, 1)))
337 goto dont_delete;
339 /* New mode must be compatible with the previous compare mode. */
341 machine_mode new_mode
342 = targetm.cc_modes_compatible (last_cmp->orig_mode, src_mode);
343 if (new_mode == VOIDmode)
344 goto dont_delete;
346 if (new_mode != last_cmp->orig_mode)
348 rtx x, flags = gen_rtx_REG (src_mode, targetm.flags_regnum);
350 /* Generate new comparison for substitution. */
351 x = gen_rtx_COMPARE (new_mode, XEXP (src, 0), XEXP (src, 1));
352 x = gen_rtx_SET (VOIDmode, flags, x);
354 if (!validate_change (last_cmp->insn,
355 &PATTERN (last_cmp->insn), x, false))
356 goto dont_delete;
358 last_cmp->orig_mode = new_mode;
362 /* All tests and substitutions succeeded! */
363 if (eh_note)
364 need_purge = true;
365 delete_insn (insn);
366 continue;
368 dont_delete:
369 last_cmp = XCNEW (struct comparison);
370 last_cmp->insn = insn;
371 last_cmp->prev_clobber = last_clobber;
372 last_cmp->in_a = XEXP (src, 0);
373 last_cmp->in_b = XEXP (src, 1);
374 last_cmp->eh_note = eh_note;
375 last_cmp->orig_mode = src_mode;
376 all_compares.safe_push (last_cmp);
378 /* It's unusual, but be prepared for comparison patterns that
379 also clobber an input, or perhaps a scratch. */
380 last_clobber = NULL;
381 last_cmp_valid = true;
384 /* Notice if this instruction kills the flags register. */
385 else if (bitmap_bit_p (killed, targetm.flags_regnum))
387 /* See if this insn could be the "clobber" that eliminates
388 a future comparison. */
389 last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
391 /* In either case, the previous compare is no longer valid. */
392 last_cmp = NULL;
393 last_cmp_valid = false;
394 continue;
397 /* Notice if this instruction uses the flags register. */
398 else if (last_cmp)
399 find_flags_uses_in_insn (last_cmp, insn);
401 /* Notice if any of the inputs to the comparison have changed. */
402 if (last_cmp_valid
403 && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
404 || (REG_P (last_cmp->in_b)
405 && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
406 last_cmp_valid = false;
409 BITMAP_FREE (killed);
411 /* Remember the live comparison for subsequent members of
412 the extended basic block. */
413 if (last_cmp)
415 bb->aux = last_cmp;
416 last_cmp->inputs_valid = last_cmp_valid;
418 /* Look to see if the flags register is live outgoing here, and
419 incoming to any successor not part of the extended basic block. */
420 if (bitmap_bit_p (df_get_live_out (bb), targetm.flags_regnum))
422 edge e;
423 edge_iterator ei;
425 FOR_EACH_EDGE (e, ei, bb->succs)
427 basic_block dest = e->dest;
428 if (bitmap_bit_p (df_get_live_in (bb),
429 targetm.flags_regnum)
430 && !single_pred_p (dest))
432 last_cmp->missing_uses = true;
433 break;
439 /* If we deleted a compare with a REG_EH_REGION note, we may need to
440 remove EH edges. */
441 if (need_purge)
442 purge_dead_edges (bb);
445 /* Find all comparisons in the function. */
447 static void
448 find_comparisons (void)
450 calculate_dominance_info (CDI_DOMINATORS);
452 find_comparison_dom_walker (CDI_DOMINATORS)
453 .walk (cfun->cfg->x_entry_block_ptr);
455 clear_aux_for_blocks ();
456 free_dominance_info (CDI_DOMINATORS);
459 /* Select an alternate CC_MODE for a comparison insn comparing A and B.
460 Note that inputs are almost certainly different than the IN_A and IN_B
461 stored in CMP -- we're called while attempting to eliminate the compare
462 after all. Return the new FLAGS rtx if successful, else return NULL.
463 Note that this function may start a change group. */
465 static rtx
466 maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
467 rtx b ATTRIBUTE_UNUSED)
469 machine_mode sel_mode;
470 const int n = cmp->n_uses;
471 rtx flags = NULL;
473 #ifndef SELECT_CC_MODE
474 /* Minimize code differences when this target macro is undefined. */
475 return NULL;
476 #define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
477 #endif
479 /* If we don't have access to all of the uses, we can't validate. */
480 if (cmp->missing_uses || n == 0)
481 return NULL;
483 /* Find a new mode that works for all of the uses. Special case the
484 common case of exactly one use. */
485 if (n == 1)
487 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
488 if (sel_mode != cmp->orig_mode)
490 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
491 validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
494 else
496 int i;
498 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
499 for (i = 1; i < n; ++i)
501 machine_mode new_mode;
502 new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
503 if (new_mode != sel_mode)
505 sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
506 if (sel_mode == VOIDmode)
507 return NULL;
511 if (sel_mode != cmp->orig_mode)
513 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
514 for (i = 0; i < n; ++i)
515 validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
519 return flags;
522 /* Attempt to replace a comparison with a prior arithmetic insn that can
523 compute the same flags value as the comparison itself. Return true if
524 successful, having made all rtl modifications necessary. */
526 static bool
527 try_eliminate_compare (struct comparison *cmp)
529 rtx_insn *insn, *bb_head;
530 rtx x, flags, in_a, cmp_src;
532 /* We must have found an interesting "clobber" preceding the compare. */
533 if (cmp->prev_clobber == NULL)
534 return false;
536 /* ??? For the moment we don't handle comparisons for which IN_B
537 is a register. We accepted these during initial comparison
538 recognition in order to eliminate duplicate compares.
539 An improvement here would be to handle x = a - b; if (a cmp b). */
540 if (!CONSTANT_P (cmp->in_b))
541 return false;
543 /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
544 Given that this target requires this pass, we can assume that most
545 insns do clobber the flags, and so the distance between the compare
546 and the clobber is likely to be small. */
547 /* ??? This is one point at which one could argue that DF_REF_CHAIN would
548 be useful, but it is thought to be too heavy-weight a solution here. */
550 in_a = cmp->in_a;
551 insn = cmp->insn;
552 bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
553 for (insn = PREV_INSN (insn);
554 insn != cmp->prev_clobber;
555 insn = PREV_INSN (insn))
557 const int abnormal_flags
558 = (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
559 | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
560 | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
561 | DF_REF_PRE_POST_MODIFY);
562 df_ref def;
564 /* Note that the BB_HEAD is always either a note or a label, but in
565 any case it means that IN_A is defined outside the block. */
566 if (insn == bb_head)
567 return false;
568 if (NOTE_P (insn) || DEBUG_INSN_P (insn))
569 continue;
571 /* Find a possible def of IN_A in INSN. */
572 FOR_EACH_INSN_DEF (def, insn)
573 if (DF_REF_REGNO (def) == REGNO (in_a))
574 break;
576 /* No definitions of IN_A; continue searching. */
577 if (def == NULL)
578 continue;
580 /* Bail if this is not a totally normal set of IN_A. */
581 if (DF_REF_IS_ARTIFICIAL (def))
582 return false;
583 if (DF_REF_FLAGS (def) & abnormal_flags)
584 return false;
586 /* We've found an insn between the compare and the clobber that sets
587 IN_A. Given that pass_cprop_hardreg has not yet run, we still find
588 situations in which we can usefully look through a copy insn. */
589 x = single_set (insn);
590 if (x == NULL)
591 return false;
592 in_a = SET_SRC (x);
593 if (!REG_P (in_a))
594 return false;
597 /* We've reached PREV_CLOBBER without finding a modification of IN_A.
598 Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
599 recall that we've already validated the shape of PREV_CLOBBER. */
600 x = XVECEXP (PATTERN (insn), 0, 0);
601 if (rtx_equal_p (SET_DEST (x), in_a))
602 cmp_src = SET_SRC (x);
604 /* Also check operations with implicit extensions, e.g.:
605 [(set (reg:DI)
606 (zero_extend:DI (plus:SI (reg:SI)(reg:SI))))
607 (set (reg:CCZ flags)
608 (compare:CCZ
609 (plus:SI (reg:SI)(reg:SI))
610 (const_int 0)))] */
611 else if (REG_P (SET_DEST (x))
612 && REG_P (in_a)
613 && REGNO (SET_DEST (x)) == REGNO (in_a)
614 && (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
615 || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
616 && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
617 cmp_src = XEXP (SET_SRC (x), 0);
618 else
619 return false;
621 /* Determine if we ought to use a different CC_MODE here. */
622 flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
623 if (flags == NULL)
624 flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
626 /* Generate a new comparison for installation in the setter. */
627 x = copy_rtx (cmp_src);
628 x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
629 x = gen_rtx_SET (VOIDmode, flags, x);
631 /* Succeed if the new instruction is valid. Note that we may have started
632 a change group within maybe_select_cc_mode, therefore we must continue. */
633 validate_change (insn, &XVECEXP (PATTERN (insn), 0, 1), x, true);
634 if (!apply_change_group ())
635 return false;
637 /* Success. Delete the compare insn... */
638 delete_insn (cmp->insn);
640 /* ... and any notes that are now invalid due to multiple sets. */
641 x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
642 if (x)
643 remove_note (insn, x);
644 x = find_reg_note (insn, REG_EQUAL, NULL);
645 if (x)
646 remove_note (insn, x);
647 x = find_reg_note (insn, REG_EQUIV, NULL);
648 if (x)
649 remove_note (insn, x);
651 return true;
654 /* Main entry point to the pass. */
656 static unsigned int
657 execute_compare_elim_after_reload (void)
659 df_analyze ();
661 gcc_checking_assert (!all_compares.exists ());
663 /* Locate all comparisons and their uses, and eliminate duplicates. */
664 find_comparisons ();
665 if (all_compares.exists ())
667 struct comparison *cmp;
668 size_t i;
670 /* Eliminate comparisons that are redundant with flags computation. */
671 FOR_EACH_VEC_ELT (all_compares, i, cmp)
673 try_eliminate_compare (cmp);
674 XDELETE (cmp);
677 all_compares.release ();
680 return 0;
683 namespace {
685 const pass_data pass_data_compare_elim_after_reload =
687 RTL_PASS, /* type */
688 "cmpelim", /* name */
689 OPTGROUP_NONE, /* optinfo_flags */
690 TV_NONE, /* tv_id */
691 0, /* properties_required */
692 0, /* properties_provided */
693 0, /* properties_destroyed */
694 0, /* todo_flags_start */
695 ( TODO_df_finish | TODO_df_verify ), /* todo_flags_finish */
698 class pass_compare_elim_after_reload : public rtl_opt_pass
700 public:
701 pass_compare_elim_after_reload (gcc::context *ctxt)
702 : rtl_opt_pass (pass_data_compare_elim_after_reload, ctxt)
705 /* opt_pass methods: */
706 virtual bool gate (function *)
708 /* Setting this target hook value is how a backend indicates the need. */
709 if (targetm.flags_regnum == INVALID_REGNUM)
710 return false;
711 return flag_compare_elim_after_reload;
714 virtual unsigned int execute (function *)
716 return execute_compare_elim_after_reload ();
719 }; // class pass_compare_elim_after_reload
721 } // anon namespace
723 rtl_opt_pass *
724 make_pass_compare_elim_after_reload (gcc::context *ctxt)
726 return new pass_compare_elim_after_reload (ctxt);