--- gcc/common.opt (/gcc-local/trunk) (revision 30596) +++ gcc/common.opt (/gcc-local/export-ddg) (revision 30596) @@ -461,6 +461,10 @@ fexpensive-optimizations Common Report Var(flag_expensive_optimizations) Optimization Perform a number of minor, expensive optimizations +fexport-ddg +Common Report Var(flag_export_ddg) Init(1) +Gather and export data relation information + ffast-math Common --- gcc/function.h (/gcc-local/trunk) (revision 30596) +++ gcc/function.h (/gcc-local/export-ddg) (revision 30596) @@ -296,6 +296,14 @@ struct function GTY(()) during the nested function. */ struct var_refs_queue *fixup_var_refs_queue; + /* Data references and data dependence relations exported from Tree-SSA + level for use on RTL level. */ + struct ddg_info_def * GTY((skip)) x_ddg_info; + + /* This serves as GC root for trees for which data references + were exported. */ + VEC(tree, gc) *ddg_info_root_for_trees; + /* Current nesting level for temporaries. */ int x_temp_slot_level; --- gcc/tree-data-ref-export.h (/gcc-local/trunk) (revision 30596) +++ gcc/tree-data-ref-export.h (/gcc-local/export-ddg) (revision 30596) @@ -0,0 +1,11 @@ +#ifndef TREE_DATA_REF_EXPORT_H +#define TREE_DATA_REF_EXPORT_H + +extern void verify_trees (void); +extern void replace_var_in_datarefs (const_tree, const_tree); + +extern void ddg_export_disambiguate_only_intra_loop_deps (bool); +extern bool may_alias_mems_by_ddr (const_rtx, const_rtx, int); + +#endif /* TREE_DATA_REF_EXPORT_H */ + --- gcc/tree-data-ref-export.c (/gcc-local/trunk) (revision 30596) +++ gcc/tree-data-ref-export.c (/gcc-local/export-ddg) (revision 30596) @@ -0,0 +1,711 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "ggc.h" +#include "tree.h" + +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "timevar.h" +#include "cfgloop.h" +#include "tree-chrec.h" +#include "tree-data-ref.h" +#include "tree-scalar-evolution.h" +#include "tree-pass.h" +#include "langhooks.h" +#include "hashtab.h" + +#include "tree-data-ref-export.h" + +/* Holds exported data references and relations. */ +struct ddg_info_def +{ + htab_t tree_to_dataref; + + htab_t datarefs_pair_to_ddr; + + /* Used by the verifier. */ + VEC (data_reference_p, heap) *verifier_seen_datarefs; + + int ddrs_known, ddrs_no, ddrs_unknown, ddrs_not_found; + + /* Number of memory references without/with relevant exported info. */ + int refs_bad, refs_ok; + + /* Statistics on DDG info usage in RTL disambiguation. */ + int alias_fail_no_tree, alias_fail_no_drf, alias_fail_no_ddr, + alias_fail_useless_ddr, alias_fail_graceful, alias_success_useless, + alias_success_new, alias_success_no_dep, alias_success_nonzero_dist; + + /* Whether we should skip verification of exported data. Enabled as late as + possible in the RTL pipeline by a separate pass. */ + bool skip_verification; + + /* TRUE for passes that perform code motion across loop branches, like SMS. + For other passes we assume it is safe to disambiguate references that are + dependent and distance vectors are known and non-zero. */ + bool disambiguate_only_intra_loop_deps; +}; + +#define ddg_info (cfun->x_ddg_info) + +#define print(...) \ +do \ + if (dump_file) \ + fprintf (dump_file, __VA_ARGS__); \ +while (0) + +static void +print_generic_expr_1 (FILE *dump_file, const_tree t, int flags) +{ + if (dump_file) + { + print_generic_expr (dump_file, (tree) t, flags); + dump_addr (dump_file, " ", t); + } +} + +static void +print_inline_rtx_1 (FILE *dump_file, rtx x, int ind) +{ + if (dump_file) + { + print_inline_rtx (dump_file, x, ind); + dump_addr (dump_file, " ", x); + } +} + +typedef struct { + const_tree ref; + data_reference_p drf; +} tree_dataref; + +static hashval_t +htab_hash_tree (const tree_dataref *t) +{ + return htab_hash_pointer (t->ref); +} + +static int +htab_eq_tree (const tree_dataref *t1, const tree_dataref *t2) +{ + return t1->ref == t2->ref; +} + +static void +htab_del_tree_dataref (tree_dataref *t) +{ + if (t->drf) + free_data_ref (t->drf); +} + +typedef struct { + data_reference_p a; + data_reference_p b; + ddr_p ddr; +} datarefs_pair_ddr; + +static hashval_t +htab_hash_datarefs_pair (const datarefs_pair_ddr *dp) +{ + return iterative_hash (&dp->a, sizeof (data_reference_p), + htab_hash_pointer (dp->b)); +} + +static int +htab_eq_datarefs_pair (const datarefs_pair_ddr *dp1, + const datarefs_pair_ddr *dp2) +{ + return dp1->a == dp2->a && dp1->b == dp2->b; +} + +static void +htab_del_datarefs_pair (datarefs_pair_ddr *dp) +{ + free_dependence_relation (dp->ddr); +} + +/* For each loop in function, save datarefs and ddrs obtained via + compute_dependencies_for_loop into ddg_info. */ +static unsigned int +main_export_ddg (void) +{ + bool inside_tree_loop_opt_p = !!current_loops; + bool dom_info_was_avail_p = dom_info_available_p (CDI_DOMINATORS); + unsigned int n_loops; + struct loop *loop; + loop_iterator li; + + gcc_assert (!ddg_info); + ddg_info = XCNEW (struct ddg_info_def); + ddg_info->tree_to_dataref + = htab_create (1, (htab_hash) htab_hash_tree, (htab_eq) htab_eq_tree, + (htab_del) htab_del_tree_dataref); + ddg_info->datarefs_pair_to_ddr + = htab_create (1, (htab_hash) htab_hash_datarefs_pair, + (htab_eq) htab_eq_datarefs_pair, + (htab_del) htab_del_datarefs_pair); + + cfun->ddg_info_root_for_trees = NULL; + + if(!inside_tree_loop_opt_p) + loop_optimizer_init(AVOID_CFG_MODIFICATIONS); + + /* This can be more than actual number of loops, because number_of_loops () + includes deleted loops. */ + n_loops = number_of_loops () - 1; + + if (n_loops > 0) + { + int cur_loop = 0; + VEC (data_reference_p, heap) *datarefs = NULL; + VEC (ddr_p, heap) *ddrs = NULL; + + if (!inside_tree_loop_opt_p) + scev_initialize (); + + FOR_EACH_LOOP (li, loop, 0) + { + unsigned int i; + data_reference_p drf; + ddr_p ddr; + + compute_data_dependences_for_loop (loop, false, &datarefs, &ddrs); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + dump_data_references (dump_file, datarefs); + dump_ddrs (dump_file, ddrs); + } + + for (i = 0; VEC_iterate (data_reference_p, datarefs, i, drf); i++) + { + void **slot; + tree_dataref *td; + + /* We want to save only those data references that correspond to + iteration of innermost loop containing the reference. */ + if (!drf->ref || loop != loop_containing_stmt (drf->stmt)) + continue; + + td = XNEW (tree_dataref); + td->ref = drf->ref; + td->drf = drf; + slot = htab_find_slot (ddg_info->tree_to_dataref, td, INSERT); + + gcc_assert (!*slot); + + *slot = td; + VEC_safe_push (tree, gc, cfun->ddg_info_root_for_trees, + (tree) drf->ref); + } + + for (i = 0; VEC_iterate (ddr_p, ddrs, i, ddr); i++) + { + void **slot; + datarefs_pair_ddr *dp; + + /* As above, we want to save only those DDRs that describe + relation of references for innermost loop containing them. */ + if (!(ddr->a && ddr->b) + || loop != loop_containing_stmt (ddr->a->stmt)) + { + continue; + } + + dp = XNEW (datarefs_pair_ddr); + + dp->a = ddr->a; + dp->b = ddr->b; + dp->ddr = ddr; + slot = htab_find_slot (ddg_info->datarefs_pair_to_ddr, dp, + INSERT); + + gcc_assert (!*slot); + *slot = dp; + } + + cur_loop++; + VEC_free (data_reference_p, heap, datarefs); + VEC_free (ddr_p, heap, ddrs); + } + + if (!inside_tree_loop_opt_p) + scev_finalize (); + } + + if (!inside_tree_loop_opt_p) + loop_optimizer_finalize (); + + if (!dom_info_was_avail_p) + free_dominance_info (CDI_DOMINATORS); + + return 0; +} + +static bool +gate_export_ddg(void) +{ + return flag_export_ddg != 0; +} + +struct tree_opt_pass pass_gather_ddg_info = +{ + "export-ddg", /* name */ + gate_export_ddg, /* gate */ + main_export_ddg, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ +}; + +static unsigned int +free_ddg_info (void) +{ + if (!ddg_info) + return 0; + + /* TODO: DDR_LOOP_NESTs are not free'd. */ + htab_delete (ddg_info->datarefs_pair_to_ddr); + htab_delete (ddg_info->tree_to_dataref); + + free (ddg_info); + ddg_info = NULL; + VEC_free (tree, gc, cfun->ddg_info_root_for_trees); + return 0; +} + +struct tree_opt_pass pass_free_ddg_info = +{ + NULL, /* name */ + NULL, /* gate */ + free_ddg_info, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +/* Replace all occurences of FROM tree to TO in ddg_info_root_for_trees. */ +static void +replace_tree_in_ggc_root (const_tree from, const_tree to) +{ + int i; + tree t; + bool found = false; + + for (i = 0; VEC_iterate (tree, cfun->ddg_info_root_for_trees, i, t); i++) + if (t == from) + { + found = true; + VEC_replace (tree, cfun->ddg_info_root_for_trees, i, (tree) to); + } + + gcc_assert (found); +} + +/* Replace FROM tree to TO in ref fields of saved datarefs. */ +void +replace_var_in_datarefs (const_tree from, const_tree to) +{ + void **slot; + tree_dataref *td = XNEW (tree_dataref); + td->ref = from; + + slot = htab_find_slot (ddg_info->tree_to_dataref, td, NO_INSERT); + + /* IVOPTS might want to change a memory reference for which no dataref was + produced. However, it would be nice to enable this assert and see in + what cases it happens. */ + /* gcc_assert (slot); */ + + if (!slot) + { + free (td); + return; + } + + td->ref = to; + td->drf = ((tree_dataref *) (*slot))->drf; + ((tree_dataref *) (*slot))->drf = NULL; + htab_clear_slot (ddg_info->tree_to_dataref, slot); + + slot = htab_find_slot (ddg_info->tree_to_dataref, td, INSERT); + gcc_assert (!*slot); + *slot = td; + + replace_tree_in_ggc_root (from, to); +} + +/* Search for the dataref for T and return it if found, otherwise return + NULL. */ + +static data_reference_p +find_dataref (const_tree t) +{ + tree_dataref td, *td_p; + td.ref = t; + td_p = htab_find (ddg_info->tree_to_dataref, &td); + return td_p ? td_p->drf : NULL; +} + +/* Search for data dependence relation for DR1 and DR2, return it if found; + otherwise return NULL. */ +static ddr_p +find_ddr (data_reference_p dr1, data_reference_p dr2) +{ + datarefs_pair_ddr dp, *dp_p; + dp.a = dr1; + dp.b = dr2; + dp_p = htab_find (ddg_info->datarefs_pair_to_ddr, &dp); + if (dp_p) + return dp_p->ddr; + dp.a = dr2; + dp.b = dr1; + dp_p = htab_find (ddg_info->datarefs_pair_to_ddr, &dp); + return dp_p ? dp_p->ddr : NULL; +} + +/* For each data reference seen in the loop currently being verified, try to + find data dependence relation for it and DATAREF, record statistics, add + DATAREF to array of references in current loop. */ +static void +verify_ddrs (data_reference_p dataref) +{ + unsigned int i; + data_reference_p dr; + ddr_p ddr; + + for (i = 0; + VEC_iterate (data_reference_p, ddg_info->verifier_seen_datarefs, i, dr); + i++) + if ((ddr = find_ddr (dataref, dr))) + { + if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE) + ddg_info->ddrs_known++; + else if (DDR_ARE_DEPENDENT (ddr) == chrec_known) + ddg_info->ddrs_no++; + else if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) + ddg_info->ddrs_unknown++; + } + else + ddg_info->ddrs_not_found++; + + VEC_safe_push (data_reference_p, heap, ddg_info->verifier_seen_datarefs, + dataref); +} + +/* Print trees for which we expect to find saved dataref. */ +static tree +verify_trees_gimple (tree *tp, int *walk_subtrees, + void *data ATTRIBUTE_UNUSED) +{ + data_reference_p dataref; + const_tree t = *tp; + + if (TREE_CODE (t) == TARGET_MEM_REF) + t = TREE_OPERAND (t, 5); + if (REFERENCE_CLASS_P (t)) + { + *walk_subtrees = 0; + if ((dataref = find_dataref (t))) + { + if (dump_flags & TDF_DETAILS) + { + print (" DATAREF: "); + print_generic_expr_1 (dump_file, t, TDF_VOPS|TDF_MEMSYMS); + print ("\n"); + } + ddg_info->refs_ok++; + verify_ddrs (dataref); + } + else + { + if (dump_flags & TDF_DETAILS) + { + print ("!DATAREF: "); + print_generic_expr_1 (dump_file, t, TDF_VOPS|TDF_MEMSYMS); + print ("\n"); + } + ddg_info->refs_bad++; + } + } + return NULL_TREE; +} + + +/* Print MEMs for which we expect to have MEM_ORIG_EXPR. */ +static int +verify_trees_rtl (rtx *px, void *data ATTRIBUTE_UNUSED) +{ + rtx x = *px; + tree t; + int dummy; + + if (x == NULL_RTX || GET_CODE (x) != MEM) + return 0; + + t = MEM_ORIG_EXPR (x); + + if (!t) + { + if (dump_flags & TDF_DETAILS) + { + print ("!MEM_ORIG_EXPR: "); + print_inline_rtx_1 (dump_file, x, 0); + print ("\n"); + } + ddg_info->refs_bad++; + } + else + { + if (dump_flags & TDF_DETAILS) + { + print (" MEM_ORIG_EXPR: "); + print_inline_rtx_1 (dump_file, x, 0); + print (" -> "); + print_generic_expr_1 (dump_file, t, TDF_VOPS|TDF_MEMSYMS); + print ("\n"); + } + verify_trees_gimple (&t, &dummy, NULL); + } + + return 0; +} + +/* Depending on current IR, either check that we have saved datarefs for all + memory references, or we have MEM_ORIG_EXPRs for MEMs. */ +void +verify_trees (void) +{ + bool inside_tree_loop_opt_p = !!current_loops; + bool dom_info_was_avail_p; + loop_iterator li; + struct loop *loop; + unsigned cur_loop = 0; + + if (!ddg_info/* || !dump_file*/) + return; + + if (dump_flags & TDF_STATS) + print ("DDG info usage in RTL aliasing: %d no tree, %d no drf, %d no ddr, " + "%d useless ddr, %d graceful fails, %d useless successes, " + "%d new successes, %d no dep, %d nonzero dist\n", + ddg_info->alias_fail_no_tree, ddg_info->alias_fail_no_drf, + ddg_info->alias_fail_no_ddr, ddg_info->alias_fail_useless_ddr, + ddg_info->alias_fail_graceful, ddg_info->alias_success_useless, + ddg_info->alias_success_new, ddg_info->alias_success_no_dep, + ddg_info->alias_success_nonzero_dist); + + ddg_info->alias_fail_no_tree = 0; + ddg_info->alias_fail_no_drf = 0; + ddg_info->alias_fail_no_ddr = 0; + ddg_info->alias_fail_useless_ddr = 0; + ddg_info->alias_fail_graceful = 0; + ddg_info->alias_success_useless = 0; + ddg_info->alias_success_new = 0; + ddg_info->alias_success_no_dep = 0; + ddg_info->alias_success_nonzero_dist = 0; + + if (ddg_info->skip_verification) + return; + + dom_info_was_avail_p = dom_info_available_p (CDI_DOMINATORS); + + if (!inside_tree_loop_opt_p) + loop_optimizer_init(AVOID_CFG_MODIFICATIONS); + + + FOR_EACH_LOOP (li, loop, 0) + { + unsigned int i; + basic_block *bbs = get_loop_body (loop); + + ddg_info->refs_bad = ddg_info->refs_ok = 0; + ddg_info->ddrs_known = ddg_info->ddrs_no = ddg_info->ddrs_unknown = 0; + ddg_info->ddrs_not_found = 0; + + for (i = 0; i < loop->num_nodes; i++) + if (current_ir_type () == IR_GIMPLE) + { + block_stmt_iterator bsi; + for (bsi = bsi_start (bbs[i]); !bsi_end_p (bsi); bsi_next (&bsi)) + walk_tree_without_duplicates (bsi_stmt_ptr (bsi), + verify_trees_gimple, NULL); + } + else + { + rtx insn; + + FOR_BB_INSNS (bbs[i], insn) + if (INSN_P (insn) && !CALL_P (insn)) + for_each_rtx (&PATTERN (insn), verify_trees_rtl, NULL); + } + + VEC_free (data_reference_p, heap, ddg_info->verifier_seen_datarefs); + if (dump_flags & TDF_STATS) + print (" loop %d: %d refs, %d ok, %d bad; %d not found ddrs, " + "%d known deps, %d no deps, %d unknown deps\n", + cur_loop, ddg_info->refs_bad+ddg_info->refs_ok, + ddg_info->refs_ok, ddg_info->refs_bad, + ddg_info->ddrs_not_found, ddg_info->ddrs_known, + ddg_info->ddrs_no, ddg_info->ddrs_unknown); + cur_loop++; + } + + if (!inside_tree_loop_opt_p) + loop_optimizer_finalize (); + + if (!dom_info_was_avail_p) + free_dominance_info (CDI_DOMINATORS); +} + +static unsigned int +disable_ddg_verification (void) +{ + if (ddg_info) + ddg_info->skip_verification = true; + + return 0; +} + +struct tree_opt_pass pass_disable_ddg_verification = +{ + NULL, /* name */ + NULL, /* gate */ + disable_ddg_verification, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +void +ddg_export_disambiguate_only_intra_loop_deps (bool b) +{ + if (ddg_info) + ddg_info->disambiguate_only_intra_loop_deps = b; +} + +/* Return TRUE if any of DIST_VECTS is non-zero. */ +static bool +nonzero_dist_vects (VEC (lambda_vector, heap) *dist_vects, int loops_count) +{ + lambda_vector dist_v; + int i, j; + + for (i = 0; VEC_iterate (lambda_vector, dist_vects, i, dist_v); i++) + for (j = 0; j < loops_count; j++) + if (dist_v[j]) + return true; + + return false; +} + +/* Return TRUE if we cannot prove from exported DDG info that MEM1 and MEM2 + are independent memory references. CALL is used to differentiate callers: + CALL=0 for early calls from RTL alias analysis, CALL=1 for late calls from + RTL alias analysis, CALL=2 for calls from modulo-scheduling DDG + construction. */ +bool +may_alias_mems_by_ddr (const_rtx mem1, const_rtx mem2, int call) +{ + const_tree t1 = MEM_ORIG_EXPR (mem1), t2 = MEM_ORIG_EXPR (mem2); + data_reference_p drf1, drf2; + ddr_p ddr; + + if (!ddg_info) + return true; + + if (!t1 || !t2) + { + if (call == 1) + ddg_info->alias_fail_graceful++; + else + ddg_info->alias_fail_no_tree++; + return true; + } + + drf1 = find_dataref (t1); + drf2 = find_dataref (t2); + + if (!drf1 || !drf2) + { + if (call == 1) + ddg_info->alias_fail_graceful++; + else + ddg_info->alias_fail_no_drf++; + return true; + } + + ddr = find_ddr (drf1, drf2); + + if (!ddr) + { + if (call == 1) + ddg_info->alias_fail_graceful++; + else + ddg_info->alias_fail_no_ddr++; + return true; + } + + if (DDR_ARE_DEPENDENT (ddr) == chrec_known) + { + if (call != 1) + ddg_info->alias_success_no_dep++; + +account_new: + + if (call == 0) + ddg_info->alias_success_useless++; + else if (call == 1) + { + ddg_info->alias_success_useless--; + ddg_info->alias_success_new++; + } + else + { + gcc_assert (call == 2); + ddg_info->alias_success_new++; + } + return false; + } + + if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE && DDR_NUM_DIST_VECTS (ddr) > 0 + && !ddg_info->disambiguate_only_intra_loop_deps + && nonzero_dist_vects (DDR_DIST_VECTS (ddr), DDR_NB_LOOPS (ddr))) + { + if (call != 1) + ddg_info->alias_success_nonzero_dist++; + + goto account_new; + } + + if (call == 1) + ddg_info->alias_fail_graceful++; + else + ddg_info->alias_fail_useless_ddr++; + return true; +} + --- gcc/Makefile.in (/gcc-local/trunk) (revision 30596) +++ gcc/Makefile.in (/gcc-local/export-ddg) (revision 30596) @@ -812,6 +812,7 @@ C_PRETTY_PRINT_H = c-pretty-print.h $(PR SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H) LAMBDA_H = lambda.h $(TREE_H) vec.h $(GGC_H) TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h graphds.h +TREE_DATA_REF_EXPORT_H = tree-data-ref-export.h $(TREE_DATA_REF_H) VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H) TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h REAL_H = real.h $(MACHMODE_H) @@ -1120,6 +1121,7 @@ OBJS-common = \ tree-chrec.o \ tree-complex.o \ tree-data-ref.o \ + tree-data-ref-export.o \ tree-dfa.o \ tree-dump.o \ tree-eh.o \ @@ -2222,6 +2224,10 @@ tree-data-ref.o: tree-data-ref.c $(CONFI $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \ $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ $(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h langhooks.h +tree-data-ref-export.o: tree-data-ref-export.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \ + $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ + $(TREE_DATA_REF_EXPORT_H) $(SCEV_H) tree-pass.h tree-chrec.h langhooks.h tree-vect-analyze.o: tree-vect-analyze.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(BASIC_BLOCK_H) \ $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \