Message ID | 20150319082944.GC64546@msticlxl57.ims.intel.com |
---|---|
State | New |
Headers | show |
On Thu, Mar 19, 2015 at 11:29:44AM +0300, Ilya Enkovich wrote: > + /* We might propagate instrumented function pointer into > + not instrumented function and vice versa. In such a > + case we need to either fix function declaration or > + remove bounds from call statement. */ > + if (callee) > + skip_bounds = chkp_redirect_edge (e); I just want to say that I'm not really excited about all this compile time cost that is added everywhere unconditionally for chkp. I think much better would be to guard most of it with proper option check first and only do the more expensive part if the option has been used. In particular, the above call isn't inlined, > +bool > +chkp_redirect_edge (cgraph_edge *e) > +{ > + bool instrumented = false; > + tree decl = e->callee->decl; > + > + if (e->callee->instrumentation_clone > + || chkp_function_instrumented_p (decl)) > + instrumented = true; Calls here for non-instrumented code another function that calls lookup_attribute (cheap if DECL_ATTRIBUTES is NULL, not really cheap otherwise). > + if (instrumented > + && !gimple_call_with_bounds_p (e->call_stmt)) > + e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl)); > + else if (!instrumented > + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL) > + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU) > + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX) > + && gimple_call_with_bounds_p (e->call_stmt)) Plus the ordering of the conditions above is bad, you first check for 3 out of a few thousands builtin and only then call the predicate, which should be probably done right after the !instrumented case. So, for the very likely case of -fcheck-pointer-bounds not being used at all, you've added at least 7-8 non-inlinable calls here. There are dozens of similar calls inserted just about everywhere. Jakub
2015-03-24 11:33 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: > On Thu, Mar 19, 2015 at 11:29:44AM +0300, Ilya Enkovich wrote: >> + /* We might propagate instrumented function pointer into >> + not instrumented function and vice versa. In such a >> + case we need to either fix function declaration or >> + remove bounds from call statement. */ >> + if (callee) >> + skip_bounds = chkp_redirect_edge (e); > > I just want to say that I'm not really excited about all this compile time > cost that is added everywhere unconditionally for chkp. > I think much better would be to guard most of it with proper option check > first and only do the more expensive part if the option has been used. Agree, overhead for not instrumented code should be minimized. Unfortunately there is no option check I can use to guard chkp codes due to LTO. Currently it is allowed to pass -fcheck-pointer-bounds for IL generation and don't pass it for final code generation. I suppose I may set this (or some new) flag if see instrumented node when read cgraph and then use it to guard chkp related codes. Would it be acceptable? > > In particular, the above call isn't inlined, > >> +bool >> +chkp_redirect_edge (cgraph_edge *e) >> +{ >> + bool instrumented = false; >> + tree decl = e->callee->decl; >> + >> + if (e->callee->instrumentation_clone >> + || chkp_function_instrumented_p (decl)) >> + instrumented = true; > > Calls here for non-instrumented code another function that calls > lookup_attribute (cheap if DECL_ATTRIBUTES is NULL, not really cheap > otherwise). Maybe replace attribute usage with a new flag in tree_decl_with_vis structure? > >> + if (instrumented >> + && !gimple_call_with_bounds_p (e->call_stmt)) >> + e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl)); >> + else if (!instrumented >> + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL) >> + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU) >> + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX) >> + && gimple_call_with_bounds_p (e->call_stmt)) > > Plus the ordering of the conditions above is bad, you first check > for 3 out of a few thousands builtin and only then call the predicate, > which should be probably done right after the !instrumented case. Will fix it. > > So, for the very likely case of -fcheck-pointer-bounds not being used at > all, you've added at least 7-8 non-inlinable calls here. > > There are dozens of similar calls inserted just about everywhere. The most popular guard call should be chkp_function_instrumented_p. Replacing attribute with a flag should help. Thanks for review! Ilya > > Jakub
On Tue, Mar 24, 2015 at 12:22:27PM +0300, Ilya Enkovich wrote: > 2015-03-24 11:33 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: > > On Thu, Mar 19, 2015 at 11:29:44AM +0300, Ilya Enkovich wrote: > >> + /* We might propagate instrumented function pointer into > >> + not instrumented function and vice versa. In such a > >> + case we need to either fix function declaration or > >> + remove bounds from call statement. */ > >> + if (callee) > >> + skip_bounds = chkp_redirect_edge (e); > > > > I just want to say that I'm not really excited about all this compile time > > cost that is added everywhere unconditionally for chkp. > > I think much better would be to guard most of it with proper option check > > first and only do the more expensive part if the option has been used. > > Agree, overhead for not instrumented code should be minimized. > Unfortunately there is no option check I can use to guard chkp codes > due to LTO. Currently it is allowed to pass -fcheck-pointer-bounds for > IL generation and don't pass it for final code generation. I suppose I > may set this (or some new) flag if see instrumented node when read > cgraph and then use it to guard chkp related codes. Would it be > acceptable? The question is what you want to do in the LTO case for the different cases, in particular a TU compiled with -fcheck-pointer-bounds and LTO link without that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. It could be handled as LTO incompatible option, where lto1 would error out if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds code, or e.g. similar to var-tracking, you could consider adjusting the IL upon LTO reading if if some TU has been built with -fcheck-pointer-bounds and the LTO link is -fno-check-pointer-bounds. Dunno what will happen with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. Or another possibility is to or in -fcheck-pointer-bounds from all TUs. > Maybe replace attribute usage with a new flag in tree_decl_with_vis structure? Depends, might be better to stick it into cgraph_node instead, depends on whether you are querying it already early in the FEs or just during GIMPLE when the cgraph node should be created too. Jakub
On Tue, Mar 24, 2015 at 3:06 PM, Jakub Jelinek <jakub@redhat.com> wrote: > On Tue, Mar 24, 2015 at 12:22:27PM +0300, Ilya Enkovich wrote: >> 2015-03-24 11:33 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: >> > On Thu, Mar 19, 2015 at 11:29:44AM +0300, Ilya Enkovich wrote: >> >> + /* We might propagate instrumented function pointer into >> >> + not instrumented function and vice versa. In such a >> >> + case we need to either fix function declaration or >> >> + remove bounds from call statement. */ >> >> + if (callee) >> >> + skip_bounds = chkp_redirect_edge (e); >> > >> > I just want to say that I'm not really excited about all this compile time >> > cost that is added everywhere unconditionally for chkp. >> > I think much better would be to guard most of it with proper option check >> > first and only do the more expensive part if the option has been used. >> >> Agree, overhead for not instrumented code should be minimized. >> Unfortunately there is no option check I can use to guard chkp codes >> due to LTO. Currently it is allowed to pass -fcheck-pointer-bounds for >> IL generation and don't pass it for final code generation. I suppose I >> may set this (or some new) flag if see instrumented node when read >> cgraph and then use it to guard chkp related codes. Would it be >> acceptable? > > The question is what you want to do in the LTO case for the different cases, > in particular a TU compiled with -fcheck-pointer-bounds and LTO link without > that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. > It could be handled as LTO incompatible option, where lto1 would error out > if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds > code, or e.g. similar to var-tracking, you could consider adjusting the IL > upon LTO reading if if some TU has been built with -fcheck-pointer-bounds > and the LTO link is -fno-check-pointer-bounds. Dunno what will happen > with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. > Or another possibility is to or in -fcheck-pointer-bounds from all TUs. > >> Maybe replace attribute usage with a new flag in tree_decl_with_vis structure? > > Depends, might be better to stick it into cgraph_node instead, depends on > whether you are querying it already early in the FEs or just during GIMPLE > when the cgraph node should be created too. I also wonder why it is necessary to execute pass_chkp_instrumentation_passes when mpx is not active. That is, can we guard that properly in void pass_manager::execute_early_local_passes () { execute_pass_list (cfun, pass_build_ssa_passes_1->sub); execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub); execute_pass_list (cfun, pass_local_optimization_passes_1->sub); } (why's that so oddly wrapped?) class pass_chkp_instrumentation_passes also has no gate that guards with flag_mpx or so. That would save a IL walk over all functions (fixup_cfg) and a cgraph edge rebuild. Richard. > Jakub
2015-03-24 17:06 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: > On Tue, Mar 24, 2015 at 12:22:27PM +0300, Ilya Enkovich wrote: >> 2015-03-24 11:33 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: >> > On Thu, Mar 19, 2015 at 11:29:44AM +0300, Ilya Enkovich wrote: >> >> + /* We might propagate instrumented function pointer into >> >> + not instrumented function and vice versa. In such a >> >> + case we need to either fix function declaration or >> >> + remove bounds from call statement. */ >> >> + if (callee) >> >> + skip_bounds = chkp_redirect_edge (e); >> > >> > I just want to say that I'm not really excited about all this compile time >> > cost that is added everywhere unconditionally for chkp. >> > I think much better would be to guard most of it with proper option check >> > first and only do the more expensive part if the option has been used. >> >> Agree, overhead for not instrumented code should be minimized. >> Unfortunately there is no option check I can use to guard chkp codes >> due to LTO. Currently it is allowed to pass -fcheck-pointer-bounds for >> IL generation and don't pass it for final code generation. I suppose I >> may set this (or some new) flag if see instrumented node when read >> cgraph and then use it to guard chkp related codes. Would it be >> acceptable? > > The question is what you want to do in the LTO case for the different cases, > in particular a TU compiled with -fcheck-pointer-bounds and LTO link without > that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. > It could be handled as LTO incompatible option, where lto1 would error out > if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds > code, or e.g. similar to var-tracking, you could consider adjusting the IL > upon LTO reading if if some TU has been built with -fcheck-pointer-bounds > and the LTO link is -fno-check-pointer-bounds. Dunno what will happen > with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. > Or another possibility is to or in -fcheck-pointer-bounds from all TUs. Mixing instrumented and not instrumented TUs is allowed. All instrumentation passes happen before LTO link. The only code generation problem if instrumented code is linked with no -fcheck-pointer-bounds is disabled chkp_finish_file call which generates static constructors. I think I just should set flag_check_pointer_bounds if see any instrumented symbol on LTO read. It would cause chkp_finish_file call when required and would be available as guard for chkp related codes. > >> Maybe replace attribute usage with a new flag in tree_decl_with_vis structure? > > Depends, might be better to stick it into cgraph_node instead, depends on > whether you are querying it already early in the FEs or just during GIMPLE > when the cgraph node should be created too. Flag in cgraph_node should work. I'll have a look. Thanks, Ilya > > Jakub
On Wed, Mar 25, 2015 at 11:05:17AM +0300, Ilya Enkovich wrote: > > The question is what you want to do in the LTO case for the different cases, > > in particular a TU compiled with -fcheck-pointer-bounds and LTO link without > > that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. > > It could be handled as LTO incompatible option, where lto1 would error out > > if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds > > code, or e.g. similar to var-tracking, you could consider adjusting the IL > > upon LTO reading if if some TU has been built with -fcheck-pointer-bounds > > and the LTO link is -fno-check-pointer-bounds. Dunno what will happen > > with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. > > Or another possibility is to or in -fcheck-pointer-bounds from all TUs. > > Mixing instrumented and not instrumented TUs is allowed. All > instrumentation passes happen before LTO link. The only code > generation problem if instrumented code is linked with no > -fcheck-pointer-bounds is disabled chkp_finish_file call which > generates static constructors. I think I just should set > flag_check_pointer_bounds if see any instrumented symbol on LTO read. > It would cause chkp_finish_file call when required and would be > available as guard for chkp related codes. Thus perhaps oring the flag_check_pointer_bounds option from all the TUs is the desirable behavior for LTO? I think Richard or Honza would know where would be the best spot to do that. Jakub
2015-03-24 17:40 GMT+03:00 Richard Biener <richard.guenther@gmail.com>: > On Tue, Mar 24, 2015 at 3:06 PM, Jakub Jelinek <jakub@redhat.com> wrote: >> On Tue, Mar 24, 2015 at 12:22:27PM +0300, Ilya Enkovich wrote: >> >> The question is what you want to do in the LTO case for the different cases, >> in particular a TU compiled with -fcheck-pointer-bounds and LTO link without >> that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. >> It could be handled as LTO incompatible option, where lto1 would error out >> if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds >> code, or e.g. similar to var-tracking, you could consider adjusting the IL >> upon LTO reading if if some TU has been built with -fcheck-pointer-bounds >> and the LTO link is -fno-check-pointer-bounds. Dunno what will happen >> with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. >> Or another possibility is to or in -fcheck-pointer-bounds from all TUs. >> >>> Maybe replace attribute usage with a new flag in tree_decl_with_vis structure? >> >> Depends, might be better to stick it into cgraph_node instead, depends on >> whether you are querying it already early in the FEs or just during GIMPLE >> when the cgraph node should be created too. > > I also wonder why it is necessary to execute pass_chkp_instrumentation_passes > when mpx is not active. > > That is, can we guard that properly in > > void > pass_manager::execute_early_local_passes () > { > execute_pass_list (cfun, pass_build_ssa_passes_1->sub); > execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub); > execute_pass_list (cfun, pass_local_optimization_passes_1->sub); > } I'm worried about new functions generated in LTO. But with re-created flag_check_pointer_bounds it should be safe to guard it. > > (why's that so oddly wrapped?) > > class pass_chkp_instrumentation_passes > > also has no gate that guards with flag_mpx or so. > > That would save a IL walk over all functions (fixup_cfg) and a cgraph > edge rebuild. Right. Will fix it. Thanks, Ilya > > Richard. > >> Jakub
2015-03-25 11:16 GMT+03:00 Jakub Jelinek <jakub@redhat.com>: > On Wed, Mar 25, 2015 at 11:05:17AM +0300, Ilya Enkovich wrote: >> > The question is what you want to do in the LTO case for the different cases, >> > in particular a TU compiled with -fcheck-pointer-bounds and LTO link without >> > that, or TU compiled without -fcheck-pointer-bounds and LTO link with it. >> > It could be handled as LTO incompatible option, where lto1 would error out >> > if you try to mix -fcheck-pointer-bounds with -fno-check-pointer-bounds >> > code, or e.g. similar to var-tracking, you could consider adjusting the IL >> > upon LTO reading if if some TU has been built with -fcheck-pointer-bounds >> > and the LTO link is -fno-check-pointer-bounds. Dunno what will happen >> > with -fno-check-pointer-bounds TUs LTO linked with -fcheck-pointer-bounds. >> > Or another possibility is to or in -fcheck-pointer-bounds from all TUs. >> >> Mixing instrumented and not instrumented TUs is allowed. All >> instrumentation passes happen before LTO link. The only code >> generation problem if instrumented code is linked with no >> -fcheck-pointer-bounds is disabled chkp_finish_file call which >> generates static constructors. I think I just should set >> flag_check_pointer_bounds if see any instrumented symbol on LTO read. >> It would cause chkp_finish_file call when required and would be >> available as guard for chkp related codes. > > Thus perhaps oring the flag_check_pointer_bounds option from all the TUs is > the desirable behavior for LTO? > I think Richard or Honza would know where would be the best spot to do that. > > Jakub Is such oring used for some other flags to have an example? Thanks, Ilya
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 5ca1901..a0b0465 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1278,14 +1278,25 @@ cgraph_edge::redirect_call_stmt_to_callee (void) { cgraph_edge *e = this; - tree decl = gimple_call_fndecl (e->call_stmt); - tree lhs = gimple_call_lhs (e->call_stmt); + tree decl; + tree lhs; gcall *new_stmt; gimple_stmt_iterator gsi; + bool skip_bounds = false; #ifdef ENABLE_CHECKING cgraph_node *node; #endif + /* We might propagate instrumented function pointer into + not instrumented function and vice versa. In such a + case we need to either fix function declaration or + remove bounds from call statement. */ + if (callee) + skip_bounds = chkp_redirect_edge (e); + + decl = gimple_call_fndecl (e->call_stmt); + lhs = gimple_call_lhs (e->call_stmt); + if (e->speculative) { cgraph_edge *e2; @@ -1391,7 +1402,8 @@ cgraph_edge::redirect_call_stmt_to_callee (void) } if (e->indirect_unknown_callee - || decl == e->callee->decl) + || (decl == e->callee->decl + && !skip_bounds)) return e->call_stmt; #ifdef ENABLE_CHECKING @@ -1416,13 +1428,19 @@ cgraph_edge::redirect_call_stmt_to_callee (void) } } - if (e->callee->clone.combined_args_to_skip) + if (e->callee->clone.combined_args_to_skip + || skip_bounds) { int lp_nr; - new_stmt - = gimple_call_copy_skip_args (e->call_stmt, - e->callee->clone.combined_args_to_skip); + new_stmt = e->call_stmt; + if (e->callee->clone.combined_args_to_skip) + new_stmt + = gimple_call_copy_skip_args (new_stmt, + e->callee->clone.combined_args_to_skip); + if (skip_bounds) + new_stmt = chkp_copy_call_skip_bounds (new_stmt); + gimple_call_set_fndecl (new_stmt, e->callee->decl); gimple_call_set_fntype (new_stmt, gimple_call_fntype (e->call_stmt)); diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c new file mode 100644 index 0000000..cb4d229 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcheck-pointer-bounds -mmpx" } */ + +#include "math.h" + +double +test1 (double x, double y, double (*fn)(double, double)) +{ + return fn (x, y); +} + +double +test2 (double x, double y) +{ + return test1 (x, y, copysign); +} diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c new file mode 100644 index 0000000..951e7de --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcheck-pointer-bounds -mmpx -fno-inline" } */ + +#include "math.h" + +double +test1 (double x, double y, double (*fn)(double, double)) +{ + return fn (x, y); +} + +double +test2 (double x, double y) +{ + return test1 (x, y, copysign); +} diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-3.c b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-3.c new file mode 100755 index 0000000..439f631 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-3.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fexceptions -fcheck-pointer-bounds -mmpx" } */ + +extern int f2 (const char*, int, ...); +extern long int f3 (int *); +extern void err (void) __attribute__((__error__("error"))); + +extern __inline __attribute__ ((__always_inline__)) int +f1 (int i, ...) +{ + if (__builtin_constant_p (i)) + { + if (i) + err (); + return f2 ("", i); + } + + return f2 ("", i); +} + +int +test () +{ + int i; + + if (f1 (0)) + if (f3 (&i)) + i = 0; + + return i; +} + + diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c index d2df4ba..b9508d8 100644 --- a/gcc/tree-chkp.c +++ b/gcc/tree-chkp.c @@ -500,6 +500,71 @@ chkp_expand_bounds_reset_for_mem (tree mem, tree ptr) expand_normal (bndstx); } +/* Build a GIMPLE_CALL identical to CALL but skipping bounds + arguments. */ + +gcall * +chkp_copy_call_skip_bounds (gcall *call) +{ + bitmap bounds; + unsigned i; + + bitmap_obstack_initialize (NULL); + bounds = BITMAP_ALLOC (NULL); + + for (i = 0; i < gimple_call_num_args (call); i++) + if (POINTER_BOUNDS_P (gimple_call_arg (call, i))) + bitmap_set_bit (bounds, i); + + if (bitmap_empty_p (bounds)) + return call; + + call = gimple_call_copy_skip_args (call, bounds); + gimple_call_set_with_bounds (call, false); + + BITMAP_FREE (bounds); + bitmap_obstack_release (NULL); + + return call; +} + +/* Redirect edge E to the correct node according to call_stmt. + Return 1 if bounds removal from call_stmt should be done + instead of redirection. */ + +bool +chkp_redirect_edge (cgraph_edge *e) +{ + bool instrumented = false; + tree decl = e->callee->decl; + + if (e->callee->instrumentation_clone + || chkp_function_instrumented_p (decl)) + instrumented = true; + + if (instrumented + && !gimple_call_with_bounds_p (e->call_stmt)) + e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl)); + else if (!instrumented + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL) + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU) + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX) + && gimple_call_with_bounds_p (e->call_stmt)) + { + if (e->callee->instrumented_version) + e->redirect_callee (e->callee->instrumented_version); + else + { + tree args = TYPE_ARG_TYPES (TREE_TYPE (decl)); + /* Avoid bounds removal if all args will be removed. */ + if (!args || TREE_VALUE (args) != void_type_node) + return true; + } + } + + return false; +} + /* Mark statement S to not be instrumented. */ static void chkp_mark_stmt (gimple s) diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h index 86f3618..40e2489 100644 --- a/gcc/tree-chkp.h +++ b/gcc/tree-chkp.h @@ -54,5 +54,7 @@ extern void chkp_copy_bounds_for_assign (gimple assign, extern bool chkp_gimple_call_builtin_p (gimple call, enum built_in_function code); extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr); +extern gcall *chkp_copy_call_skip_bounds (gcall *call); +extern bool chkp_redirect_edge (cgraph_edge *e); #endif /* GCC_TREE_CHKP_H */