Mercurial > hg > CbC > CbC_gcc
comparison gcc/ipa-pure-const.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
comparison
equal
deleted
inserted
replaced
56:3c8a44c06a95 | 63:b7f97abdc517 |
---|---|
1 /* Callgraph based analysis of static variables. | 1 /* Callgraph based analysis of static variables. |
2 Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. | 2 Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 |
3 Free Software Foundation, Inc. | |
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> | 4 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> |
4 | 5 |
5 This file is part of GCC. | 6 This file is part of GCC. |
6 | 7 |
7 GCC is free software; you can redistribute it and/or modify it under | 8 GCC is free software; you can redistribute it and/or modify it under |
46 #include "gimple.h" | 47 #include "gimple.h" |
47 #include "cgraph.h" | 48 #include "cgraph.h" |
48 #include "output.h" | 49 #include "output.h" |
49 #include "flags.h" | 50 #include "flags.h" |
50 #include "timevar.h" | 51 #include "timevar.h" |
52 #include "toplev.h" | |
51 #include "diagnostic.h" | 53 #include "diagnostic.h" |
54 #include "gimple-pretty-print.h" | |
52 #include "langhooks.h" | 55 #include "langhooks.h" |
53 #include "target.h" | 56 #include "target.h" |
54 #include "lto-streamer.h" | 57 #include "lto-streamer.h" |
55 #include "cfgloop.h" | 58 #include "cfgloop.h" |
56 #include "tree-scalar-evolution.h" | 59 #include "tree-scalar-evolution.h" |
60 #include "intl.h" | |
61 #include "opts.h" | |
57 | 62 |
58 static struct pointer_set_t *visited_nodes; | 63 static struct pointer_set_t *visited_nodes; |
59 | 64 |
60 /* Lattice values for const and pure functions. Everything starts out | 65 /* Lattice values for const and pure functions. Everything starts out |
61 being const, then may drop to pure and then neither depending on | 66 being const, then may drop to pure and then neither depending on |
103 /* Holders of ipa cgraph hooks: */ | 108 /* Holders of ipa cgraph hooks: */ |
104 static struct cgraph_node_hook_list *function_insertion_hook_holder; | 109 static struct cgraph_node_hook_list *function_insertion_hook_holder; |
105 static struct cgraph_2node_hook_list *node_duplication_hook_holder; | 110 static struct cgraph_2node_hook_list *node_duplication_hook_holder; |
106 static struct cgraph_node_hook_list *node_removal_hook_holder; | 111 static struct cgraph_node_hook_list *node_removal_hook_holder; |
107 | 112 |
113 /* Try to guess if function body will always be visible to compiler | |
114 when compiling the call and whether compiler will be able | |
115 to propagate the information by itself. */ | |
116 | |
117 static bool | |
118 function_always_visible_to_compiler_p (tree decl) | |
119 { | |
120 return (!TREE_PUBLIC (decl) || DECL_DECLARED_INLINE_P (decl)); | |
121 } | |
122 | |
123 /* Emit suggestion about attribute ATTRIB_NAME for DECL. KNOWN_FINITE | |
124 is true if the function is known to be finite. The diagnostic is | |
125 controlled by OPTION. WARNED_ABOUT is a pointer_set unique for | |
126 OPTION, this function may initialize it and it is always returned | |
127 by the function. */ | |
128 | |
129 static struct pointer_set_t * | |
130 suggest_attribute (int option, tree decl, bool known_finite, | |
131 struct pointer_set_t *warned_about, | |
132 const char * attrib_name) | |
133 { | |
134 if (!option_enabled (option)) | |
135 return warned_about; | |
136 if (TREE_THIS_VOLATILE (decl) | |
137 || (known_finite && function_always_visible_to_compiler_p (decl))) | |
138 return warned_about; | |
139 | |
140 if (!warned_about) | |
141 warned_about = pointer_set_create (); | |
142 if (pointer_set_contains (warned_about, decl)) | |
143 return warned_about; | |
144 pointer_set_insert (warned_about, decl); | |
145 warning_at (DECL_SOURCE_LOCATION (decl), | |
146 option, | |
147 known_finite | |
148 ? _("function might be candidate for attribute %<%s%>") | |
149 : _("function might be candidate for attribute %<%s%>" | |
150 " if it is known to return normally"), attrib_name); | |
151 return warned_about; | |
152 } | |
153 | |
154 /* Emit suggestion about __attribute_((pure)) for DECL. KNOWN_FINITE | |
155 is true if the function is known to be finite. */ | |
156 | |
157 static void | |
158 warn_function_pure (tree decl, bool known_finite) | |
159 { | |
160 static struct pointer_set_t *warned_about; | |
161 | |
162 warned_about | |
163 = suggest_attribute (OPT_Wsuggest_attribute_pure, decl, | |
164 known_finite, warned_about, "pure"); | |
165 } | |
166 | |
167 /* Emit suggestion about __attribute_((const)) for DECL. KNOWN_FINITE | |
168 is true if the function is known to be finite. */ | |
169 | |
170 static void | |
171 warn_function_const (tree decl, bool known_finite) | |
172 { | |
173 static struct pointer_set_t *warned_about; | |
174 warned_about | |
175 = suggest_attribute (OPT_Wsuggest_attribute_const, decl, | |
176 known_finite, warned_about, "const"); | |
177 } | |
108 /* Init the function state. */ | 178 /* Init the function state. */ |
109 | 179 |
110 static void | 180 static void |
111 finish_state (void) | 181 finish_state (void) |
112 { | 182 { |
157 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) | 227 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) |
158 return; | 228 return; |
159 | 229 |
160 /* If the variable has the "used" attribute, treat it as if it had a | 230 /* If the variable has the "used" attribute, treat it as if it had a |
161 been touched by the devil. */ | 231 been touched by the devil. */ |
162 if (lookup_attribute ("used", DECL_ATTRIBUTES (t))) | 232 if (DECL_PRESERVE_P (t)) |
163 { | 233 { |
164 local->pure_const_state = IPA_NEITHER; | 234 local->pure_const_state = IPA_NEITHER; |
165 if (dump_file) | 235 if (dump_file) |
166 fprintf (dump_file, " Used static/global variable is not const/pure\n"); | 236 fprintf (dump_file, " Used static/global variable is not const/pure\n"); |
167 return; | 237 return; |
322 } | 392 } |
323 } | 393 } |
324 | 394 |
325 /* When not in IPA mode, we can still handle self recursion. */ | 395 /* When not in IPA mode, we can still handle self recursion. */ |
326 if (!ipa && callee_t == current_function_decl) | 396 if (!ipa && callee_t == current_function_decl) |
327 local->looping = true; | 397 { |
398 if (dump_file) | |
399 fprintf (dump_file, " Recursive call can loop.\n"); | |
400 local->looping = true; | |
401 } | |
328 /* Either calle is unknown or we are doing local analysis. | 402 /* Either calle is unknown or we are doing local analysis. |
329 Look to see if there are any bits available for the callee (such as by | 403 Look to see if there are any bits available for the callee (such as by |
330 declaration or because it is builtin) and process solely on the basis of | 404 declaration or because it is builtin) and process solely on the basis of |
331 those bits. */ | 405 those bits. */ |
332 else if (!ipa || !callee_t) | 406 else if (!ipa || !callee_t) |
350 local->can_throw = true; | 424 local->can_throw = true; |
351 } | 425 } |
352 if (flags & ECF_CONST) | 426 if (flags & ECF_CONST) |
353 { | 427 { |
354 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t)) | 428 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t)) |
355 local->looping = true; | 429 { |
430 if (dump_file) | |
431 fprintf (dump_file, " calls looping pure.\n"); | |
432 local->looping = true; | |
433 } | |
356 } | 434 } |
357 else if (flags & ECF_PURE) | 435 else if (flags & ECF_PURE) |
358 { | 436 { |
359 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t)) | 437 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t)) |
360 local->looping = true; | 438 { |
439 if (dump_file) | |
440 fprintf (dump_file, " calls looping const.\n"); | |
441 local->looping = true; | |
442 } | |
361 if (dump_file) | 443 if (dump_file) |
362 fprintf (dump_file, " pure function call in not const\n"); | 444 fprintf (dump_file, " pure function call in not const\n"); |
363 if (local->pure_const_state == IPA_CONST) | 445 if (local->pure_const_state == IPA_CONST) |
364 local->pure_const_state = IPA_PURE; | 446 local->pure_const_state = IPA_PURE; |
365 } | 447 } |
450 break; | 532 break; |
451 case GIMPLE_ASM: | 533 case GIMPLE_ASM: |
452 for (i = 0; i < gimple_asm_nclobbers (stmt); i++) | 534 for (i = 0; i < gimple_asm_nclobbers (stmt); i++) |
453 { | 535 { |
454 tree op = gimple_asm_clobber_op (stmt, i); | 536 tree op = gimple_asm_clobber_op (stmt, i); |
455 if (simple_cst_equal(TREE_VALUE (op), memory_identifier_string) == 1) | 537 if (strcmp (TREE_STRING_POINTER (TREE_VALUE (op)), "memory") == 0) |
456 { | 538 { |
457 if (dump_file) | 539 if (dump_file) |
458 fprintf (dump_file, " memory asm clobber is not const/pure"); | 540 fprintf (dump_file, " memory asm clobber is not const/pure"); |
459 /* Abandon all hope, ye who enter here. */ | 541 /* Abandon all hope, ye who enter here. */ |
460 local->pure_const_state = IPA_NEITHER; | 542 local->pure_const_state = IPA_NEITHER; |
601 /* There are some shared nodes, in particular the initializers on | 683 /* There are some shared nodes, in particular the initializers on |
602 static declarations. We do not need to scan them more than once | 684 static declarations. We do not need to scan them more than once |
603 since all we would be interested in are the addressof | 685 since all we would be interested in are the addressof |
604 operations. */ | 686 operations. */ |
605 visited_nodes = pointer_set_create (); | 687 visited_nodes = pointer_set_create (); |
606 set_function_state (node, analyze_function (node, true)); | 688 if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) |
689 set_function_state (node, analyze_function (node, true)); | |
607 pointer_set_destroy (visited_nodes); | 690 pointer_set_destroy (visited_nodes); |
608 visited_nodes = NULL; | 691 visited_nodes = NULL; |
609 } | 692 } |
610 | 693 |
611 /* Called when new clone is inserted to callgraph late. */ | 694 /* Called when new clone is inserted to callgraph late. */ |
687 | 770 |
688 | 771 |
689 /* Serialize the ipa info for lto. */ | 772 /* Serialize the ipa info for lto. */ |
690 | 773 |
691 static void | 774 static void |
692 pure_const_write_summary (cgraph_node_set set) | 775 pure_const_write_summary (cgraph_node_set set, |
776 varpool_node_set vset ATTRIBUTE_UNUSED) | |
693 { | 777 { |
694 struct cgraph_node *node; | 778 struct cgraph_node *node; |
695 struct lto_simple_output_block *ob | 779 struct lto_simple_output_block *ob |
696 = lto_create_simple_output_block (LTO_section_ipa_pure_const); | 780 = lto_create_simple_output_block (LTO_section_ipa_pure_const); |
697 unsigned int count = 0; | 781 unsigned int count = 0; |
935 w_l->looping = this_looping; | 1019 w_l->looping = this_looping; |
936 | 1020 |
937 switch (this_state) | 1021 switch (this_state) |
938 { | 1022 { |
939 case IPA_CONST: | 1023 case IPA_CONST: |
940 if (!TREE_READONLY (w->decl) && dump_file) | 1024 if (!TREE_READONLY (w->decl)) |
941 fprintf (dump_file, "Function found to be %sconst: %s\n", | 1025 { |
942 this_looping ? "looping " : "", | 1026 warn_function_const (w->decl, !this_looping); |
943 cgraph_node_name (w)); | 1027 if (dump_file) |
1028 fprintf (dump_file, "Function found to be %sconst: %s\n", | |
1029 this_looping ? "looping " : "", | |
1030 cgraph_node_name (w)); | |
1031 } | |
944 cgraph_set_readonly_flag (w, true); | 1032 cgraph_set_readonly_flag (w, true); |
945 cgraph_set_looping_const_or_pure_flag (w, this_looping); | 1033 cgraph_set_looping_const_or_pure_flag (w, this_looping); |
946 break; | 1034 break; |
947 | 1035 |
948 case IPA_PURE: | 1036 case IPA_PURE: |
949 if (!DECL_PURE_P (w->decl) && dump_file) | 1037 if (!DECL_PURE_P (w->decl)) |
950 fprintf (dump_file, "Function found to be %spure: %s\n", | 1038 { |
951 this_looping ? "looping " : "", | 1039 warn_function_pure (w->decl, !this_looping); |
952 cgraph_node_name (w)); | 1040 if (dump_file) |
1041 fprintf (dump_file, "Function found to be %spure: %s\n", | |
1042 this_looping ? "looping " : "", | |
1043 cgraph_node_name (w)); | |
1044 } | |
953 cgraph_set_pure_flag (w, true); | 1045 cgraph_set_pure_flag (w, true); |
954 cgraph_set_looping_const_or_pure_flag (w, this_looping); | 1046 cgraph_set_looping_const_or_pure_flag (w, this_looping); |
955 break; | 1047 break; |
956 | 1048 |
957 default: | 1049 default: |
1092 0 /* todo_flags_finish */ | 1184 0 /* todo_flags_finish */ |
1093 }, | 1185 }, |
1094 generate_summary, /* generate_summary */ | 1186 generate_summary, /* generate_summary */ |
1095 pure_const_write_summary, /* write_summary */ | 1187 pure_const_write_summary, /* write_summary */ |
1096 pure_const_read_summary, /* read_summary */ | 1188 pure_const_read_summary, /* read_summary */ |
1097 NULL, /* function_read_summary */ | 1189 NULL, /* write_optimization_summary */ |
1190 NULL, /* read_optimization_summary */ | |
1098 NULL, /* stmt_fixup */ | 1191 NULL, /* stmt_fixup */ |
1099 0, /* TODOs */ | 1192 0, /* TODOs */ |
1100 NULL, /* function_transform */ | 1193 NULL, /* function_transform */ |
1101 NULL /* variable_transform */ | 1194 NULL /* variable_transform */ |
1102 }; | 1195 }; |
1103 | 1196 |
1197 /* Return true if function should be skipped for local pure const analysis. */ | |
1198 | |
1199 static bool | |
1200 skip_function_for_local_pure_const (struct cgraph_node *node) | |
1201 { | |
1202 /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations | |
1203 we must not promote functions that are called by already processed functions. */ | |
1204 | |
1205 if (function_called_by_processed_nodes_p ()) | |
1206 { | |
1207 if (dump_file) | |
1208 fprintf (dump_file, "Function called in recursive cycle; ignoring\n"); | |
1209 return true; | |
1210 } | |
1211 if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) | |
1212 { | |
1213 if (dump_file) | |
1214 fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n"); | |
1215 return true; | |
1216 } | |
1217 return false; | |
1218 } | |
1219 | |
1104 /* Simple local pass for pure const discovery reusing the analysis from | 1220 /* Simple local pass for pure const discovery reusing the analysis from |
1105 ipa_pure_const. This pass is effective when executed together with | 1221 ipa_pure_const. This pass is effective when executed together with |
1106 other optimization passes in early optimization pass queue. */ | 1222 other optimization passes in early optimization pass queue. */ |
1107 | 1223 |
1108 static unsigned int | 1224 static unsigned int |
1109 local_pure_const (void) | 1225 local_pure_const (void) |
1110 { | 1226 { |
1111 bool changed = false; | 1227 bool changed = false; |
1112 funct_state l; | 1228 funct_state l; |
1229 bool skip; | |
1113 struct cgraph_node *node; | 1230 struct cgraph_node *node; |
1114 | 1231 |
1115 /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations | |
1116 we must not promote functions that are called by already processed functions. */ | |
1117 | |
1118 if (function_called_by_processed_nodes_p ()) | |
1119 { | |
1120 if (dump_file) | |
1121 fprintf (dump_file, "Function called in recursive cycle; ignoring\n"); | |
1122 return 0; | |
1123 } | |
1124 node = cgraph_node (current_function_decl); | 1232 node = cgraph_node (current_function_decl); |
1125 if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) | 1233 skip = skip_function_for_local_pure_const (node); |
1126 { | 1234 if (!warn_suggest_attribute_const |
1127 if (dump_file) | 1235 && !warn_suggest_attribute_pure |
1128 fprintf (dump_file, "Function has wrong visibility; ignoring\n"); | 1236 && skip) |
1129 return 0; | 1237 return 0; |
1130 } | |
1131 | |
1132 l = analyze_function (node, false); | 1238 l = analyze_function (node, false); |
1133 | 1239 |
1134 switch (l->pure_const_state) | 1240 switch (l->pure_const_state) |
1135 { | 1241 { |
1136 case IPA_CONST: | 1242 case IPA_CONST: |
1137 if (!TREE_READONLY (current_function_decl)) | 1243 if (!TREE_READONLY (current_function_decl)) |
1138 { | 1244 { |
1139 cgraph_set_readonly_flag (node, true); | 1245 warn_function_const (current_function_decl, !l->looping); |
1140 cgraph_set_looping_const_or_pure_flag (node, l->looping); | 1246 if (!skip) |
1141 changed = true; | 1247 { |
1248 cgraph_set_readonly_flag (node, true); | |
1249 cgraph_set_looping_const_or_pure_flag (node, l->looping); | |
1250 changed = true; | |
1251 } | |
1142 if (dump_file) | 1252 if (dump_file) |
1143 fprintf (dump_file, "Function found to be %sconst: %s\n", | 1253 fprintf (dump_file, "Function found to be %sconst: %s\n", |
1144 l->looping ? "looping " : "", | 1254 l->looping ? "looping " : "", |
1145 lang_hooks.decl_printable_name (current_function_decl, | 1255 lang_hooks.decl_printable_name (current_function_decl, |
1146 2)); | 1256 2)); |
1147 } | 1257 } |
1148 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) | 1258 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) |
1149 && !l->looping) | 1259 && !l->looping) |
1150 { | 1260 { |
1151 cgraph_set_looping_const_or_pure_flag (node, false); | 1261 if (!skip) |
1152 changed = true; | 1262 { |
1263 cgraph_set_looping_const_or_pure_flag (node, false); | |
1264 changed = true; | |
1265 } | |
1153 if (dump_file) | 1266 if (dump_file) |
1154 fprintf (dump_file, "Function found to be non-looping: %s\n", | 1267 fprintf (dump_file, "Function found to be non-looping: %s\n", |
1155 lang_hooks.decl_printable_name (current_function_decl, | 1268 lang_hooks.decl_printable_name (current_function_decl, |
1156 2)); | 1269 2)); |
1157 } | 1270 } |
1158 break; | 1271 break; |
1159 | 1272 |
1160 case IPA_PURE: | 1273 case IPA_PURE: |
1161 if (!TREE_READONLY (current_function_decl)) | 1274 if (!DECL_PURE_P (current_function_decl)) |
1162 { | 1275 { |
1163 cgraph_set_pure_flag (node, true); | 1276 if (!skip) |
1164 cgraph_set_looping_const_or_pure_flag (node, l->looping); | 1277 { |
1165 changed = true; | 1278 cgraph_set_pure_flag (node, true); |
1279 cgraph_set_looping_const_or_pure_flag (node, l->looping); | |
1280 changed = true; | |
1281 } | |
1282 warn_function_pure (current_function_decl, !l->looping); | |
1166 if (dump_file) | 1283 if (dump_file) |
1167 fprintf (dump_file, "Function found to be %spure: %s\n", | 1284 fprintf (dump_file, "Function found to be %spure: %s\n", |
1168 l->looping ? "looping " : "", | 1285 l->looping ? "looping " : "", |
1169 lang_hooks.decl_printable_name (current_function_decl, | 1286 lang_hooks.decl_printable_name (current_function_decl, |
1170 2)); | 1287 2)); |
1171 } | 1288 } |
1172 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) | 1289 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) |
1173 && !l->looping) | 1290 && !l->looping) |
1174 { | 1291 { |
1175 cgraph_set_looping_const_or_pure_flag (node, false); | 1292 if (!skip) |
1176 changed = true; | 1293 { |
1294 cgraph_set_looping_const_or_pure_flag (node, false); | |
1295 changed = true; | |
1296 } | |
1177 if (dump_file) | 1297 if (dump_file) |
1178 fprintf (dump_file, "Function found to be non-looping: %s\n", | 1298 fprintf (dump_file, "Function found to be non-looping: %s\n", |
1179 lang_hooks.decl_printable_name (current_function_decl, | 1299 lang_hooks.decl_printable_name (current_function_decl, |
1180 2)); | 1300 2)); |
1181 } | 1301 } |