Mercurial > hg > CbC > CbC_gcc
comparison gcc/tree-ssa-propagate.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
comparison
equal
deleted
inserted
replaced
130:e108057fa461 | 132:d34655255c78 |
---|---|
1 /* Generic SSA value propagation engine. | 1 /* Generic SSA value propagation engine. |
2 Copyright (C) 2004-2017 Free Software Foundation, Inc. | 2 Copyright (C) 2004-2018 Free Software Foundation, Inc. |
3 Contributed by Diego Novillo <dnovillo@redhat.com> | 3 Contributed by Diego Novillo <dnovillo@redhat.com> |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it | 7 GCC is free software; you can redistribute it and/or modify it |
106 Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. | 106 Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. |
107 | 107 |
108 [3] Advanced Compiler Design and Implementation, | 108 [3] Advanced Compiler Design and Implementation, |
109 Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 */ | 109 Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 */ |
110 | 110 |
111 /* Function pointers used to parameterize the propagation engine. */ | 111 /* Worklists of control flow edge destinations. This contains |
112 static ssa_prop_visit_stmt_fn ssa_prop_visit_stmt; | |
113 static ssa_prop_visit_phi_fn ssa_prop_visit_phi; | |
114 | |
115 /* Worklist of control flow edge destinations. This contains | |
116 the CFG order number of the blocks so we can iterate in CFG | 112 the CFG order number of the blocks so we can iterate in CFG |
117 order by visiting in bit-order. */ | 113 order by visiting in bit-order. We use two worklists to |
114 first make forward progress before iterating. */ | |
118 static bitmap cfg_blocks; | 115 static bitmap cfg_blocks; |
116 static bitmap cfg_blocks_back; | |
119 static int *bb_to_cfg_order; | 117 static int *bb_to_cfg_order; |
120 static int *cfg_order_to_bb; | 118 static int *cfg_order_to_bb; |
121 | 119 |
122 /* Worklist of SSA edges which will need reexamination as their | 120 /* Worklists of SSA edges which will need reexamination as their |
123 definition has changed. SSA edges are def-use edges in the SSA | 121 definition has changed. SSA edges are def-use edges in the SSA |
124 web. For each D-U edge, we store the target statement or PHI node | 122 web. For each D-U edge, we store the target statement or PHI node |
125 UID in a bitmap. UIDs order stmts in execution order. */ | 123 UID in a bitmap. UIDs order stmts in execution order. We use |
124 two worklists to first make forward progress before iterating. */ | |
126 static bitmap ssa_edge_worklist; | 125 static bitmap ssa_edge_worklist; |
126 static bitmap ssa_edge_worklist_back; | |
127 static vec<gimple *> uid_to_stmt; | 127 static vec<gimple *> uid_to_stmt; |
128 | 128 |
129 /* Return true if the block worklist empty. */ | 129 /* Current RPO index in the iteration. */ |
130 | 130 static int curr_order; |
131 static inline bool | |
132 cfg_blocks_empty_p (void) | |
133 { | |
134 return bitmap_empty_p (cfg_blocks); | |
135 } | |
136 | |
137 | |
138 /* Add a basic block to the worklist. The block must not be the ENTRY | |
139 or EXIT block. */ | |
140 | |
141 static void | |
142 cfg_blocks_add (basic_block bb) | |
143 { | |
144 gcc_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) | |
145 && bb != EXIT_BLOCK_PTR_FOR_FN (cfun)); | |
146 bitmap_set_bit (cfg_blocks, bb_to_cfg_order[bb->index]); | |
147 } | |
148 | |
149 | |
150 /* Remove a block from the worklist. */ | |
151 | |
152 static basic_block | |
153 cfg_blocks_get (void) | |
154 { | |
155 gcc_assert (!cfg_blocks_empty_p ()); | |
156 int order_index = bitmap_first_set_bit (cfg_blocks); | |
157 bitmap_clear_bit (cfg_blocks, order_index); | |
158 return BASIC_BLOCK_FOR_FN (cfun, cfg_order_to_bb [order_index]); | |
159 } | |
160 | 131 |
161 | 132 |
162 /* We have just defined a new value for VAR. If IS_VARYING is true, | 133 /* We have just defined a new value for VAR. If IS_VARYING is true, |
163 add all immediate uses of VAR to VARYING_SSA_EDGES, otherwise add | 134 add all immediate uses of VAR to VARYING_SSA_EDGES, otherwise add |
164 them to INTERESTING_SSA_EDGES. */ | 135 them to INTERESTING_SSA_EDGES. */ |
170 use_operand_p use_p; | 141 use_operand_p use_p; |
171 | 142 |
172 FOR_EACH_IMM_USE_FAST (use_p, iter, var) | 143 FOR_EACH_IMM_USE_FAST (use_p, iter, var) |
173 { | 144 { |
174 gimple *use_stmt = USE_STMT (use_p); | 145 gimple *use_stmt = USE_STMT (use_p); |
146 if (!prop_simulate_again_p (use_stmt)) | |
147 continue; | |
175 | 148 |
176 /* If we did not yet simulate the block wait for this to happen | 149 /* If we did not yet simulate the block wait for this to happen |
177 and do not add the stmt to the SSA edge worklist. */ | 150 and do not add the stmt to the SSA edge worklist. */ |
178 if (! (gimple_bb (use_stmt)->flags & BB_VISITED)) | 151 basic_block use_bb = gimple_bb (use_stmt); |
152 if (! (use_bb->flags & BB_VISITED)) | |
179 continue; | 153 continue; |
180 | 154 |
181 if (prop_simulate_again_p (use_stmt) | 155 /* If this is a use on a not yet executable edge do not bother to |
182 && bitmap_set_bit (ssa_edge_worklist, gimple_uid (use_stmt))) | 156 queue it. */ |
157 if (gimple_code (use_stmt) == GIMPLE_PHI | |
158 && !(EDGE_PRED (use_bb, PHI_ARG_INDEX_FROM_USE (use_p))->flags | |
159 & EDGE_EXECUTABLE)) | |
160 continue; | |
161 | |
162 bitmap worklist; | |
163 if (bb_to_cfg_order[gimple_bb (use_stmt)->index] < curr_order) | |
164 worklist = ssa_edge_worklist_back; | |
165 else | |
166 worklist = ssa_edge_worklist; | |
167 if (bitmap_set_bit (worklist, gimple_uid (use_stmt))) | |
183 { | 168 { |
184 uid_to_stmt[gimple_uid (use_stmt)] = use_stmt; | 169 uid_to_stmt[gimple_uid (use_stmt)] = use_stmt; |
185 if (dump_file && (dump_flags & TDF_DETAILS)) | 170 if (dump_file && (dump_flags & TDF_DETAILS)) |
186 { | 171 { |
187 fprintf (dump_file, "ssa_edge_worklist: adding SSA use in "); | 172 fprintf (dump_file, "ssa_edge_worklist: adding SSA use in "); |
205 if (e->flags & EDGE_EXECUTABLE) | 190 if (e->flags & EDGE_EXECUTABLE) |
206 return; | 191 return; |
207 | 192 |
208 e->flags |= EDGE_EXECUTABLE; | 193 e->flags |= EDGE_EXECUTABLE; |
209 | 194 |
210 cfg_blocks_add (bb); | 195 int bb_order = bb_to_cfg_order[bb->index]; |
196 if (bb_order < curr_order) | |
197 bitmap_set_bit (cfg_blocks_back, bb_order); | |
198 else | |
199 bitmap_set_bit (cfg_blocks, bb_order); | |
211 | 200 |
212 if (dump_file && (dump_flags & TDF_DETAILS)) | 201 if (dump_file && (dump_flags & TDF_DETAILS)) |
213 fprintf (dump_file, "Adding destination of edge (%d -> %d) to worklist\n", | 202 fprintf (dump_file, "Adding destination of edge (%d -> %d) to worklist\n", |
214 e->src->index, e->dest->index); | 203 e->src->index, e->dest->index); |
215 } | 204 } |
216 | 205 |
217 | 206 |
218 /* Simulate the execution of STMT and update the work lists accordingly. */ | 207 /* Simulate the execution of STMT and update the work lists accordingly. */ |
219 | 208 |
220 static void | 209 void |
221 simulate_stmt (gimple *stmt) | 210 ssa_propagation_engine::simulate_stmt (gimple *stmt) |
222 { | 211 { |
223 enum ssa_prop_result val = SSA_PROP_NOT_INTERESTING; | 212 enum ssa_prop_result val = SSA_PROP_NOT_INTERESTING; |
224 edge taken_edge = NULL; | 213 edge taken_edge = NULL; |
225 tree output_name = NULL_TREE; | 214 tree output_name = NULL_TREE; |
226 | 215 |
232 if (!prop_simulate_again_p (stmt)) | 221 if (!prop_simulate_again_p (stmt)) |
233 return; | 222 return; |
234 | 223 |
235 if (gimple_code (stmt) == GIMPLE_PHI) | 224 if (gimple_code (stmt) == GIMPLE_PHI) |
236 { | 225 { |
237 val = ssa_prop_visit_phi (as_a <gphi *> (stmt)); | 226 val = visit_phi (as_a <gphi *> (stmt)); |
238 output_name = gimple_phi_result (stmt); | 227 output_name = gimple_phi_result (stmt); |
239 } | 228 } |
240 else | 229 else |
241 val = ssa_prop_visit_stmt (stmt, &taken_edge, &output_name); | 230 val = visit_stmt (stmt, &taken_edge, &output_name); |
242 | 231 |
243 if (val == SSA_PROP_VARYING) | 232 if (val == SSA_PROP_VARYING) |
244 { | 233 { |
245 prop_set_simulate_again (stmt, false); | 234 prop_set_simulate_again (stmt, false); |
246 | 235 |
312 fprintf (dump_file, "marking stmt to be not simulated again\n"); | 301 fprintf (dump_file, "marking stmt to be not simulated again\n"); |
313 prop_set_simulate_again (stmt, false); | 302 prop_set_simulate_again (stmt, false); |
314 } | 303 } |
315 } | 304 } |
316 | 305 |
317 /* Process an SSA edge worklist. WORKLIST is the SSA edge worklist to | |
318 drain. This pops statements off the given WORKLIST and processes | |
319 them until one statement was simulated or there are no more statements | |
320 on WORKLIST. We take a pointer to WORKLIST because it may be reallocated | |
321 when an SSA edge is added to it in simulate_stmt. Return true if a stmt | |
322 was simulated. */ | |
323 | |
324 static void | |
325 process_ssa_edge_worklist () | |
326 { | |
327 /* Process the next entry from the worklist. */ | |
328 unsigned stmt_uid = bitmap_first_set_bit (ssa_edge_worklist); | |
329 bitmap_clear_bit (ssa_edge_worklist, stmt_uid); | |
330 gimple *stmt = uid_to_stmt[stmt_uid]; | |
331 | |
332 /* We should not have stmts in not yet simulated BBs on the worklist. */ | |
333 gcc_assert (gimple_bb (stmt)->flags & BB_VISITED); | |
334 | |
335 if (dump_file && (dump_flags & TDF_DETAILS)) | |
336 { | |
337 fprintf (dump_file, "\nSimulating statement: "); | |
338 print_gimple_stmt (dump_file, stmt, 0, dump_flags); | |
339 } | |
340 | |
341 simulate_stmt (stmt); | |
342 } | |
343 | |
344 | 306 |
345 /* Simulate the execution of BLOCK. Evaluate the statement associated | 307 /* Simulate the execution of BLOCK. Evaluate the statement associated |
346 with each variable reference inside the block. */ | 308 with each variable reference inside the block. */ |
347 | 309 |
348 static void | 310 void |
349 simulate_block (basic_block block) | 311 ssa_propagation_engine::simulate_block (basic_block block) |
350 { | 312 { |
351 gimple_stmt_iterator gsi; | 313 gimple_stmt_iterator gsi; |
352 | 314 |
353 /* There is nothing to do for the exit block. */ | 315 /* There is nothing to do for the exit block. */ |
354 if (block == EXIT_BLOCK_PTR_FOR_FN (cfun)) | 316 if (block == EXIT_BLOCK_PTR_FOR_FN (cfun)) |
416 edge_iterator ei; | 378 edge_iterator ei; |
417 basic_block bb; | 379 basic_block bb; |
418 | 380 |
419 /* Worklists of SSA edges. */ | 381 /* Worklists of SSA edges. */ |
420 ssa_edge_worklist = BITMAP_ALLOC (NULL); | 382 ssa_edge_worklist = BITMAP_ALLOC (NULL); |
383 ssa_edge_worklist_back = BITMAP_ALLOC (NULL); | |
384 bitmap_tree_view (ssa_edge_worklist); | |
385 bitmap_tree_view (ssa_edge_worklist_back); | |
421 | 386 |
422 /* Worklist of basic-blocks. */ | 387 /* Worklist of basic-blocks. */ |
423 bb_to_cfg_order = XNEWVEC (int, last_basic_block_for_fn (cfun) + 1); | 388 bb_to_cfg_order = XNEWVEC (int, last_basic_block_for_fn (cfun) + 1); |
424 cfg_order_to_bb = XNEWVEC (int, n_basic_blocks_for_fn (cfun)); | 389 cfg_order_to_bb = XNEWVEC (int, n_basic_blocks_for_fn (cfun)); |
425 int n = pre_and_rev_post_order_compute_fn (cfun, NULL, | 390 int n = pre_and_rev_post_order_compute_fn (cfun, NULL, |
426 cfg_order_to_bb, false); | 391 cfg_order_to_bb, false); |
427 for (int i = 0; i < n; ++i) | 392 for (int i = 0; i < n; ++i) |
428 bb_to_cfg_order[cfg_order_to_bb[i]] = i; | 393 bb_to_cfg_order[cfg_order_to_bb[i]] = i; |
429 cfg_blocks = BITMAP_ALLOC (NULL); | 394 cfg_blocks = BITMAP_ALLOC (NULL); |
430 | 395 cfg_blocks_back = BITMAP_ALLOC (NULL); |
431 if (dump_file && (dump_flags & TDF_DETAILS)) | |
432 dump_immediate_uses (dump_file); | |
433 | 396 |
434 /* Initially assume that every edge in the CFG is not executable. | 397 /* Initially assume that every edge in the CFG is not executable. |
435 (including the edges coming out of the entry block). Mark blocks | 398 (including the edges coming out of the entry block). Mark blocks |
436 as not visited, blocks not yet visited will have all their statements | 399 as not visited, blocks not yet visited will have all their statements |
437 simulated once an incoming edge gets executable. */ | 400 simulated once an incoming edge gets executable. */ |
473 | 436 |
474 static void | 437 static void |
475 ssa_prop_fini (void) | 438 ssa_prop_fini (void) |
476 { | 439 { |
477 BITMAP_FREE (cfg_blocks); | 440 BITMAP_FREE (cfg_blocks); |
441 BITMAP_FREE (cfg_blocks_back); | |
478 free (bb_to_cfg_order); | 442 free (bb_to_cfg_order); |
479 free (cfg_order_to_bb); | 443 free (cfg_order_to_bb); |
480 BITMAP_FREE (ssa_edge_worklist); | 444 BITMAP_FREE (ssa_edge_worklist); |
445 BITMAP_FREE (ssa_edge_worklist_back); | |
481 uid_to_stmt.release (); | 446 uid_to_stmt.release (); |
482 } | 447 } |
483 | 448 |
484 | 449 |
485 /* Return true if EXPR is an acceptable right-hand-side for a | 450 /* Return true if EXPR is an acceptable right-hand-side for a |
779 /* The call simplified to an expression that is | 744 /* The call simplified to an expression that is |
780 not a valid GIMPLE RHS. */ | 745 not a valid GIMPLE RHS. */ |
781 return false; | 746 return false; |
782 } | 747 } |
783 | 748 |
784 | |
785 /* Entry point to the propagation engine. | 749 /* Entry point to the propagation engine. |
786 | 750 |
787 VISIT_STMT is called for every statement visited. | 751 The VISIT_STMT virtual function is called for every statement |
788 VISIT_PHI is called for every PHI node visited. */ | 752 visited and the VISIT_PHI virtual function is called for every PHI |
753 node visited. */ | |
789 | 754 |
790 void | 755 void |
791 ssa_propagate (ssa_prop_visit_stmt_fn visit_stmt, | 756 ssa_propagation_engine::ssa_propagate (void) |
792 ssa_prop_visit_phi_fn visit_phi) | 757 { |
793 { | |
794 ssa_prop_visit_stmt = visit_stmt; | |
795 ssa_prop_visit_phi = visit_phi; | |
796 | |
797 ssa_prop_init (); | 758 ssa_prop_init (); |
798 | 759 |
799 /* Iterate until the worklists are empty. */ | 760 curr_order = 0; |
800 while (! cfg_blocks_empty_p () | 761 |
801 || ! bitmap_empty_p (ssa_edge_worklist)) | 762 /* Iterate until the worklists are empty. We iterate both blocks |
802 { | 763 and stmts in RPO order, using sets of two worklists to first |
803 /* First simulate whole blocks. */ | 764 complete the current iteration before iterating over backedges. */ |
804 if (! cfg_blocks_empty_p ()) | 765 while (1) |
805 { | 766 { |
806 /* Pull the next block to simulate off the worklist. */ | 767 int next_block_order = (bitmap_empty_p (cfg_blocks) |
807 basic_block dest_block = cfg_blocks_get (); | 768 ? -1 : bitmap_first_set_bit (cfg_blocks)); |
808 simulate_block (dest_block); | 769 int next_stmt_uid = (bitmap_empty_p (ssa_edge_worklist) |
770 ? -1 : bitmap_first_set_bit (ssa_edge_worklist)); | |
771 if (next_block_order == -1 && next_stmt_uid == -1) | |
772 { | |
773 if (bitmap_empty_p (cfg_blocks_back) | |
774 && bitmap_empty_p (ssa_edge_worklist_back)) | |
775 break; | |
776 | |
777 if (dump_file && (dump_flags & TDF_DETAILS)) | |
778 fprintf (dump_file, "Regular worklists empty, now processing " | |
779 "backedge destinations\n"); | |
780 std::swap (cfg_blocks, cfg_blocks_back); | |
781 std::swap (ssa_edge_worklist, ssa_edge_worklist_back); | |
809 continue; | 782 continue; |
810 } | 783 } |
811 | 784 |
812 /* Then simulate from the SSA edge worklist. */ | 785 int next_stmt_bb_order = -1; |
813 process_ssa_edge_worklist (); | 786 gimple *next_stmt = NULL; |
787 if (next_stmt_uid != -1) | |
788 { | |
789 next_stmt = uid_to_stmt[next_stmt_uid]; | |
790 next_stmt_bb_order = bb_to_cfg_order[gimple_bb (next_stmt)->index]; | |
791 } | |
792 | |
793 /* Pull the next block to simulate off the worklist if it comes first. */ | |
794 if (next_block_order != -1 | |
795 && (next_stmt_bb_order == -1 | |
796 || next_block_order <= next_stmt_bb_order)) | |
797 { | |
798 curr_order = next_block_order; | |
799 bitmap_clear_bit (cfg_blocks, next_block_order); | |
800 basic_block bb | |
801 = BASIC_BLOCK_FOR_FN (cfun, cfg_order_to_bb [next_block_order]); | |
802 simulate_block (bb); | |
803 } | |
804 /* Else simulate from the SSA edge worklist. */ | |
805 else | |
806 { | |
807 curr_order = next_stmt_bb_order; | |
808 if (dump_file && (dump_flags & TDF_DETAILS)) | |
809 { | |
810 fprintf (dump_file, "\nSimulating statement: "); | |
811 print_gimple_stmt (dump_file, next_stmt, 0, dump_flags); | |
812 } | |
813 simulate_stmt (next_stmt); | |
814 } | |
814 } | 815 } |
815 | 816 |
816 ssa_prop_fini (); | 817 ssa_prop_fini (); |
817 } | 818 } |
818 | 819 |
859 | 860 |
860 /* Replace USE references in statement STMT with the values stored in | 861 /* Replace USE references in statement STMT with the values stored in |
861 PROP_VALUE. Return true if at least one reference was replaced. */ | 862 PROP_VALUE. Return true if at least one reference was replaced. */ |
862 | 863 |
863 bool | 864 bool |
864 replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value) | 865 substitute_and_fold_engine::replace_uses_in (gimple *stmt) |
865 { | 866 { |
866 bool replaced = false; | 867 bool replaced = false; |
867 use_operand_p use; | 868 use_operand_p use; |
868 ssa_op_iter iter; | 869 ssa_op_iter iter; |
869 | 870 |
870 FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) | 871 FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) |
871 { | 872 { |
872 tree tuse = USE_FROM_PTR (use); | 873 tree tuse = USE_FROM_PTR (use); |
873 tree val = (*get_value) (tuse); | 874 tree val = get_value (tuse); |
874 | 875 |
875 if (val == tuse || val == NULL_TREE) | 876 if (val == tuse || val == NULL_TREE) |
876 continue; | 877 continue; |
877 | 878 |
878 if (gimple_code (stmt) == GIMPLE_ASM | 879 if (gimple_code (stmt) == GIMPLE_ASM |
897 | 898 |
898 | 899 |
899 /* Replace propagated values into all the arguments for PHI using the | 900 /* Replace propagated values into all the arguments for PHI using the |
900 values from PROP_VALUE. */ | 901 values from PROP_VALUE. */ |
901 | 902 |
902 static bool | 903 bool |
903 replace_phi_args_in (gphi *phi, ssa_prop_get_value_fn get_value) | 904 substitute_and_fold_engine::replace_phi_args_in (gphi *phi) |
904 { | 905 { |
905 size_t i; | 906 size_t i; |
906 bool replaced = false; | 907 bool replaced = false; |
907 | 908 |
908 if (dump_file && (dump_flags & TDF_DETAILS)) | 909 if (dump_file && (dump_flags & TDF_DETAILS)) |
915 { | 916 { |
916 tree arg = gimple_phi_arg_def (phi, i); | 917 tree arg = gimple_phi_arg_def (phi, i); |
917 | 918 |
918 if (TREE_CODE (arg) == SSA_NAME) | 919 if (TREE_CODE (arg) == SSA_NAME) |
919 { | 920 { |
920 tree val = (*get_value) (arg); | 921 tree val = get_value (arg); |
921 | 922 |
922 if (val && val != arg && may_propagate_copy (arg, val)) | 923 if (val && val != arg && may_propagate_copy (arg, val)) |
923 { | 924 { |
924 edge e = gimple_phi_arg_edge (phi, i); | 925 edge e = gimple_phi_arg_edge (phi, i); |
925 | 926 |
966 | 967 |
967 class substitute_and_fold_dom_walker : public dom_walker | 968 class substitute_and_fold_dom_walker : public dom_walker |
968 { | 969 { |
969 public: | 970 public: |
970 substitute_and_fold_dom_walker (cdi_direction direction, | 971 substitute_and_fold_dom_walker (cdi_direction direction, |
971 ssa_prop_get_value_fn get_value_fn_, | 972 class substitute_and_fold_engine *engine) |
972 ssa_prop_fold_stmt_fn fold_fn_) | 973 : dom_walker (direction), |
973 : dom_walker (direction), get_value_fn (get_value_fn_), | 974 something_changed (false), |
974 fold_fn (fold_fn_), something_changed (false) | 975 substitute_and_fold_engine (engine) |
975 { | 976 { |
976 stmts_to_remove.create (0); | 977 stmts_to_remove.create (0); |
977 stmts_to_fixup.create (0); | 978 stmts_to_fixup.create (0); |
978 need_eh_cleanup = BITMAP_ALLOC (NULL); | 979 need_eh_cleanup = BITMAP_ALLOC (NULL); |
979 } | 980 } |
985 } | 986 } |
986 | 987 |
987 virtual edge before_dom_children (basic_block); | 988 virtual edge before_dom_children (basic_block); |
988 virtual void after_dom_children (basic_block) {} | 989 virtual void after_dom_children (basic_block) {} |
989 | 990 |
990 ssa_prop_get_value_fn get_value_fn; | |
991 ssa_prop_fold_stmt_fn fold_fn; | |
992 bool something_changed; | 991 bool something_changed; |
993 vec<gimple *> stmts_to_remove; | 992 vec<gimple *> stmts_to_remove; |
994 vec<gimple *> stmts_to_fixup; | 993 vec<gimple *> stmts_to_fixup; |
995 bitmap need_eh_cleanup; | 994 bitmap need_eh_cleanup; |
995 | |
996 class substitute_and_fold_engine *substitute_and_fold_engine; | |
996 }; | 997 }; |
997 | 998 |
998 edge | 999 edge |
999 substitute_and_fold_dom_walker::before_dom_children (basic_block bb) | 1000 substitute_and_fold_dom_walker::before_dom_children (basic_block bb) |
1000 { | 1001 { |
1007 tree res = gimple_phi_result (phi); | 1008 tree res = gimple_phi_result (phi); |
1008 if (virtual_operand_p (res)) | 1009 if (virtual_operand_p (res)) |
1009 continue; | 1010 continue; |
1010 if (res && TREE_CODE (res) == SSA_NAME) | 1011 if (res && TREE_CODE (res) == SSA_NAME) |
1011 { | 1012 { |
1012 tree sprime = get_value_fn (res); | 1013 tree sprime = substitute_and_fold_engine->get_value (res); |
1013 if (sprime | 1014 if (sprime |
1014 && sprime != res | 1015 && sprime != res |
1015 && may_propagate_copy (res, sprime)) | 1016 && may_propagate_copy (res, sprime)) |
1016 { | 1017 { |
1017 stmts_to_remove.safe_push (phi); | 1018 stmts_to_remove.safe_push (phi); |
1018 continue; | 1019 continue; |
1019 } | 1020 } |
1020 } | 1021 } |
1021 something_changed |= replace_phi_args_in (phi, get_value_fn); | 1022 something_changed |= substitute_and_fold_engine->replace_phi_args_in (phi); |
1022 } | 1023 } |
1023 | 1024 |
1024 /* Propagate known values into stmts. In some case it exposes | 1025 /* Propagate known values into stmts. In some case it exposes |
1025 more trivially deletable stmts to walk backward. */ | 1026 more trivially deletable stmts to walk backward. */ |
1026 for (gimple_stmt_iterator i = gsi_start_bb (bb); | 1027 for (gimple_stmt_iterator i = gsi_start_bb (bb); |
1033 /* No point propagating into a stmt we have a value for we | 1034 /* No point propagating into a stmt we have a value for we |
1034 can propagate into all uses. Mark it for removal instead. */ | 1035 can propagate into all uses. Mark it for removal instead. */ |
1035 tree lhs = gimple_get_lhs (stmt); | 1036 tree lhs = gimple_get_lhs (stmt); |
1036 if (lhs && TREE_CODE (lhs) == SSA_NAME) | 1037 if (lhs && TREE_CODE (lhs) == SSA_NAME) |
1037 { | 1038 { |
1038 tree sprime = get_value_fn (lhs); | 1039 tree sprime = substitute_and_fold_engine->get_value (lhs); |
1039 if (sprime | 1040 if (sprime |
1040 && sprime != lhs | 1041 && sprime != lhs |
1041 && may_propagate_copy (lhs, sprime) | 1042 && may_propagate_copy (lhs, sprime) |
1042 && !stmt_could_throw_p (stmt) | 1043 && !stmt_could_throw_p (cfun, stmt) |
1043 && !gimple_has_side_effects (stmt) | 1044 && !gimple_has_side_effects (stmt) |
1044 /* We have to leave ASSERT_EXPRs around for jump-threading. */ | 1045 /* We have to leave ASSERT_EXPRs around for jump-threading. */ |
1045 && (!is_gimple_assign (stmt) | 1046 && (!is_gimple_assign (stmt) |
1046 || gimple_assign_rhs_code (stmt) != ASSERT_EXPR)) | 1047 || gimple_assign_rhs_code (stmt) != ASSERT_EXPR)) |
1047 { | 1048 { |
1062 gimple *old_stmt = stmt; | 1063 gimple *old_stmt = stmt; |
1063 bool was_noreturn = (is_gimple_call (stmt) | 1064 bool was_noreturn = (is_gimple_call (stmt) |
1064 && gimple_call_noreturn_p (stmt)); | 1065 && gimple_call_noreturn_p (stmt)); |
1065 | 1066 |
1066 /* Replace real uses in the statement. */ | 1067 /* Replace real uses in the statement. */ |
1067 did_replace |= replace_uses_in (stmt, get_value_fn); | 1068 did_replace |= substitute_and_fold_engine->replace_uses_in (stmt); |
1068 | 1069 |
1069 /* If we made a replacement, fold the statement. */ | 1070 /* If we made a replacement, fold the statement. */ |
1070 if (did_replace) | 1071 if (did_replace) |
1071 { | 1072 { |
1072 fold_stmt (&i, follow_single_use_edges); | 1073 fold_stmt (&i, follow_single_use_edges); |
1075 } | 1076 } |
1076 | 1077 |
1077 /* Some statements may be simplified using propagator | 1078 /* Some statements may be simplified using propagator |
1078 specific information. Do this before propagating | 1079 specific information. Do this before propagating |
1079 into the stmt to not disturb pass specific information. */ | 1080 into the stmt to not disturb pass specific information. */ |
1080 if (fold_fn) | 1081 update_stmt_if_modified (stmt); |
1081 { | 1082 if (substitute_and_fold_engine->fold_stmt(&i)) |
1082 update_stmt_if_modified (stmt); | 1083 { |
1083 if ((*fold_fn)(&i)) | 1084 did_replace = true; |
1084 { | 1085 prop_stats.num_stmts_folded++; |
1085 did_replace = true; | 1086 stmt = gsi_stmt (i); |
1086 prop_stats.num_stmts_folded++; | 1087 gimple_set_modified (stmt, true); |
1087 stmt = gsi_stmt (i); | |
1088 gimple_set_modified (stmt, true); | |
1089 } | |
1090 } | 1088 } |
1091 | 1089 |
1092 /* If this is a control statement the propagator left edges | 1090 /* If this is a control statement the propagator left edges |
1093 unexecuted on force the condition in a way consistent with | 1091 unexecuted on force the condition in a way consistent with |
1094 that. See PR66945 for cases where the propagator can end | 1092 that. See PR66945 for cases where the propagator can end |
1170 last to first element. Otherwise we scan from first to last element. | 1168 last to first element. Otherwise we scan from first to last element. |
1171 | 1169 |
1172 Return TRUE when something changed. */ | 1170 Return TRUE when something changed. */ |
1173 | 1171 |
1174 bool | 1172 bool |
1175 substitute_and_fold (ssa_prop_get_value_fn get_value_fn, | 1173 substitute_and_fold_engine::substitute_and_fold (void) |
1176 ssa_prop_fold_stmt_fn fold_fn) | 1174 { |
1177 { | |
1178 gcc_assert (get_value_fn); | |
1179 | |
1180 if (dump_file && (dump_flags & TDF_DETAILS)) | 1175 if (dump_file && (dump_flags & TDF_DETAILS)) |
1181 fprintf (dump_file, "\nSubstituting values and folding statements\n\n"); | 1176 fprintf (dump_file, "\nSubstituting values and folding statements\n\n"); |
1182 | 1177 |
1183 memset (&prop_stats, 0, sizeof (prop_stats)); | 1178 memset (&prop_stats, 0, sizeof (prop_stats)); |
1184 | 1179 |
1185 calculate_dominance_info (CDI_DOMINATORS); | 1180 calculate_dominance_info (CDI_DOMINATORS); |
1186 substitute_and_fold_dom_walker walker(CDI_DOMINATORS, | 1181 substitute_and_fold_dom_walker walker (CDI_DOMINATORS, this); |
1187 get_value_fn, fold_fn); | |
1188 walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun)); | 1182 walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun)); |
1189 | 1183 |
1190 /* We cannot remove stmts during the BB walk, especially not release | 1184 /* We cannot remove stmts during the BB walk, especially not release |
1191 SSA names there as that destroys the lattice of our callers. | 1185 SSA names there as that destroys the lattice of our callers. |
1192 Remove stmts in reverse order to make debug stmt creation possible. */ | 1186 Remove stmts in reverse order to make debug stmt creation possible. */ |