This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Return true when gimple_simplify valueizes
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 24 Jul 2015 10:21:35 +0200 (CEST)
- Subject: [PATCH] Return true when gimple_simplify valueizes
- Authentication-results: sourceware.org; auth=none
The stmt interface for gimple_simplify currently does not return
"changed" when valueization would change it (it does if canonicalization
does). This causes "missed" optimizations compared to the fold based
code in fold_stmt.
Fixed as follows which runs into the issue that for variadic builtins
type_num_arguments doesn't yield the number of arguments. So take
that from the ops array state instead. Also special-case valueization
when replacing a call with its valueized variant so it works in-place.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Richard.
2015-07-24 Richard Biener <rguenther@suse.de>
* gimple-fold.c (replace_stmt_with_simplification): Special-case
valueizing call operands.
* gimple-match-head.c (maybe_push_res_to_seq): Take
number of call arguments from ops array.
(do_valueize): New function.
(gimple_simplify): Return true if valueization changed
any operand even if the result didn't simplify further.
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c (revision 226086)
--- gcc/gimple-fold.c (working copy)
*************** replace_stmt_with_simplification (gimple
*** 3398,3403 ****
--- 3398,3416 ----
return true;
}
}
+ else if (rcode.is_fn_code ()
+ && gimple_call_builtin_p (stmt, rcode))
+ {
+ unsigned i;
+ for (i = 0; i < gimple_call_num_args (stmt); ++i)
+ {
+ gcc_assert (ops[i] != NULL_TREE);
+ gimple_call_set_arg (stmt, i, ops[i]);
+ }
+ if (i < 3)
+ gcc_assert (ops[i] == NULL_TREE);
+ return true;
+ }
else if (!inplace)
{
if (gimple_has_lhs (stmt))
Index: gcc/gimple-match-head.c
===================================================================
*** gcc/gimple-match-head.c (revision 226086)
--- gcc/gimple-match-head.c (working copy)
*************** maybe_push_res_to_seq (code_helper rcode
*** 337,355 ****
tree decl = builtin_decl_implicit (rcode);
if (!decl)
return NULL_TREE;
- unsigned nargs = type_num_arguments (TREE_TYPE (decl));
- gcc_assert (nargs <= 3);
/* Play safe and do not allow abnormals to be mentioned in
newly created statements. */
! if ((TREE_CODE (ops[0]) == SSA_NAME
! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
! || (nargs >= 2
! && TREE_CODE (ops[1]) == SSA_NAME
! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
! || (nargs == 3
! && TREE_CODE (ops[2]) == SSA_NAME
! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
! return NULL_TREE;
if (!res)
res = make_ssa_name (type);
gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]);
--- 337,354 ----
tree decl = builtin_decl_implicit (rcode);
if (!decl)
return NULL_TREE;
/* Play safe and do not allow abnormals to be mentioned in
newly created statements. */
! unsigned nargs;
! for (nargs = 0; nargs < 3; ++nargs)
! {
! if (!ops[nargs])
! break;
! if (TREE_CODE (ops[nargs]) == SSA_NAME
! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[nargs]))
! return NULL_TREE;
! }
! gcc_assert (nargs != 0);
if (!res)
res = make_ssa_name (type);
gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]);
*************** gimple_simplify (enum built_in_function
*** 562,567 ****
--- 561,583 ----
return maybe_push_res_to_seq (rcode, type, ops, seq);
}
+ /* Helper for gimple_simplify valueizing OP using VALUEIZE and setting
+ VALUEIZED to true if valueization changed OP. */
+
+ static inline tree
+ do_valueize (tree op, tree (*valueize)(tree), bool &valueized)
+ {
+ if (valueize && TREE_CODE (op) == SSA_NAME)
+ {
+ tree tem = valueize (op);
+ if (tem && tem != op)
+ {
+ op = tem;
+ valueized = true;
+ }
+ }
+ return op;
+ }
/* The main STMT based simplification entry. It is used by the fold_stmt
and the fold_stmt_to_constant APIs. */
*************** gimple_simplify (gimple stmt,
*** 586,616 ****
|| code == VIEW_CONVERT_EXPR)
{
tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
! if (top_valueize && TREE_CODE (op0) == SSA_NAME)
! {
! tree tem = top_valueize (op0);
! if (tem)
! op0 = tem;
! }
*rcode = code;
ops[0] = op0;
! return gimple_resimplify1 (seq, rcode, type, ops, valueize);
}
else if (code == BIT_FIELD_REF)
{
tree rhs1 = gimple_assign_rhs1 (stmt);
tree op0 = TREE_OPERAND (rhs1, 0);
! if (top_valueize && TREE_CODE (op0) == SSA_NAME)
! {
! tree tem = top_valueize (op0);
! if (tem)
! op0 = tem;
! }
*rcode = code;
ops[0] = op0;
ops[1] = TREE_OPERAND (rhs1, 1);
ops[2] = TREE_OPERAND (rhs1, 2);
! return gimple_resimplify3 (seq, rcode, type, ops, valueize);
}
else if (code == SSA_NAME
&& top_valueize)
--- 602,626 ----
|| code == VIEW_CONVERT_EXPR)
{
tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
! bool valueized = false;
! op0 = do_valueize (op0, top_valueize, valueized);
*rcode = code;
ops[0] = op0;
! return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
! || valueized);
}
else if (code == BIT_FIELD_REF)
{
tree rhs1 = gimple_assign_rhs1 (stmt);
tree op0 = TREE_OPERAND (rhs1, 0);
! bool valueized = false;
! op0 = do_valueize (op0, top_valueize, valueized);
*rcode = code;
ops[0] = op0;
ops[1] = TREE_OPERAND (rhs1, 1);
ops[2] = TREE_OPERAND (rhs1, 2);
! return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
! || valueized);
}
else if (code == SSA_NAME
&& top_valueize)
*************** gimple_simplify (gimple stmt,
*** 627,691 ****
case GIMPLE_UNARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
! if (top_valueize && TREE_CODE (rhs1) == SSA_NAME)
! {
! tree tem = top_valueize (rhs1);
! if (tem)
! rhs1 = tem;
! }
*rcode = code;
ops[0] = rhs1;
! return gimple_resimplify1 (seq, rcode, type, ops, valueize);
}
case GIMPLE_BINARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
- if (top_valueize && TREE_CODE (rhs1) == SSA_NAME)
- {
- tree tem = top_valueize (rhs1);
- if (tem)
- rhs1 = tem;
- }
tree rhs2 = gimple_assign_rhs2 (stmt);
! if (top_valueize && TREE_CODE (rhs2) == SSA_NAME)
! {
! tree tem = top_valueize (rhs2);
! if (tem)
! rhs2 = tem;
! }
*rcode = code;
ops[0] = rhs1;
ops[1] = rhs2;
! return gimple_resimplify2 (seq, rcode, type, ops, valueize);
}
case GIMPLE_TERNARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
- if (top_valueize && TREE_CODE (rhs1) == SSA_NAME)
- {
- tree tem = top_valueize (rhs1);
- if (tem)
- rhs1 = tem;
- }
tree rhs2 = gimple_assign_rhs2 (stmt);
- if (top_valueize && TREE_CODE (rhs2) == SSA_NAME)
- {
- tree tem = top_valueize (rhs2);
- if (tem)
- rhs2 = tem;
- }
tree rhs3 = gimple_assign_rhs3 (stmt);
! if (top_valueize && TREE_CODE (rhs3) == SSA_NAME)
! {
! tree tem = top_valueize (rhs3);
! if (tem)
! rhs3 = tem;
! }
*rcode = code;
ops[0] = rhs1;
ops[1] = rhs2;
ops[2] = rhs3;
! return gimple_resimplify3 (seq, rcode, type, ops, valueize);
}
default:
gcc_unreachable ();
--- 637,677 ----
case GIMPLE_UNARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
! bool valueized = false;
! rhs1 = do_valueize (rhs1, top_valueize, valueized);
*rcode = code;
ops[0] = rhs1;
! return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
! || valueized);
}
case GIMPLE_BINARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
tree rhs2 = gimple_assign_rhs2 (stmt);
! bool valueized = false;
! rhs1 = do_valueize (rhs1, top_valueize, valueized);
! rhs2 = do_valueize (rhs2, top_valueize, valueized);
*rcode = code;
ops[0] = rhs1;
ops[1] = rhs2;
! return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
! || valueized);
}
case GIMPLE_TERNARY_RHS:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
tree rhs2 = gimple_assign_rhs2 (stmt);
tree rhs3 = gimple_assign_rhs3 (stmt);
! bool valueized = false;
! rhs1 = do_valueize (rhs1, top_valueize, valueized);
! rhs2 = do_valueize (rhs2, top_valueize, valueized);
! rhs3 = do_valueize (rhs3, top_valueize, valueized);
*rcode = code;
ops[0] = rhs1;
ops[1] = rhs2;
ops[2] = rhs3;
! return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
! || valueized);
}
default:
gcc_unreachable ();
*************** gimple_simplify (gimple stmt,
*** 695,790 ****
case GIMPLE_CALL:
/* ??? This way we can't simplify calls with side-effects. */
! if (gimple_call_lhs (stmt) != NULL_TREE)
{
tree fn = gimple_call_fn (stmt);
/* ??? Internal function support missing. */
if (!fn)
return false;
! if (top_valueize && TREE_CODE (fn) == SSA_NAME)
! {
! tree tem = top_valueize (fn);
! if (tem)
! fn = tem;
! }
! if (!fn
! || TREE_CODE (fn) != ADDR_EXPR
! || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL
! || DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) != BUILT_IN_NORMAL
! || !builtin_decl_implicit (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0)))
! || !gimple_builtin_call_types_compatible_p (stmt,
! TREE_OPERAND (fn, 0)))
return false;
tree decl = TREE_OPERAND (fn, 0);
tree type = TREE_TYPE (gimple_call_lhs (stmt));
switch (gimple_call_num_args (stmt))
{
case 1:
! {
! tree arg1 = gimple_call_arg (stmt, 0);
! if (top_valueize && TREE_CODE (arg1) == SSA_NAME)
! {
! tree tem = top_valueize (arg1);
! if (tem)
! arg1 = tem;
! }
! *rcode = DECL_FUNCTION_CODE (decl);
! ops[0] = arg1;
! return gimple_resimplify1 (seq, rcode, type, ops, valueize);
! }
case 2:
! {
! tree arg1 = gimple_call_arg (stmt, 0);
! if (top_valueize && TREE_CODE (arg1) == SSA_NAME)
! {
! tree tem = top_valueize (arg1);
! if (tem)
! arg1 = tem;
! }
! tree arg2 = gimple_call_arg (stmt, 1);
! if (top_valueize && TREE_CODE (arg2) == SSA_NAME)
! {
! tree tem = top_valueize (arg2);
! if (tem)
! arg2 = tem;
! }
! *rcode = DECL_FUNCTION_CODE (decl);
! ops[0] = arg1;
! ops[1] = arg2;
! return gimple_resimplify2 (seq, rcode, type, ops, valueize);
! }
case 3:
! {
! tree arg1 = gimple_call_arg (stmt, 0);
! if (top_valueize && TREE_CODE (arg1) == SSA_NAME)
! {
! tree tem = top_valueize (arg1);
! if (tem)
! arg1 = tem;
! }
! tree arg2 = gimple_call_arg (stmt, 1);
! if (top_valueize && TREE_CODE (arg2) == SSA_NAME)
! {
! tree tem = top_valueize (arg2);
! if (tem)
! arg2 = tem;
! }
! tree arg3 = gimple_call_arg (stmt, 2);
! if (top_valueize && TREE_CODE (arg3) == SSA_NAME)
! {
! tree tem = top_valueize (arg3);
! if (tem)
! arg3 = tem;
! }
! *rcode = DECL_FUNCTION_CODE (decl);
! ops[0] = arg1;
! ops[1] = arg2;
! ops[2] = arg3;
! return gimple_resimplify3 (seq, rcode, type, ops, valueize);
! }
default:
! return false;
}
}
break;
--- 681,726 ----
case GIMPLE_CALL:
/* ??? This way we can't simplify calls with side-effects. */
! if (gimple_call_lhs (stmt) != NULL_TREE
! && gimple_call_num_args (stmt) >= 1
! && gimple_call_num_args (stmt) <= 3)
{
tree fn = gimple_call_fn (stmt);
/* ??? Internal function support missing. */
if (!fn)
return false;
! bool valueized = false;
! fn = do_valueize (fn, top_valueize, valueized);
! if (TREE_CODE (fn) != ADDR_EXPR
! || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
return false;
tree decl = TREE_OPERAND (fn, 0);
+ if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL
+ || !builtin_decl_implicit (DECL_FUNCTION_CODE (decl))
+ || !gimple_builtin_call_types_compatible_p (stmt, decl))
+ return false;
+
tree type = TREE_TYPE (gimple_call_lhs (stmt));
+ *rcode = DECL_FUNCTION_CODE (decl);
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ ops[i] = do_valueize (arg, top_valueize, valueized);
+ }
switch (gimple_call_num_args (stmt))
{
case 1:
! return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
! || valueized);
case 2:
! return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
! || valueized);
case 3:
! return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
! || valueized);
default:
! gcc_unreachable ();
}
}
break;
*************** gimple_simplify (gimple stmt,
*** 792,814 ****
case GIMPLE_COND:
{
tree lhs = gimple_cond_lhs (stmt);
- if (top_valueize && TREE_CODE (lhs) == SSA_NAME)
- {
- tree tem = top_valueize (lhs);
- if (tem)
- lhs = tem;
- }
tree rhs = gimple_cond_rhs (stmt);
! if (top_valueize && TREE_CODE (rhs) == SSA_NAME)
! {
! tree tem = top_valueize (rhs);
! if (tem)
! rhs = tem;
! }
*rcode = gimple_cond_code (stmt);
ops[0] = lhs;
ops[1] = rhs;
! return gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize);
}
default:
--- 728,743 ----
case GIMPLE_COND:
{
tree lhs = gimple_cond_lhs (stmt);
tree rhs = gimple_cond_rhs (stmt);
! bool valueized = false;
! lhs = do_valueize (lhs, top_valueize, valueized);
! rhs = do_valueize (rhs, top_valueize, valueized);
*rcode = gimple_cond_code (stmt);
ops[0] = lhs;
ops[1] = rhs;
! return (gimple_resimplify2 (seq, rcode,
! boolean_type_node, ops, valueize)
! || valueized);
}
default: