OSDN Git Service

2004-09-07 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-mudflap.c
1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
2    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3    Contributed by Frank Ch. Eigler <fche@redhat.com>
4    and Graydon Hoare <graydon@redhat.com>
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, USA.  */
22
23
24 #include "config.h"
25 #include "errors.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tm.h"
29 #include "hard-reg-set.h"
30 #include "rtl.h"
31 #include "tree.h"
32 #include "tm_p.h"
33 #include "basic-block.h"
34 #include "flags.h"
35 #include "function.h"
36 #include "tree-inline.h"
37 #include "tree-gimple.h"
38 #include "tree-flow.h"
39 #include "tree-mudflap.h"
40 #include "tree-dump.h"
41 #include "tree-pass.h"
42 #include "hashtab.h"
43 #include "diagnostic.h"
44 #include <demangle.h>
45 #include "langhooks.h"
46 #include "ggc.h"
47 #include "cgraph.h"
48
49 /* Internal function decls */
50
51 /* Helpers.  */
52 static tree mf_build_string (const char *string);
53 static tree mf_varname_tree (tree);
54 static tree mf_file_function_line_tree (location_t);
55
56 /* Indirection-related instrumentation.  */
57 static void mf_decl_cache_locals (void);
58 static void mf_decl_clear_locals (void);
59 static void mf_xform_derefs (void);
60 static void execute_mudflap_function_ops (void);
61
62 /* Addressable variables instrumentation.  */
63 static void mf_xform_decls (tree, tree);
64 static tree mx_xfn_xform_decls (tree *, int *, void *);
65 static void mx_register_decls (tree, tree *);
66 static void execute_mudflap_function_decls (void);
67
68
69 /* ------------------------------------------------------------------------ */
70 /* Some generally helpful functions for mudflap instrumentation.  */
71
72 /* Build a reference to a literal string.  */
73 static tree
74 mf_build_string (const char *string)
75 {
76   size_t len = strlen (string);
77   tree result = mf_mark (build_string (len + 1, string));
78
79   TREE_TYPE (result) = build_array_type
80     (char_type_node, build_index_type (build_int_cst (NULL_TREE, len)));
81   TREE_CONSTANT (result) = 1;
82   TREE_INVARIANT (result) = 1;
83   TREE_READONLY (result) = 1;
84   TREE_STATIC (result) = 1;
85
86   result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
87
88   return mf_mark (result);
89 }
90
91 /* Create a properly typed STRING_CST node that describes the given
92    declaration.  It will be used as an argument for __mf_register().
93    Try to construct a helpful string, including file/function/variable
94    name.  */
95
96 static tree
97 mf_varname_tree (tree decl)
98 {
99   static pretty_printer buf_rec;
100   static int initialized = 0;
101   pretty_printer *buf = & buf_rec;
102   const char *buf_contents;
103   tree result;
104
105   if (decl == NULL_TREE)
106     abort ();
107
108   if (!initialized)
109     {
110       pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
111       initialized = 1;
112     }
113   pp_clear_output_area (buf);
114
115   /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]].  */
116   {
117     expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl));
118     const char *sourcefile;
119     unsigned sourceline = xloc.line;
120     unsigned sourcecolumn = 0;
121 #ifdef USE_MAPPED_LOCATION
122     sourcecolumn = xloc.column;
123 #endif
124     sourcefile = xloc.file;
125     if (sourcefile == NULL && current_function_decl != NULL_TREE)
126       sourcefile = DECL_SOURCE_FILE (current_function_decl);
127     if (sourcefile == NULL)
128       sourcefile = "<unknown file>";
129
130     pp_string (buf, sourcefile);
131
132     if (sourceline != 0)
133       {
134         pp_string (buf, ":");
135         pp_decimal_int (buf, sourceline);
136
137         if (sourcecolumn != 0)
138           {
139             pp_string (buf, ":");
140             pp_decimal_int (buf, sourcecolumn);
141           }
142       }
143   }
144
145   if (current_function_decl != NULL_TREE)
146     {
147       /* Add (FUNCTION) */
148       pp_string (buf, " (");
149       {
150         const char *funcname = NULL;
151         if (DECL_NAME (current_function_decl))
152           funcname = lang_hooks.decl_printable_name (current_function_decl, 1);
153         if (funcname == NULL)
154           funcname = "anonymous fn";
155
156         pp_string (buf, funcname);
157       }
158       pp_string (buf, ") ");
159     }
160   else
161     pp_string (buf, " ");
162
163   /* Add <variable-declaration>, possibly demangled.  */
164   {
165     const char *declname = NULL;
166
167     if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
168         DECL_NAME (decl) != NULL)
169       {
170         /* The gcc/cp decl_printable_name hook doesn't do as good a job as
171            the libiberty demangler.  */
172         declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)),
173                                    DMGL_AUTO | DMGL_VERBOSE);
174       }
175
176     if (declname == NULL)
177       declname = lang_hooks.decl_printable_name (decl, 3);
178
179     if (declname == NULL)
180       declname = "<unnamed variable>";
181
182     pp_string (buf, declname);
183   }
184
185   /* Return the lot as a new STRING_CST.  */
186   buf_contents = pp_base_formatted_text (buf);
187   result = mf_build_string (buf_contents);
188   pp_clear_output_area (buf);
189
190   return result;
191 }
192
193
194 /* And another friend, for producing a simpler message.  */
195
196 static tree
197 mf_file_function_line_tree (location_t location)
198 {
199   expanded_location xloc = expand_location (location);
200   const char *file = NULL, *colon, *line, *op, *name, *cp;
201   char linecolbuf[30]; /* Enough for two decimal numbers plus a colon.  */
202   char *string;
203   tree result;
204
205   /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]].  */
206   file = xloc.file;
207   if (file == NULL && current_function_decl != NULL_TREE)
208     file = DECL_SOURCE_FILE (current_function_decl);
209   if (file == NULL)
210     file = "<unknown file>";
211
212   if (xloc.line > 0)
213     {
214 #ifdef USE_MAPPED_LOCATION
215       if (xloc.column > 0)
216         sprintf (linecolbuf, "%d:%d", xloc.line, xloc.column);
217       else
218 #endif
219         sprintf (linecolbuf, "%d", xloc.line);
220       colon = ":";
221       line = linecolbuf;
222     }
223   else
224     colon = line = "";
225
226   /* Add (FUNCTION).  */
227   name = lang_hooks.decl_printable_name (current_function_decl, 1);
228   if (name)
229     {
230       op = " (";
231       cp = ")";
232     }
233   else
234     op = name = cp = "";
235
236   string = concat (file, colon, line, op, name, cp, NULL);
237   result = mf_build_string (string);
238   free (string);
239
240   return result;
241 }
242
243
244 /* global tree nodes */
245
246 /* Global tree objects for global variables and functions exported by
247    mudflap runtime library.  mf_init_extern_trees must be called
248    before using these.  */
249
250 /* uintptr_t (usually "unsigned long") */
251 static GTY (()) tree mf_uintptr_type;
252
253 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
254 static GTY (()) tree mf_cache_struct_type;
255
256 /* struct __mf_cache * const */
257 static GTY (()) tree mf_cache_structptr_type;
258
259 /* extern struct __mf_cache __mf_lookup_cache []; */
260 static GTY (()) tree mf_cache_array_decl;
261
262 /* extern unsigned char __mf_lc_shift; */
263 static GTY (()) tree mf_cache_shift_decl;
264
265 /* extern uintptr_t __mf_lc_mask; */
266 static GTY (()) tree mf_cache_mask_decl;
267
268 /* Their function-scope local shadows, used in single-threaded mode only.  */
269
270 /* auto const unsigned char __mf_lc_shift_l; */
271 static GTY (()) tree mf_cache_shift_decl_l;
272
273 /* auto const uintptr_t __mf_lc_mask_l; */
274 static GTY (()) tree mf_cache_mask_decl_l;
275
276 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
277 static GTY (()) tree mf_check_fndecl;
278
279 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
280 static GTY (()) tree mf_register_fndecl;
281
282 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
283 static GTY (()) tree mf_unregister_fndecl;
284
285 /* extern void __mf_init (); */
286 static GTY (()) tree mf_init_fndecl;
287
288 /* extern int __mf_set_options (const char*); */
289 static GTY (()) tree mf_set_options_fndecl;
290
291
292 /* Helper for mudflap_init: construct a decl with the given category,
293    name, and type, mark it an external reference, and pushdecl it.  */
294 static inline tree
295 mf_make_builtin (enum tree_code category, const char *name, tree type)
296 {
297   tree decl = mf_mark (build_decl (category, get_identifier (name), type));
298   TREE_PUBLIC (decl) = 1;
299   DECL_EXTERNAL (decl) = 1;
300   lang_hooks.decls.pushdecl (decl);
301   return decl;
302 }
303
304 /* Helper for mudflap_init: construct a tree corresponding to the type
305      struct __mf_cache { uintptr_t low; uintptr_t high; };
306      where uintptr_t is the FIELD_TYPE argument.  */
307 static inline tree
308 mf_make_mf_cache_struct_type (tree field_type)
309 {
310   /* There is, abominably, no language-independent way to construct a
311      RECORD_TYPE.  So we have to call the basic type construction
312      primitives by hand.  */
313   tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type);
314   tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type);
315
316   tree struct_type = make_node (RECORD_TYPE);
317   DECL_CONTEXT (fieldlo) = struct_type;
318   DECL_CONTEXT (fieldhi) = struct_type;
319   TREE_CHAIN (fieldlo) = fieldhi;
320   TYPE_FIELDS (struct_type) = fieldlo;
321   TYPE_NAME (struct_type) = get_identifier ("__mf_cache");
322   layout_type (struct_type);
323
324   return struct_type;
325 }
326
327 #define build_function_type_0(rtype)            \
328   build_function_type (rtype, void_list_node)
329 #define build_function_type_1(rtype, arg1)                 \
330   build_function_type (rtype, tree_cons (0, arg1, void_list_node))
331 #define build_function_type_3(rtype, arg1, arg2, arg3)                  \
332   build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2,   \
333                                                              tree_cons (0, arg3, void_list_node))))
334 #define build_function_type_4(rtype, arg1, arg2, arg3, arg4)            \
335   build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2,   \
336                                                              tree_cons (0, arg3, tree_cons (0, arg4, \
337                                                                                             void_list_node)))))
338
339 /* Initialize the global tree nodes that correspond to mf-runtime.h
340    declarations.  */
341 void
342 mudflap_init (void)
343 {
344   static bool done = false;
345   tree mf_const_string_type;
346   tree mf_cache_array_type;
347   tree mf_check_register_fntype;
348   tree mf_unregister_fntype;
349   tree mf_init_fntype;
350   tree mf_set_options_fntype;
351
352   if (done)
353     return;
354   done = true;
355
356   mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode,
357                                                     /*unsignedp=*/true);
358   mf_const_string_type
359     = build_pointer_type (build_qualified_type
360                           (char_type_node, TYPE_QUAL_CONST));
361
362   mf_cache_struct_type = mf_make_mf_cache_struct_type (mf_uintptr_type);
363   mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
364   mf_cache_array_type = build_array_type (mf_cache_struct_type, 0);
365   mf_check_register_fntype =
366     build_function_type_4 (void_type_node, ptr_type_node, size_type_node,
367                            integer_type_node, mf_const_string_type);
368   mf_unregister_fntype =
369     build_function_type_3 (void_type_node, ptr_type_node, size_type_node,
370                            integer_type_node);
371   mf_init_fntype =
372     build_function_type_0 (void_type_node);
373   mf_set_options_fntype =
374     build_function_type_1 (integer_type_node, mf_const_string_type);
375
376   mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache",
377                                          mf_cache_array_type);
378   mf_cache_shift_decl = mf_make_builtin (VAR_DECL, "__mf_lc_shift",
379                                          unsigned_char_type_node);
380   mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask",
381                                         mf_uintptr_type);
382   mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check",
383                                      mf_check_register_fntype);
384   mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register",
385                                         mf_check_register_fntype);
386   mf_unregister_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_unregister",
387                                           mf_unregister_fntype);
388   mf_init_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_init",
389                                     mf_init_fntype);
390   mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options",
391                                            mf_set_options_fntype);
392 }
393 #undef build_function_type_4
394 #undef build_function_type_3
395 #undef build_function_type_1
396 #undef build_function_type_0
397
398
399 /* ------------------------------------------------------------------------ */
400 /* Memory reference transforms. Perform the mudflap indirection-related
401    tree transforms on the current function.
402
403    This is the second part of the mudflap instrumentation.  It works on
404    low-level GIMPLE using the CFG, because we want to run this pass after
405    tree optimizations have been performed, but we have to preserve the CFG
406    for expansion from trees to RTL.  */
407
408 static void
409 execute_mudflap_function_ops (void)
410 {
411   if (mf_marked_p (current_function_decl))
412     return;
413
414   push_gimplify_context ();
415
416   /* In multithreaded mode, don't cache the lookup cache parameters.  */
417   if (! flag_mudflap_threads)
418     mf_decl_cache_locals ();
419
420   mf_xform_derefs ();
421
422   if (! flag_mudflap_threads)
423     mf_decl_clear_locals ();
424
425   pop_gimplify_context (NULL);
426 }
427
428 /* Create and initialize local shadow variables for the lookup cache
429    globals.  Put their decls in the *_l globals for use by
430    mf_build_check_statement_for.  */
431
432 static void
433 mf_decl_cache_locals (void)
434 {
435   tree t, shift_init_stmts, mask_init_stmts;
436   tree_stmt_iterator tsi;
437
438   /* Build the cache vars.  */
439   mf_cache_shift_decl_l
440     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
441                                "__mf_lookup_shift_l"));
442
443   mf_cache_mask_decl_l
444     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
445                                "__mf_lookup_mask_l"));
446
447   /* Build initialization nodes for the cache vars.  We just load the
448      globals into the cache variables.  */
449   t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
450              mf_cache_shift_decl_l, mf_cache_shift_decl);
451   SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
452   gimplify_to_stmt_list (&t);
453   shift_init_stmts = t;
454
455   t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
456              mf_cache_mask_decl_l, mf_cache_mask_decl);
457   SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
458   gimplify_to_stmt_list (&t);
459   mask_init_stmts = t;
460
461   /* Anticipating multiple entry points, we insert the cache vars
462      initializers in each successor of the ENTRY_BLOCK_PTR.  */
463   for (tsi = tsi_start (shift_init_stmts);
464        ! tsi_end_p (tsi);
465        tsi_next (&tsi))
466     insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
467
468   for (tsi = tsi_start (mask_init_stmts);
469        ! tsi_end_p (tsi);
470        tsi_next (&tsi))
471     insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
472   bsi_commit_edge_inserts (NULL);
473 }
474
475
476 static void
477 mf_decl_clear_locals (void)
478 {
479   /* Unset local shadows.  */
480   mf_cache_shift_decl_l = NULL_TREE;
481   mf_cache_mask_decl_l = NULL_TREE;
482 }
483
484 static void
485 mf_build_check_statement_for (tree addr, tree size,
486                               block_stmt_iterator *instr_bsi,
487                               location_t *locus, tree dirflag)
488 {
489   tree_stmt_iterator head, tsi;
490   tree ptrtype = TREE_TYPE (addr);
491   block_stmt_iterator bsi;
492   basic_block cond_bb, then_bb, join_bb;
493   edge e;
494   tree cond, t, u, v, l1, l2;
495   tree mf_value;
496   tree mf_base;
497   tree mf_elem;
498
499   /* We first need to split the current basic block, and start altering
500      the CFG.  This allows us to insert the statements we're about to
501      construct into the right basic blocks.  The label l1 is the label
502      of the block for the THEN clause of the conditional jump we're
503      about to construct, and l2 is the ELSE clause, which is just the
504      continuation of the old statement stream.  */
505   l1 = create_artificial_label ();
506   l2 = create_artificial_label ();
507   cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi));
508   bsi = *instr_bsi;
509   bsi_prev (&bsi);
510   if (! bsi_end_p (bsi))
511     {
512       e = split_block (cond_bb, bsi_stmt (bsi));
513       cond_bb = e->src;
514       join_bb = e->dest;
515     }
516   else
517     {
518       join_bb = cond_bb;
519       cond_bb = create_empty_bb (join_bb->prev_bb);
520       e = make_edge (cond_bb, join_bb, 0);
521     }
522   e->flags = EDGE_FALSE_VALUE;
523   then_bb = create_empty_bb (cond_bb);
524   make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
525   make_edge (then_bb, join_bb, EDGE_FALLTHRU);
526
527   /* We expect that the conditional jump we will construct will not
528      be taken very often as it basically is an exception condition.  */
529   predict_edge_def (then_bb->pred, PRED_MUDFLAP, NOT_TAKEN);
530
531   /* Update dominance info.  Note that bb_join's data was
532      updated by split_block.  */
533   if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
534     {
535       set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
536       set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
537     }
538
539   /* Build our local variables.  */
540   mf_value = create_tmp_var (ptrtype, "__mf_value");
541   mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
542   mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
543
544   /* Build: __mf_value = <address expression>.  */
545   t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
546   SET_EXPR_LOCUS (t, locus);
547   gimplify_to_stmt_list (&t);
548   head = tsi_start (t);
549   tsi = tsi_last (t);
550
551   /* Build: __mf_base = (uintptr_t)__mf_value.  */
552   t = build (MODIFY_EXPR, void_type_node, mf_base,
553              build1 (NOP_EXPR, mf_uintptr_type, mf_value));
554   SET_EXPR_LOCUS (t, locus);
555   gimplify_to_stmt_list (&t);
556   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
557
558   /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
559                                             & __mf_mask].  */
560   t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base,
561              (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l));
562   t = build (BIT_AND_EXPR, mf_uintptr_type, t,
563              (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
564   t = build (ARRAY_REF,
565              TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
566              mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
567   t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
568   t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
569   SET_EXPR_LOCUS (t, locus);
570   gimplify_to_stmt_list (&t);
571   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
572
573   /* Quick validity check.
574
575      if (__mf_elem->low > __mf_base
576          || (__mf_elem_high < __mf_base + sizeof(T) - 1))
577         {
578           __mf_check ();
579           ... and only if single-threaded:
580           __mf_lookup_shift_1 = f...;
581           __mf_lookup_mask_l = ...;
582         }
583
584      It is expected that this body of code is rarely executed so we mark
585      the edge to the THEN clause of the conditional jump as unlikely.  */
586
587   /* Construct t <-- '__mf_elem->low  > __mf_base'.  */
588   t = build (COMPONENT_REF, mf_uintptr_type,
589              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
590              TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
591   t = build (GT_EXPR, boolean_type_node, t, mf_base);
592
593   /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
594
595      First build:
596         1) u <--  '__mf_elem->high'
597         2) v <--  '__mf_base + sizeof (T) - 1'.
598
599      Then build 'u <-- (u < v).  */
600
601
602   u = build (COMPONENT_REF, mf_uintptr_type,
603              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
604              TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
605
606   v = convert (mf_uintptr_type,
607                size_binop (MINUS_EXPR, size, size_one_node));
608   v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
609
610   u = build (LT_EXPR, boolean_type_node, u, v);
611
612   /* Build the composed conditional: t <-- 't || u'.  Then store the
613      result of the evaluation of 't' in a temporary variable which we
614      can use as the condition for the conditional jump.  */
615   t = build (TRUTH_OR_EXPR, boolean_type_node, t, u);
616   cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond");
617   t = build (MODIFY_EXPR, boolean_type_node, cond, t);
618   gimplify_to_stmt_list (&t);
619   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
620
621   /* Build the conditional jump.  'cond' is just a temporary so we can
622      simply build a void COND_EXPR.  We do need labels in both arms though.  */
623   t = build (COND_EXPR, void_type_node, cond,
624              build (GOTO_EXPR, void_type_node, tree_block_label (then_bb)),
625              build (GOTO_EXPR, void_type_node, tree_block_label (join_bb)));
626   SET_EXPR_LOCUS (t, locus);
627   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
628
629   /* At this point, after so much hard work, we have only constructed
630      the conditional jump,
631
632      if (__mf_elem->low > __mf_base
633          || (__mf_elem_high < __mf_base + sizeof(T) - 1))
634
635      The lowered GIMPLE tree representing this code is in the statement
636      list starting at 'head'.
637
638      We can insert this now in the current basic block, ie. the one that
639      the statement we're instrumenting was originally in.  */
640   bsi = bsi_last (cond_bb);
641   for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
642     bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
643
644   /*  Now build up the body of the cache-miss handling:
645
646      __mf_check();
647      refresh *_l vars.
648
649      This is the body of the conditional.  */
650   
651   u = tree_cons (NULL_TREE,
652                  mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION
653                                              : *locus),
654                  NULL_TREE);
655   u = tree_cons (NULL_TREE, dirflag, u);
656   u = tree_cons (NULL_TREE, size, u);
657   u = tree_cons (NULL_TREE, mf_value, u);
658   t = build_function_call_expr (mf_check_fndecl, u);
659   gimplify_to_stmt_list (&t);
660   head = tsi_start (t);
661   tsi = tsi_last (t);
662
663   if (! flag_mudflap_threads)
664     {
665       t = build (MODIFY_EXPR, void_type_node,
666                  mf_cache_shift_decl_l, mf_cache_shift_decl);
667       tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
668
669       t = build (MODIFY_EXPR, void_type_node,
670                  mf_cache_mask_decl_l, mf_cache_mask_decl);
671       tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
672     }
673
674   /* Insert the check code in the THEN block.  */
675   bsi = bsi_start (then_bb);
676   for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
677     bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
678
679   *instr_bsi = bsi_start (join_bb);
680   bsi_next (instr_bsi);
681 }
682
683 static void
684 mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
685                    location_t *locus, tree dirflag)
686 {
687   tree type, ptr_type, addr, size, t;
688
689   /* Don't instrument read operations.  */
690   if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
691     return;
692
693   /* Don't instrument marked nodes.  */
694   if (mf_marked_p (*tp))
695     return;
696
697   t = *tp;
698   type = TREE_TYPE (t);
699   size = TYPE_SIZE_UNIT (type);
700
701   switch (TREE_CODE (t))
702     {
703     case ARRAY_REF:
704       {
705         /* Omit checking if we can statically determine that the access is
706            valid.  For non-addressable local arrays this is not optional,
707            since we won't have called __mf_register for the object.  */
708         tree op0, op1;
709
710         op0 = TREE_OPERAND (t, 0);
711         op1 = TREE_OPERAND (t, 1);
712         while (TREE_CODE (op1) == INTEGER_CST)
713           {
714             tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
715
716             /* Test for index in range.  Break if not.  */
717             if (!dom
718                 || (! TYPE_MIN_VALUE (dom)
719                     || ! really_constant_p (TYPE_MIN_VALUE (dom)))
720                 || (! TYPE_MAX_VALUE (dom)
721                     || ! really_constant_p (TYPE_MAX_VALUE (dom)))
722                 || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
723                     || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
724               break;
725
726             /* If we're looking at a non-external VAR_DECL, then the 
727                access must be ok.  */
728             if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0))
729               return;
730
731             /* Only continue if we're still looking at an array.  */
732             if (TREE_CODE (op0) != ARRAY_REF)
733               break;
734
735             op1 = TREE_OPERAND (op0, 1);
736             op0 = TREE_OPERAND (op0, 0);
737           }
738       
739         /* If we got here, we couldn't statically the check.  */
740         ptr_type = build_pointer_type (type);
741         addr = build1 (ADDR_EXPR, ptr_type, t);
742       }
743       break;
744
745     case INDIRECT_REF:
746       addr = TREE_OPERAND (t, 0);
747       ptr_type = TREE_TYPE (addr);
748       break;
749
750     case ARRAY_RANGE_REF:
751       warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
752       return;
753
754     case COMPONENT_REF:
755       {
756         tree field;
757
758         /* If we're not dereferencing something, then the access
759            must be ok.  */
760         if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
761           return;
762
763         field = TREE_OPERAND (t, 1);
764
765         /* If we're looking at a bit field, then we can't take its address
766            with ADDR_EXPR -- lang_hooks.mark_addressable will error.  Do
767            things the hard way with PLUS.  */
768         if (DECL_BIT_FIELD_TYPE (field))
769           {
770             if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
771               size = DECL_SIZE_UNIT (field);
772
773             addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
774             addr = fold_convert (ptr_type_node, addr);
775             addr = fold (build (PLUS_EXPR, ptr_type_node,
776                                 addr, fold_convert (ptr_type_node,
777                                                     byte_position (field))));
778           }
779         else
780           {
781             ptr_type = build_pointer_type (type);
782             addr = build1 (ADDR_EXPR, ptr_type, t);
783           }
784       }
785       break;
786
787     case BIT_FIELD_REF:
788       {
789         tree ofs, rem, bpu;
790
791         /* If we're not dereferencing something, then the access
792            must be ok.  */
793         if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
794           return;
795
796         bpu = bitsize_int (BITS_PER_UNIT);
797         ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
798         rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
799         ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu);
800
801         size = convert (bitsizetype, TREE_OPERAND (t, 1));
802         size = size_binop (PLUS_EXPR, size, rem);
803         size = size_binop (CEIL_DIV_EXPR, size, bpu);
804         size = convert (sizetype, size);
805
806         addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
807         addr = convert (ptr_type_node, addr);
808         addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs));
809       }
810       break;
811
812     default:
813       return;
814     }
815
816   mf_build_check_statement_for (addr, size, iter, locus, dirflag);
817 }
818
819 static void
820 mf_xform_derefs (void)
821 {
822   basic_block bb, next;
823   block_stmt_iterator i;
824   int saved_last_basic_block = last_basic_block;
825
826   bb = ENTRY_BLOCK_PTR ->next_bb;
827   do
828     {
829       next = bb->next_bb;
830       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
831         {
832           tree s = bsi_stmt (i);
833
834           /* Only a few GIMPLE statements can reference memory.  */
835           switch (TREE_CODE (s))
836             {
837             case MODIFY_EXPR:
838               mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
839                                  integer_one_node);
840               mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
841                                  integer_zero_node);
842               break;
843
844             case RETURN_EXPR:
845               if (TREE_OPERAND (s, 0) != NULL_TREE)
846                 {
847                   if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
848                     mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1),
849                                        EXPR_LOCUS (s), integer_zero_node);
850                   else
851                     mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
852                                        integer_zero_node);
853                 }
854               break;
855
856             default:
857               ;
858             }
859         }
860       bb = next;
861     }
862   while (bb && bb->index <= saved_last_basic_block);
863 }
864
865 /* ------------------------------------------------------------------------ */
866 /* ADDR_EXPR transforms.  Perform the declaration-related mudflap tree
867    transforms on the current function.
868
869    This is the first part of the mudflap instrumentation.  It works on
870    high-level GIMPLE because after lowering, all variables are moved out
871    of their BIND_EXPR binding context, and we lose liveness information
872    for the declarations we wish to instrument.  */
873
874 static void
875 execute_mudflap_function_decls (void)
876 {
877   if (mf_marked_p (current_function_decl))
878     return;
879
880   push_gimplify_context ();
881
882   mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
883                   DECL_ARGUMENTS (current_function_decl));
884
885   pop_gimplify_context (NULL);
886 }
887
888 /* This struct is passed between mf_xform_decls to store state needed
889    during the traversal searching for objects that have their
890    addresses taken.  */
891 struct mf_xform_decls_data
892 {
893   tree param_decls;
894 };
895
896
897 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
898    _DECLs if appropriate.  Arrange to call the __mf_register function
899    now, and the __mf_unregister function later for each.  */
900 static void
901 mx_register_decls (tree decl, tree *stmt_list)
902 {
903   tree finally_stmts = NULL_TREE;
904   tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
905
906   while (decl != NULL_TREE)
907     {
908       /* Eligible decl?  */
909       if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
910           /* It must be a non-external, automatic variable.  */
911           && ! DECL_EXTERNAL (decl)
912           && ! TREE_STATIC (decl)
913           /* The decl must have its address taken.  */
914           && TREE_ADDRESSABLE (decl)
915           /* The type of the variable must be complete.  */
916           && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
917           /* The decl hasn't been decomposed somehow.  */
918           && DECL_VALUE_EXPR (decl) == NULL
919           /* Don't process the same decl twice.  */
920           && ! mf_marked_p (decl))
921         {
922           tree size = NULL_TREE, variable_name;
923           tree unregister_fncall, unregister_fncall_params;
924           tree register_fncall, register_fncall_params;
925
926           size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
927
928           /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
929           unregister_fncall_params =
930             tree_cons (NULL_TREE,
931                        convert (ptr_type_node,
932                                 mf_mark (build1 (ADDR_EXPR,
933                                                  build_pointer_type (TREE_TYPE (decl)),
934                                                  decl))),
935                        tree_cons (NULL_TREE, 
936                                   size,
937                                   tree_cons (NULL_TREE,
938                                              /* __MF_TYPE_STACK */
939                                              build_int_cst (NULL_TREE, 3),
940                                              NULL_TREE)));
941           /* __mf_unregister (...) */
942           unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
943                                                         unregister_fncall_params);
944
945           /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */
946           variable_name = mf_varname_tree (decl);
947           register_fncall_params =
948             tree_cons (NULL_TREE,
949                    convert (ptr_type_node,
950                             mf_mark (build1 (ADDR_EXPR,
951                                              build_pointer_type (TREE_TYPE (decl)),
952                                              decl))),
953                        tree_cons (NULL_TREE,
954                                   size,
955                                   tree_cons (NULL_TREE,
956                                              /* __MF_TYPE_STACK */
957                                              build_int_cst (NULL_TREE, 3),
958                                              tree_cons (NULL_TREE,
959                                                         variable_name,
960                                                         NULL_TREE))));
961
962           /* __mf_register (...) */
963           register_fncall = build_function_call_expr (mf_register_fndecl,
964                                                       register_fncall_params);
965
966           /* Accumulate the two calls.  */
967           /* ??? Set EXPR_LOCATION.  */
968           gimplify_stmt (&register_fncall);
969           gimplify_stmt (&unregister_fncall);
970
971           /* Add the __mf_register call at the current appending point.  */
972           if (tsi_end_p (initially_stmts))
973             internal_error ("mudflap ran off end of BIND_EXPR body");
974           tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT);
975
976           /* Accumulate the FINALLY piece.  */
977           append_to_statement_list (unregister_fncall, &finally_stmts);
978
979           mf_mark (decl);
980         }
981
982       decl = TREE_CHAIN (decl);
983     }
984
985   /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
986   if (finally_stmts != NULL_TREE)
987     {
988       tree t = build (TRY_FINALLY_EXPR, void_type_node,
989                       *stmt_list, finally_stmts);
990       *stmt_list = NULL;
991       append_to_statement_list (t, stmt_list);
992     }
993 }
994
995
996 /* Process every variable mentioned in BIND_EXPRs.  */
997 static tree
998 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
999 {
1000   struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
1001
1002   if (*t == NULL_TREE || *t == error_mark_node)
1003     {
1004       *continue_p = 0;
1005       return NULL_TREE;
1006     }
1007
1008   *continue_p = 1;
1009
1010   switch (TREE_CODE (*t))
1011     {
1012     case BIND_EXPR:
1013       {
1014         /* Process function parameters now (but only once).  */
1015         mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
1016         d->param_decls = NULL_TREE;
1017
1018         mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
1019       }
1020       break;
1021
1022     default:
1023       break;
1024     }
1025
1026   return NULL;
1027 }
1028
1029 /* Perform the object lifetime tracking mudflap transform on the given function
1030    tree.  The tree is mutated in place, with possibly copied subtree nodes.
1031
1032    For every auto variable declared, if its address is ever taken
1033    within the function, then supply its lifetime to the mudflap
1034    runtime with the __mf_register and __mf_unregister calls.
1035 */
1036
1037 static void
1038 mf_xform_decls (tree fnbody, tree fnparams)
1039 {
1040   struct mf_xform_decls_data d;
1041   d.param_decls = fnparams;
1042   walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
1043 }
1044
1045
1046 /* ------------------------------------------------------------------------ */
1047 /* Externally visible mudflap functions.  */
1048
1049
1050 /* Mark and return the given tree node to prevent further mudflap
1051    transforms.  */
1052 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
1053
1054 tree
1055 mf_mark (tree t)
1056 {
1057   void **slot;
1058
1059   if (marked_trees == NULL)
1060     marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
1061
1062   slot = htab_find_slot (marked_trees, t, INSERT);
1063   *slot = t;
1064   return t;
1065 }
1066
1067 int
1068 mf_marked_p (tree t)
1069 {
1070   void *entry;
1071
1072   if (marked_trees == NULL)
1073     return 0;
1074
1075   entry = htab_find (marked_trees, t);
1076   return (entry != NULL);
1077 }
1078
1079 /* Remember given node as a static of some kind: global data,
1080    function-scope static, or an anonymous constant.  Its assembler
1081    label is given.  */
1082
1083 /* A list of globals whose incomplete declarations we encountered.
1084    Instead of emitting the __mf_register call for them here, it's
1085    delayed until program finish time.  If they're still incomplete by
1086    then, warnings are emitted.  */
1087
1088 static GTY (()) varray_type deferred_static_decls;
1089
1090 /* A list of statements for calling __mf_register() at startup time.  */
1091 static GTY (()) tree enqueued_call_stmt_chain;
1092
1093 static void
1094 mudflap_register_call (tree obj, tree object_size, tree varname)
1095 {
1096   tree arg, args, call_stmt;
1097
1098   args = tree_cons (NULL_TREE, varname, NULL_TREE);
1099
1100   arg = build_int_cst (NULL_TREE, 4); /* __MF_TYPE_STATIC */
1101   args = tree_cons (NULL_TREE, arg, args);
1102
1103   arg = convert (size_type_node, object_size);
1104   args = tree_cons (NULL_TREE, arg, args);
1105
1106   arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
1107   arg = convert (ptr_type_node, arg);
1108   args = tree_cons (NULL_TREE, arg, args);
1109
1110   call_stmt = build_function_call_expr (mf_register_fndecl, args);
1111
1112   append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
1113 }
1114
1115 void
1116 mudflap_enqueue_decl (tree obj)
1117 {
1118   if (mf_marked_p (obj))
1119     return;
1120
1121   /* We don't need to process variable decls that are internally
1122      generated extern.  If we did, we'd end up with warnings for them
1123      during mudflap_finish_file ().  That would confuse the user,
1124      since the text would refer to variables that don't show up in the
1125      user's source code.  */
1126   if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
1127     return;
1128
1129   if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
1130     {
1131       tree object_size;
1132
1133       mf_mark (obj);
1134
1135       object_size = size_in_bytes (TREE_TYPE (obj));
1136
1137       if (dump_file)
1138         {
1139           fprintf (dump_file, "enqueue_decl obj=`");
1140           print_generic_expr (dump_file, obj, dump_flags);
1141           fprintf (dump_file, "' size=");
1142           print_generic_expr (dump_file, object_size, dump_flags);
1143           fprintf (dump_file, "\n");
1144         }
1145
1146       /* NB: the above condition doesn't require TREE_USED or
1147          TREE_ADDRESSABLE.  That's because this object may be a global
1148          only used from other compilation units.  XXX: Maybe static
1149          objects could require those attributes being set.  */
1150
1151       mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1152     }
1153   else
1154     {
1155       size_t i;
1156
1157       if (! deferred_static_decls)
1158         VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1159
1160       /* Ugh, linear search... */
1161       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1162         if (VARRAY_TREE (deferred_static_decls, i) == obj)
1163           {
1164             warning ("mudflap cannot track lifetime of `%s'",
1165                      IDENTIFIER_POINTER (DECL_NAME (obj)));
1166             return;
1167           }
1168
1169       VARRAY_PUSH_TREE (deferred_static_decls, obj);
1170     }
1171 }
1172
1173 void
1174 mudflap_enqueue_constant (tree obj)
1175 {
1176   tree object_size, varname;
1177
1178   if (mf_marked_p (obj))
1179     return;
1180
1181   if (TREE_CODE (obj) == STRING_CST)
1182     object_size = build_int_cst (NULL_TREE, TREE_STRING_LENGTH (obj));
1183   else
1184     object_size = size_in_bytes (TREE_TYPE (obj));
1185
1186   if (dump_file)
1187     {
1188       fprintf (dump_file, "enqueue_constant obj=`");
1189       print_generic_expr (dump_file, obj, dump_flags);
1190       fprintf (dump_file, "' size=");
1191       print_generic_expr (dump_file, object_size, dump_flags);
1192       fprintf (dump_file, "\n");
1193     }
1194
1195   if (TREE_CODE (obj) == STRING_CST)
1196     varname = mf_build_string ("string literal");
1197   else
1198     varname = mf_build_string ("constant");
1199
1200   mudflap_register_call (obj, object_size, varname);
1201 }
1202
1203
1204 /* Emit any file-wide instrumentation.  */
1205 void
1206 mudflap_finish_file (void)
1207 {
1208   tree ctor_statements = NULL_TREE;
1209
1210   /* Try to give the deferred objects one final try.  */
1211   if (deferred_static_decls)
1212     {
1213       size_t i;
1214
1215       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1216         {
1217           tree obj = VARRAY_TREE (deferred_static_decls, i);
1218
1219           /* Call enqueue_decl again on the same object it has previously
1220              put into the table.  (It won't modify the table this time, so
1221              infinite iteration is not a problem.)  */
1222           mudflap_enqueue_decl (obj);
1223         }
1224
1225       VARRAY_CLEAR (deferred_static_decls);
1226     }
1227
1228   /* Insert a call to __mf_init.  */
1229   {
1230     tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE);
1231     append_to_statement_list (call2_stmt, &ctor_statements);
1232   }
1233   
1234   /* If appropriate, call __mf_set_options to pass along read-ignore mode.  */
1235   if (flag_mudflap_ignore_reads)
1236     {
1237       tree arg = tree_cons (NULL_TREE, 
1238                             mf_build_string ("-ignore-reads"), NULL_TREE);
1239       tree call_stmt = build_function_call_expr (mf_set_options_fndecl, arg);
1240       append_to_statement_list (call_stmt, &ctor_statements);
1241     }
1242
1243   /* Append all the enqueued registration calls.  */
1244   if (enqueued_call_stmt_chain)
1245     {
1246       append_to_statement_list (enqueued_call_stmt_chain, &ctor_statements);
1247       enqueued_call_stmt_chain = NULL_TREE;
1248     }
1249
1250   cgraph_build_static_cdtor ('I', ctor_statements, 
1251                              MAX_RESERVED_INIT_PRIORITY-1);
1252 }
1253
1254
1255 static bool
1256 gate_mudflap (void)
1257 {
1258   return flag_mudflap != 0;
1259 }
1260
1261 struct tree_opt_pass pass_mudflap_1 = 
1262 {
1263   "mudflap1",                           /* name */
1264   gate_mudflap,                         /* gate */
1265   execute_mudflap_function_decls,       /* execute */
1266   NULL,                                 /* sub */
1267   NULL,                                 /* next */
1268   0,                                    /* static_pass_number */
1269   0,                                    /* tv_id */
1270   PROP_gimple_any,                      /* properties_required */
1271   0,                                    /* properties_provided */
1272   0,                                    /* properties_destroyed */
1273   0,                                    /* todo_flags_start */
1274   TODO_dump_func,                       /* todo_flags_finish */
1275   0                                     /* letter */
1276 };
1277
1278 struct tree_opt_pass pass_mudflap_2 = 
1279 {
1280   "mudflap2",                           /* name */
1281   gate_mudflap,                         /* gate */
1282   execute_mudflap_function_ops,         /* execute */
1283   NULL,                                 /* sub */
1284   NULL,                                 /* next */
1285   0,                                    /* static_pass_number */
1286   0,                                    /* tv_id */
1287   PROP_gimple_leh,                      /* properties_required */
1288   0,                                    /* properties_provided */
1289   0,                                    /* properties_destroyed */
1290   0,                                    /* todo_flags_start */
1291   TODO_verify_flow | TODO_verify_stmts
1292   | TODO_dump_func,                     /* todo_flags_finish */
1293   0                                     /* letter */
1294 };
1295
1296 #include "gt-tree-mudflap.h"