Mercurial > hg > CbC > CbC_gcc
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); |