This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix handling of const/pure noreturn functions (PR tree-optimization/44485)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 26 Aug 2010 17:00:50 +0200
- Subject: [PATCH] Fix handling of const/pure noreturn functions (PR tree-optimization/44485)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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?
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