comparison gcc/compare-elim.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Post-reload compare elimination. 1 /* Post-reload compare elimination.
2 Copyright (C) 2010-2017 Free Software Foundation, Inc. 2 Copyright (C) 2010-2018 Free Software Foundation, Inc.
3 3
4 This file is part of GCC. 4 This file is part of GCC.
5 5
6 GCC is free software; you can redistribute it and/or modify it under 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 7 the terms of the GNU General Public License as published by the Free
94 /* The comparison instruction. */ 94 /* The comparison instruction. */
95 rtx_insn *insn; 95 rtx_insn *insn;
96 96
97 /* The insn prior to the comparison insn that clobbers the flags. */ 97 /* The insn prior to the comparison insn that clobbers the flags. */
98 rtx_insn *prev_clobber; 98 rtx_insn *prev_clobber;
99
100 /* The insn prior to the comparison insn that sets in_a REG. */
101 rtx_insn *in_a_setter;
99 102
100 /* The two values being compared. These will be either REGs or 103 /* The two values being compared. These will be either REGs or
101 constants. */ 104 constants. */
102 rtx in_a, in_b; 105 rtx in_a, in_b;
103 106
307 in BB->AUX. Called via dom_walker.walk (). */ 310 in BB->AUX. Called via dom_walker.walk (). */
308 311
309 edge 312 edge
310 find_comparison_dom_walker::before_dom_children (basic_block bb) 313 find_comparison_dom_walker::before_dom_children (basic_block bb)
311 { 314 {
312 struct comparison *last_cmp; 315 rtx_insn *insn, *next;
313 rtx_insn *insn, *next, *last_clobber;
314 bool last_cmp_valid;
315 bool need_purge = false; 316 bool need_purge = false;
316 bitmap killed; 317 rtx_insn *last_setter[FIRST_PSEUDO_REGISTER];
317
318 killed = BITMAP_ALLOC (NULL);
319 318
320 /* The last comparison that was made. Will be reset to NULL 319 /* The last comparison that was made. Will be reset to NULL
321 once the flags are clobbered. */ 320 once the flags are clobbered. */
322 last_cmp = NULL; 321 struct comparison *last_cmp = NULL;
323 322
324 /* True iff the last comparison has not been clobbered, nor 323 /* True iff the last comparison has not been clobbered, nor
325 have its inputs. Used to eliminate duplicate compares. */ 324 have its inputs. Used to eliminate duplicate compares. */
326 last_cmp_valid = false; 325 bool last_cmp_valid = false;
327 326
328 /* The last insn that clobbered the flags, if that insn is of 327 /* The last insn that clobbered the flags, if that insn is of
329 a form that may be valid for eliminating a following compare. 328 a form that may be valid for eliminating a following compare.
330 To be reset to NULL once the flags are set otherwise. */ 329 To be reset to NULL once the flags are set otherwise. */
331 last_clobber = NULL; 330 rtx_insn *last_clobber = NULL;
332 331
333 /* Propagate the last live comparison throughout the extended basic block. */ 332 /* Propagate the last live comparison throughout the extended basic block. */
334 if (single_pred_p (bb)) 333 if (single_pred_p (bb))
335 { 334 {
336 last_cmp = (struct comparison *) single_pred (bb)->aux; 335 last_cmp = (struct comparison *) single_pred (bb)->aux;
337 if (last_cmp) 336 if (last_cmp)
338 last_cmp_valid = last_cmp->inputs_valid; 337 last_cmp_valid = last_cmp->inputs_valid;
339 } 338 }
340 339
340 memset (last_setter, 0, sizeof (last_setter));
341 for (insn = BB_HEAD (bb); insn; insn = next) 341 for (insn = BB_HEAD (bb); insn; insn = next)
342 { 342 {
343 rtx src; 343 rtx src;
344 344
345 next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn)); 345 next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
346 if (!NONDEBUG_INSN_P (insn)) 346 if (!NONDEBUG_INSN_P (insn))
347 continue; 347 continue;
348
349 /* Compute the set of registers modified by this instruction. */
350 bitmap_clear (killed);
351 df_simulate_find_defs (insn, killed);
352 348
353 src = conforming_compare (insn); 349 src = conforming_compare (insn);
354 if (src) 350 if (src)
355 { 351 {
356 rtx eh_note = NULL; 352 rtx eh_note = NULL;
371 last_cmp->prev_clobber = last_clobber; 367 last_cmp->prev_clobber = last_clobber;
372 last_cmp->in_a = XEXP (src, 0); 368 last_cmp->in_a = XEXP (src, 0);
373 last_cmp->in_b = XEXP (src, 1); 369 last_cmp->in_b = XEXP (src, 1);
374 last_cmp->eh_note = eh_note; 370 last_cmp->eh_note = eh_note;
375 last_cmp->orig_mode = GET_MODE (src); 371 last_cmp->orig_mode = GET_MODE (src);
372 if (last_cmp->in_b == const0_rtx
373 && last_setter[REGNO (last_cmp->in_a)])
374 {
375 rtx set = single_set (last_setter[REGNO (last_cmp->in_a)]);
376 if (set && rtx_equal_p (SET_DEST (set), last_cmp->in_a))
377 last_cmp->in_a_setter = last_setter[REGNO (last_cmp->in_a)];
378 }
376 all_compares.safe_push (last_cmp); 379 all_compares.safe_push (last_cmp);
377 380
378 /* It's unusual, but be prepared for comparison patterns that 381 /* It's unusual, but be prepared for comparison patterns that
379 also clobber an input, or perhaps a scratch. */ 382 also clobber an input, or perhaps a scratch. */
380 last_clobber = NULL; 383 last_clobber = NULL;
386 /* Notice if this instruction uses the flags register. */ 389 /* Notice if this instruction uses the flags register. */
387 if (last_cmp) 390 if (last_cmp)
388 find_flags_uses_in_insn (last_cmp, insn); 391 find_flags_uses_in_insn (last_cmp, insn);
389 392
390 /* Notice if this instruction kills the flags register. */ 393 /* Notice if this instruction kills the flags register. */
391 if (bitmap_bit_p (killed, targetm.flags_regnum)) 394 df_ref def;
392 { 395 FOR_EACH_INSN_DEF (def, insn)
393 /* See if this insn could be the "clobber" that eliminates 396 if (DF_REF_REGNO (def) == targetm.flags_regnum)
394 a future comparison. */ 397 {
395 last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL); 398 /* See if this insn could be the "clobber" that eliminates
396 399 a future comparison. */
397 /* In either case, the previous compare is no longer valid. */ 400 last_clobber = (arithmetic_flags_clobber_p (insn)
398 last_cmp = NULL; 401 ? insn : NULL);
399 last_cmp_valid = false; 402
400 } 403 /* In either case, the previous compare is no longer valid. */
404 last_cmp = NULL;
405 last_cmp_valid = false;
406 break;
407 }
401 } 408 }
402 409
403 /* Notice if any of the inputs to the comparison have changed. */ 410 /* Notice if any of the inputs to the comparison have changed
404 if (last_cmp_valid 411 and remember last insn that sets each register. */
405 && (bitmap_bit_p (killed, REGNO (last_cmp->in_a)) 412 df_ref def;
406 || (REG_P (last_cmp->in_b) 413 FOR_EACH_INSN_DEF (def, insn)
407 && bitmap_bit_p (killed, REGNO (last_cmp->in_b))))) 414 {
408 last_cmp_valid = false; 415 if (last_cmp_valid
409 } 416 && (DF_REF_REGNO (def) == REGNO (last_cmp->in_a)
410 417 || (REG_P (last_cmp->in_b)
411 BITMAP_FREE (killed); 418 && DF_REF_REGNO (def) == REGNO (last_cmp->in_b))))
419 last_cmp_valid = false;
420 last_setter[DF_REF_REGNO (def)] = insn;
421 }
422 }
412 423
413 /* Remember the live comparison for subsequent members of 424 /* Remember the live comparison for subsequent members of
414 the extended basic block. */ 425 the extended basic block. */
415 if (last_cmp) 426 if (last_cmp)
416 { 427 {
623 if so. Otherwise return NULL. */ 634 if so. Otherwise return NULL. */
624 635
625 static rtx 636 static rtx
626 try_validate_parallel (rtx set_a, rtx set_b) 637 try_validate_parallel (rtx set_a, rtx set_b)
627 { 638 {
628 rtx par 639 rtx par = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
629 = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b)); 640 rtx_insn *insn = make_insn_raw (par);
630 641
631 rtx_insn *insn; 642 if (insn_invalid_p (insn, false))
632 insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, par, 0, -1, 0); 643 {
633 644 crtl->emit.x_cur_insn_uid--;
634 return recog_memoized (insn) > 0 ? par : NULL_RTX; 645 return NULL_RTX;
646 }
647
648 SET_PREV_INSN (insn) = NULL_RTX;
649 SET_NEXT_INSN (insn) = NULL_RTX;
650 INSN_LOCATION (insn) = 0;
651 return insn;
635 } 652 }
636 653
637 /* For a comparison instruction described by CMP check if it compares a 654 /* For a comparison instruction described by CMP check if it compares a
638 register with zero i.e. it is of the form CC := CMP R1, 0. 655 register with zero i.e. it is of the form CC := CMP R1, 0.
639 If it is, find the instruction defining R1 (say I1) and try to create a 656 If it is, find the instruction defining R1 (say I1) and try to create a
641 arithmetic instruction. Example: 658 arithmetic instruction. Example:
642 I1: R1 := R2 + R3 659 I1: R1 := R2 + R3
643 <instructions that don't read the condition register> 660 <instructions that don't read the condition register>
644 I2: CC := CMP R1 0 661 I2: CC := CMP R1 0
645 I2 can be merged with I1 into: 662 I2 can be merged with I1 into:
646 I1: { R1 := R2 + R3 ; CC := CMP (R2 + R3) 0 } 663 I1: { CC := CMP (R2 + R3) 0 ; R1 := R2 + R3 }
647 This catches cases where R1 is used between I1 and I2 and therefore 664 This catches cases where R1 is used between I1 and I2 and therefore
648 combine and other RTL optimisations will not try to propagate it into 665 combine and other RTL optimisations will not try to propagate it into
649 I2. Return true if we succeeded in merging CMP. */ 666 I2. Return true if we succeeded in merging CMP. */
650 667
651 static bool 668 static bool
652 try_merge_compare (struct comparison *cmp) 669 try_merge_compare (struct comparison *cmp)
653 { 670 {
654 rtx_insn *cmp_insn = cmp->insn; 671 rtx_insn *cmp_insn = cmp->insn;
655 672
656 if (!REG_P (cmp->in_a) || cmp->in_b != const0_rtx) 673 if (cmp->in_b != const0_rtx || cmp->in_a_setter == NULL)
657 return false; 674 return false;
658 rtx in_a = cmp->in_a; 675 rtx in_a = cmp->in_a;
659 df_ref use; 676 df_ref use;
660 677
661 FOR_EACH_INSN_USE (use, cmp_insn) 678 FOR_EACH_INSN_USE (use, cmp_insn)
662 if (DF_REF_REGNO (use) == REGNO (in_a)) 679 if (DF_REF_REGNO (use) == REGNO (in_a))
663 break; 680 break;
664 if (!use) 681 if (!use)
665 return false; 682 return false;
666 683
667 /* Validate the data flow information before attempting to 684 rtx_insn *def_insn = cmp->in_a_setter;
668 find the instruction that defines in_a. */
669
670 struct df_link *ref_chain;
671 ref_chain = DF_REF_CHAIN (use);
672 if (!ref_chain || !ref_chain->ref
673 || !DF_REF_INSN_INFO (ref_chain->ref) || ref_chain->next != NULL)
674 return false;
675
676 rtx_insn *def_insn = DF_REF_INSN (ref_chain->ref);
677 /* We found the insn that defines in_a. Only consider the cases where
678 it is in the same block as the comparison. */
679 if (BLOCK_FOR_INSN (cmp_insn) != BLOCK_FOR_INSN (def_insn))
680 return false;
681
682 rtx set = single_set (def_insn); 685 rtx set = single_set (def_insn);
683 if (!set) 686 if (!set)
684 return false; 687 return false;
685 688
686 if (!can_merge_compare_into_arith (cmp_insn, def_insn)) 689 if (!can_merge_compare_into_arith (cmp_insn, def_insn))
687 return false; 690 return false;
688 691
689 rtx src = SET_SRC (set); 692 rtx src = SET_SRC (set);
693
694 /* If the source uses addressing modes with side effects, we can't
695 do the merge because we'd end up with a PARALLEL that has two
696 instances of that side effect in it. */
697 if (side_effects_p (src))
698 return false;
699
690 rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src))); 700 rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src)));
691 if (!flags) 701 if (!flags)
692 { 702 {
693 /* We may already have a change group going through maybe_select_cc_mode. 703 /* We may already have a change group going through maybe_select_cc_mode.
694 Discard it properly. */ 704 Discard it properly. */
804 cmp_src = in_a; 814 cmp_src = in_a;
805 815
806 else 816 else
807 return false; 817 return false;
808 818
819 /* If the source uses addressing modes with side effects, we can't
820 do the merge because we'd end up with a PARALLEL that has two
821 instances of that side effect in it. */
822 if (side_effects_p (cmp_src))
823 return false;
824
809 /* Determine if we ought to use a different CC_MODE here. */ 825 /* Determine if we ought to use a different CC_MODE here. */
810 flags = maybe_select_cc_mode (cmp, cmp_src, in_b); 826 flags = maybe_select_cc_mode (cmp, cmp_src, in_b);
811 if (flags == NULL) 827 if (flags == NULL)
812 flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum); 828 flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
813 829
853 /* Main entry point to the pass. */ 869 /* Main entry point to the pass. */
854 870
855 static unsigned int 871 static unsigned int
856 execute_compare_elim_after_reload (void) 872 execute_compare_elim_after_reload (void)
857 { 873 {
858 df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
859 df_analyze (); 874 df_analyze ();
860 875
861 gcc_checking_assert (!all_compares.exists ()); 876 gcc_checking_assert (!all_compares.exists ());
862 877
863 /* Locate all comparisons and their uses, and eliminate duplicates. */ 878 /* Locate all comparisons and their uses, and eliminate duplicates. */