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