comparison gcc/postreload-gcse.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
comparison
equal deleted inserted replaced
131:84e7813d76e9 145:1830386684a0
1 /* Post reload partially redundant load elimination 1 /* Post reload partially redundant load elimination
2 Copyright (C) 2004-2018 Free Software Foundation, Inc. 2 Copyright (C) 2004-2020 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
33 #include "recog.h" 33 #include "recog.h"
34 34
35 #include "cfgrtl.h" 35 #include "cfgrtl.h"
36 #include "profile.h" 36 #include "profile.h"
37 #include "expr.h" 37 #include "expr.h"
38 #include "params.h"
39 #include "tree-pass.h" 38 #include "tree-pass.h"
40 #include "dbgcnt.h" 39 #include "dbgcnt.h"
40 #include "intl.h"
41 #include "gcse-common.h" 41 #include "gcse-common.h"
42 #include "gcse.h"
43 #include "regs.h"
44 #include "function-abi.h"
42 45
43 /* The following code implements gcse after reload, the purpose of this 46 /* The following code implements gcse after reload, the purpose of this
44 pass is to cleanup redundant loads generated by reload and other 47 pass is to cleanup redundant loads generated by reload and other
45 optimizations that come after gcse. It searches for simple inter-block 48 optimizations that come after gcse. It searches for simple inter-block
46 redundancies and tries to eliminate them by adding moves and loads 49 redundancies and tries to eliminate them by adding moves and loads
362 insert_expr_in_table (rtx x, rtx_insn *insn) 365 insert_expr_in_table (rtx x, rtx_insn *insn)
363 { 366 {
364 int do_not_record_p; 367 int do_not_record_p;
365 hashval_t hash; 368 hashval_t hash;
366 struct expr *cur_expr, **slot; 369 struct expr *cur_expr, **slot;
367 struct occr *avail_occr, *last_occr = NULL; 370 struct occr *avail_occr;
368 371
369 hash = hash_expr (x, &do_not_record_p); 372 hash = hash_expr (x, &do_not_record_p);
370 373
371 /* Do not insert expression in the table if it contains volatile operands, 374 /* Do not insert expression in the table if it contains volatile operands,
372 or if hash_expr determines the expression is something we don't want 375 or if hash_expr determines the expression is something we don't want
403 obstack and use the existing table entry. */ 406 obstack and use the existing table entry. */
404 obstack_free (&expr_obstack, cur_expr); 407 obstack_free (&expr_obstack, cur_expr);
405 cur_expr = *slot; 408 cur_expr = *slot;
406 } 409 }
407 410
408 /* Search for another occurrence in the same basic block. */ 411 /* Search for another occurrence in the same basic block. We insert
412 insns blockwise from start to end, so keep appending to the
413 start of the list so we have to check only a single element. */
409 avail_occr = cur_expr->avail_occr; 414 avail_occr = cur_expr->avail_occr;
410 while (avail_occr 415 if (avail_occr
411 && BLOCK_FOR_INSN (avail_occr->insn) != BLOCK_FOR_INSN (insn)) 416 && BLOCK_FOR_INSN (avail_occr->insn) == BLOCK_FOR_INSN (insn))
412 {
413 /* If an occurrence isn't found, save a pointer to the end of
414 the list. */
415 last_occr = avail_occr;
416 avail_occr = avail_occr->next;
417 }
418
419 if (avail_occr)
420 /* Found another instance of the expression in the same basic block.
421 Prefer this occurrence to the currently recorded one. We want
422 the last one in the block and the block is scanned from start
423 to end. */
424 avail_occr->insn = insn; 417 avail_occr->insn = insn;
425 else 418 else
426 { 419 {
427 /* First occurrence of this expression in this basic block. */ 420 /* First occurrence of this expression in this basic block. */
428 avail_occr = (struct occr *) obstack_alloc (&occr_obstack, 421 avail_occr = (struct occr *) obstack_alloc (&occr_obstack,
429 sizeof (struct occr)); 422 sizeof (struct occr));
430
431 /* First occurrence of this expression in any block? */
432 if (cur_expr->avail_occr == NULL)
433 cur_expr->avail_occr = avail_occr;
434 else
435 last_occr->next = avail_occr;
436
437 avail_occr->insn = insn; 423 avail_occr->insn = insn;
438 avail_occr->next = NULL; 424 avail_occr->next = cur_expr->avail_occr;
439 avail_occr->deleted_p = 0; 425 avail_occr->deleted_p = 0;
426 cur_expr->avail_occr = avail_occr;
440 } 427 }
441 } 428 }
442 429
443 430
444 /* Lookup pattern PAT in the expression hash table. 431 /* Lookup pattern PAT in the expression hash table.
502 fprintf (file, "\n\nexpression hash table\n"); 489 fprintf (file, "\n\nexpression hash table\n");
503 fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n", 490 fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n",
504 (long) expr_table->size (), 491 (long) expr_table->size (),
505 (long) expr_table->elements (), 492 (long) expr_table->elements (),
506 expr_table->collisions ()); 493 expr_table->collisions ());
507 if (expr_table->elements () > 0) 494 if (!expr_table->is_empty ())
508 { 495 {
509 fprintf (file, "\n\ntable entries:\n"); 496 fprintf (file, "\n\ntable entries:\n");
510 expr_table->traverse <FILE *, dump_expr_hash_table_entry> (file); 497 expr_table->traverse <FILE *, dump_expr_hash_table_entry> (file);
511 } 498 }
512 fprintf (file, "\n"); 499 fprintf (file, "\n");
670 /* SETTER must be an insn of some kind that sets memory. Call 657 /* SETTER must be an insn of some kind that sets memory. Call
671 note_stores to examine each hunk of memory that is modified. 658 note_stores to examine each hunk of memory that is modified.
672 It will set mems_conflict_p to nonzero if there may be a 659 It will set mems_conflict_p to nonzero if there may be a
673 conflict between X and SETTER. */ 660 conflict between X and SETTER. */
674 mems_conflict_p = 0; 661 mems_conflict_p = 0;
675 note_stores (PATTERN (setter), find_mem_conflicts, x); 662 note_stores (setter, find_mem_conflicts, x);
676 if (mems_conflict_p) 663 if (mems_conflict_p)
677 return 1; 664 return 1;
678 665
679 list_entry = list_entry->next; 666 list_entry = list_entry->next;
680 } 667 }
772 record_opr_changes (rtx_insn *insn) 759 record_opr_changes (rtx_insn *insn)
773 { 760 {
774 rtx note; 761 rtx note;
775 762
776 /* Find all stores and record them. */ 763 /* Find all stores and record them. */
777 note_stores (PATTERN (insn), record_last_set_info, insn); 764 note_stores (insn, record_last_set_info, insn);
778 765
779 /* Also record autoincremented REGs for this insn as changed. */ 766 /* Also record autoincremented REGs for this insn as changed. */
780 for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 767 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
781 if (REG_NOTE_KIND (note) == REG_INC) 768 if (REG_NOTE_KIND (note) == REG_INC)
782 record_last_reg_set_info (insn, XEXP (note, 0)); 769 record_last_reg_set_info (insn, XEXP (note, 0));
783 770
784 /* Finally, if this is a call, record all call clobbers. */ 771 /* Finally, if this is a call, record all call clobbers. */
785 if (CALL_P (insn)) 772 if (CALL_P (insn))
786 { 773 {
787 unsigned int regno; 774 unsigned int regno;
788 rtx link, x;
789 hard_reg_set_iterator hrsi; 775 hard_reg_set_iterator hrsi;
790 EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi) 776 /* We don't track modes of hard registers, so we need to be
777 conservative and assume that partial kills are full kills. */
778 HARD_REG_SET callee_clobbers
779 = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
780 EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
791 record_last_reg_set_info_regno (insn, regno); 781 record_last_reg_set_info_regno (insn, regno);
792
793 for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
794 {
795 gcc_assert (GET_CODE (XEXP (link, 0)) != CLOBBER_HIGH);
796 if (GET_CODE (XEXP (link, 0)) == CLOBBER)
797 {
798 x = XEXP (XEXP (link, 0), 0);
799 if (REG_P (x))
800 {
801 gcc_assert (HARD_REGISTER_P (x));
802 record_last_reg_set_info (insn, x);
803 }
804 }
805 }
806 782
807 if (! RTL_CONST_OR_PURE_CALL_P (insn)) 783 if (! RTL_CONST_OR_PURE_CALL_P (insn))
808 record_last_mem_set_info (insn); 784 record_last_mem_set_info (insn);
809 } 785 }
810 } 786 }
993 return occr; 969 return occr;
994 970
995 /* If we could not find an occurrence in BB, see if BB 971 /* If we could not find an occurrence in BB, see if BB
996 has a single predecessor with an occurrence that is 972 has a single predecessor with an occurrence that is
997 transparent through BB. */ 973 transparent through BB. */
998 if (single_pred_p (bb) 974 if (transp
975 && single_pred_p (bb)
999 && bitmap_bit_p (transp[bb->index], bitmap_index) 976 && bitmap_bit_p (transp[bb->index], bitmap_index)
1000 && (occr = get_bb_avail_insn (single_pred (bb), orig_occr, bitmap_index))) 977 && (occr = get_bb_avail_insn (single_pred (bb), orig_occr, bitmap_index)))
1001 { 978 {
1002 rtx avail_reg = get_avail_load_store_reg (occr->insn); 979 rtx avail_reg = get_avail_load_store_reg (occr->insn);
1003 if (!reg_set_between_p (avail_reg, 980 if (!reg_set_between_p (avail_reg,
1166 && critical_edge_split)) 1143 && critical_edge_split))
1167 goto cleanup; 1144 goto cleanup;
1168 1145
1169 /* Check if it's worth applying the partial redundancy elimination. */ 1146 /* Check if it's worth applying the partial redundancy elimination. */
1170 if (ok_count.to_gcov_type () 1147 if (ok_count.to_gcov_type ()
1171 < GCSE_AFTER_RELOAD_PARTIAL_FRACTION * not_ok_count.to_gcov_type ()) 1148 < param_gcse_after_reload_partial_fraction * not_ok_count.to_gcov_type ())
1172 goto cleanup; 1149 goto cleanup;
1173 if (ok_count.to_gcov_type () 1150
1174 < GCSE_AFTER_RELOAD_CRITICAL_FRACTION * critical_count.to_gcov_type ()) 1151 gcov_type threshold;
1152 #if (GCC_VERSION >= 5000)
1153 if (__builtin_mul_overflow (param_gcse_after_reload_critical_fraction,
1154 critical_count.to_gcov_type (), &threshold))
1155 threshold = profile_count::max_count;
1156 #else
1157 threshold
1158 = (param_gcse_after_reload_critical_fraction
1159 * critical_count.to_gcov_type ());
1160 #endif
1161
1162 if (ok_count.to_gcov_type () < threshold)
1175 goto cleanup; 1163 goto cleanup;
1176 1164
1177 /* Generate moves to the loaded register from where 1165 /* Generate moves to the loaded register from where
1178 the memory is available. */ 1166 the memory is available. */
1179 for (occr = avail_occrs; occr; occr = occr->next) 1167 for (occr = avail_occrs; occr; occr = occr->next)
1359 due to spilling. */ 1347 due to spilling. */
1360 1348
1361 static void 1349 static void
1362 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED) 1350 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
1363 { 1351 {
1352 /* Disable computing transparentness if it is too expensive. */
1353 bool do_transp
1354 = !gcse_or_cprop_is_too_expensive (_("using simple load CSE after register "
1355 "allocation"));
1364 1356
1365 memset (&stats, 0, sizeof (stats)); 1357 memset (&stats, 0, sizeof (stats));
1366 1358
1367 /* Allocate memory for this pass. 1359 /* Allocate memory for this pass.
1368 Also computes and initializes the insns' CUIDs. */ 1360 Also computes and initializes the insns' CUIDs. */
1374 compute_hash_table (); 1366 compute_hash_table ();
1375 1367
1376 if (dump_file) 1368 if (dump_file)
1377 dump_hash_table (dump_file); 1369 dump_hash_table (dump_file);
1378 1370
1379 if (expr_table->elements () > 0) 1371 if (!expr_table->is_empty ())
1380 { 1372 {
1381 /* Knowing which MEMs are transparent through a block can signifiantly 1373 /* Knowing which MEMs are transparent through a block can signifiantly
1382 increase the number of redundant loads found. So compute transparency 1374 increase the number of redundant loads found. So compute transparency
1383 information for each memory expression in the hash table. */ 1375 information for each memory expression in the hash table. */
1384 df_analyze (); 1376 df_analyze ();
1385 /* This can not be part of the normal allocation routine because 1377 if (do_transp)
1386 we have to know the number of elements in the hash table. */ 1378 {
1387 transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), 1379 /* This cannot be part of the normal allocation routine because
1388 expr_table->elements ()); 1380 we have to know the number of elements in the hash table. */
1389 bitmap_vector_ones (transp, last_basic_block_for_fn (cfun)); 1381 transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
1390 expr_table->traverse <FILE *, compute_expr_transp> (dump_file); 1382 expr_table->elements ());
1383 bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
1384 expr_table->traverse <FILE *, compute_expr_transp> (dump_file);
1385 }
1386 else
1387 transp = NULL;
1391 eliminate_partially_redundant_loads (); 1388 eliminate_partially_redundant_loads ();
1392 delete_redundant_insns (); 1389 delete_redundant_insns ();
1393 sbitmap_vector_free (transp); 1390 if (do_transp)
1391 sbitmap_vector_free (transp);
1394 1392
1395 if (dump_file) 1393 if (dump_file)
1396 { 1394 {
1397 fprintf (dump_file, "GCSE AFTER RELOAD stats:\n"); 1395 fprintf (dump_file, "GCSE AFTER RELOAD stats:\n");
1398 fprintf (dump_file, "copies inserted: %d\n", stats.copies_inserted); 1396 fprintf (dump_file, "copies inserted: %d\n", stats.copies_inserted);