1 /* Callgraph based analysis of static variables.
2 Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* This file marks functions as being either const (TREE_READONLY) or
22 pure (DECL_PURE_P). It can also set a variant of these that
23 are allowed to loop indefinitely (DECL_LOOPING_CONST_PURE_P).
25 This must be run after inlining decisions have been made since
26 otherwise, the local sets will not contain information that is
27 consistent with post inlined state. The global sets are not prone
28 to this problem since they are by definition transitive. */
30 /* The code in this module is called by the ipa pass manager. It
31 should be one of the later passes since it's information is used by
32 the rest of the compilation. */
36 #include "coretypes.h"
39 #include "tree-flow.h"
40 #include "tree-inline.h"
41 #include "tree-pass.h"
42 #include "langhooks.h"
43 #include "pointer-set.h"
45 #include "ipa-utils.h"
52 #include "diagnostic.h"
53 #include "langhooks.h"
56 static struct pointer_set_t *visited_nodes;
58 /* Lattice values for const and pure functions. Everything starts out
59 being const, then may drop to pure and then neither depending on
61 enum pure_const_state_e
68 /* Holder for the const_state. There is one of these per function
73 enum pure_const_state_e pure_const_state;
74 /* What user set here; we can be always sure about this. */
75 enum pure_const_state_e state_set_in_source;
77 /* True if the function could possibly infinite loop. There are a
78 lot of ways that this could be determined. We are pretty
79 conservative here. While it is possible to cse pure and const
80 calls, it is not legal to have dce get rid of the call if there
81 is a possibility that the call could infinite loop since this is
82 a behavioral change. */
88 typedef struct funct_state_d * funct_state;
90 /* The storage of the funct_state is abstracted because there is the
91 possibility that it may be desirable to move this to the cgraph
94 /* Array, indexed by cgraph node uid, of function states. */
96 DEF_VEC_P (funct_state);
97 DEF_VEC_ALLOC_P (funct_state, heap);
98 static VEC (funct_state, heap) *funct_state_vec;
100 /* Holders of ipa cgraph hooks: */
101 static struct cgraph_node_hook_list *function_insertion_hook_holder;
102 static struct cgraph_2node_hook_list *node_duplication_hook_holder;
103 static struct cgraph_node_hook_list *node_removal_hook_holder;
105 /* Init the function state. */
110 free (funct_state_vec);
114 /* Return the function state from NODE. */
116 static inline funct_state
117 get_function_state (struct cgraph_node *node)
120 || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
122 return VEC_index (funct_state, funct_state_vec, node->uid);
125 /* Set the function state S for NODE. */
128 set_function_state (struct cgraph_node *node, funct_state s)
131 || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
132 VEC_safe_grow_cleared (funct_state, heap, funct_state_vec, node->uid + 1);
133 VEC_replace (funct_state, funct_state_vec, node->uid, s);
136 /* Check to see if the use (or definition when CHECKING_WRITE is true)
137 variable T is legal in a function that is either pure or const. */
140 check_decl (funct_state local,
141 tree t, bool checking_write)
145 /* Do not want to do anything with volatile except mark any
146 function that uses one to be not const or pure. */
147 if (TREE_THIS_VOLATILE (t))
149 local->pure_const_state = IPA_NEITHER;
151 fprintf (dump_file, " Volatile operand is not const/pure");
155 /* Do not care about a local automatic that is not static. */
156 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
159 /* If the variable has the "used" attribute, treat it as if it had a
160 been touched by the devil. */
161 if (lookup_attribute ("used", DECL_ATTRIBUTES (t)))
163 local->pure_const_state = IPA_NEITHER;
165 fprintf (dump_file, " Used static/global variable is not const/pure\n");
169 /* Since we have dealt with the locals and params cases above, if we
170 are CHECKING_WRITE, this cannot be a pure or constant
174 local->pure_const_state = IPA_NEITHER;
176 fprintf (dump_file, " static/global memory write is not const/pure\n");
180 if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
182 /* Readonly reads are safe. */
183 if (TREE_READONLY (t) && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t)))
184 return; /* Read of a constant, do not change the function state. */
188 fprintf (dump_file, " global memory read is not const\n");
189 /* Just a regular read. */
190 if (local->pure_const_state == IPA_CONST)
191 local->pure_const_state = IPA_PURE;
196 /* Compilation level statics can be read if they are readonly
198 if (TREE_READONLY (t))
202 fprintf (dump_file, " static memory read is not const\n");
203 /* Just a regular read. */
204 if (local->pure_const_state == IPA_CONST)
205 local->pure_const_state = IPA_PURE;
210 /* Check to see if the use (or definition when CHECKING_WRITE is true)
211 variable T is legal in a function that is either pure or const. */
214 check_op (funct_state local,
215 tree t, bool checking_write)
217 while (t && handled_component_p (t))
218 t = TREE_OPERAND (t, 0);
221 if (INDIRECT_REF_P (t) || TREE_CODE (t) == TARGET_MEM_REF)
223 if (TREE_THIS_VOLATILE (t))
225 local->pure_const_state = IPA_NEITHER;
227 fprintf (dump_file, " Volatile indirect ref is not const/pure\n");
230 else if (checking_write)
232 local->pure_const_state = IPA_NEITHER;
234 fprintf (dump_file, " Indirect ref write is not const/pure\n");
240 fprintf (dump_file, " Indirect ref read is not const\n");
241 if (local->pure_const_state == IPA_CONST)
242 local->pure_const_state = IPA_PURE;
247 /* Check the parameters of a function call to CALL_EXPR to see if
248 there are any references in the parameters that are not allowed for
249 pure or const functions. Also check to see if this is either an
250 indirect call, a call outside the compilation unit, or has special
251 attributes that may also effect the purity. The CALL_EXPR node for
252 the entire call expression. */
255 check_call (funct_state local, gimple call, bool ipa)
257 int flags = gimple_call_flags (call);
258 tree callee_t = gimple_call_fndecl (call);
259 struct cgraph_node* callee;
260 enum availability avail = AVAIL_NOT_AVAILABLE;
261 bool possibly_throws = stmt_could_throw_p (call);
262 bool possibly_throws_externally = (possibly_throws
263 && stmt_can_throw_external (call));
268 for (i = 0; i < gimple_num_ops (call); i++)
269 if (gimple_op (call, i)
270 && tree_could_throw_p (gimple_op (call, i)))
272 if (possibly_throws && flag_non_call_exceptions)
275 fprintf (dump_file, " operand can throw; looping\n");
276 local->looping = true;
278 if (possibly_throws_externally)
281 fprintf (dump_file, " operand can throw externally\n");
282 local->can_throw = true;
287 /* The const and pure flags are set by a variety of places in the
288 compiler (including here). If someone has already set the flags
289 for the callee, (such as for some of the builtins) we will use
290 them, otherwise we will compute our own information.
292 Const and pure functions have less clobber effects than other
293 functions so we process these first. Otherwise if it is a call
294 outside the compilation unit or an indirect call we punt. This
295 leaves local calls which will be processed by following the call
299 callee = cgraph_node(callee_t);
300 avail = cgraph_function_body_availability (callee);
302 /* When bad things happen to bad functions, they cannot be const
304 if (setjmp_call_p (callee_t))
307 fprintf (dump_file, " setjmp is not const/pure\n");
308 local->looping = true;
309 local->pure_const_state = IPA_NEITHER;
312 if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
313 switch (DECL_FUNCTION_CODE (callee_t))
315 case BUILT_IN_LONGJMP:
316 case BUILT_IN_NONLOCAL_GOTO:
318 fprintf (dump_file, " longjmp and nonlocal goto is not const/pure\n");
319 local->pure_const_state = IPA_NEITHER;
320 local->looping = true;
327 /* When not in IPA mode, we can still handle self recursion. */
328 if (!ipa && callee_t == current_function_decl)
329 local->looping = true;
330 /* The callee is either unknown (indirect call) or there is just no
331 scannable code for it (external call) . We look to see if there
332 are any bits available for the callee (such as by declaration or
333 because it is builtin) and process solely on the basis of those
335 else if (avail <= AVAIL_OVERWRITABLE || !ipa)
337 if (possibly_throws && flag_non_call_exceptions)
340 fprintf (dump_file, " can throw; looping\n");
341 local->looping = true;
343 if (possibly_throws_externally)
347 fprintf (dump_file, " can throw externally in region %i\n",
348 lookup_stmt_eh_region (call));
350 fprintf (dump_file, " callee:%s\n",
351 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (callee_t)));
353 local->can_throw = true;
355 if (flags & ECF_CONST)
357 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
358 local->looping = true;
360 else if (flags & ECF_PURE)
362 if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
363 local->looping = true;
365 fprintf (dump_file, " pure function call in not const\n");
366 if (local->pure_const_state == IPA_CONST)
367 local->pure_const_state = IPA_PURE;
372 fprintf (dump_file, " uknown function call is not const/pure\n");
373 local->pure_const_state = IPA_NEITHER;
374 local->looping = true;
377 /* Direct functions calls are handled by IPA propagation. */
380 /* Look into pointer pointed to by GSIP and figure out what interesting side effects
383 check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa)
385 gimple stmt = gsi_stmt (*gsip);
391 fprintf (dump_file, " scanning: ");
392 print_gimple_stmt (dump_file, stmt, 0, 0);
394 if (gimple_loaded_syms (stmt))
395 EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
396 check_decl (local, referenced_var_lookup (i), false);
397 if (gimple_stored_syms (stmt))
398 EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi)
399 check_decl (local, referenced_var_lookup (i), true);
401 if (gimple_code (stmt) != GIMPLE_CALL
402 && stmt_could_throw_p (stmt))
404 if (flag_non_call_exceptions)
407 fprintf (dump_file, " can throw; looping");
408 local->looping = true;
410 if (stmt_can_throw_external (stmt))
413 fprintf (dump_file, " can throw externally");
414 local->can_throw = true;
417 switch (gimple_code (stmt))
420 check_op (local, gimple_assign_lhs (stmt), true);
424 check_op (local, gimple_call_lhs (stmt), true);
426 check_call (local, stmt, ipa);
429 if (DECL_NONLOCAL (gimple_label_label (stmt)))
430 /* Target of long jump. */
433 fprintf (dump_file, " nonlocal label is not const/pure");
434 local->pure_const_state = IPA_NEITHER;
438 for (i = 0; i < gimple_asm_noutputs (stmt); i++)
439 check_op (local, TREE_VALUE (gimple_asm_output_op (stmt, i)), true);
440 for (i = 0; i < gimple_asm_ninputs (stmt); i++)
441 check_op (local, TREE_VALUE (gimple_asm_input_op (stmt, i)), false);
442 for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
444 tree op = gimple_asm_clobber_op (stmt, i);
445 if (simple_cst_equal(TREE_VALUE (op), memory_identifier_string) == 1)
448 fprintf (dump_file, " memory asm clobber is not const/pure");
449 /* Abandon all hope, ye who enter here. */
450 local->pure_const_state = IPA_NEITHER;
453 if (gimple_asm_volatile_p (stmt))
456 fprintf (dump_file, " volatile is not const/pure");
457 /* Abandon all hope, ye who enter here. */
458 local->pure_const_state = IPA_NEITHER;
459 local->looping = true;
466 for (; i < gimple_num_ops (stmt); i++)
467 check_op (local, gimple_op (stmt, i), false);
471 /* This is the main routine for finding the reference patterns for
472 global variables within a function FN. */
475 analyze_function (struct cgraph_node *fn, bool ipa)
477 tree decl = fn->decl;
478 tree old_decl = current_function_decl;
480 basic_block this_block;
482 if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
485 fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
489 l = XCNEW (struct funct_state_d);
490 l->pure_const_state = IPA_CONST;
491 l->state_set_in_source = IPA_NEITHER;
493 l->can_throw = false;
497 fprintf (dump_file, "\n\n local analysis of %s\n ",
498 cgraph_node_name (fn));
501 push_cfun (DECL_STRUCT_FUNCTION (decl));
502 current_function_decl = decl;
504 FOR_EACH_BB (this_block)
506 gimple_stmt_iterator gsi;
507 struct walk_stmt_info wi;
509 memset (&wi, 0, sizeof(wi));
510 for (gsi = gsi_start_bb (this_block);
514 check_stmt (&gsi, l, ipa);
515 if (l->pure_const_state == IPA_NEITHER && l->looping && l->can_throw)
521 if (l->pure_const_state != IPA_NEITHER)
523 /* Const functions cannot have back edges (an
524 indication of possible infinite loop side
526 if (mark_dfs_back_edges ())
531 if (TREE_READONLY (decl))
533 l->pure_const_state = IPA_CONST;
534 l->state_set_in_source = IPA_CONST;
535 if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
538 if (DECL_PURE_P (decl))
540 if (l->pure_const_state != IPA_CONST)
541 l->pure_const_state = IPA_PURE;
542 l->state_set_in_source = IPA_PURE;
543 if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
546 if (TREE_NOTHROW (decl))
547 l->can_throw = false;
550 current_function_decl = old_decl;
554 fprintf (dump_file, "Function is locally looping.\n");
556 fprintf (dump_file, "Function is locally throwing.\n");
557 if (l->pure_const_state == IPA_CONST)
558 fprintf (dump_file, "Function is locally const.\n");
559 if (l->pure_const_state == IPA_PURE)
560 fprintf (dump_file, "Function is locally pure.\n");
565 /* Called when new function is inserted to callgraph late. */
567 add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
569 if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
571 /* There are some shared nodes, in particular the initializers on
572 static declarations. We do not need to scan them more than once
573 since all we would be interested in are the addressof
575 visited_nodes = pointer_set_create ();
576 set_function_state (node, analyze_function (node, true));
577 pointer_set_destroy (visited_nodes);
578 visited_nodes = NULL;
581 /* Called when new clone is inserted to callgraph late. */
584 duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
585 void *data ATTRIBUTE_UNUSED)
587 if (get_function_state (src))
589 funct_state l = XNEW (struct funct_state_d);
590 gcc_assert (!get_function_state (dst));
591 memcpy (l, get_function_state (src), sizeof (*l));
592 set_function_state (dst, l);
596 /* Called when new clone is inserted to callgraph late. */
599 remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
601 if (get_function_state (node))
603 free (get_function_state (node));
604 set_function_state (node, NULL);
609 /* Analyze each function in the cgraph to see if it is locally PURE or
613 generate_summary (void)
615 struct cgraph_node *node;
617 node_removal_hook_holder =
618 cgraph_add_node_removal_hook (&remove_node_data, NULL);
619 node_duplication_hook_holder =
620 cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
621 function_insertion_hook_holder =
622 cgraph_add_function_insertion_hook (&add_new_function, NULL);
623 /* There are some shared nodes, in particular the initializers on
624 static declarations. We do not need to scan them more than once
625 since all we would be interested in are the addressof
627 visited_nodes = pointer_set_create ();
629 /* Process all of the functions.
631 We do NOT process any AVAIL_OVERWRITABLE functions, we cannot
632 guarantee that what we learn about the one we see will be true
633 for the one that overrides it.
635 for (node = cgraph_nodes; node; node = node->next)
636 if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
637 set_function_state (node, analyze_function (node, true));
639 pointer_set_destroy (visited_nodes);
640 visited_nodes = NULL;
643 /* Produce the global information by preforming a transitive closure
644 on the local information that was produced by generate_summary.
645 Note that there is no function_transform pass since this only
646 updates the function_decl. */
651 struct cgraph_node *node;
652 struct cgraph_node *w;
653 struct cgraph_node **order =
654 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
657 struct ipa_dfs_info * w_info;
659 cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
660 cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
661 cgraph_remove_node_removal_hook (node_removal_hook_holder);
662 order_pos = ipa_utils_reduced_inorder (order, true, false);
665 dump_cgraph (dump_file);
666 ipa_utils_print_order(dump_file, "reduced", order, order_pos);
669 /* Propagate the local information thru the call graph to produce
670 the global information. All the nodes within a cycle will have
671 the same info so we collapse cycles first. Then we can do the
672 propagation in one pass from the leaves to the roots. */
673 for (i = 0; i < order_pos; i++ )
675 enum pure_const_state_e pure_const_state = IPA_CONST;
676 bool looping = false;
677 bool can_throw = false;
681 /* Find the worst state for any node in the cycle. */
685 struct cgraph_edge *e;
686 funct_state w_l = get_function_state (w);
687 if (pure_const_state < w_l->pure_const_state)
688 pure_const_state = w_l->pure_const_state;
695 if (pure_const_state == IPA_NEITHER
704 for (e = w->callees; e; e = e->next_callee)
706 struct cgraph_node *y = e->callee;
708 if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE)
710 funct_state y_l = get_function_state (y);
711 if (pure_const_state < y_l->pure_const_state)
712 pure_const_state = y_l->pure_const_state;
713 if (pure_const_state == IPA_NEITHER
718 if (y_l->can_throw && !TREE_NOTHROW (w->decl)
719 /* FIXME: We should check that the throw can get external.
720 We also should handle only loops formed by can throw external
725 w_info = (struct ipa_dfs_info *) w->aux;
726 w = w_info->next_cycle;
729 /* Copy back the region's pure_const_state which is shared by
730 all nodes in the region. */
734 funct_state w_l = get_function_state (w);
735 enum pure_const_state_e this_state = pure_const_state;
736 bool this_looping = looping;
738 if (w_l->state_set_in_source != IPA_NEITHER)
740 if (this_state > w_l->state_set_in_source)
741 this_state = w_l->state_set_in_source;
742 this_looping = false;
745 /* All nodes within a cycle share the same info. */
746 w_l->pure_const_state = this_state;
747 w_l->looping = this_looping;
752 if (!TREE_READONLY (w->decl) && dump_file)
753 fprintf (dump_file, "Function found to be %sconst: %s\n",
754 this_looping ? "looping " : "",
755 cgraph_node_name (w));
756 TREE_READONLY (w->decl) = 1;
757 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
761 if (!DECL_PURE_P (w->decl) && dump_file)
762 fprintf (dump_file, "Function found to be %spure: %s\n",
763 this_looping ? "looping " : "",
764 cgraph_node_name (w));
765 DECL_PURE_P (w->decl) = 1;
766 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
772 if (!can_throw && !TREE_NOTHROW (w->decl))
774 /* FIXME: TREE_NOTHROW is not set because passmanager will execute
775 verify_ssa and verify_cfg on every function. Before fixup_cfg is done,
776 those functions are going to have NOTHROW calls in EH regions reulting
779 fprintf (dump_file, "Function found to be nothrow: %s\n",
780 cgraph_node_name (w));
782 w_info = (struct ipa_dfs_info *) w->aux;
783 w = w_info->next_cycle;
788 for (node = cgraph_nodes; node; node = node->next)
790 /* Get rid of the aux information. */
793 w_info = (struct ipa_dfs_info *) node->aux;
797 if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
798 free (get_function_state (node));
802 VEC_free (funct_state, heap, funct_state_vec);
808 gate_pure_const (void)
810 return (flag_ipa_pure_const
811 /* Don't bother doing anything if the program has errors. */
812 && !(errorcount || sorrycount));
815 struct ipa_opt_pass pass_ipa_pure_const =
819 "pure-const", /* name */
820 gate_pure_const, /* gate */
821 propagate, /* execute */
824 0, /* static_pass_number */
825 TV_IPA_PURE_CONST, /* tv_id */
826 0, /* properties_required */
827 0, /* properties_provided */
828 0, /* properties_destroyed */
829 0, /* todo_flags_start */
830 0 /* todo_flags_finish */
832 generate_summary, /* generate_summary */
833 NULL, /* write_summary */
834 NULL, /* read_summary */
835 NULL, /* function_read_summary */
837 NULL, /* function_transform */
838 NULL /* variable_transform */
841 /* Simple local pass for pure const discovery reusing the analysis from
842 ipa_pure_const. This pass is effective when executed together with
843 other optimization passes in early optimization pass queue. */
846 local_pure_const (void)
848 bool changed = false;
851 /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations
852 we must not promote functions that are called by already processed functions. */
854 if (function_called_by_processed_nodes_p ())
857 fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
861 l = analyze_function (cgraph_node (current_function_decl), false);
865 fprintf (dump_file, "Function has wrong visibility; ignoring\n");
869 switch (l->pure_const_state)
872 if (!TREE_READONLY (current_function_decl))
874 TREE_READONLY (current_function_decl) = 1;
875 DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
878 fprintf (dump_file, "Function found to be %sconst: %s\n",
879 l->looping ? "looping " : "",
880 lang_hooks.decl_printable_name (current_function_decl,
883 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
886 DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
889 fprintf (dump_file, "Function found to be non-looping: %s\n",
890 lang_hooks.decl_printable_name (current_function_decl,
896 if (!TREE_READONLY (current_function_decl))
898 DECL_PURE_P (current_function_decl) = 1;
899 DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
902 fprintf (dump_file, "Function found to be %spure: %s\n",
903 l->looping ? "looping " : "",
904 lang_hooks.decl_printable_name (current_function_decl,
907 else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
910 DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
913 fprintf (dump_file, "Function found to be non-looping: %s\n",
914 lang_hooks.decl_printable_name (current_function_decl,
922 if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
924 TREE_NOTHROW (current_function_decl) = 1;
927 fprintf (dump_file, "Function found to be nothrow: %s\n",
928 lang_hooks.decl_printable_name (current_function_decl,
934 return execute_fixup_cfg ();
939 struct gimple_opt_pass pass_local_pure_const =
943 "local-pure-const", /* name */
944 gate_pure_const, /* gate */
945 local_pure_const, /* execute */
948 0, /* static_pass_number */
949 TV_IPA_PURE_CONST, /* tv_id */
950 0, /* properties_required */
951 0, /* properties_provided */
952 0, /* properties_destroyed */
953 0, /* todo_flags_start */
954 0 /* todo_flags_finish */