From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2451 invoked by alias); 8 Apr 2011 15:49:28 -0000 Received: (qmail 2440 invoked by uid 22791); 8 Apr 2011 15:49:24 -0000 X-SWARE-Spam-Status: No, hits=-3.3 required=5.0 tests=AWL,BAYES_00,TW_FN,TW_TM,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from cantor2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 08 Apr 2011 15:49:17 +0000 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.221.2]) by mx2.suse.de (Postfix) with ESMTP id 7D27B5FC9F; Fri, 8 Apr 2011 17:49:15 +0200 (CEST) Date: Fri, 08 Apr 2011 15:49:00 -0000 From: Richard Guenther To: gcc-patches@gcc.gnu.org Cc: Diego Novillo Subject: [PATCH][RFC] Make called function type explicit, make function pointer type conversions useless Message-ID: User-Agent: Alpine 2.00 (LNX 1167 2008-08-23) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-04/txt/msg00646.txt.bz2 This is the "real" fix for PR46076 that I wanted to persue. Make function pointer type conversions useless as to more aggressively be able to turn indirect into direct calls. This requires that we preserve the original type signature of the called function as presented by the frontend. The patch does that by adding a fntype field to every call stmt in GIMPLE and extract this information during gimplification. Bootstrapped on x86_64-unknown-linux-gnu, re-bootstrapping and testing after a minor fix currently. I'll leave this for comments over the weekend, and if there are none will go ahead and check this in early next week. Thanks, Richard. 2011-04-08 Richard Guenther 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. Index: trunk/gcc/gimple.c =================================================================== *** trunk.orig/gcc/gimple.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/gimple.c 2011-04-08 17:31:33.000000000 +0200 *************** gimple_build_call_1 (tree fn, unsigned n *** 231,236 **** --- 231,237 ---- 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; } Index: trunk/gcc/gimple.h =================================================================== *** trunk.orig/gcc/gimple.h 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/gimple.h 2011-04-08 17:31:33.000000000 +0200 *************** struct GTY(()) gimple_statement_call *** 405,411 **** struct pt_solution call_used; struct pt_solution call_clobbered; ! /* [ WORD 13 ] 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. */ --- 405,414 ---- struct pt_solution call_used; struct pt_solution call_clobbered; ! /* [ 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. */ *************** gimple_call_set_lhs (gimple gs, tree lhs *** 2001,2022 **** } ! /* Return the tree node representing the function called by call ! statement GS. */ static inline tree ! gimple_call_fn (const_gimple gs) { GIMPLE_CHECK (gs, GIMPLE_CALL); ! return gimple_op (gs, 1); } ! /* Return the function type of the function called by GS. */ static inline tree ! gimple_call_fntype (const_gimple gs) { ! return TREE_TYPE (TREE_TYPE (gimple_call_fn (gs))); } /* Return a pointer to the tree node representing the function called by call --- 2004,2036 ---- } ! /* Return the function type of the function called by GS. */ static inline tree ! gimple_call_fntype (const_gimple gs) { GIMPLE_CHECK (gs, GIMPLE_CALL); ! return gs->gimple_call.fntype; } ! /* 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_fn (const_gimple gs) { ! GIMPLE_CHECK (gs, GIMPLE_CALL); ! return gimple_op (gs, 1); } /* Return a pointer to the tree node representing the function called by call Index: trunk/gcc/gimplify.c =================================================================== *** trunk.orig/gcc/gimplify.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/gimplify.c 2011-04-08 17:43:05.000000000 +0200 *************** gimplify_arg (tree *arg_p, gimple_seq *p *** 2290,2296 **** static enum gimplify_status gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) { ! tree fndecl, parms, p; enum gimplify_status ret; int i, nargs; gimple call; --- 2290,2296 ---- static enum gimplify_status gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) { ! tree fndecl, parms, p, fnptrtype; enum gimplify_status ret; int i, nargs; gimple call; *************** gimplify_call_expr (tree *expr_p, gimple *** 2349,2354 **** --- 2349,2357 ---- } } + /* 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. */ *************** gimplify_call_expr (tree *expr_p, gimple *** 2436,2442 **** /* Verify the function result. */ if (want_value && fndecl ! && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))) { error_at (loc, "using result of function returning %"); ret = GS_ERROR; --- 2439,2445 ---- /* Verify the function result. */ if (want_value && fndecl ! && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fnptrtype)))) { error_at (loc, "using result of function returning %"); ret = GS_ERROR; *************** gimplify_call_expr (tree *expr_p, gimple *** 2488,2498 **** --- 2491,2506 ---- 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; } *************** gimplify_modify_expr (tree *expr_p, gimp *** 4606,4612 **** --- 4614,4624 ---- { /* 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); } Index: trunk/gcc/lto-streamer-in.c =================================================================== *** trunk.orig/gcc/lto-streamer-in.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/lto-streamer-in.c 2011-04-08 17:31:33.000000000 +0200 *************** input_gimple_stmt (struct lto_input_bloc *** 1062,1067 **** --- 1062,1069 ---- 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: Index: trunk/gcc/lto-streamer-out.c =================================================================== *** trunk.orig/gcc/lto-streamer-out.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/lto-streamer-out.c 2011-04-08 17:31:33.000000000 +0200 *************** output_gimple_stmt (struct output_block *** 1809,1814 **** --- 1809,1816 ---- } lto_output_tree_ref (ob, op); } + if (is_gimple_call (stmt)) + lto_output_tree_ref (ob, gimple_call_fntype (stmt)); break; case GIMPLE_NOP: Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/pr46076.c 2011-04-08 17:31:33.000000000 +0200 *************** *** 1,7 **** /* { dg-do link } */ /* { dg-options "-O2" } */ ! extern void link_error (void) { /* XFAIL */ } typedef unsigned char(*Calculable)(void); --- 1,7 ---- /* { dg-do link } */ /* { dg-options "-O2" } */ ! extern void link_error (void); typedef unsigned char(*Calculable)(void); Index: trunk/gcc/tree-ssa.c =================================================================== *** trunk.orig/gcc/tree-ssa.c 2011-04-08 16:38:12.000000000 +0200 --- trunk/gcc/tree-ssa.c 2011-04-08 17:31:33.000000000 +0200 *************** useless_type_conversion_p (tree outer_ty *** 1239,1255 **** && 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))))) return true; } --- 1239,1246 ---- && TYPE_RESTRICT (outer_type)) return false; ! /* If the outer type is (void *), the conversion is not necessary. */ ! if (VOID_TYPE_P (TREE_TYPE (outer_type))) return true; } *************** useless_type_conversion_p (tree outer_ty *** 1305,1312 **** /* 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))) return false; /* We do not care for const qualification of the pointed-to types --- 1296,1303 ---- /* 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) ! && !(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