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" } } */