This rewrites TRUTH_NOT_EXPRs during gimplification as BIT_NOT_EXPR respective BIT_XOR_EXPR as RTL expansion does. This completes the series lowering the TRUTH_*_EXPRs to operations that are also available on HW and allows us to unify code handling TRUTH_*_EXPRs and BIT_*_EXPRs.
The patch has seen final adjustment for the testsuite fallout (which happened to be minor after the prerequesite fixes), so it is currently in a final bootstrap & regtest cycle. I'll commit it tomorrow if that works out fine. Thanks, Richard. 2011-07-18 Richard Guenther <rguent...@suse.de> * gimplify.c (gimplify_expr): Gimplify TRUTH_NOT_EXPR as BIT_XOR_EXPR, same as the RTL expander does. * tree-cfg.c (verify_expr): Disallow TRUTH_NOT_EXPR in the gimple IL. (verify_gimple_assign_unary): Likewise. * tree-ssa-propagate.c (valid_gimple_rhs_p): Disallow TRUTH_*_EXPR. * tree-ssa-forwprop.c (forward_propagate_comparison): Handle BIT_NOT_EXPR instead of TRUTH_NOT_EXPR. * gcc.dg/tree-ssa/bool-10.c: Adjust expected pattern. * gcc.dg/tree-ssa/bool-11.c: Likewise. Index: gcc/gimplify.c =================================================================== *** gcc/gimplify.c.orig 2011-07-18 16:20:14.000000000 +0200 --- gcc/gimplify.c 2011-07-18 16:22:55.000000000 +0200 *************** gimplify_expr (tree *expr_p, gimple_seq *** 6787,6803 **** case TRUTH_NOT_EXPR: { ! tree orig_type = TREE_TYPE (*expr_p); *expr_p = gimple_boolify (*expr_p); ! if (!useless_type_conversion_p (orig_type, TREE_TYPE (*expr_p))) ! { ! *expr_p = fold_convert_loc (saved_location, orig_type, *expr_p); ! ret = GS_OK; ! break; ! } ! ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, ! is_gimple_val, fb_rvalue); ! recalculate_side_effects (*expr_p); break; } --- 6787,6810 ---- case TRUTH_NOT_EXPR: { ! tree type = TREE_TYPE (*expr_p); ! /* The parsers are careful to generate TRUTH_NOT_EXPR ! only with operands that are always zero or one. ! We do not fold here but handle the only interesting case ! manually, as fold may re-introduce the TRUTH_NOT_EXPR. */ *expr_p = gimple_boolify (*expr_p); ! if (TYPE_PRECISION (TREE_TYPE (*expr_p)) == 1) ! *expr_p = build1_loc (input_location, BIT_NOT_EXPR, ! TREE_TYPE (*expr_p), ! TREE_OPERAND (*expr_p, 0)); ! else ! *expr_p = build2_loc (input_location, BIT_XOR_EXPR, ! TREE_TYPE (*expr_p), ! TREE_OPERAND (*expr_p, 0), ! build_int_cst (TREE_TYPE (*expr_p), 1)); ! if (!useless_type_conversion_p (type, TREE_TYPE (*expr_p))) ! *expr_p = fold_convert_loc (input_location, type, *expr_p); ! ret = GS_OK; break; } Index: gcc/tree-cfg.c =================================================================== *** gcc/tree-cfg.c.orig 2011-07-18 16:20:14.000000000 +0200 --- gcc/tree-cfg.c 2011-07-18 16:22:55.000000000 +0200 *************** verify_expr (tree *tp, int *walk_subtree *** 2753,2759 **** break; case NON_LVALUE_EXPR: ! gcc_unreachable (); CASE_CONVERT: case FIX_TRUNC_EXPR: --- 2753,2760 ---- break; case NON_LVALUE_EXPR: ! case TRUTH_NOT_EXPR: ! gcc_unreachable (); CASE_CONVERT: case FIX_TRUNC_EXPR: *************** verify_expr (tree *tp, int *walk_subtree *** 2761,2767 **** case NEGATE_EXPR: case ABS_EXPR: case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: CHECK_OP (0, "invalid operand to unary operator"); break; --- 2762,2767 ---- *************** verify_gimple_assign_unary (gimple stmt) *** 3417,3435 **** /* FIXME. */ return false; - case TRUTH_NOT_EXPR: - /* We require two-valued operand types. */ - if (!(TREE_CODE (rhs1_type) == BOOLEAN_TYPE - || (INTEGRAL_TYPE_P (rhs1_type) - && TYPE_PRECISION (rhs1_type) == 1))) - { - error ("invalid types in truth not"); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); - return true; - } - break; - case NEGATE_EXPR: case ABS_EXPR: case BIT_NOT_EXPR: --- 3417,3422 ---- Index: gcc/tree-ssa-propagate.c =================================================================== *** gcc/tree-ssa-propagate.c.orig 2011-07-18 16:20:14.000000000 +0200 --- gcc/tree-ssa-propagate.c 2011-07-18 16:22:55.000000000 +0200 *************** valid_gimple_rhs_p (tree expr) *** 601,619 **** } break; - case TRUTH_NOT_EXPR: - if (!is_gimple_val (TREE_OPERAND (expr, 0))) - return false; - break; - - case TRUTH_AND_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_OR_EXPR: - if (!is_gimple_val (TREE_OPERAND (expr, 0)) - || !is_gimple_val (TREE_OPERAND (expr, 1))) - return false; - break; - default: return false; } --- 601,606 ---- Index: gcc/testsuite/gcc.dg/tree-ssa/bool-10.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/bool-10.c.orig 2008-08-20 10:24:07.000000000 +0200 --- gcc/testsuite/gcc.dg/tree-ssa/bool-10.c 2011-07-18 16:24:16.000000000 +0200 *************** int f(_Bool x) *** 9,14 **** /* There should be no != 1 which is produced by the front-end as bool_var != 1 is the same as !bool_var. */ /* { dg-final { scan-tree-dump-times "!= 1" 0 "optimized"} } */ ! /* { dg-final { scan-tree-dump-times "!x" 1 "optimized"} } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ --- 9,14 ---- /* There should be no != 1 which is produced by the front-end as bool_var != 1 is the same as !bool_var. */ /* { dg-final { scan-tree-dump-times "!= 1" 0 "optimized"} } */ ! /* { dg-final { scan-tree-dump-times "~x" 1 "optimized"} } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/bool-11.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/bool-11.c.orig 2008-08-20 10:24:07.000000000 +0200 --- gcc/testsuite/gcc.dg/tree-ssa/bool-11.c 2011-07-18 16:24:46.000000000 +0200 *************** int f(_Bool x) *** 9,14 **** /* There should be no == 0 which is produced by the front-end as bool_var == 0 is the same as !bool_var. */ /* { dg-final { scan-tree-dump-times "== 0" 0 "optimized"} } */ ! /* { dg-final { scan-tree-dump-times "!x" 1 "optimized"} } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ --- 9,14 ---- /* There should be no == 0 which is produced by the front-end as bool_var == 0 is the same as !bool_var. */ /* { dg-final { scan-tree-dump-times "== 0" 0 "optimized"} } */ ! /* { dg-final { scan-tree-dump-times "~x" 1 "optimized"} } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ Index: gcc/tree-ssa-forwprop.c =================================================================== *** gcc/tree-ssa-forwprop.c.orig 2011-07-18 16:18:35.000000000 +0200 --- gcc/tree-ssa-forwprop.c 2011-07-18 16:26:29.000000000 +0200 *************** forward_propagate_comparison (gimple stm *** 1127,1133 **** && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)) || TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) == tcc_comparison ! || gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (use_stmt)))) { tree lhs = gimple_assign_lhs (use_stmt); --- 1127,1133 ---- && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)) || TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) == tcc_comparison ! || gimple_assign_rhs_code (use_stmt) == BIT_NOT_EXPR) && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (use_stmt)))) { tree lhs = gimple_assign_lhs (use_stmt); *************** forward_propagate_comparison (gimple stm *** 1164,1170 **** } /* We can propagate the condition into a statement that computes the logical negation of the comparison result. */ ! else if (gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) { tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); bool nans = HONOR_NANS (TYPE_MODE (type)); --- 1164,1170 ---- } /* We can propagate the condition into a statement that computes the logical negation of the comparison result. */ ! else if (gimple_assign_rhs_code (use_stmt) == BIT_NOT_EXPR) { tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); bool nans = HONOR_NANS (TYPE_MODE (type));