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  <rguent...@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:

Reply via email to