[multiple changes]
[gcc.git] / gcc / ipa-pure-const.c
1 /* Callgraph based analysis of static variables.
2 Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
4
5 This file is part of GCC.
6
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
10 version.
11
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
15 for more details.
16
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/>. */
20
21 /* This file mark functions as being either const (TREE_READONLY) or
22 pure (DECL_PURE_P). It can also set the a variant of these that
23 are allowed to infinite loop (DECL_LOOPING_CONST_PURE_P).
24
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. */
29
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. */
33
34 #include "config.h"
35 #include "system.h"
36 #include "coretypes.h"
37 #include "tm.h"
38 #include "tree.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"
44 #include "ggc.h"
45 #include "ipa-utils.h"
46 #include "c-common.h"
47 #include "tree-gimple.h"
48 #include "cgraph.h"
49 #include "output.h"
50 #include "flags.h"
51 #include "timevar.h"
52 #include "diagnostic.h"
53 #include "langhooks.h"
54 #include "target.h"
55
56 static struct pointer_set_t *visited_nodes;
57
58 /* Lattice values for const and pure functions. Everything starts out
59 being const, then may drop to pure and then neither depending on
60 what is found. */
61 enum pure_const_state_e
62 {
63 IPA_CONST,
64 IPA_PURE,
65 IPA_NEITHER
66 };
67
68 /* Holder inserted into the ipa_dfs_info aux field to hold the
69 const_state. */
70 struct funct_state_d
71 {
72 enum pure_const_state_e pure_const_state;
73 bool looping;
74 bool state_set_in_source;
75 };
76
77 typedef struct funct_state_d * funct_state;
78
79 /* Return the function state from NODE. */
80
81 static inline funct_state
82 get_function_state (struct cgraph_node *node)
83 {
84 struct ipa_dfs_info * info = (struct ipa_dfs_info *) node->aux;
85 return (funct_state) info->aux;
86 }
87
88 /* Check to see if the use (or definition when CHECHING_WRITE is true)
89 variable T is legal in a function that is either pure or const. */
90
91 static inline void
92 check_decl (funct_state local,
93 tree t, bool checking_write)
94 {
95 /* If the variable has the "used" attribute, treat it as if it had a
96 been touched by the devil. */
97 if (lookup_attribute ("used", DECL_ATTRIBUTES (t)))
98 {
99 local->pure_const_state = IPA_NEITHER;
100 local->looping = false;
101 return;
102 }
103
104 /* Do not want to do anything with volatile except mark any
105 function that uses one to be not const or pure. */
106 if (TREE_THIS_VOLATILE (t))
107 {
108 local->pure_const_state = IPA_NEITHER;
109 local->looping = false;
110 return;
111 }
112
113 /* Do not care about a local automatic that is not static. */
114 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
115 return;
116
117 /* Since we have dealt with the locals and params cases above, if we
118 are CHECKING_WRITE, this cannot be a pure or constant
119 function. */
120 if (checking_write)
121 {
122 local->pure_const_state = IPA_NEITHER;
123 local->looping = false;
124 return;
125 }
126
127 if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
128 {
129 /* If the front end set the variable to be READONLY and
130 constant, we can allow this variable in pure or const
131 functions but the scope is too large for our analysis to set
132 these bits ourselves. */
133
134 if (TREE_READONLY (t)
135 && DECL_INITIAL (t)
136 && is_gimple_min_invariant (DECL_INITIAL (t)))
137 ; /* Read of a constant, do not change the function state. */
138 else
139 {
140 /* Just a regular read. */
141 if (local->pure_const_state == IPA_CONST)
142 local->pure_const_state = IPA_PURE;
143 }
144 }
145
146 /* Compilation level statics can be read if they are readonly
147 variables. */
148 if (TREE_READONLY (t))
149 return;
150
151 /* Just a regular read. */
152 if (local->pure_const_state == IPA_CONST)
153 local->pure_const_state = IPA_PURE;
154 }
155
156 /* If T is a VAR_DECL check to see if it is an allowed reference. */
157
158 static void
159 check_operand (funct_state local,
160 tree t, bool checking_write)
161 {
162 if (!t) return;
163
164 if (TREE_CODE (t) == VAR_DECL)
165 check_decl (local, t, checking_write);
166 }
167
168 /* Examine tree T for references. */
169
170 static void
171 check_tree (funct_state local, tree t, bool checking_write)
172 {
173 if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR)
174 || TREE_CODE (t) == SSA_NAME)
175 return;
176
177 /* Any tree which is volatile disqualifies thie function from being
178 const or pure. */
179 if (TREE_THIS_VOLATILE (t))
180 {
181 local->pure_const_state = IPA_NEITHER;
182 local->looping = false;
183 return;
184 }
185
186 while (TREE_CODE (t) == REALPART_EXPR
187 || TREE_CODE (t) == IMAGPART_EXPR
188 || handled_component_p (t))
189 {
190 if (TREE_CODE (t) == ARRAY_REF)
191 check_operand (local, TREE_OPERAND (t, 1), false);
192 t = TREE_OPERAND (t, 0);
193 }
194
195 /* The bottom of an indirect reference can only be read, not
196 written. */
197 if (INDIRECT_REF_P (t))
198 {
199 check_tree (local, TREE_OPERAND (t, 0), false);
200
201 /* Any indirect reference that occurs on the lhs
202 disqualifies the function from being pure or const. Any
203 indirect reference that occurs on the rhs disqualifies the
204 function from being const. */
205 if (checking_write)
206 {
207 local->pure_const_state = IPA_NEITHER;
208 local->looping = false;
209 return;
210 }
211 else if (local->pure_const_state == IPA_CONST)
212 local->pure_const_state = IPA_PURE;
213 }
214
215 if (SSA_VAR_P (t))
216 check_operand (local, t, checking_write);
217 }
218
219 /* Scan tree T to see if there are any addresses taken in within T. */
220
221 static void
222 look_for_address_of (funct_state local, tree t)
223 {
224 if (TREE_CODE (t) == ADDR_EXPR)
225 {
226 tree x = get_base_var (t);
227 if (TREE_CODE (x) == VAR_DECL)
228 {
229 check_decl (local, x, false);
230
231 /* Taking the address of something appears to be reasonable
232 in PURE code. Not allowed in const. */
233 if (local->pure_const_state == IPA_CONST)
234 local->pure_const_state = IPA_PURE;
235 }
236 }
237 }
238
239 /* Check to see if T is a read or address of operation on a var we are
240 interested in analyzing. LOCAL is passed in to get access to its
241 bit vectors. */
242
243 static void
244 check_rhs_var (funct_state local, tree t)
245 {
246 look_for_address_of (local, t);
247
248 /* Memcmp and strlen can both trap and they are declared pure. */
249 if (tree_could_trap_p (t)
250 && local->pure_const_state == IPA_CONST)
251 local->pure_const_state = IPA_PURE;
252
253 check_tree(local, t, false);
254 }
255
256 /* Check to see if T is an assignment to a var we are interested in
257 analyzing. LOCAL is passed in to get access to its bit vectors. */
258
259 static void
260 check_lhs_var (funct_state local, tree t)
261 {
262 /* Memcmp and strlen can both trap and they are declared pure.
263 Which seems to imply that we can apply the same rule here. */
264 if (tree_could_trap_p (t)
265 && local->pure_const_state == IPA_CONST)
266 local->pure_const_state = IPA_PURE;
267
268 check_tree(local, t, true);
269 }
270
271 /* This is a scaled down version of get_asm_expr_operands from
272 tree_ssa_operands.c. The version there runs much later and assumes
273 that aliasing information is already available. Here we are just
274 trying to find if the set of inputs and outputs contain references
275 or address of operations to local static variables. STMT is the
276 actual asm statement. */
277
278 static void
279 get_asm_expr_operands (funct_state local, tree stmt)
280 {
281 int noutputs = list_length (ASM_OUTPUTS (stmt));
282 const char **oconstraints
283 = (const char **) alloca ((noutputs) * sizeof (const char *));
284 int i;
285 tree link;
286 const char *constraint;
287 bool allows_mem, allows_reg, is_inout;
288
289 for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
290 {
291 oconstraints[i] = constraint
292 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
293 parse_output_constraint (&constraint, i, 0, 0,
294 &allows_mem, &allows_reg, &is_inout);
295
296 check_lhs_var (local, TREE_VALUE (link));
297 }
298
299 for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
300 {
301 constraint
302 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
303 parse_input_constraint (&constraint, 0, 0, noutputs, 0,
304 oconstraints, &allows_mem, &allows_reg);
305
306 check_rhs_var (local, TREE_VALUE (link));
307 }
308
309 for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
310 if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1)
311 /* Abandon all hope, ye who enter here. */
312 local->pure_const_state = IPA_NEITHER;
313
314 if (ASM_VOLATILE_P (stmt))
315 local->pure_const_state = IPA_NEITHER;
316 }
317
318 /* Check the parameters of a function call to CALL_EXPR to see if
319 there are any references in the parameters that are not allowed for
320 pure or const functions. Also check to see if this is either an
321 indirect call, a call outside the compilation unit, or has special
322 attributes that may also effect the purity. The CALL_EXPR node for
323 the entire call expression. */
324
325 static void
326 check_call (funct_state local, tree call_expr)
327 {
328 int flags = call_expr_flags (call_expr);
329 tree operand;
330 call_expr_arg_iterator iter;
331 tree callee_t = get_callee_fndecl (call_expr);
332 struct cgraph_node* callee;
333 enum availability avail = AVAIL_NOT_AVAILABLE;
334
335 FOR_EACH_CALL_EXPR_ARG (operand, iter, call_expr)
336 check_rhs_var (local, operand);
337
338 /* The const and pure flags are set by a variety of places in the
339 compiler (including here). If someone has already set the flags
340 for the callee, (such as for some of the builtins) we will use
341 them, otherwise we will compute our own information.
342
343 Const and pure functions have less clobber effects than other
344 functions so we process these first. Otherwise if it is a call
345 outside the compilation unit or an indirect call we punt. This
346 leaves local calls which will be processed by following the call
347 graph. */
348 if (callee_t)
349 {
350 callee = cgraph_node(callee_t);
351 avail = cgraph_function_body_availability (callee);
352
353 /* When bad things happen to bad functions, they cannot be const
354 or pure. */
355 if (setjmp_call_p (callee_t))
356 {
357 local->pure_const_state = IPA_NEITHER;
358 local->looping = false;
359 }
360
361 if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
362 switch (DECL_FUNCTION_CODE (callee_t))
363 {
364 case BUILT_IN_LONGJMP:
365 case BUILT_IN_NONLOCAL_GOTO:
366 local->pure_const_state = IPA_NEITHER;
367 local->looping = false;
368 break;
369 default:
370 break;
371 }
372 }
373
374 /* The callee is either unknown (indirect call) or there is just no
375 scannable code for it (external call) . We look to see if there
376 are any bits available for the callee (such as by declaration or
377 because it is builtin) and process solely on the basis of those
378 bits. */
379 if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
380 {
381 if (flags & ECF_PURE)
382 {
383 if (local->pure_const_state == IPA_CONST)
384 local->pure_const_state = IPA_PURE;
385 }
386 else
387 local->pure_const_state = IPA_NEITHER;
388 }
389 else
390 {
391 /* We have the code and we will scan it for the effects. */
392 if (flags & ECF_PURE)
393 {
394 if (local->pure_const_state == IPA_CONST)
395 local->pure_const_state = IPA_PURE;
396 }
397 }
398 }
399
400 /* TP is the part of the tree currently under the microscope.
401 WALK_SUBTREES is part of the walk_tree api but is unused here.
402 DATA is cgraph_node of the function being walked. */
403
404 /* FIXME: When this is converted to run over SSA form, this code
405 should be converted to use the operand scanner. */
406
407 static tree
408 scan_function (tree *tp,
409 int *walk_subtrees,
410 void *data)
411 {
412 struct cgraph_node *fn = (struct cgraph_node *) data;
413 tree t = *tp;
414 funct_state local = get_function_state (fn);
415
416 switch (TREE_CODE (t))
417 {
418 case VAR_DECL:
419 if (DECL_INITIAL (t))
420 walk_tree (&DECL_INITIAL (t), scan_function, fn, visited_nodes);
421 *walk_subtrees = 0;
422 break;
423
424 case GIMPLE_MODIFY_STMT:
425 {
426 /* First look on the lhs and see what variable is stored to */
427 tree lhs = GIMPLE_STMT_OPERAND (t, 0);
428 tree rhs = GIMPLE_STMT_OPERAND (t, 1);
429 check_lhs_var (local, lhs);
430
431 /* For the purposes of figuring out what the cast affects */
432
433 /* Next check the operands on the rhs to see if they are ok. */
434 switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
435 {
436 case tcc_binary:
437 {
438 tree op0 = TREE_OPERAND (rhs, 0);
439 tree op1 = TREE_OPERAND (rhs, 1);
440 check_rhs_var (local, op0);
441 check_rhs_var (local, op1);
442 }
443 break;
444 case tcc_unary:
445 {
446 tree op0 = TREE_OPERAND (rhs, 0);
447 check_rhs_var (local, op0);
448 }
449
450 break;
451 case tcc_reference:
452 check_rhs_var (local, rhs);
453 break;
454 case tcc_declaration:
455 check_rhs_var (local, rhs);
456 break;
457 case tcc_expression:
458 switch (TREE_CODE (rhs))
459 {
460 case ADDR_EXPR:
461 check_rhs_var (local, rhs);
462 break;
463 default:
464 break;
465 }
466 break;
467 case tcc_vl_exp:
468 switch (TREE_CODE (rhs))
469 {
470 case CALL_EXPR:
471 check_call (local, rhs);
472 break;
473 default:
474 break;
475 }
476 break;
477 default:
478 break;
479 }
480 *walk_subtrees = 0;
481 }
482 break;
483
484 case ADDR_EXPR:
485 /* This case is here to find addresses on rhs of constructors in
486 decl_initial of static variables. */
487 check_rhs_var (local, t);
488 *walk_subtrees = 0;
489 break;
490
491 case LABEL_EXPR:
492 if (DECL_NONLOCAL (TREE_OPERAND (t, 0)))
493 /* Target of long jump. */
494 {
495 local->pure_const_state = IPA_NEITHER;
496 local->looping = false;
497 }
498 break;
499
500 case CALL_EXPR:
501 check_call (local, t);
502 *walk_subtrees = 0;
503 break;
504
505 case ASM_EXPR:
506 get_asm_expr_operands (local, t);
507 *walk_subtrees = 0;
508 break;
509
510 default:
511 break;
512 }
513 return NULL;
514 }
515
516 /* This is the main routine for finding the reference patterns for
517 global variables within a function FN. */
518
519 static void
520 analyze_function (struct cgraph_node *fn)
521 {
522 funct_state l = XCNEW (struct funct_state_d);
523 tree decl = fn->decl;
524 struct ipa_dfs_info * w_info = (struct ipa_dfs_info *) fn->aux;
525
526 w_info->aux = l;
527
528 l->pure_const_state = IPA_CONST;
529 l->state_set_in_source = false;
530 if (DECL_LOOPING_CONST_OR_PURE_P (decl))
531 l->looping = true;
532 else
533 l->looping = false;
534
535 /* If this function does not return normally or does not bind local,
536 do not touch this unless it has been marked as const or pure by the
537 front end. */
538 if (TREE_THIS_VOLATILE (decl)
539 || !targetm.binds_local_p (decl))
540 {
541 l->pure_const_state = IPA_NEITHER;
542 return;
543 }
544
545 if (TREE_READONLY (decl))
546 {
547 l->pure_const_state = IPA_CONST;
548 l->state_set_in_source = true;
549 }
550 if (DECL_PURE_P (decl))
551 {
552 l->pure_const_state = IPA_PURE;
553 l->state_set_in_source = true;
554 }
555
556 if (dump_file)
557 {
558 fprintf (dump_file, "\n local analysis of %s with initial value = %d\n ",
559 cgraph_node_name (fn),
560 l->pure_const_state);
561 }
562
563 if (!l->state_set_in_source)
564 {
565 struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
566 basic_block this_block;
567
568 FOR_EACH_BB_FN (this_block, this_cfun)
569 {
570 block_stmt_iterator bsi;
571 for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
572 {
573 walk_tree (bsi_stmt_ptr (bsi), scan_function,
574 fn, visited_nodes);
575 if (l->pure_const_state == IPA_NEITHER)
576 goto end;
577 }
578 }
579
580 if (l->pure_const_state != IPA_NEITHER)
581 {
582 tree old_decl = current_function_decl;
583 /* Const functions cannot have back edges (an
584 indication of possible infinite loop side
585 effect. */
586
587 current_function_decl = fn->decl;
588
589 /* The C++ front end, has a tendency to some times jerk away
590 a function after it has created it. This should have
591 been fixed. */
592 gcc_assert (DECL_STRUCT_FUNCTION (fn->decl));
593
594 push_cfun (DECL_STRUCT_FUNCTION (fn->decl));
595
596 if (mark_dfs_back_edges ())
597 l->pure_const_state = IPA_NEITHER;
598
599 current_function_decl = old_decl;
600 pop_cfun ();
601 }
602 }
603
604 end:
605 if (dump_file)
606 {
607 fprintf (dump_file, "after local analysis of %s with initial value = %d\n ",
608 cgraph_node_name (fn),
609 l->pure_const_state);
610 }
611 }
612
613 \f
614 /* Produce the global information by preforming a transitive closure
615 on the local information that was produced by ipa_analyze_function
616 and ipa_analyze_variable. */
617
618 static unsigned int
619 static_execute (void)
620 {
621 struct cgraph_node *node;
622 struct cgraph_node *w;
623 struct cgraph_node **order =
624 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
625 int order_pos = ipa_utils_reduced_inorder (order, true, false);
626 int i;
627 struct ipa_dfs_info * w_info;
628
629 if (!memory_identifier_string)
630 memory_identifier_string = build_string(7, "memory");
631
632 /* There are some shared nodes, in particular the initializers on
633 static declarations. We do not need to scan them more than once
634 since all we would be interested in are the addressof
635 operations. */
636 visited_nodes = pointer_set_create ();
637
638 /* Process all of the functions.
639
640 We do not want to process any of the clones so we check that this
641 is a master clone. However, we do NOT process any
642 AVAIL_OVERWRITABLE functions (these are never clones) we cannot
643 guarantee that what we learn about the one we see will be true
644 for the one that overriders it.
645 */
646 for (node = cgraph_nodes; node; node = node->next)
647 if (node->analyzed && cgraph_is_master_clone (node))
648 analyze_function (node);
649
650 pointer_set_destroy (visited_nodes);
651 visited_nodes = NULL;
652 if (dump_file)
653 {
654 dump_cgraph (dump_file);
655 ipa_utils_print_order(dump_file, "reduced", order, order_pos);
656 }
657
658 /* Propagate the local information thru the call graph to produce
659 the global information. All the nodes within a cycle will have
660 the same info so we collapse cycles first. Then we can do the
661 propagation in one pass from the leaves to the roots. */
662 for (i = 0; i < order_pos; i++ )
663 {
664 enum pure_const_state_e pure_const_state = IPA_CONST;
665 bool looping = false;
666 int count = 0;
667 node = order[i];
668
669 /* Find the worst state for any node in the cycle. */
670 w = node;
671 while (w)
672 {
673 funct_state w_l = get_function_state (w);
674 if (pure_const_state < w_l->pure_const_state)
675 pure_const_state = w_l->pure_const_state;
676
677 if (w_l->looping)
678 looping = true;
679
680 if (pure_const_state == IPA_NEITHER)
681 break;
682
683 if (!w_l->state_set_in_source)
684 {
685 struct cgraph_edge *e;
686 count++;
687
688 if (count > 1)
689 looping = true;
690
691 for (e = w->callees; e; e = e->next_callee)
692 {
693 struct cgraph_node *y = e->callee;
694 /* Only look at the master nodes and skip external nodes. */
695 y = cgraph_master_clone (y);
696
697 if (w == y)
698 looping = true;
699 if (y)
700 {
701 funct_state y_l = get_function_state (y);
702 if (pure_const_state < y_l->pure_const_state)
703 pure_const_state = y_l->pure_const_state;
704 if (pure_const_state == IPA_NEITHER)
705 break;
706 if (y_l->looping)
707 looping = true;
708 }
709 }
710 }
711 w_info = (struct ipa_dfs_info *) w->aux;
712 w = w_info->next_cycle;
713 }
714
715 /* Copy back the region's pure_const_state which is shared by
716 all nodes in the region. */
717 w = node;
718 while (w)
719 {
720 funct_state w_l = get_function_state (w);
721
722 /* All nodes within a cycle share the same info. */
723 if (!w_l->state_set_in_source)
724 {
725 w_l->pure_const_state = pure_const_state;
726 switch (pure_const_state)
727 {
728 case IPA_CONST:
729 TREE_READONLY (w->decl) = 1;
730 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
731 if (dump_file)
732 fprintf (dump_file, "Function found to be %sconst: %s\n",
733 looping ? "looping " : "",
734 lang_hooks.decl_printable_name(w->decl, 2));
735 break;
736
737 case IPA_PURE:
738 DECL_PURE_P (w->decl) = 1;
739 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
740 if (dump_file)
741 fprintf (dump_file, "Function found to be %spure: %s\n",
742 looping ? "looping " : "",
743 lang_hooks.decl_printable_name(w->decl, 2));
744 break;
745
746 default:
747 break;
748 }
749 }
750 w_info = (struct ipa_dfs_info *) w->aux;
751 w = w_info->next_cycle;
752 }
753 }
754
755 /* Cleanup. */
756 for (node = cgraph_nodes; node; node = node->next)
757 /* Get rid of the aux information. */
758 if (node->aux)
759 {
760 w_info = (struct ipa_dfs_info *) node->aux;
761 if (w_info->aux)
762 free (w_info->aux);
763 free (node->aux);
764 node->aux = NULL;
765 }
766
767 free (order);
768 return 0;
769 }
770
771 static bool
772 gate_pure_const (void)
773 {
774 return (flag_unit_at_a_time != 0 && flag_ipa_pure_const
775 /* Don't bother doing anything if the program has errors. */
776 && !(errorcount || sorrycount));
777 }
778
779 struct simple_ipa_opt_pass pass_ipa_pure_const =
780 {
781 {
782 SIMPLE_IPA_PASS,
783 "pure-const", /* name */
784 gate_pure_const, /* gate */
785 static_execute, /* execute */
786 NULL, /* sub */
787 NULL, /* next */
788 0, /* static_pass_number */
789 TV_IPA_PURE_CONST, /* tv_id */
790 0, /* properties_required */
791 0, /* properties_provided */
792 0, /* properties_destroyed */
793 0, /* todo_flags_start */
794 0 /* todo_flags_finish */
795 }
796 };
797
798