From f20ca7258739d74b12cf381293b10f72125732c5 Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguenther@suse.de>
Date: Tue, 12 Apr 2011 10:44:15 +0000
Subject: [PATCH] re PR tree-optimization/46076 (constant propagation and
 compile-time math no longer happening versus 4.4 and 4.5)

2011-04-12  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/46076
	* gimple.h (struct gimple_statement_call): Add fntype field.
	(gimple_call_fntype): Adjust.
	(gimple_call_set_fntype): New function.
	* gimple.c (gimple_build_call_1): Set the call function type.
	* gimplify.c (gimplify_call_expr): Preserve the function
	type the frontend used for the call.
	(gimplify_modify_expr): Likewise.
	* lto-streamer-in.c (input_gimple_stmt): Input the call stmts
	function type.
	* lto-streamer-out.c (output_gimple_stmt): Output the call stmts
	function type.
	* tree-ssa.c (useless_type_conversion_p): Function pointer
	conversions are useless.

	* gcc.dg/tree-ssa/pr46076.c: Un-XFAIL.

From-SVN: r172310
---
 gcc/ChangeLog                           | 17 ++++++++++++++
 gcc/gimple.c                            |  1 +
 gcc/gimple.h                            | 30 ++++++++++++++++++-------
 gcc/gimplify.c                          | 16 +++++++++++--
 gcc/lto-streamer-in.c                   |  2 ++
 gcc/lto-streamer-out.c                  |  2 ++
 gcc/testsuite/ChangeLog                 |  5 +++++
 gcc/testsuite/gcc.dg/tree-ssa/pr46076.c |  2 +-
 gcc/tree-ssa.c                          | 17 ++++----------
 9 files changed, 68 insertions(+), 24 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c438014b8904..00108150bf40 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2011-04-12  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/46076
+	* gimple.h (struct gimple_statement_call): Add fntype field.
+	(gimple_call_fntype): Adjust.
+	(gimple_call_set_fntype): New function.
+	* gimple.c (gimple_build_call_1): Set the call function type.
+	* gimplify.c (gimplify_call_expr): Preserve the function
+	type the frontend used for the call.
+	(gimplify_modify_expr): Likewise.
+	* lto-streamer-in.c (input_gimple_stmt): Input the call stmts
+	function type.
+	* lto-streamer-out.c (output_gimple_stmt): Output the call stmts
+	function type.
+	* tree-ssa.c (useless_type_conversion_p): Function pointer
+	conversions are useless.
+
 2011-04-12  Martin Jambor  <mjambor@suse.cz>
 
 	* cgraph.h (cgraph_node): Remove function declaration.
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 1cc16d4bc518..090fc94dd2f6 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -231,6 +231,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
   if (TREE_CODE (fn) == FUNCTION_DECL)
     fn = build_fold_addr_expr (fn);
   gimple_set_op (s, 1, fn);
+  gimple_call_set_fntype (s, TREE_TYPE (TREE_TYPE (fn)));
   gimple_call_reset_alias_info (s);
   return s;
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index be45e4b921de..572cabcc57fb 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -405,7 +405,10 @@ struct GTY(()) gimple_statement_call
   struct pt_solution call_used;
   struct pt_solution call_clobbered;
 
-  /* [ WORD 13 ]
+  /* [ WORD 13 ]  */
+  tree fntype;
+
+  /* [ WORD 14 ]
      Operand vector.  NOTE!  This must always be the last field
      of this structure.  In particular, this means that this
      structure cannot be embedded inside another one.  */
@@ -2001,22 +2004,33 @@ gimple_call_set_lhs (gimple gs, tree lhs)
 }
 
 
-/* Return the tree node representing the function called by call
-   statement GS.  */
+/* Return the function type of the function called by GS.  */
 
 static inline tree
-gimple_call_fn (const_gimple gs)
+gimple_call_fntype (const_gimple gs)
 {
   GIMPLE_CHECK (gs, GIMPLE_CALL);
-  return gimple_op (gs, 1);
+  return gs->gimple_call.fntype;
 }
 
-/* Return the function type of the function called by GS.  */
+/* Set the type of the function called by GS to FNTYPE.  */
+
+static inline void
+gimple_call_set_fntype (gimple gs, tree fntype)
+{
+  GIMPLE_CHECK (gs, GIMPLE_CALL);
+  gs->gimple_call.fntype = fntype;
+}
+
+
+/* Return the tree node representing the function called by call
+   statement GS.  */
 
 static inline tree
-gimple_call_fntype (const_gimple gs)
+gimple_call_fn (const_gimple gs)
 {
-  return TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+  GIMPLE_CHECK (gs, GIMPLE_CALL);
+  return gimple_op (gs, 1);
 }
 
 /* Return a pointer to the tree node representing the function called by call
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 9afd4ff27fe2..47bcb821f715 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -2290,7 +2290,7 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location)
 static enum gimplify_status
 gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 {
-  tree fndecl, parms, p;
+  tree fndecl, parms, p, fnptrtype;
   enum gimplify_status ret;
   int i, nargs;
   gimple call;
@@ -2349,6 +2349,9 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 	}
     }
 
+  /* Remember the original function pointer type.  */
+  fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
+
   /* There is a sequence point before the call, so any side effects in
      the calling expression must occur before the actual call.  Force
      gimplify_expr to use an internal post queue.  */
@@ -2436,7 +2439,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 
   /* Verify the function result.  */
   if (want_value && fndecl
-      && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
+      && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fnptrtype))))
     {
       error_at (loc, "using result of function returning %<void%>");
       ret = GS_ERROR;
@@ -2488,11 +2491,16 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 	 have to do is replicate it as a GIMPLE_CALL tuple.  */
       gimple_stmt_iterator gsi;
       call = gimple_build_call_from_tree (*expr_p);
+      gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
       gimplify_seq_add_stmt (pre_p, call);
       gsi = gsi_last (*pre_p);
       fold_stmt (&gsi);
       *expr_p = NULL_TREE;
     }
+  else
+    /* Remember the original function type.  */
+    CALL_EXPR_FN (*expr_p) = build1 (NOP_EXPR, fnptrtype,
+				     CALL_EXPR_FN (*expr_p));
 
   return ret;
 }
@@ -4607,7 +4615,11 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
     {
       /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
 	 instead of a GIMPLE_ASSIGN.  */
+      tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
+      CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
+      STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
       assign = gimple_build_call_from_tree (*from_p);
+      gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
       if (!gimple_call_noreturn_p (assign))
 	gimple_call_set_lhs (assign, *to_p);
     }
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index ddc0cae5328c..b250023143e9 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1062,6 +1062,8 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
 	      op = TREE_OPERAND (op, 0);
 	    }
 	}
+      if (is_gimple_call (stmt))
+	gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
       break;
 
     case GIMPLE_NOP:
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 787f4f2494d3..a29cdd5fccf0 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1759,6 +1759,8 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
 	    }
 	  lto_output_tree_ref (ob, op);
 	}
+      if (is_gimple_call (stmt))
+	lto_output_tree_ref (ob, gimple_call_fntype (stmt));
       break;
 
     case GIMPLE_NOP:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 91c792fef95c..105a162f5417 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-04-12  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/46076
+	* gcc.dg/tree-ssa/pr46076.c: Un-XFAIL.
+
 2011-04-12  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
 	PR testsuite/21164
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c b/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c
index e9dc434ece02..a2777a604b9b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c
@@ -1,7 +1,7 @@
 /* { dg-do link } */
 /* { dg-options "-O2" } */
 
-extern void link_error (void) { /* XFAIL */ }
+extern void link_error (void);
 
 typedef unsigned char(*Calculable)(void);
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 5a41818c575c..4cd86c6781f6 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1239,17 +1239,8 @@ useless_type_conversion_p (tree outer_type, tree inner_type)
 	  && TYPE_RESTRICT (outer_type))
 	return false;
 
-      /* If the outer type is (void *) or a pointer to an incomplete
-	 record type or a pointer to an unprototyped function,
-	 then the conversion is not necessary.  */
-      if (VOID_TYPE_P (TREE_TYPE (outer_type))
-	  || ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
-	       || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
-	      && (TREE_CODE (TREE_TYPE (outer_type))
-		  == TREE_CODE (TREE_TYPE (inner_type)))
-	      && !prototype_p (TREE_TYPE (outer_type))
-	      && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (outer_type)),
-					    TREE_TYPE (TREE_TYPE (inner_type)))))
+      /* If the outer type is (void *), the conversion is not necessary.  */
+      if (VOID_TYPE_P (TREE_TYPE (outer_type)))
 	return true;
     }
 
@@ -1305,8 +1296,8 @@ useless_type_conversion_p (tree outer_type, tree inner_type)
       /* Do not lose casts to function pointer types.  */
       if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
 	   || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
-	  && !useless_type_conversion_p (TREE_TYPE (outer_type),
-					 TREE_TYPE (inner_type)))
+	  && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
+	       || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
 	return false;
 
       /* We do not care for const qualification of the pointed-to types
-- 
GitLab