xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-nrv.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino /* Language independent return value optimizations
2*e4b17023SJohn Marino    Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
3*e4b17023SJohn Marino    Free Software Foundation, Inc.
4*e4b17023SJohn Marino 
5*e4b17023SJohn Marino This file is part of GCC.
6*e4b17023SJohn Marino 
7*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
8*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
9*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
10*e4b17023SJohn Marino any later version.
11*e4b17023SJohn Marino 
12*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
13*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
14*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*e4b17023SJohn Marino GNU General Public License for more details.
16*e4b17023SJohn Marino 
17*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18*e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
19*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
20*e4b17023SJohn Marino 
21*e4b17023SJohn Marino #include "config.h"
22*e4b17023SJohn Marino #include "system.h"
23*e4b17023SJohn Marino #include "coretypes.h"
24*e4b17023SJohn Marino #include "tm.h"
25*e4b17023SJohn Marino #include "tree.h"
26*e4b17023SJohn Marino #include "function.h"
27*e4b17023SJohn Marino #include "basic-block.h"
28*e4b17023SJohn Marino #include "tree-pretty-print.h"
29*e4b17023SJohn Marino #include "tree-flow.h"
30*e4b17023SJohn Marino #include "timevar.h"
31*e4b17023SJohn Marino #include "tree-dump.h"
32*e4b17023SJohn Marino #include "tree-pass.h"
33*e4b17023SJohn Marino #include "langhooks.h"
34*e4b17023SJohn Marino #include "flags.h"	/* For "optimize" in gate_pass_return_slot.
35*e4b17023SJohn Marino 			   FIXME: That should be up to the pass manager,
36*e4b17023SJohn Marino 			   but pass_nrv is not in pass_all_optimizations.  */
37*e4b17023SJohn Marino 
38*e4b17023SJohn Marino /* This file implements return value optimizations for functions which
39*e4b17023SJohn Marino    return aggregate types.
40*e4b17023SJohn Marino 
41*e4b17023SJohn Marino    Basically this pass searches the function for return statements which
42*e4b17023SJohn Marino    return a local aggregate.  When converted to RTL such statements will
43*e4b17023SJohn Marino    generate a copy from the local aggregate to final return value destination
44*e4b17023SJohn Marino    mandated by the target's ABI.
45*e4b17023SJohn Marino 
46*e4b17023SJohn Marino    That copy can often be avoided by directly constructing the return value
47*e4b17023SJohn Marino    into the final destination mandated by the target's ABI.
48*e4b17023SJohn Marino 
49*e4b17023SJohn Marino    This is basically a generic equivalent to the C++ front-end's
50*e4b17023SJohn Marino    Named Return Value optimization.  */
51*e4b17023SJohn Marino 
52*e4b17023SJohn Marino struct nrv_data
53*e4b17023SJohn Marino {
54*e4b17023SJohn Marino   /* This is the temporary (a VAR_DECL) which appears in all of
55*e4b17023SJohn Marino      this function's RETURN_EXPR statements.  */
56*e4b17023SJohn Marino   tree var;
57*e4b17023SJohn Marino 
58*e4b17023SJohn Marino   /* This is the function's RESULT_DECL.  We will replace all occurrences
59*e4b17023SJohn Marino      of VAR with RESULT_DECL when we apply this optimization.  */
60*e4b17023SJohn Marino   tree result;
61*e4b17023SJohn Marino   int modified;
62*e4b17023SJohn Marino };
63*e4b17023SJohn Marino 
64*e4b17023SJohn Marino static tree finalize_nrv_r (tree *, int *, void *);
65*e4b17023SJohn Marino 
66*e4b17023SJohn Marino /* Callback for the tree walker.
67*e4b17023SJohn Marino 
68*e4b17023SJohn Marino    If TP refers to a RETURN_EXPR, then set the expression being returned
69*e4b17023SJohn Marino    to nrv_data->result.
70*e4b17023SJohn Marino 
71*e4b17023SJohn Marino    If TP refers to nrv_data->var, then replace nrv_data->var with
72*e4b17023SJohn Marino    nrv_data->result.
73*e4b17023SJohn Marino 
74*e4b17023SJohn Marino    If we reach a node where we know all the subtrees are uninteresting,
75*e4b17023SJohn Marino    then set *WALK_SUBTREES to zero.  */
76*e4b17023SJohn Marino 
77*e4b17023SJohn Marino static tree
finalize_nrv_r(tree * tp,int * walk_subtrees,void * data)78*e4b17023SJohn Marino finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
79*e4b17023SJohn Marino {
80*e4b17023SJohn Marino   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
81*e4b17023SJohn Marino   struct nrv_data *dp = (struct nrv_data *) wi->info;
82*e4b17023SJohn Marino 
83*e4b17023SJohn Marino   /* No need to walk into types.  */
84*e4b17023SJohn Marino   if (TYPE_P (*tp))
85*e4b17023SJohn Marino     *walk_subtrees = 0;
86*e4b17023SJohn Marino 
87*e4b17023SJohn Marino   /* Otherwise replace all occurrences of VAR with RESULT.  */
88*e4b17023SJohn Marino   else if (*tp == dp->var)
89*e4b17023SJohn Marino     {
90*e4b17023SJohn Marino       *tp = dp->result;
91*e4b17023SJohn Marino       dp->modified = 1;
92*e4b17023SJohn Marino     }
93*e4b17023SJohn Marino 
94*e4b17023SJohn Marino   /* Keep iterating.  */
95*e4b17023SJohn Marino   return NULL_TREE;
96*e4b17023SJohn Marino }
97*e4b17023SJohn Marino 
98*e4b17023SJohn Marino /* Main entry point for return value optimizations.
99*e4b17023SJohn Marino 
100*e4b17023SJohn Marino    If this function always returns the same local variable, and that
101*e4b17023SJohn Marino    local variable is an aggregate type, then replace the variable with
102*e4b17023SJohn Marino    the function's DECL_RESULT.
103*e4b17023SJohn Marino 
104*e4b17023SJohn Marino    This is the equivalent of the C++ named return value optimization
105*e4b17023SJohn Marino    applied to optimized trees in a language independent form.  If we
106*e4b17023SJohn Marino    ever encounter languages which prevent this kind of optimization,
107*e4b17023SJohn Marino    then we could either have the languages register the optimization or
108*e4b17023SJohn Marino    we could change the gating function to check the current language.  */
109*e4b17023SJohn Marino 
110*e4b17023SJohn Marino static unsigned int
tree_nrv(void)111*e4b17023SJohn Marino tree_nrv (void)
112*e4b17023SJohn Marino {
113*e4b17023SJohn Marino   tree result = DECL_RESULT (current_function_decl);
114*e4b17023SJohn Marino   tree result_type = TREE_TYPE (result);
115*e4b17023SJohn Marino   tree found = NULL;
116*e4b17023SJohn Marino   basic_block bb;
117*e4b17023SJohn Marino   gimple_stmt_iterator gsi;
118*e4b17023SJohn Marino   struct nrv_data data;
119*e4b17023SJohn Marino 
120*e4b17023SJohn Marino   /* If this function does not return an aggregate type in memory, then
121*e4b17023SJohn Marino      there is nothing to do.  */
122*e4b17023SJohn Marino   if (!aggregate_value_p (result, current_function_decl))
123*e4b17023SJohn Marino     return 0;
124*e4b17023SJohn Marino 
125*e4b17023SJohn Marino   /* If a GIMPLE type is returned in memory, finalize_nrv_r might create
126*e4b17023SJohn Marino      non-GIMPLE.  */
127*e4b17023SJohn Marino   if (is_gimple_reg_type (result_type))
128*e4b17023SJohn Marino     return 0;
129*e4b17023SJohn Marino 
130*e4b17023SJohn Marino   /* If the front end already did something like this, don't do it here.  */
131*e4b17023SJohn Marino   if (DECL_NAME (result))
132*e4b17023SJohn Marino     return 0;
133*e4b17023SJohn Marino 
134*e4b17023SJohn Marino   /* If the result has its address taken then it might be modified
135*e4b17023SJohn Marino      by means not detected in the following loop.  Bail out in this
136*e4b17023SJohn Marino      case.  */
137*e4b17023SJohn Marino   if (TREE_ADDRESSABLE (result))
138*e4b17023SJohn Marino     return 0;
139*e4b17023SJohn Marino 
140*e4b17023SJohn Marino   /* Look through each block for assignments to the RESULT_DECL.  */
141*e4b17023SJohn Marino   FOR_EACH_BB (bb)
142*e4b17023SJohn Marino     {
143*e4b17023SJohn Marino       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
144*e4b17023SJohn Marino 	{
145*e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (gsi);
146*e4b17023SJohn Marino 	  tree ret_val;
147*e4b17023SJohn Marino 
148*e4b17023SJohn Marino 	  if (gimple_code (stmt) == GIMPLE_RETURN)
149*e4b17023SJohn Marino 	    {
150*e4b17023SJohn Marino 	      /* In a function with an aggregate return value, the
151*e4b17023SJohn Marino 		 gimplifier has changed all non-empty RETURN_EXPRs to
152*e4b17023SJohn Marino 		 return the RESULT_DECL.  */
153*e4b17023SJohn Marino 	      ret_val = gimple_return_retval (stmt);
154*e4b17023SJohn Marino 	      if (ret_val)
155*e4b17023SJohn Marino 		gcc_assert (ret_val == result);
156*e4b17023SJohn Marino 	    }
157*e4b17023SJohn Marino 	  else if (gimple_has_lhs (stmt)
158*e4b17023SJohn Marino 		   && gimple_get_lhs (stmt) == result)
159*e4b17023SJohn Marino 	    {
160*e4b17023SJohn Marino               tree rhs;
161*e4b17023SJohn Marino 
162*e4b17023SJohn Marino 	      if (!gimple_assign_copy_p (stmt))
163*e4b17023SJohn Marino 		return 0;
164*e4b17023SJohn Marino 
165*e4b17023SJohn Marino 	      rhs = gimple_assign_rhs1 (stmt);
166*e4b17023SJohn Marino 
167*e4b17023SJohn Marino 	      /* Now verify that this return statement uses the same value
168*e4b17023SJohn Marino 		 as any previously encountered return statement.  */
169*e4b17023SJohn Marino 	      if (found != NULL)
170*e4b17023SJohn Marino 		{
171*e4b17023SJohn Marino 		  /* If we found a return statement using a different variable
172*e4b17023SJohn Marino 		     than previous return statements, then we can not perform
173*e4b17023SJohn Marino 		     NRV optimizations.  */
174*e4b17023SJohn Marino 		  if (found != rhs)
175*e4b17023SJohn Marino 		    return 0;
176*e4b17023SJohn Marino 		}
177*e4b17023SJohn Marino 	      else
178*e4b17023SJohn Marino 		found = rhs;
179*e4b17023SJohn Marino 
180*e4b17023SJohn Marino 	      /* The returned value must be a local automatic variable of the
181*e4b17023SJohn Marino 		 same type and alignment as the function's result.  */
182*e4b17023SJohn Marino 	      if (TREE_CODE (found) != VAR_DECL
183*e4b17023SJohn Marino 		  || TREE_THIS_VOLATILE (found)
184*e4b17023SJohn Marino 		  || DECL_CONTEXT (found) != current_function_decl
185*e4b17023SJohn Marino 		  || TREE_STATIC (found)
186*e4b17023SJohn Marino 		  || TREE_ADDRESSABLE (found)
187*e4b17023SJohn Marino 		  || DECL_ALIGN (found) > DECL_ALIGN (result)
188*e4b17023SJohn Marino 		  || !useless_type_conversion_p (result_type,
189*e4b17023SJohn Marino 						 TREE_TYPE (found)))
190*e4b17023SJohn Marino 		return 0;
191*e4b17023SJohn Marino 	    }
192*e4b17023SJohn Marino 	  else if (gimple_has_lhs (stmt))
193*e4b17023SJohn Marino 	    {
194*e4b17023SJohn Marino 	      tree addr = get_base_address (gimple_get_lhs (stmt));
195*e4b17023SJohn Marino 	       /* If there's any MODIFY of component of RESULT,
196*e4b17023SJohn Marino 		  then bail out.  */
197*e4b17023SJohn Marino 	      if (addr && addr == result)
198*e4b17023SJohn Marino 		return 0;
199*e4b17023SJohn Marino 	    }
200*e4b17023SJohn Marino 	}
201*e4b17023SJohn Marino     }
202*e4b17023SJohn Marino 
203*e4b17023SJohn Marino   if (!found)
204*e4b17023SJohn Marino     return 0;
205*e4b17023SJohn Marino 
206*e4b17023SJohn Marino   /* If dumping details, then note once and only the NRV replacement.  */
207*e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
208*e4b17023SJohn Marino     {
209*e4b17023SJohn Marino       fprintf (dump_file, "NRV Replaced: ");
210*e4b17023SJohn Marino       print_generic_expr (dump_file, found, dump_flags);
211*e4b17023SJohn Marino       fprintf (dump_file, "  with: ");
212*e4b17023SJohn Marino       print_generic_expr (dump_file, result, dump_flags);
213*e4b17023SJohn Marino       fprintf (dump_file, "\n");
214*e4b17023SJohn Marino     }
215*e4b17023SJohn Marino 
216*e4b17023SJohn Marino   /* At this point we know that all the return statements return the
217*e4b17023SJohn Marino      same local which has suitable attributes for NRV.   Copy debugging
218*e4b17023SJohn Marino      information from FOUND to RESULT if it will be useful.  But don't set
219*e4b17023SJohn Marino      DECL_ABSTRACT_ORIGIN to point at another function.  */
220*e4b17023SJohn Marino   if (!DECL_IGNORED_P (found)
221*e4b17023SJohn Marino       && !(DECL_ABSTRACT_ORIGIN (found)
222*e4b17023SJohn Marino 	   && DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (found)) != current_function_decl))
223*e4b17023SJohn Marino     {
224*e4b17023SJohn Marino       DECL_NAME (result) = DECL_NAME (found);
225*e4b17023SJohn Marino       DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
226*e4b17023SJohn Marino       DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
227*e4b17023SJohn Marino     }
228*e4b17023SJohn Marino 
229*e4b17023SJohn Marino   TREE_ADDRESSABLE (result) |= TREE_ADDRESSABLE (found);
230*e4b17023SJohn Marino 
231*e4b17023SJohn Marino   /* Now walk through the function changing all references to VAR to be
232*e4b17023SJohn Marino      RESULT.  */
233*e4b17023SJohn Marino   data.var = found;
234*e4b17023SJohn Marino   data.result = result;
235*e4b17023SJohn Marino   FOR_EACH_BB (bb)
236*e4b17023SJohn Marino     {
237*e4b17023SJohn Marino       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
238*e4b17023SJohn Marino 	{
239*e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (gsi);
240*e4b17023SJohn Marino 	  /* If this is a copy from VAR to RESULT, remove it.  */
241*e4b17023SJohn Marino 	  if (gimple_assign_copy_p (stmt)
242*e4b17023SJohn Marino 	      && gimple_assign_lhs (stmt) == result
243*e4b17023SJohn Marino 	      && gimple_assign_rhs1 (stmt) == found)
244*e4b17023SJohn Marino 	    {
245*e4b17023SJohn Marino 	      unlink_stmt_vdef (stmt);
246*e4b17023SJohn Marino 	      gsi_remove (&gsi, true);
247*e4b17023SJohn Marino 	    }
248*e4b17023SJohn Marino 	  else
249*e4b17023SJohn Marino 	    {
250*e4b17023SJohn Marino 	      struct walk_stmt_info wi;
251*e4b17023SJohn Marino 	      memset (&wi, 0, sizeof (wi));
252*e4b17023SJohn Marino 	      wi.info = &data;
253*e4b17023SJohn Marino 	      data.modified = 0;
254*e4b17023SJohn Marino 	      walk_gimple_op (stmt, finalize_nrv_r, &wi);
255*e4b17023SJohn Marino 	      if (data.modified)
256*e4b17023SJohn Marino 		update_stmt (stmt);
257*e4b17023SJohn Marino 	      gsi_next (&gsi);
258*e4b17023SJohn Marino 	    }
259*e4b17023SJohn Marino 	}
260*e4b17023SJohn Marino     }
261*e4b17023SJohn Marino 
262*e4b17023SJohn Marino   SET_DECL_VALUE_EXPR (found, result);
263*e4b17023SJohn Marino   DECL_HAS_VALUE_EXPR_P (found) = 1;
264*e4b17023SJohn Marino 
265*e4b17023SJohn Marino   /* FOUND is no longer used.  Ensure it gets removed.  */
266*e4b17023SJohn Marino   clear_is_used (found);
267*e4b17023SJohn Marino   return 0;
268*e4b17023SJohn Marino }
269*e4b17023SJohn Marino 
270*e4b17023SJohn Marino static bool
gate_pass_return_slot(void)271*e4b17023SJohn Marino gate_pass_return_slot (void)
272*e4b17023SJohn Marino {
273*e4b17023SJohn Marino   return optimize > 0;
274*e4b17023SJohn Marino }
275*e4b17023SJohn Marino 
276*e4b17023SJohn Marino struct gimple_opt_pass pass_nrv =
277*e4b17023SJohn Marino {
278*e4b17023SJohn Marino  {
279*e4b17023SJohn Marino   GIMPLE_PASS,
280*e4b17023SJohn Marino   "nrv",				/* name */
281*e4b17023SJohn Marino   gate_pass_return_slot,		/* gate */
282*e4b17023SJohn Marino   tree_nrv,				/* execute */
283*e4b17023SJohn Marino   NULL,					/* sub */
284*e4b17023SJohn Marino   NULL,					/* next */
285*e4b17023SJohn Marino   0,					/* static_pass_number */
286*e4b17023SJohn Marino   TV_TREE_NRV,				/* tv_id */
287*e4b17023SJohn Marino   PROP_ssa | PROP_cfg,				/* properties_required */
288*e4b17023SJohn Marino   0,					/* properties_provided */
289*e4b17023SJohn Marino   0,					/* properties_destroyed */
290*e4b17023SJohn Marino   0,					/* todo_flags_start */
291*e4b17023SJohn Marino   TODO_ggc_collect			/* todo_flags_finish */
292*e4b17023SJohn Marino  }
293*e4b17023SJohn Marino };
294*e4b17023SJohn Marino 
295*e4b17023SJohn Marino /* Determine (pessimistically) whether DEST is available for NRV
296*e4b17023SJohn Marino    optimization, where DEST is expected to be the LHS of a modify
297*e4b17023SJohn Marino    expression where the RHS is a function returning an aggregate.
298*e4b17023SJohn Marino 
299*e4b17023SJohn Marino    DEST is available if it is not clobbered or used by the call.  */
300*e4b17023SJohn Marino 
301*e4b17023SJohn Marino static bool
dest_safe_for_nrv_p(gimple call)302*e4b17023SJohn Marino dest_safe_for_nrv_p (gimple call)
303*e4b17023SJohn Marino {
304*e4b17023SJohn Marino   tree dest = gimple_call_lhs (call);
305*e4b17023SJohn Marino 
306*e4b17023SJohn Marino   dest = get_base_address (dest);
307*e4b17023SJohn Marino   if (! dest)
308*e4b17023SJohn Marino     return false;
309*e4b17023SJohn Marino 
310*e4b17023SJohn Marino   if (TREE_CODE (dest) == SSA_NAME)
311*e4b17023SJohn Marino     return true;
312*e4b17023SJohn Marino 
313*e4b17023SJohn Marino   if (call_may_clobber_ref_p (call, dest)
314*e4b17023SJohn Marino       || ref_maybe_used_by_stmt_p (call, dest))
315*e4b17023SJohn Marino     return false;
316*e4b17023SJohn Marino 
317*e4b17023SJohn Marino   return true;
318*e4b17023SJohn Marino }
319*e4b17023SJohn Marino 
320*e4b17023SJohn Marino /* Walk through the function looking for GIMPLE_ASSIGNs with calls that
321*e4b17023SJohn Marino    return in memory on the RHS.  For each of these, determine whether it is
322*e4b17023SJohn Marino    safe to pass the address of the LHS as the return slot, and mark the
323*e4b17023SJohn Marino    call appropriately if so.
324*e4b17023SJohn Marino 
325*e4b17023SJohn Marino    The NRV shares the return slot with a local variable in the callee; this
326*e4b17023SJohn Marino    optimization shares the return slot with the target of the call within
327*e4b17023SJohn Marino    the caller.  If the NRV is performed (which we can't know in general),
328*e4b17023SJohn Marino    this optimization is safe if the address of the target has not
329*e4b17023SJohn Marino    escaped prior to the call.  If it has, modifications to the local
330*e4b17023SJohn Marino    variable will produce visible changes elsewhere, as in PR c++/19317.  */
331*e4b17023SJohn Marino 
332*e4b17023SJohn Marino static unsigned int
execute_return_slot_opt(void)333*e4b17023SJohn Marino execute_return_slot_opt (void)
334*e4b17023SJohn Marino {
335*e4b17023SJohn Marino   basic_block bb;
336*e4b17023SJohn Marino 
337*e4b17023SJohn Marino   FOR_EACH_BB (bb)
338*e4b17023SJohn Marino     {
339*e4b17023SJohn Marino       gimple_stmt_iterator gsi;
340*e4b17023SJohn Marino       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
341*e4b17023SJohn Marino 	{
342*e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (gsi);
343*e4b17023SJohn Marino 	  bool slot_opt_p;
344*e4b17023SJohn Marino 
345*e4b17023SJohn Marino 	  if (is_gimple_call (stmt)
346*e4b17023SJohn Marino 	      && gimple_call_lhs (stmt)
347*e4b17023SJohn Marino 	      && !gimple_call_return_slot_opt_p (stmt)
348*e4b17023SJohn Marino 	      && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
349*e4b17023SJohn Marino 				    gimple_call_fndecl (stmt)))
350*e4b17023SJohn Marino 	    {
351*e4b17023SJohn Marino 	      /* Check if the location being assigned to is
352*e4b17023SJohn Marino 	         clobbered by the call.  */
353*e4b17023SJohn Marino 	      slot_opt_p = dest_safe_for_nrv_p (stmt);
354*e4b17023SJohn Marino 	      gimple_call_set_return_slot_opt (stmt, slot_opt_p);
355*e4b17023SJohn Marino 	    }
356*e4b17023SJohn Marino 	}
357*e4b17023SJohn Marino     }
358*e4b17023SJohn Marino   return 0;
359*e4b17023SJohn Marino }
360*e4b17023SJohn Marino 
361*e4b17023SJohn Marino struct gimple_opt_pass pass_return_slot =
362*e4b17023SJohn Marino {
363*e4b17023SJohn Marino  {
364*e4b17023SJohn Marino   GIMPLE_PASS,
365*e4b17023SJohn Marino   "retslot",				/* name */
366*e4b17023SJohn Marino   NULL,					/* gate */
367*e4b17023SJohn Marino   execute_return_slot_opt,		/* execute */
368*e4b17023SJohn Marino   NULL,					/* sub */
369*e4b17023SJohn Marino   NULL,					/* next */
370*e4b17023SJohn Marino   0,					/* static_pass_number */
371*e4b17023SJohn Marino   TV_NONE,				/* tv_id */
372*e4b17023SJohn Marino   PROP_ssa,				/* properties_required */
373*e4b17023SJohn Marino   0,					/* properties_provided */
374*e4b17023SJohn Marino   0,					/* properties_destroyed */
375*e4b17023SJohn Marino   0,					/* todo_flags_start */
376*e4b17023SJohn Marino   0					/* todo_flags_finish */
377*e4b17023SJohn Marino  }
378*e4b17023SJohn Marino };
379