This makes SCCVN combine COMPLEX_EXPR arguments with its operands,
allowing to optimize piecewise pass-thru of a complex value.

The meat of the patch is the tuplification fix

!         && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
---
!         && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (def_stmt),
!                                     0)) == SSA_NAME)

and special-casing of COMPLEX_EXPR in simplify_binary_expression.
The rest is some TLC in the functions.

Bootstrap and regtest ongoing for x86_64-unknown-linux-gnu.

Richard.

2011-09-06  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/48149
        * tree-ssa-sccvn.c (vn_get_expr_for): Simplify.  Fix tuplification bug.
        (vn_valueize): Move earlier.
        (valueize_expr): Use vn_valueize.
        (simplify_binary_expression): Simplify, also combine COMPLEX_EXPR
        operands.
        (simplify_unary_expression): Simplify.

        * gcc.dg/tree-ssa/ssa-fre-32.c: New testcase.

Index: trunk/gcc/tree-ssa-sccvn.c
===================================================================
*** trunk.orig/gcc/tree-ssa-sccvn.c     2011-09-06 14:58:32.000000000 +0200
--- trunk/gcc/tree-ssa-sccvn.c  2011-09-06 14:58:53.000000000 +0200
*************** vn_get_expr_for (tree name)
*** 217,222 ****
--- 217,223 ----
    vn_ssa_aux_t vn = VN_INFO (name);
    gimple def_stmt;
    tree expr = NULL_TREE;
+   enum tree_code code;
  
    if (vn->valnum == VN_TOP)
      return name;
*************** vn_get_expr_for (tree name)
*** 241,277 ****
    /* Otherwise use the defining statement to build the expression.  */
    def_stmt = SSA_NAME_DEF_STMT (vn->valnum);
  
!   /* If the value number is a default-definition or a PHI result
!      use it directly.  */
!   if (gimple_nop_p (def_stmt)
!       || gimple_code (def_stmt) == GIMPLE_PHI)
!     return vn->valnum;
! 
    if (!is_gimple_assign (def_stmt))
      return vn->valnum;
  
    /* FIXME tuples.  This is incomplete and likely will miss some
       simplifications.  */
!   switch (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)))
      {
      case tcc_reference:
!       if ((gimple_assign_rhs_code (def_stmt) == VIEW_CONVERT_EXPR
!          || gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
!          || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR)
!         && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
!       expr = fold_build1 (gimple_assign_rhs_code (def_stmt),
                            gimple_expr_type (def_stmt),
                            TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0));
        break;
  
      case tcc_unary:
!       expr = fold_build1 (gimple_assign_rhs_code (def_stmt),
                          gimple_expr_type (def_stmt),
                          gimple_assign_rhs1 (def_stmt));
        break;
  
      case tcc_binary:
!       expr = fold_build2 (gimple_assign_rhs_code (def_stmt),
                          gimple_expr_type (def_stmt),
                          gimple_assign_rhs1 (def_stmt),
                          gimple_assign_rhs2 (def_stmt));
--- 242,275 ----
    /* Otherwise use the defining statement to build the expression.  */
    def_stmt = SSA_NAME_DEF_STMT (vn->valnum);
  
!   /* If the value number is not an assignment use it directly.  */
    if (!is_gimple_assign (def_stmt))
      return vn->valnum;
  
    /* FIXME tuples.  This is incomplete and likely will miss some
       simplifications.  */
!   code = gimple_assign_rhs_code (def_stmt);
!   switch (TREE_CODE_CLASS (code))
      {
      case tcc_reference:
!       if ((code == REALPART_EXPR
!          || code == IMAGPART_EXPR
!          || code == VIEW_CONVERT_EXPR)
!         && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (def_stmt),
!                                     0)) == SSA_NAME)
!       expr = fold_build1 (code,
                            gimple_expr_type (def_stmt),
                            TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0));
        break;
  
      case tcc_unary:
!       expr = fold_build1 (code,
                          gimple_expr_type (def_stmt),
                          gimple_assign_rhs1 (def_stmt));
        break;
  
      case tcc_binary:
!       expr = fold_build2 (code,
                          gimple_expr_type (def_stmt),
                          gimple_assign_rhs1 (def_stmt),
                          gimple_assign_rhs2 (def_stmt));
*************** stmt_has_constants (gimple stmt)
*** 2822,2827 ****
--- 2820,2838 ----
    return false;
  }
  
+ /* Valueize NAME if it is an SSA name, otherwise just return it.  */
+ 
+ static inline tree
+ vn_valueize (tree name)
+ {
+   if (TREE_CODE (name) == SSA_NAME)
+     {
+       tree tem = SSA_VAL (name);
+       return tem == VN_TOP ? name : tem;
+     }
+   return name;
+ }
+ 
  /* Replace SSA_NAMES in expr with their value numbers, and return the
     result.
     This is performed in place. */
*************** valueize_expr (tree expr)
*** 2831,2851 ****
  {
    switch (TREE_CODE_CLASS (TREE_CODE (expr)))
      {
-     case tcc_unary:
-       if (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
-         && SSA_VAL (TREE_OPERAND (expr, 0)) != VN_TOP)
-       TREE_OPERAND (expr, 0) = SSA_VAL (TREE_OPERAND (expr, 0));
-       break;
      case tcc_binary:
!       if (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
!         && SSA_VAL (TREE_OPERAND (expr, 0)) != VN_TOP)
!       TREE_OPERAND (expr, 0) = SSA_VAL (TREE_OPERAND (expr, 0));
!       if (TREE_CODE (TREE_OPERAND (expr, 1)) == SSA_NAME
!         && SSA_VAL (TREE_OPERAND (expr, 1)) != VN_TOP)
!       TREE_OPERAND (expr, 1) = SSA_VAL (TREE_OPERAND (expr, 1));
!       break;
!     default:
        break;
      }
    return expr;
  }
--- 2842,2854 ----
  {
    switch (TREE_CODE_CLASS (TREE_CODE (expr)))
      {
      case tcc_binary:
!       TREE_OPERAND (expr, 1) = vn_valueize (TREE_OPERAND (expr, 1));
!       /* Fallthru.  */
!     case tcc_unary:
!       TREE_OPERAND (expr, 0) = vn_valueize (TREE_OPERAND (expr, 0));
        break;
+     default:;
      }
    return expr;
  }
*************** simplify_binary_expression (gimple stmt)
*** 2859,2864 ****
--- 2862,2868 ----
    tree result = NULL_TREE;
    tree op0 = gimple_assign_rhs1 (stmt);
    tree op1 = gimple_assign_rhs2 (stmt);
+   enum tree_code code = gimple_assign_rhs_code (stmt);
  
    /* This will not catch every single case we could combine, but will
       catch those with constants.  The goal here is to simultaneously
*************** simplify_binary_expression (gimple stmt)
*** 2867,2889 ****
    if (TREE_CODE (op0) == SSA_NAME)
      {
        if (VN_INFO (op0)->has_constants
!         || TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison)
        op0 = valueize_expr (vn_get_expr_for (op0));
!       else if (SSA_VAL (op0) != VN_TOP && SSA_VAL (op0) != op0)
!       op0 = SSA_VAL (op0);
      }
  
    if (TREE_CODE (op1) == SSA_NAME)
      {
!       if (VN_INFO (op1)->has_constants)
        op1 = valueize_expr (vn_get_expr_for (op1));
!       else if (SSA_VAL (op1) != VN_TOP && SSA_VAL (op1) != op1)
!       op1 = SSA_VAL (op1);
      }
  
    /* Pointer plus constant can be represented as invariant address.
       Do so to allow further propatation, see also tree forwprop.  */
!   if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
        && host_integerp (op1, 1)
        && TREE_CODE (op0) == ADDR_EXPR
        && is_gimple_min_invariant (op0))
--- 2871,2895 ----
    if (TREE_CODE (op0) == SSA_NAME)
      {
        if (VN_INFO (op0)->has_constants
!         || TREE_CODE_CLASS (code) == tcc_comparison
!         || code == COMPLEX_EXPR)
        op0 = valueize_expr (vn_get_expr_for (op0));
!       else
!       op0 = vn_valueize (op0);
      }
  
    if (TREE_CODE (op1) == SSA_NAME)
      {
!       if (VN_INFO (op1)->has_constants
!         || code == COMPLEX_EXPR)
        op1 = valueize_expr (vn_get_expr_for (op1));
!       else
!       op1 = vn_valueize (op1);
      }
  
    /* Pointer plus constant can be represented as invariant address.
       Do so to allow further propatation, see also tree forwprop.  */
!   if (code == POINTER_PLUS_EXPR
        && host_integerp (op1, 1)
        && TREE_CODE (op0) == ADDR_EXPR
        && is_gimple_min_invariant (op0))
*************** simplify_binary_expression (gimple stmt)
*** 2898,2905 ****
  
    fold_defer_overflow_warnings ();
  
!   result = fold_binary (gimple_assign_rhs_code (stmt),
!                       gimple_expr_type (stmt), op0, op1);
    if (result)
      STRIP_USELESS_TYPE_CONVERSION (result);
  
--- 2904,2910 ----
  
    fold_defer_overflow_warnings ();
  
!   result = fold_binary (code, gimple_expr_type (stmt), op0, op1);
    if (result)
      STRIP_USELESS_TYPE_CONVERSION (result);
  
*************** simplify_unary_expression (gimple stmt)
*** 2924,2935 ****
  {
    tree result = NULL_TREE;
    tree orig_op0, op0 = gimple_assign_rhs1 (stmt);
  
    /* We handle some tcc_reference codes here that are all
       GIMPLE_ASSIGN_SINGLE codes.  */
!   if (gimple_assign_rhs_code (stmt) == REALPART_EXPR
!       || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR
!       || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR)
      op0 = TREE_OPERAND (op0, 0);
  
    if (TREE_CODE (op0) != SSA_NAME)
--- 2929,2941 ----
  {
    tree result = NULL_TREE;
    tree orig_op0, op0 = gimple_assign_rhs1 (stmt);
+   enum tree_code code = gimple_assign_rhs_code (stmt);
  
    /* We handle some tcc_reference codes here that are all
       GIMPLE_ASSIGN_SINGLE codes.  */
!   if (code == REALPART_EXPR
!       || code == IMAGPART_EXPR
!       || code == VIEW_CONVERT_EXPR)
      op0 = TREE_OPERAND (op0, 0);
  
    if (TREE_CODE (op0) != SSA_NAME)
*************** simplify_unary_expression (gimple stmt)
*** 2938,2947 ****
    orig_op0 = op0;
    if (VN_INFO (op0)->has_constants)
      op0 = valueize_expr (vn_get_expr_for (op0));
!   else if (gimple_assign_cast_p (stmt)
!          || gimple_assign_rhs_code (stmt) == REALPART_EXPR
!          || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR
!          || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR)
      {
        /* We want to do tree-combining on conversion-like expressions.
           Make sure we feed only SSA_NAMEs or constants to fold though.  */
--- 2944,2953 ----
    orig_op0 = op0;
    if (VN_INFO (op0)->has_constants)
      op0 = valueize_expr (vn_get_expr_for (op0));
!   else if (CONVERT_EXPR_CODE_P (code)
!          || code == REALPART_EXPR
!          || code == IMAGPART_EXPR
!          || code == VIEW_CONVERT_EXPR)
      {
        /* We want to do tree-combining on conversion-like expressions.
           Make sure we feed only SSA_NAMEs or constants to fold though.  */
*************** simplify_unary_expression (gimple stmt)
*** 2958,2965 ****
    if (op0 == orig_op0)
      return NULL_TREE;
  
!   result = fold_unary_ignore_overflow (gimple_assign_rhs_code (stmt),
!                                      gimple_expr_type (stmt), op0);
    if (result)
      {
        STRIP_USELESS_TYPE_CONVERSION (result);
--- 2964,2970 ----
    if (op0 == orig_op0)
      return NULL_TREE;
  
!   result = fold_unary_ignore_overflow (code, gimple_expr_type (stmt), op0);
    if (result)
      {
        STRIP_USELESS_TYPE_CONVERSION (result);
*************** simplify_unary_expression (gimple stmt)
*** 2970,2988 ****
    return NULL_TREE;
  }
  
- /* Valueize NAME if it is an SSA name, otherwise just return it.  */
- 
- static inline tree
- vn_valueize (tree name)
- {
-   if (TREE_CODE (name) == SSA_NAME)
-     {
-       tree tem = SSA_VAL (name);
-       return tem == VN_TOP ? name : tem;
-     }
-   return name;
- }
- 
  /* Try to simplify RHS using equivalences and constant folding.  */
  
  static tree
--- 2975,2980 ----
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c    2011-09-06 
15:03:20.000000000 +0200
***************
*** 0 ****
--- 1,28 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-fre1-details" } */
+ 
+ _Complex float 
+ foo (_Complex float x)
+ {    
+   float r = __real x;
+   float i = __imag x;
+   _Complex float z;
+   __real z = r;
+   __imag z = i;
+   return z;
+ } 
+ 
+ _Complex float 
+ bar (_Complex float x)
+ {    
+   float r = __real x;
+   float i = __imag x;
+   _Complex float z = x;
+   __real z = r;
+   __imag z = i;
+   return z;
+ } 
+ 
+ /* We should CSE all the way to replace the final assignment to z with x.  */
+ /* { dg-final { scan-tree-dump-times "with x_1\\\(D\\\) in z" 3 "fre1" } } */
+ /* { dg-final { cleanup-tree-dump "fre1" } } */

Reply via email to