We can fold OBJ_TYPE_REFs to direct calls if the callee is known. Even easier now that we keep fntypes separately.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2011-04-18 Richard Guenther <rguent...@suse.de> * gimple.h (gimple_call_addr_fndecl): New function. (gimple_call_fndecl): Use it. * gimple-fold.c (gimple_fold_call): Fold away OBJ_TYPE_REFs for direct calls. * tree-ssa-ccp.c (ccp_fold_stmt): Remove OBJ_TYPE_REF folding. * tree-ssa-pre.c (eliminate): Also simplify indirect OBJ_TYPE_REFs. Index: gcc/gimple.h =================================================================== *** gcc/gimple.h (revision 172640) --- gcc/gimple.h (working copy) *************** gimple_call_set_fndecl (gimple gs, tree *** 2065,2070 **** --- 2065,2088 ---- gimple_set_op (gs, 1, build_fold_addr_expr_loc (gimple_location (gs), decl)); } + /* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL + associated with the callee if known. Otherwise return NULL_TREE. */ + + static inline tree + gimple_call_addr_fndecl (const_tree fn) + { + if (TREE_CODE (fn) == ADDR_EXPR) + { + tree fndecl = TREE_OPERAND (fn, 0); + if (TREE_CODE (fndecl) == MEM_REF + && TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR + && integer_zerop (TREE_OPERAND (fndecl, 1))) + fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + return fndecl; + } + return NULL_TREE; + } /* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it. Otherwise return NULL. This function is analogous to *************** gimple_call_set_fndecl (gimple gs, tree *** 2073,2093 **** static inline tree gimple_call_fndecl (const_gimple gs) { ! tree addr = gimple_call_fn (gs); ! if (TREE_CODE (addr) == ADDR_EXPR) ! { ! tree fndecl = TREE_OPERAND (addr, 0); ! if (TREE_CODE (fndecl) == MEM_REF) ! { ! if (TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR ! && integer_zerop (TREE_OPERAND (fndecl, 1))) ! return TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0); ! else ! return NULL_TREE; ! } ! return TREE_OPERAND (addr, 0); ! } ! return NULL_TREE; } --- 2091,2097 ---- static inline tree gimple_call_fndecl (const_gimple gs) { ! return gimple_call_addr_fndecl (gimple_call_fn (gs)); } Index: gcc/gimple-fold.c =================================================================== *** gcc/gimple-fold.c (revision 172640) --- gcc/gimple-fold.c (working copy) *************** bool *** 1450,1460 **** gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) { gimple stmt = gsi_stmt (*gsi); ! ! tree callee = gimple_call_fndecl (stmt); /* Check for builtins that CCP can handle using information not available in the generic fold routines. */ if (!inplace && callee && DECL_BUILT_IN (callee)) { tree result = gimple_fold_builtin (stmt); --- 1450,1460 ---- gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) { gimple stmt = gsi_stmt (*gsi); ! tree callee; /* Check for builtins that CCP can handle using information not available in the generic fold routines. */ + callee = gimple_call_fndecl (stmt); if (!inplace && callee && DECL_BUILT_IN (callee)) { tree result = gimple_fold_builtin (stmt); *************** gimple_fold_call (gimple_stmt_iterator * *** 1466,1471 **** --- 1466,1481 ---- return true; } } + + /* Check for virtual calls that became direct calls. */ + callee = gimple_call_fn (stmt); + if (TREE_CODE (callee) == OBJ_TYPE_REF + && gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE) + { + gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee)); + return true; + } + return false; } Index: gcc/tree-ssa-ccp.c =================================================================== *** gcc/tree-ssa-ccp.c (revision 172640) --- gcc/tree-ssa-ccp.c (working copy) *************** ccp_fold_stmt (gimple_stmt_iterator *gsi *** 1702,1708 **** tree lhs = gimple_call_lhs (stmt); tree val; tree argt; - tree callee; bool changed = false; unsigned i; --- 1702,1707 ---- *************** ccp_fold_stmt (gimple_stmt_iterator *gsi *** 1743,1759 **** } } - callee = gimple_call_fn (stmt); - if (TREE_CODE (callee) == OBJ_TYPE_REF - && TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == SSA_NAME) - { - tree expr = OBJ_TYPE_REF_EXPR (callee); - OBJ_TYPE_REF_EXPR (callee) = valueize_op (expr); - if (gimple_fold_call (gsi, false)) - changed = true; - OBJ_TYPE_REF_EXPR (callee) = expr; - } - return changed; } --- 1742,1747 ---- Index: gcc/tree-ssa-pre.c =================================================================== *** gcc/tree-ssa-pre.c (revision 172640) --- gcc/tree-ssa-pre.c (working copy) *************** eliminate (void) *** 4380,4392 **** } /* Visit indirect calls and turn them into direct calls if possible. */ ! if (is_gimple_call (stmt) ! && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME) { tree orig_fn = gimple_call_fn (stmt); ! tree fn = VN_INFO (orig_fn)->valnum; ! if (TREE_CODE (fn) == ADDR_EXPR ! && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL && useless_type_conversion_p (TREE_TYPE (orig_fn), TREE_TYPE (fn))) { --- 4380,4397 ---- } /* Visit indirect calls and turn them into direct calls if possible. */ ! if (is_gimple_call (stmt)) { tree orig_fn = gimple_call_fn (stmt); ! tree fn; ! if (TREE_CODE (orig_fn) == SSA_NAME) ! fn = VN_INFO (orig_fn)->valnum; ! else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF ! && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME) ! fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum; ! else ! continue; ! if (gimple_call_addr_fndecl (fn) != NULL_TREE && useless_type_conversion_p (TREE_TYPE (orig_fn), TREE_TYPE (fn))) {