00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "config.h"
00035 #include "system.h"
00036 #include "coretypes.h"
00037 #include "tm.h"
00038 #include "tree.h"
00039 #include "tree-flow.h"
00040 #include "tree-inline.h"
00041 #include "tree-pass.h"
00042 #include "langhooks.h"
00043 #include "pointer-set.h"
00044 #include "ggc.h"
00045 #include "ipa-utils.h"
00046 #include "c-common.h"
00047 #include "tree-gimple.h"
00048 #include "cgraph.h"
00049 #include "output.h"
00050 #include "flags.h"
00051 #include "timevar.h"
00052 #include "diagnostic.h"
00053 #include "langhooks.h"
00054 #include "target.h"
00055
00056 static struct pointer_set_t *visited_nodes;
00057
00058
00059
00060
00061 enum pure_const_state_e
00062 {
00063 IPA_CONST,
00064 IPA_PURE,
00065 IPA_NEITHER
00066 };
00067
00068
00069
00070 struct funct_state_d
00071 {
00072 enum pure_const_state_e pure_const_state;
00073 bool state_set_in_source;
00074 };
00075
00076 typedef struct funct_state_d * funct_state;
00077
00078
00079
00080 static inline funct_state
00081 get_function_state (struct cgraph_node *node)
00082 {
00083 struct ipa_dfs_info * info = node->aux;
00084 return info->aux;
00085 }
00086
00087
00088
00089
00090 static inline void
00091 check_decl (funct_state local,
00092 tree t, bool checking_write)
00093 {
00094
00095
00096 if (lookup_attribute ("used", DECL_ATTRIBUTES (t)))
00097 {
00098 local->pure_const_state = IPA_NEITHER;
00099 return;
00100 }
00101
00102
00103
00104 if (TREE_THIS_VOLATILE (t))
00105 {
00106 local->pure_const_state = IPA_NEITHER;
00107 return;
00108 }
00109
00110
00111 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
00112 return;
00113
00114
00115
00116
00117 if (checking_write)
00118 local->pure_const_state = IPA_NEITHER;
00119
00120 if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
00121 {
00122
00123
00124
00125
00126
00127 if (TREE_READONLY (t)
00128 && DECL_INITIAL (t)
00129 && is_gimple_min_invariant (DECL_INITIAL (t)))
00130 ;
00131 else
00132 {
00133
00134 if (local->pure_const_state == IPA_CONST)
00135 local->pure_const_state = IPA_PURE;
00136 }
00137 }
00138
00139
00140
00141 if (TREE_READONLY (t))
00142 return;
00143
00144
00145 if (local->pure_const_state == IPA_CONST)
00146 local->pure_const_state = IPA_PURE;
00147 }
00148
00149
00150
00151 static void
00152 check_operand (funct_state local,
00153 tree t, bool checking_write)
00154 {
00155 if (!t) return;
00156
00157 if (TREE_CODE (t) == VAR_DECL)
00158 check_decl (local, t, checking_write);
00159 }
00160
00161
00162
00163 static void
00164 check_tree (funct_state local, tree t, bool checking_write)
00165 {
00166 if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
00167 return;
00168
00169
00170
00171 if (TREE_THIS_VOLATILE (t))
00172 {
00173 local->pure_const_state = IPA_NEITHER;
00174 return;
00175 }
00176
00177 while (TREE_CODE (t) == REALPART_EXPR
00178 || TREE_CODE (t) == IMAGPART_EXPR
00179 || handled_component_p (t))
00180 {
00181 if (TREE_CODE (t) == ARRAY_REF)
00182 check_operand (local, TREE_OPERAND (t, 1), false);
00183 t = TREE_OPERAND (t, 0);
00184 }
00185
00186
00187
00188 if (INDIRECT_REF_P (t))
00189 {
00190 check_tree (local, TREE_OPERAND (t, 0), false);
00191
00192
00193
00194
00195
00196 if (checking_write)
00197 {
00198 local->pure_const_state = IPA_NEITHER;
00199 return;
00200 }
00201 else if (local->pure_const_state == IPA_CONST)
00202 local->pure_const_state = IPA_PURE;
00203 }
00204
00205 if (SSA_VAR_P (t))
00206 check_operand (local, t, checking_write);
00207 }
00208
00209
00210
00211 static void
00212 look_for_address_of (funct_state local, tree t)
00213 {
00214 if (TREE_CODE (t) == ADDR_EXPR)
00215 {
00216 tree x = get_base_var (t);
00217 if (TREE_CODE (x) == VAR_DECL)
00218 {
00219 check_decl (local, x, false);
00220
00221
00222
00223 if (local->pure_const_state == IPA_CONST)
00224 local->pure_const_state = IPA_PURE;
00225 }
00226 }
00227 }
00228
00229
00230
00231
00232
00233 static void
00234 check_rhs_var (funct_state local, tree t)
00235 {
00236 look_for_address_of (local, t);
00237
00238
00239 if (tree_could_trap_p (t)
00240 && local->pure_const_state == IPA_CONST)
00241 local->pure_const_state = IPA_PURE;
00242
00243 check_tree(local, t, false);
00244 }
00245
00246
00247
00248
00249 static void
00250 check_lhs_var (funct_state local, tree t)
00251 {
00252
00253
00254 if (tree_could_trap_p (t)
00255 && local->pure_const_state == IPA_CONST)
00256 local->pure_const_state = IPA_PURE;
00257
00258 check_tree(local, t, true);
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268 static void
00269 get_asm_expr_operands (funct_state local, tree stmt)
00270 {
00271 int noutputs = list_length (ASM_OUTPUTS (stmt));
00272 const char **oconstraints
00273 = (const char **) alloca ((noutputs) * sizeof (const char *));
00274 int i;
00275 tree link;
00276 const char *constraint;
00277 bool allows_mem, allows_reg, is_inout;
00278
00279 for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
00280 {
00281 oconstraints[i] = constraint
00282 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
00283 parse_output_constraint (&constraint, i, 0, 0,
00284 &allows_mem, &allows_reg, &is_inout);
00285
00286 check_lhs_var (local, TREE_VALUE (link));
00287 }
00288
00289 for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
00290 {
00291 constraint
00292 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
00293 parse_input_constraint (&constraint, 0, 0, noutputs, 0,
00294 oconstraints, &allows_mem, &allows_reg);
00295
00296 check_rhs_var (local, TREE_VALUE (link));
00297 }
00298
00299 for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
00300 if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1)
00301
00302 local->pure_const_state = IPA_NEITHER;
00303
00304 if (ASM_VOLATILE_P (stmt))
00305 local->pure_const_state = IPA_NEITHER;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315 static void
00316 check_call (funct_state local, tree call_expr)
00317 {
00318 int flags = call_expr_flags(call_expr);
00319 tree operand_list = TREE_OPERAND (call_expr, 1);
00320 tree operand;
00321 tree callee_t = get_callee_fndecl (call_expr);
00322 struct cgraph_node* callee;
00323 enum availability avail = AVAIL_NOT_AVAILABLE;
00324
00325 for (operand = operand_list;
00326 operand != NULL_TREE;
00327 operand = TREE_CHAIN (operand))
00328 {
00329 tree argument = TREE_VALUE (operand);
00330 check_rhs_var (local, argument);
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 if (callee_t)
00344 {
00345 callee = cgraph_node(callee_t);
00346 avail = cgraph_function_body_availability (callee);
00347
00348
00349
00350 if (setjmp_call_p (callee_t))
00351 local->pure_const_state = IPA_NEITHER;
00352
00353 if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
00354 switch (DECL_FUNCTION_CODE (callee_t))
00355 {
00356 case BUILT_IN_LONGJMP:
00357 case BUILT_IN_NONLOCAL_GOTO:
00358 local->pure_const_state = IPA_NEITHER;
00359 break;
00360 default:
00361 break;
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370 if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
00371 {
00372 if (flags & ECF_PURE)
00373 {
00374 if (local->pure_const_state == IPA_CONST)
00375 local->pure_const_state = IPA_PURE;
00376 }
00377 else
00378 local->pure_const_state = IPA_NEITHER;
00379 }
00380 else
00381 {
00382
00383 if (flags & ECF_PURE)
00384 {
00385 if (local->pure_const_state == IPA_CONST)
00386 local->pure_const_state = IPA_PURE;
00387 }
00388 }
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398 static tree
00399 scan_function (tree *tp,
00400 int *walk_subtrees,
00401 void *data)
00402 {
00403 struct cgraph_node *fn = data;
00404 tree t = *tp;
00405 funct_state local = get_function_state (fn);
00406
00407 switch (TREE_CODE (t))
00408 {
00409 case VAR_DECL:
00410 if (DECL_INITIAL (t))
00411 walk_tree (&DECL_INITIAL (t), scan_function, fn, visited_nodes);
00412 *walk_subtrees = 0;
00413 break;
00414
00415 case MODIFY_EXPR:
00416 {
00417
00418 tree lhs = TREE_OPERAND (t, 0);
00419 tree rhs = TREE_OPERAND (t, 1);
00420 check_lhs_var (local, lhs);
00421
00422
00423
00424
00425 switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
00426 {
00427 case tcc_binary:
00428 {
00429 tree op0 = TREE_OPERAND (rhs, 0);
00430 tree op1 = TREE_OPERAND (rhs, 1);
00431 check_rhs_var (local, op0);
00432 check_rhs_var (local, op1);
00433 }
00434 break;
00435 case tcc_unary:
00436 {
00437 tree op0 = TREE_OPERAND (rhs, 0);
00438 check_rhs_var (local, op0);
00439 }
00440
00441 break;
00442 case tcc_reference:
00443 check_rhs_var (local, rhs);
00444 break;
00445 case tcc_declaration:
00446 check_rhs_var (local, rhs);
00447 break;
00448 case tcc_expression:
00449 switch (TREE_CODE (rhs))
00450 {
00451 case ADDR_EXPR:
00452 check_rhs_var (local, rhs);
00453 break;
00454 case CALL_EXPR:
00455 check_call (local, rhs);
00456 break;
00457 default:
00458 break;
00459 }
00460 break;
00461 default:
00462 break;
00463 }
00464 *walk_subtrees = 0;
00465 }
00466 break;
00467
00468 case ADDR_EXPR:
00469
00470
00471 check_rhs_var (local, t);
00472 *walk_subtrees = 0;
00473 break;
00474
00475 case LABEL_EXPR:
00476 if (DECL_NONLOCAL (TREE_OPERAND (t, 0)))
00477
00478 local->pure_const_state = IPA_NEITHER;
00479 break;
00480
00481 case CALL_EXPR:
00482 check_call (local, t);
00483 *walk_subtrees = 0;
00484 break;
00485
00486 case ASM_EXPR:
00487 get_asm_expr_operands (local, t);
00488 *walk_subtrees = 0;
00489 break;
00490
00491 default:
00492 break;
00493 }
00494 return NULL;
00495 }
00496
00497
00498
00499
00500 static void
00501 analyze_function (struct cgraph_node *fn)
00502 {
00503 funct_state l = XCNEW (struct funct_state_d);
00504 tree decl = fn->decl;
00505 struct ipa_dfs_info * w_info = fn->aux;
00506
00507 w_info->aux = l;
00508
00509 l->pure_const_state = IPA_CONST;
00510 l->state_set_in_source = false;
00511
00512
00513
00514
00515 if (TREE_THIS_VOLATILE (decl)
00516 || !targetm.binds_local_p (decl))
00517 {
00518 l->pure_const_state = IPA_NEITHER;
00519 return;
00520 }
00521
00522 if (TREE_READONLY (decl))
00523 {
00524 l->pure_const_state = IPA_CONST;
00525 l->state_set_in_source = true;
00526 }
00527 if (DECL_IS_PURE (decl))
00528 {
00529 l->pure_const_state = IPA_PURE;
00530 l->state_set_in_source = true;
00531 }
00532
00533 if (dump_file)
00534 {
00535 fprintf (dump_file, "\n local analysis of %s with initial value = %d\n ",
00536 cgraph_node_name (fn),
00537 l->pure_const_state);
00538 }
00539
00540 if (!l->state_set_in_source)
00541 {
00542 struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
00543 basic_block this_block;
00544
00545 FOR_EACH_BB_FN (this_block, this_cfun)
00546 {
00547 block_stmt_iterator bsi;
00548 for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
00549 {
00550 walk_tree (bsi_stmt_ptr (bsi), scan_function,
00551 fn, visited_nodes);
00552 if (l->pure_const_state == IPA_NEITHER)
00553 goto end;
00554 }
00555 }
00556
00557 if (l->pure_const_state != IPA_NEITHER)
00558 {
00559 tree old_decl = current_function_decl;
00560
00561
00562
00563
00564 current_function_decl = fn->decl;
00565
00566
00567
00568
00569 gcc_assert (DECL_STRUCT_FUNCTION (fn->decl));
00570
00571 push_cfun (DECL_STRUCT_FUNCTION (fn->decl));
00572
00573 if (mark_dfs_back_edges ())
00574 l->pure_const_state = IPA_NEITHER;
00575
00576 current_function_decl = old_decl;
00577 pop_cfun ();
00578 }
00579 }
00580
00581 end:
00582 if (dump_file)
00583 {
00584 fprintf (dump_file, "after local analysis of %s with initial value = %d\n ",
00585 cgraph_node_name (fn),
00586 l->pure_const_state);
00587 }
00588 }
00589
00590
00591
00592
00593
00594
00595 static unsigned int
00596 static_execute (void)
00597 {
00598 struct cgraph_node *node;
00599 struct cgraph_node *w;
00600 struct cgraph_node **order =
00601 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
00602 int order_pos = order_pos = ipa_utils_reduced_inorder (order, true, false);
00603 int i;
00604 struct ipa_dfs_info * w_info;
00605
00606 if (!memory_identifier_string)
00607 memory_identifier_string = build_string(7, "memory");
00608
00609
00610
00611
00612
00613 visited_nodes = pointer_set_create ();
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 for (node = cgraph_nodes; node; node = node->next)
00624 if (node->analyzed && cgraph_is_master_clone (node))
00625 analyze_function (node);
00626
00627 pointer_set_destroy (visited_nodes);
00628 visited_nodes = NULL;
00629 if (dump_file)
00630 {
00631 dump_cgraph (dump_file);
00632 ipa_utils_print_order(dump_file, "reduced", order, order_pos);
00633 }
00634
00635
00636
00637
00638
00639 for (i = 0; i < order_pos; i++ )
00640 {
00641 enum pure_const_state_e pure_const_state = IPA_CONST;
00642 node = order[i];
00643
00644
00645 w = node;
00646 while (w)
00647 {
00648 funct_state w_l = get_function_state (w);
00649 if (pure_const_state < w_l->pure_const_state)
00650 pure_const_state = w_l->pure_const_state;
00651
00652 if (pure_const_state == IPA_NEITHER)
00653 break;
00654
00655 if (!w_l->state_set_in_source)
00656 {
00657 struct cgraph_edge *e;
00658 for (e = w->callees; e; e = e->next_callee)
00659 {
00660 struct cgraph_node *y = e->callee;
00661
00662 y = cgraph_master_clone (y);
00663 if (y)
00664 {
00665 funct_state y_l = get_function_state (y);
00666 if (pure_const_state < y_l->pure_const_state)
00667 pure_const_state = y_l->pure_const_state;
00668 if (pure_const_state == IPA_NEITHER)
00669 break;
00670 }
00671 }
00672 }
00673 w_info = w->aux;
00674 w = w_info->next_cycle;
00675 }
00676
00677
00678
00679 w = node;
00680 while (w)
00681 {
00682 funct_state w_l = get_function_state (w);
00683
00684
00685 if (!w_l->state_set_in_source)
00686 {
00687 w_l->pure_const_state = pure_const_state;
00688 switch (pure_const_state)
00689 {
00690 case IPA_CONST:
00691 TREE_READONLY (w->decl) = 1;
00692 if (dump_file)
00693 fprintf (dump_file, "Function found to be const: %s\n",
00694 lang_hooks.decl_printable_name(w->decl, 2));
00695 break;
00696
00697 case IPA_PURE:
00698 DECL_IS_PURE (w->decl) = 1;
00699 if (dump_file)
00700 fprintf (dump_file, "Function found to be pure: %s\n",
00701 lang_hooks.decl_printable_name(w->decl, 2));
00702 break;
00703
00704 default:
00705 break;
00706 }
00707 }
00708 w_info = w->aux;
00709 w = w_info->next_cycle;
00710 }
00711 }
00712
00713
00714 for (node = cgraph_nodes; node; node = node->next)
00715
00716 if (node->aux)
00717 {
00718 w_info = node->aux;
00719 if (w_info->aux)
00720 free (w_info->aux);
00721 free (node->aux);
00722 node->aux = NULL;
00723 }
00724
00725 free (order);
00726 return 0;
00727 }
00728
00729 static bool
00730 gate_pure_const (void)
00731 {
00732 return (flag_unit_at_a_time != 0 && flag_ipa_pure_const
00733
00734 && !(errorcount || sorrycount));
00735 }
00736
00737 struct tree_opt_pass pass_ipa_pure_const =
00738 {
00739 "pure-const",
00740 gate_pure_const,
00741 static_execute,
00742 NULL,
00743 NULL,
00744 0,
00745 TV_IPA_PURE_CONST,
00746 0,
00747 0,
00748 0,
00749 0,
00750 0,
00751 0
00752 };
00753
00754