On Sun, Mar 17, 2013 at 4:46 PM, Marc Glisse <marc.gli...@inria.fr> wrote:
> Hello,
>
> this patch adds a bit of folding to VEC_COND_EXPR so it is possible to
> generate ABS_EXPR and MAX_EXPR for vectors without relying on the
> vectorizer. I would have preferred to merge the COND_EXPR and VEC_COND_EXPR
> cases, but there are too many things that need fixing first, so I just
> copied the most relevant block. Folding from the front-end is ugly, but
> that's how the scalar case works, and they can both move to gimple folding
> together later.
>
> Bootstrap + testsuite on x86_64-linux-gnu.
>
> 2013-03-17  Marc Glisse  <marc.gli...@inria.fr>
>
> gcc/
>         * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
>         VEC_COND_EXPR cannot be lvalues.
>         (fold_ternary_loc) <VEC_COND_EXPR>: Call
> fold_cond_expr_with_comparison.
>
> gcc/cp/
>         * call.c (build_conditional_expr_1): Fold VEC_COND_EXPR.
>
> gcc/testsuite/
>         * g++.dg/ext/vector21.C: New testcase.
>
> --
> Marc Glisse
> Index: gcc/testsuite/g++.dg/ext/vector21.C
> ===================================================================
> --- gcc/testsuite/g++.dg/ext/vector21.C (revision 0)
> +++ gcc/testsuite/g++.dg/ext/vector21.C (revision 0)
> @@ -0,0 +1,39 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-gimple" } */
> +
> +typedef int vec __attribute__ ((vector_size (4 * sizeof (int))));
> +
> +void f1 (vec *x)
> +{
> +  *x = (*x >= 0) ? *x : -*x;
> +}
> +void f2 (vec *x)
> +{
> +  *x = (0 < *x) ? *x : -*x;
> +}
> +void g1 (vec *x)
> +{
> +  *x = (*x < 0) ? -*x : *x;
> +}
> +void g2 (vec *x)
> +{
> +  *x = (0 > *x) ? -*x : *x;
> +}
> +void h (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *y : *x;
> +}
> +void i (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *x : *y;
> +}
> +void j (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *x : *x;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "ABS_EXPR" 4 "gimple" } } */
> +/* { dg-final { scan-tree-dump "MIN_EXPR" "gimple" } } */
> +/* { dg-final { scan-tree-dump "MAX_EXPR" "gimple" } } */
> +/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */
> +/* { dg-final { cleanup-tree-dump "gimple" } } */
>
> Property changes on: gcc/testsuite/g++.dg/ext/vector21.C
> ___________________________________________________________________
> Added: svn:keywords
>    + Author Date Id Revision URL
> Added: svn:eol-style
>    + native
>
> Index: gcc/fold-const.c
> ===================================================================
> --- gcc/fold-const.c    (revision 196748)
> +++ gcc/fold-const.c    (working copy)
> @@ -4625,21 +4625,21 @@ fold_cond_expr_with_comparison (location
>       A == 0 ? A : 0 is always 0 unless A is -0.  Note that
>       both transformations are correct when A is NaN: A != 0
>       is then true, and A == 0 is false.  */
>
>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>        && integer_zerop (arg01) && integer_zerop (arg2))
>      {
>        if (comp_code == NE_EXPR)
>         return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type,
> arg1));
>        else if (comp_code == EQ_EXPR)
> -       return build_int_cst (type, 0);
> +       return build_zero_cst (type);
>      }
>
>    /* Try some transformations of A op B ? A : B.
>
>       A == B? A : B    same as B
>       A != B? A : B    same as A
>       A >= B? A : B    same as max (A, B)
>       A > B?  A : B    same as max (B, A)
>       A <= B? A : B    same as min (A, B)
>       A < B?  A : B    same as min (B, A)
> @@ -4662,21 +4662,22 @@ fold_cond_expr_with_comparison (location
>       expressions will be false, so all four give B.  The min()
>       and max() versions would give a NaN instead.  */
>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>        && operand_equal_for_comparison_p (arg01, arg2, arg00)
>        /* Avoid these transformations if the COND_EXPR may be used
>          as an lvalue in the C++ front-end.  PR c++/19199.  */
>        && (in_gimple_form
>           || (strcmp (lang_hooks.name, "GNU C++") != 0
>               && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
>           || ! maybe_lvalue_p (arg1)
> -         || ! maybe_lvalue_p (arg2)))
> +         || ! maybe_lvalue_p (arg2)
> +         || TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE))

You mean that the VEC_COND_EXPRs can never be used as an lvalue in
the C++ frontend?

>      {
>        tree comp_op0 = arg00;
>        tree comp_op1 = arg01;
>        tree comp_type = TREE_TYPE (comp_op0);
>
>        /* Avoid adding NOP_EXPRs in case this is an lvalue.  */
>        if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
>         {
>           comp_type = type;
>           comp_op0 = arg1;
> @@ -14138,20 +14139,51 @@ fold_ternary_loc (location_t loc, enum t
>        return NULL_TREE;
>
>      case VEC_COND_EXPR:
>        if (TREE_CODE (arg0) == VECTOR_CST)
>         {
>           if (integer_all_onesp (arg0) && !TREE_SIDE_EFFECTS (op2))
>             return pedantic_non_lvalue_loc (loc, op1);
>           if (integer_zerop (arg0) && !TREE_SIDE_EFFECTS (op1))
>             return pedantic_non_lvalue_loc (loc, op2);
>         }
> +      if (operand_equal_p (arg1, op2, 0))
> +       return pedantic_omit_one_operand_loc (loc, type, arg1, arg0);
> +
> +      /* If we have A op B ? A : C, we may be able to convert this to a
> +        simpler expression, depending on the operation and the values
> +        of B and C.  Signed zeros prevent all of these transformations,
> +        for reasons given above each one.
> +
> +         Also try swapping the arguments and inverting the conditional.  */
> +      if (COMPARISON_CLASS_P (arg0)
> +         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
> +         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
> +       {
> +         tem = fold_cond_expr_with_comparison (loc, type, arg0, op1, op2);
> +         if (tem)
> +           return tem;
> +       }
> +
> +      if (COMPARISON_CLASS_P (arg0)
> +         && operand_equal_p (TREE_OPERAND (arg0, 0), op2, 0)
> +         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
> +       {
> +         location_t loc0 = expr_location_or (arg0, loc);
> +         tem = fold_truth_not_expr (loc0, arg0);
> +         if (tem && COMPARISON_CLASS_P (tem))
> +           {
> +             tem = fold_cond_expr_with_comparison (loc, type, tem, op2,
> op1);
> +             if (tem)
> +               return tem;
> +           }
> +       }
>        return NULL_TREE;

Btw, instead of copying this whole block I'd prefer

     case COND_EXPR:
     case VEC_COND_EXPR:
         ... common cases...

         /* ???  Fixup the code below for VEC_COND_EXRP.  */
         if (code == VEC_COND_EXPR)
           break;

Thanks,
Richard.

>      case CALL_EXPR:
>        /* CALL_EXPRs used to be ternary exprs.  Catch any mistaken uses
>          of fold_ternary on them.  */
>        gcc_unreachable ();
>
>      case BIT_FIELD_REF:
>        if ((TREE_CODE (arg0) == VECTOR_CST
>            || (TREE_CODE (arg0) == CONSTRUCTOR
> Index: gcc/cp/call.c
> ===================================================================
> --- gcc/cp/call.c       (revision 196748)
> +++ gcc/cp/call.c       (working copy)
> @@ -4430,23 +4430,23 @@ build_conditional_expr_1 (tree arg1, tre
>           || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type))
>         {
>           if (complain & tf_error)
>             error ("incompatible vector types in conditional expression: "
>                    "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE
> (orig_arg2),
>                    TREE_TYPE (orig_arg3));
>           return error_mark_node;
>         }
>
>        if (!COMPARISON_CLASS_P (arg1))
> -       arg1 = build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
> +       arg1 = fold_build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
>                        build_zero_cst (arg1_type));
> -      return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
> +      return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
>      }
>
>    /* [expr.cond]
>
>       The first expression is implicitly converted to bool (clause
>       _conv_).  */
>    arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1,
> complain,
>                                             LOOKUP_NORMAL);
>    if (error_operand_p (arg1))
>      return error_mark_node;
>

Reply via email to