Message ID | 20100826150050.GC702@tyan-ft48-01.lab.bos.redhat.com |
---|---|
State | New |
Headers | show |
On Thu, Aug 26, 2010 at 5:00 PM, Jakub Jelinek <jakub@redhat.com> wrote: > Hi! > > On this testcase, local_pure_const discovery first determines bar > is TREE_READONLY/DECL_LOOPING_CONST_OR_PURE_P and only later on > finds out it is also noreturn (TREE_THIS_VOLATILE). > flags_from_decl_or_type in that case would not return ECF_CONST, which means > a call which didn't have vops suddenly needs them and the calling pass of > fixup_noreturn_call doesn't expect .MEM needs to be renamed. > Fixed by treating noreturn const or pure as noreturn const/pure looping > functions. I wanted to make sure DECL_LOOPING_CONST_OR_PURE_P is > going to be set for noreturn const or pure functions declared with > attribute, but that would be quite difficult (would need to handle that > in all the pure/const/noreturn attribute handling, and in C and C++ decl > merging, etc.). There are only very few places which check > DECL_LOOPING_CONST_OR_PURE_P directly, it is easier just to use > flags_from_decl_or_type there as most of the other places already do. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Ok. Thanks, Richard. > 2010-08-26 Jakub Jelinek <jakub@redhat.com> > > PR tree-optimization/44485 > * calls.c (flags_from_decl_or_type): For const or pure > noreturn functions return ECF_LOOPING_CONST_OR_PURE|ECF_NORETURN > together with ECF_CONST resp. ECF_PURE. > * builtins.c (expand_builtin): Use flags_from_decl_or_type > instead of querying flags directly. > * tree-ssa-loop-niter.c (finite_loop_p): Likewise. > * tree-ssa-dce.c (find_obviously_necessary_stmts): Likewise. > > * gcc.dg/pr44485.c: New test. > > --- gcc/calls.c.jj 2010-08-16 19:24:16.000000000 +0200 > +++ gcc/calls.c 2010-08-26 12:21:17.000000000 +0200 > @@ -601,7 +601,7 @@ flags_from_decl_or_type (const_tree exp) > flags |= ECF_RETURNS_TWICE; > > /* Process the pure and const attributes. */ > - if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) > + if (TREE_READONLY (exp)) > flags |= ECF_CONST; > if (DECL_PURE_P (exp)) > flags |= ECF_PURE; > @@ -616,11 +616,15 @@ flags_from_decl_or_type (const_tree exp) > > flags = special_function_p (exp, flags); > } > - else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) > + else if (TYPE_P (exp) && TYPE_READONLY (exp)) > flags |= ECF_CONST; > > if (TREE_THIS_VOLATILE (exp)) > - flags |= ECF_NORETURN; > + { > + flags |= ECF_NORETURN; > + if (flags & (ECF_CONST|ECF_PURE)) > + flags |= ECF_LOOPING_CONST_OR_PURE; > + } > > return flags; > } > --- gcc/builtins.c.jj 2010-08-20 16:51:09.000000000 +0200 > +++ gcc/builtins.c 2010-08-26 13:59:07.000000000 +0200 > @@ -5748,6 +5748,7 @@ expand_builtin (tree exp, rtx target, rt > tree fndecl = get_callee_fndecl (exp); > enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); > enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp)); > + int flags; > > if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) > return targetm.expand_builtin (exp, target, subtarget, mode, ignore); > @@ -5770,8 +5771,8 @@ expand_builtin (tree exp, rtx target, rt > none of its arguments are volatile, we can avoid expanding the > built-in call and just evaluate the arguments for side-effects. */ > if (target == const0_rtx > - && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)) > - && !DECL_LOOPING_CONST_OR_PURE_P (fndecl)) > + && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE)) > + && !(flags & ECF_LOOPING_CONST_OR_PURE)) > { > bool volatilep = false; > tree arg; > --- gcc/tree-ssa-loop-niter.c.jj 2010-08-20 16:05:40.000000000 +0200 > +++ gcc/tree-ssa-loop-niter.c 2010-08-26 13:59:04.000000000 +0200 > @@ -1970,12 +1970,12 @@ finite_loop_p (struct loop *loop) > edge ex; > struct tree_niter_desc desc; > bool finite = false; > + int flags; > > if (flag_unsafe_loop_optimizations) > return true; > - if ((TREE_READONLY (current_function_decl) > - || DECL_PURE_P (current_function_decl)) > - && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)) > + flags = flags_from_decl_or_type (current_function_decl); > + if ((flags & (ECF_CONST|ECF_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) > { > if (dump_file && (dump_flags & TDF_DETAILS)) > fprintf (dump_file, "Found loop %i to be finite: it is within pure or const function.\n", > --- gcc/tree-ssa-dce.c.jj 2010-07-05 12:37:02.000000000 +0200 > +++ gcc/tree-ssa-dce.c 2010-08-26 13:59:01.000000000 +0200 > @@ -433,6 +433,7 @@ find_obviously_necessary_stmts (struct e > gimple_stmt_iterator gsi; > edge e; > gimple phi, stmt; > + int flags; > > FOR_EACH_BB (bb) > { > @@ -454,9 +455,8 @@ find_obviously_necessary_stmts (struct e > > /* Pure and const functions are finite and thus have no infinite loops in > them. */ > - if ((TREE_READONLY (current_function_decl) > - || DECL_PURE_P (current_function_decl)) > - && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)) > + flags = flags_from_decl_or_type (current_function_decl); > + if ((flags & (ECF_CONST|ECF_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) > return; > > /* Prevent the empty possibly infinite loops from being removed. */ > --- gcc/testsuite/gcc.dg/pr44485.c.jj 2010-08-26 13:59:52.000000000 +0200 > +++ gcc/testsuite/gcc.dg/pr44485.c 2010-08-26 13:57:32.000000000 +0200 > @@ -0,0 +1,31 @@ > +/* PR tree-optimization/44485 */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -funsafe-math-optimizations" } */ > + > +unsigned short b; > +int bar (unsigned); > + > +void > +baz (void) > +{ > + if (bar (0)) > + for (b = 0; b < 30; b++) > + ; > +} > + > +int > +bar (unsigned z) > +{ > + unsigned short c; > + for (; ; z += 1) > +l1: > + if (z) > + goto l2; > +l2: > + for (z = 0; z < 9; z++) > + if (z) > + goto l1; > + for (c = 0; c; c = (__UINTPTR_TYPE__) baz) > + ; > + return 0; > +} > > Jakub >
--- gcc/calls.c.jj 2010-08-16 19:24:16.000000000 +0200 +++ gcc/calls.c 2010-08-26 12:21:17.000000000 +0200 @@ -601,7 +601,7 @@ flags_from_decl_or_type (const_tree exp) flags |= ECF_RETURNS_TWICE; /* Process the pure and const attributes. */ - if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) + if (TREE_READONLY (exp)) flags |= ECF_CONST; if (DECL_PURE_P (exp)) flags |= ECF_PURE; @@ -616,11 +616,15 @@ flags_from_decl_or_type (const_tree exp) flags = special_function_p (exp, flags); } - else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) + else if (TYPE_P (exp) && TYPE_READONLY (exp)) flags |= ECF_CONST; if (TREE_THIS_VOLATILE (exp)) - flags |= ECF_NORETURN; + { + flags |= ECF_NORETURN; + if (flags & (ECF_CONST|ECF_PURE)) + flags |= ECF_LOOPING_CONST_OR_PURE; + } return flags; } --- gcc/builtins.c.jj 2010-08-20 16:51:09.000000000 +0200 +++ gcc/builtins.c 2010-08-26 13:59:07.000000000 +0200 @@ -5748,6 +5748,7 @@ expand_builtin (tree exp, rtx target, rt tree fndecl = get_callee_fndecl (exp); enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp)); + int flags; if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) return targetm.expand_builtin (exp, target, subtarget, mode, ignore); @@ -5770,8 +5771,8 @@ expand_builtin (tree exp, rtx target, rt none of its arguments are volatile, we can avoid expanding the built-in call and just evaluate the arguments for side-effects. */ if (target == const0_rtx - && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)) - && !DECL_LOOPING_CONST_OR_PURE_P (fndecl)) + && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE)) + && !(flags & ECF_LOOPING_CONST_OR_PURE)) { bool volatilep = false; tree arg; --- gcc/tree-ssa-loop-niter.c.jj 2010-08-20 16:05:40.000000000 +0200 +++ gcc/tree-ssa-loop-niter.c 2010-08-26 13:59:04.000000000 +0200 @@ -1970,12 +1970,12 @@ finite_loop_p (struct loop *loop) edge ex; struct tree_niter_desc desc; bool finite = false; + int flags; if (flag_unsafe_loop_optimizations) return true; - if ((TREE_READONLY (current_function_decl) - || DECL_PURE_P (current_function_decl)) - && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)) + flags = flags_from_decl_or_type (current_function_decl); + if ((flags & (ECF_CONST|ECF_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Found loop %i to be finite: it is within pure or const function.\n", --- gcc/tree-ssa-dce.c.jj 2010-07-05 12:37:02.000000000 +0200 +++ gcc/tree-ssa-dce.c 2010-08-26 13:59:01.000000000 +0200 @@ -433,6 +433,7 @@ find_obviously_necessary_stmts (struct e gimple_stmt_iterator gsi; edge e; gimple phi, stmt; + int flags; FOR_EACH_BB (bb) { @@ -454,9 +455,8 @@ find_obviously_necessary_stmts (struct e /* Pure and const functions are finite and thus have no infinite loops in them. */ - if ((TREE_READONLY (current_function_decl) - || DECL_PURE_P (current_function_decl)) - && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)) + flags = flags_from_decl_or_type (current_function_decl); + if ((flags & (ECF_CONST|ECF_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) return; /* Prevent the empty possibly infinite loops from being removed. */ --- gcc/testsuite/gcc.dg/pr44485.c.jj 2010-08-26 13:59:52.000000000 +0200 +++ gcc/testsuite/gcc.dg/pr44485.c 2010-08-26 13:57:32.000000000 +0200 @@ -0,0 +1,31 @@ +/* PR tree-optimization/44485 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -funsafe-math-optimizations" } */ + +unsigned short b; +int bar (unsigned); + +void +baz (void) +{ + if (bar (0)) + for (b = 0; b < 30; b++) + ; +} + +int +bar (unsigned z) +{ + unsigned short c; + for (; ; z += 1) +l1: + if (z) + goto l2; +l2: + for (z = 0; z < 9; z++) + if (z) + goto l1; + for (c = 0; c; c = (__UINTPTR_TYPE__) baz) + ; + return 0; +}