+2011-04-18 Richard Guenther <rguenther@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.
+
2011-04-18 Richard Guenther <rguenther@suse.de>
PR middle-end/48650
gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
{
gimple stmt = gsi_stmt (*gsi);
-
- tree callee = gimple_call_fndecl (stmt);
+ 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);
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;
}
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
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;
+ return gimple_call_addr_fndecl (gimple_call_fn (gs));
}
tree lhs = gimple_call_lhs (stmt);
tree val;
tree argt;
- tree callee;
bool changed = false;
unsigned i;
}
}
- 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;
}
}
/* Visit indirect calls and turn them into direct calls if
possible. */
- if (is_gimple_call (stmt)
- && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+ if (is_gimple_call (stmt))
{
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
+ 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)))
{