diff mbox

[vec-cmp,4/6] Support vector mask invariants

Message ID 20151008151140.GE63757@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Oct. 8, 2015, 3:11 p.m. UTC
Hi,

This patch adds a special handling of boolean vector invariants.  We need additional code to determine type of generated invariant.  For VEC_COND_EXPR case we even provide this type directly because statement vectype doesn't allow us to compute it.  Separate code is used to generate and expand such vectors.

Thanks,
Ilya
--
gcc/

2015-10-08  Ilya Enkovich  <enkovich.gnu@gmail.com>

	* expr.c (const_vector_mask_from_tree): New.
	(const_vector_from_tree): Use const_vector_mask_from_tree
	for boolean vectors.
	* tree-vect-stmts.c (vect_init_vector): Support boolean vector
	invariants.
	(vect_get_vec_def_for_operand): Add VECTYPE arg.
	(vectorizable_condition): Directly provide vectype for invariants
	used in comparison.
	* tree-vectorizer.h (vect_get_vec_def_for_operand): Add VECTYPE
	arg.

Comments

Richard Biener Oct. 13, 2015, 1:54 p.m. UTC | #1
On Thu, Oct 8, 2015 at 5:11 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> Hi,
>
> This patch adds a special handling of boolean vector invariants.  We need additional code to determine type of generated invariant.  For VEC_COND_EXPR case we even provide this type directly because statement vectype doesn't allow us to compute it.  Separate code is used to generate and expand such vectors.
>
> Thanks,
> Ilya
> --
> gcc/
>
> 2015-10-08  Ilya Enkovich  <enkovich.gnu@gmail.com>
>
>         * expr.c (const_vector_mask_from_tree): New.
>         (const_vector_from_tree): Use const_vector_mask_from_tree
>         for boolean vectors.
>         * tree-vect-stmts.c (vect_init_vector): Support boolean vector
>         invariants.
>         (vect_get_vec_def_for_operand): Add VECTYPE arg.
>         (vectorizable_condition): Directly provide vectype for invariants
>         used in comparison.
>         * tree-vectorizer.h (vect_get_vec_def_for_operand): Add VECTYPE
>         arg.
>
>
> diff --git a/gcc/expr.c b/gcc/expr.c
> index 88da8cb..a624a34 100644
> --- a/gcc/expr.c
> +++ b/gcc/expr.c
> @@ -11320,6 +11320,40 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
>    return 1;
>  }
>
> +/* Return a CONST_VECTOR rtx representing vector mask for
> +   a VECTOR_CST of booleans.  */
> +static rtx
> +const_vector_mask_from_tree (tree exp)
> +{
> +  rtvec v;
> +  unsigned i;
> +  int units;
> +  tree elt;
> +  machine_mode inner, mode;
> +
> +  mode = TYPE_MODE (TREE_TYPE (exp));
> +  units = GET_MODE_NUNITS (mode);
> +  inner = GET_MODE_INNER (mode);
> +
> +  v = rtvec_alloc (units);
> +
> +  for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
> +    {
> +      elt = VECTOR_CST_ELT (exp, i);
> +
> +      gcc_assert (TREE_CODE (elt) == INTEGER_CST);
> +      if (integer_zerop (elt))
> +       RTVEC_ELT (v, i) = CONST0_RTX (inner);
> +      else if (integer_onep (elt)
> +              || integer_minus_onep (elt))
> +       RTVEC_ELT (v, i) = CONSTM1_RTX (inner);
> +      else
> +       gcc_unreachable ();
> +    }
> +
> +  return gen_rtx_CONST_VECTOR (mode, v);
> +}
> +
>  /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
>  static rtx
>  const_vector_from_tree (tree exp)
> @@ -11335,6 +11369,9 @@ const_vector_from_tree (tree exp)
>    if (initializer_zerop (exp))
>      return CONST0_RTX (mode);
>
> +  if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp)))
> +      return const_vector_mask_from_tree (exp);
> +
>    units = GET_MODE_NUNITS (mode);
>    inner = GET_MODE_INNER (mode);
>
> diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
> index 6949c71..337ea7b 100644
> --- a/gcc/tree-vect-stmts.c
> +++ b/gcc/tree-vect-stmts.c
> @@ -1308,27 +1308,61 @@ vect_init_vector_1 (gimple *stmt, gimple *new_stmt, gimple_stmt_iterator *gsi)
>  tree
>  vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>  {
> +  tree val_type = TREE_TYPE (val);
> +  machine_mode mode = TYPE_MODE (type);
> +  machine_mode val_mode = TYPE_MODE(val_type);
>    tree new_var;
>    gimple *init_stmt;
>    tree vec_oprnd;
>    tree new_temp;
>
>    if (TREE_CODE (type) == VECTOR_TYPE
> -      && TREE_CODE (TREE_TYPE (val)) != VECTOR_TYPE)
> -    {
> -      if (!types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
> +      && TREE_CODE (val_type) != VECTOR_TYPE)
> +    {
> +      /* Handle vector of bool represented as a vector of
> +        integers here rather than on expand because it is
> +        a default mask type for targets.  Vector mask is
> +        built in a following way:
> +
> +        tmp = (int)val
> +        vec_tmp = {tmp, ..., tmp}
> +        vec_cst = VIEW_CONVERT_EXPR<vector(N) _Bool>(vec_tmp);  */
> +      if (TREE_CODE (val_type) == BOOLEAN_TYPE
> +         && VECTOR_MODE_P (mode)
> +         && SCALAR_INT_MODE_P (GET_MODE_INNER (mode))
> +         && GET_MODE_INNER (mode) != val_mode)
>         {
> -         if (CONSTANT_CLASS_P (val))
> -           val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
> -         else
> +         unsigned size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
> +         tree stype = build_nonstandard_integer_type (size, 1);
> +         tree vectype = get_vectype_for_scalar_type (stype);
> +
> +         new_temp = make_ssa_name (stype);
> +         init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
> +         vect_init_vector_1 (stmt, init_stmt, gsi);
> +
> +         val = make_ssa_name (vectype);
> +         new_temp = build_vector_from_val (vectype, new_temp);
> +         init_stmt = gimple_build_assign (val, new_temp);
> +         vect_init_vector_1 (stmt, init_stmt, gsi);
> +
> +         val = build1 (VIEW_CONVERT_EXPR, type, val);

So I don't quite understand - why don't we want to build

   tmp = (bool-element-type)val;
   vec_cst = {tmp, tmp, tmp ... };

?

> +       }
> +      else
> +       {
> +         if (!types_compatible_p (TREE_TYPE (type), val_type))
>             {
> -             new_temp = make_ssa_name (TREE_TYPE (type));
> -             init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
> -             vect_init_vector_1 (stmt, init_stmt, gsi);
> -             val = new_temp;
> +             if (CONSTANT_CLASS_P (val))
> +               val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
> +             else
> +               {
> +                 new_temp = make_ssa_name (TREE_TYPE (type));
> +                 init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
> +                 vect_init_vector_1 (stmt, init_stmt, gsi);
> +                 val = new_temp;
> +               }
>             }
> +         val = build_vector_from_val (type, val);
>         }
> -      val = build_vector_from_val (type, val);
>      }
>
>    new_var = vect_get_new_vect_var (type, vect_simple_var, "cst_");
> @@ -1350,16 +1384,19 @@ vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>     STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def.
>
>     In case OP is an invariant or constant, a new stmt that creates a vector def
> -   needs to be introduced.  */
> +   needs to be introduced.  VECTYPE may be used to specify a required type for
> +   vector invariant.  */
>
>  tree
> -vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
> +vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def,
> +                             tree vectype)
>  {
>    tree vec_oprnd;
>    gimple *vec_stmt;
>    gimple *def_stmt;
>    stmt_vec_info def_stmt_info = NULL;
>    stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
> +  tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
>    unsigned int nunits;
>    loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
>    tree def;
> @@ -1403,7 +1440,14 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>      /* Case 1: operand is a constant.  */
>      case vect_constant_def:
>        {
> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
> +       if (vectype)
> +         vector_type = vectype;
> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
> +       else
> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));

Rather than this...

> +
>         gcc_assert (vector_type);
>         nunits = TYPE_VECTOR_SUBPARTS (vector_type);
>
> @@ -1421,7 +1465,13 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>      /* Case 2: operand is defined outside the loop - loop invariant.  */
>      case vect_external_def:
>        {
> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
> +       if (vectype)
> +         vector_type = vectype;
> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
> +       else
> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
>         gcc_assert (vector_type);

and this ...

>         if (scalar_def)
> @@ -7437,13 +7487,13 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi,
>               gimple *gtemp;
>               vec_cond_lhs =
>               vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0),
> -                                           stmt, NULL);
> +                                           stmt, NULL, comp_vectype);
>               vect_is_simple_use (TREE_OPERAND (cond_expr, 0), stmt,
>                                   loop_vinfo, NULL, &gtemp, &def, &dts[0]);
>
>               vec_cond_rhs =
>                 vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
> -                                               stmt, NULL);
> +                                             stmt, NULL, comp_vectype);
>               vect_is_simple_use (TREE_OPERAND (cond_expr, 1), stmt,
>                                   loop_vinfo, NULL, &gtemp, &def, &dts[1]);

I'd simply open-code this here?

>               if (reduc_index == 1)
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index 23a82ee..1a1e509 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -1032,7 +1032,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
>  extern void vect_finish_stmt_generation (gimple *, gimple *,
>                                           gimple_stmt_iterator *);
>  extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
> -extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *);
> +extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *, tree = NULL);
>  extern tree vect_init_vector (gimple *, tree, tree,
>                                gimple_stmt_iterator *);
>  extern tree vect_get_vec_def_for_stmt_copy (enum vect_def_type, tree);
Ilya Enkovich Oct. 13, 2015, 2:52 p.m. UTC | #2
2015-10-13 16:54 GMT+03:00 Richard Biener <richard.guenther@gmail.com>:
> On Thu, Oct 8, 2015 at 5:11 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>> Hi,
>>
>> This patch adds a special handling of boolean vector invariants.  We need additional code to determine type of generated invariant.  For VEC_COND_EXPR case we even provide this type directly because statement vectype doesn't allow us to compute it.  Separate code is used to generate and expand such vectors.
>>
>> Thanks,
>> Ilya
>> --
>> gcc/
>>
>> 2015-10-08  Ilya Enkovich  <enkovich.gnu@gmail.com>
>>
>>         * expr.c (const_vector_mask_from_tree): New.
>>         (const_vector_from_tree): Use const_vector_mask_from_tree
>>         for boolean vectors.
>>         * tree-vect-stmts.c (vect_init_vector): Support boolean vector
>>         invariants.
>>         (vect_get_vec_def_for_operand): Add VECTYPE arg.
>>         (vectorizable_condition): Directly provide vectype for invariants
>>         used in comparison.
>>         * tree-vectorizer.h (vect_get_vec_def_for_operand): Add VECTYPE
>>         arg.
>>
>>
>> diff --git a/gcc/expr.c b/gcc/expr.c
>> index 88da8cb..a624a34 100644
>> --- a/gcc/expr.c
>> +++ b/gcc/expr.c
>> @@ -11320,6 +11320,40 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
>>    return 1;
>>  }
>>
>> +/* Return a CONST_VECTOR rtx representing vector mask for
>> +   a VECTOR_CST of booleans.  */
>> +static rtx
>> +const_vector_mask_from_tree (tree exp)
>> +{
>> +  rtvec v;
>> +  unsigned i;
>> +  int units;
>> +  tree elt;
>> +  machine_mode inner, mode;
>> +
>> +  mode = TYPE_MODE (TREE_TYPE (exp));
>> +  units = GET_MODE_NUNITS (mode);
>> +  inner = GET_MODE_INNER (mode);
>> +
>> +  v = rtvec_alloc (units);
>> +
>> +  for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
>> +    {
>> +      elt = VECTOR_CST_ELT (exp, i);
>> +
>> +      gcc_assert (TREE_CODE (elt) == INTEGER_CST);
>> +      if (integer_zerop (elt))
>> +       RTVEC_ELT (v, i) = CONST0_RTX (inner);
>> +      else if (integer_onep (elt)
>> +              || integer_minus_onep (elt))
>> +       RTVEC_ELT (v, i) = CONSTM1_RTX (inner);
>> +      else
>> +       gcc_unreachable ();
>> +    }
>> +
>> +  return gen_rtx_CONST_VECTOR (mode, v);
>> +}
>> +
>>  /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
>>  static rtx
>>  const_vector_from_tree (tree exp)
>> @@ -11335,6 +11369,9 @@ const_vector_from_tree (tree exp)
>>    if (initializer_zerop (exp))
>>      return CONST0_RTX (mode);
>>
>> +  if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp)))
>> +      return const_vector_mask_from_tree (exp);
>> +
>>    units = GET_MODE_NUNITS (mode);
>>    inner = GET_MODE_INNER (mode);
>>
>> diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
>> index 6949c71..337ea7b 100644
>> --- a/gcc/tree-vect-stmts.c
>> +++ b/gcc/tree-vect-stmts.c
>> @@ -1308,27 +1308,61 @@ vect_init_vector_1 (gimple *stmt, gimple *new_stmt, gimple_stmt_iterator *gsi)
>>  tree
>>  vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>>  {
>> +  tree val_type = TREE_TYPE (val);
>> +  machine_mode mode = TYPE_MODE (type);
>> +  machine_mode val_mode = TYPE_MODE(val_type);
>>    tree new_var;
>>    gimple *init_stmt;
>>    tree vec_oprnd;
>>    tree new_temp;
>>
>>    if (TREE_CODE (type) == VECTOR_TYPE
>> -      && TREE_CODE (TREE_TYPE (val)) != VECTOR_TYPE)
>> -    {
>> -      if (!types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
>> +      && TREE_CODE (val_type) != VECTOR_TYPE)
>> +    {
>> +      /* Handle vector of bool represented as a vector of
>> +        integers here rather than on expand because it is
>> +        a default mask type for targets.  Vector mask is
>> +        built in a following way:
>> +
>> +        tmp = (int)val
>> +        vec_tmp = {tmp, ..., tmp}
>> +        vec_cst = VIEW_CONVERT_EXPR<vector(N) _Bool>(vec_tmp);  */
>> +      if (TREE_CODE (val_type) == BOOLEAN_TYPE
>> +         && VECTOR_MODE_P (mode)
>> +         && SCALAR_INT_MODE_P (GET_MODE_INNER (mode))
>> +         && GET_MODE_INNER (mode) != val_mode)
>>         {
>> -         if (CONSTANT_CLASS_P (val))
>> -           val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
>> -         else
>> +         unsigned size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
>> +         tree stype = build_nonstandard_integer_type (size, 1);
>> +         tree vectype = get_vectype_for_scalar_type (stype);
>> +
>> +         new_temp = make_ssa_name (stype);
>> +         init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>> +         vect_init_vector_1 (stmt, init_stmt, gsi);
>> +
>> +         val = make_ssa_name (vectype);
>> +         new_temp = build_vector_from_val (vectype, new_temp);
>> +         init_stmt = gimple_build_assign (val, new_temp);
>> +         vect_init_vector_1 (stmt, init_stmt, gsi);
>> +
>> +         val = build1 (VIEW_CONVERT_EXPR, type, val);
>l
> So I don't quite understand - why don't we want to build
>
>    tmp = (bool-element-type)val;
>    vec_cst = {tmp, tmp, tmp ... };
>
> ?

This code was written at a time boolean vector elements always had
bitsize 1. I'll rework it in accordance with new boolean types.

>
>> +       }
>> +      else
>> +       {
>> +         if (!types_compatible_p (TREE_TYPE (type), val_type))
>>             {
>> -             new_temp = make_ssa_name (TREE_TYPE (type));
>> -             init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>> -             vect_init_vector_1 (stmt, init_stmt, gsi);
>> -             val = new_temp;
>> +             if (CONSTANT_CLASS_P (val))
>> +               val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
>> +             else
>> +               {
>> +                 new_temp = make_ssa_name (TREE_TYPE (type));
>> +                 init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>> +                 vect_init_vector_1 (stmt, init_stmt, gsi);
>> +                 val = new_temp;
>> +               }
>>             }
>> +         val = build_vector_from_val (type, val);
>>         }
>> -      val = build_vector_from_val (type, val);
>>      }
>>
>>    new_var = vect_get_new_vect_var (type, vect_simple_var, "cst_");
>> @@ -1350,16 +1384,19 @@ vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>>     STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def.
>>
>>     In case OP is an invariant or constant, a new stmt that creates a vector def
>> -   needs to be introduced.  */
>> +   needs to be introduced.  VECTYPE may be used to specify a required type for
>> +   vector invariant.  */
>>
>>  tree
>> -vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>> +vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def,
>> +                             tree vectype)
>>  {
>>    tree vec_oprnd;
>>    gimple *vec_stmt;
>>    gimple *def_stmt;
>>    stmt_vec_info def_stmt_info = NULL;
>>    stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
>> +  tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
>>    unsigned int nunits;
>>    loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
>>    tree def;
>> @@ -1403,7 +1440,14 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>>      /* Case 1: operand is a constant.  */
>>      case vect_constant_def:
>>        {
>> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
>> +       if (vectype)
>> +         vector_type = vectype;
>> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
>> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
>> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
>> +       else
>> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
>
> Rather than this...
>
>> +
>>         gcc_assert (vector_type);
>>         nunits = TYPE_VECTOR_SUBPARTS (vector_type);
>>
>> @@ -1421,7 +1465,13 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>>      /* Case 2: operand is defined outside the loop - loop invariant.  */
>>      case vect_external_def:
>>        {
>> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
>> +       if (vectype)
>> +         vector_type = vectype;
>> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
>> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
>> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
>> +       else
>> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
>>         gcc_assert (vector_type);
>
> and this ...
>
>>         if (scalar_def)
>> @@ -7437,13 +7487,13 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi,
>>               gimple *gtemp;
>>               vec_cond_lhs =
>>               vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0),
>> -                                           stmt, NULL);
>> +                                           stmt, NULL, comp_vectype);
>>               vect_is_simple_use (TREE_OPERAND (cond_expr, 0), stmt,
>>                                   loop_vinfo, NULL, &gtemp, &def, &dts[0]);
>>
>>               vec_cond_rhs =
>>                 vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
>> -                                               stmt, NULL);
>> +                                             stmt, NULL, comp_vectype);
>>               vect_is_simple_use (TREE_OPERAND (cond_expr, 1), stmt,
>>                                   loop_vinfo, NULL, &gtemp, &def, &dts[1]);
>
> I'd simply open-code this here?

I don't understand what you mean. vect_get_vec_def_for_operand has two
changes made.
1. For boolean invariants use build_same_sized_truth_vector_type
instead of get_vectype_for_scalar_type in case statement produces a
boolean vector. This covers cases when we use invariants in
comparison, AND, IOR, XOR.
2. COND_EXPR is an exception because it has built-in boolean vector
result not reflected in its vecinfo. Thus I added additional operand
for vect_get_vec_def_for_operand to directly specify vectype for
vector definition in case it is a loop invariant.
So what do you propose to do with these changes?

Thanks,
Ilya
Richard Biener Oct. 14, 2015, 8:49 a.m. UTC | #3
On Tue, Oct 13, 2015 at 4:52 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> 2015-10-13 16:54 GMT+03:00 Richard Biener <richard.guenther@gmail.com>:
>> On Thu, Oct 8, 2015 at 5:11 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>>> Hi,
>>>
>>> This patch adds a special handling of boolean vector invariants.  We need additional code to determine type of generated invariant.  For VEC_COND_EXPR case we even provide this type directly because statement vectype doesn't allow us to compute it.  Separate code is used to generate and expand such vectors.
>>>
>>> Thanks,
>>> Ilya
>>> --
>>> gcc/
>>>
>>> 2015-10-08  Ilya Enkovich  <enkovich.gnu@gmail.com>
>>>
>>>         * expr.c (const_vector_mask_from_tree): New.
>>>         (const_vector_from_tree): Use const_vector_mask_from_tree
>>>         for boolean vectors.
>>>         * tree-vect-stmts.c (vect_init_vector): Support boolean vector
>>>         invariants.
>>>         (vect_get_vec_def_for_operand): Add VECTYPE arg.
>>>         (vectorizable_condition): Directly provide vectype for invariants
>>>         used in comparison.
>>>         * tree-vectorizer.h (vect_get_vec_def_for_operand): Add VECTYPE
>>>         arg.
>>>
>>>
>>> diff --git a/gcc/expr.c b/gcc/expr.c
>>> index 88da8cb..a624a34 100644
>>> --- a/gcc/expr.c
>>> +++ b/gcc/expr.c
>>> @@ -11320,6 +11320,40 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
>>>    return 1;
>>>  }
>>>
>>> +/* Return a CONST_VECTOR rtx representing vector mask for
>>> +   a VECTOR_CST of booleans.  */
>>> +static rtx
>>> +const_vector_mask_from_tree (tree exp)
>>> +{
>>> +  rtvec v;
>>> +  unsigned i;
>>> +  int units;
>>> +  tree elt;
>>> +  machine_mode inner, mode;
>>> +
>>> +  mode = TYPE_MODE (TREE_TYPE (exp));
>>> +  units = GET_MODE_NUNITS (mode);
>>> +  inner = GET_MODE_INNER (mode);
>>> +
>>> +  v = rtvec_alloc (units);
>>> +
>>> +  for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
>>> +    {
>>> +      elt = VECTOR_CST_ELT (exp, i);
>>> +
>>> +      gcc_assert (TREE_CODE (elt) == INTEGER_CST);
>>> +      if (integer_zerop (elt))
>>> +       RTVEC_ELT (v, i) = CONST0_RTX (inner);
>>> +      else if (integer_onep (elt)
>>> +              || integer_minus_onep (elt))
>>> +       RTVEC_ELT (v, i) = CONSTM1_RTX (inner);
>>> +      else
>>> +       gcc_unreachable ();
>>> +    }
>>> +
>>> +  return gen_rtx_CONST_VECTOR (mode, v);
>>> +}
>>> +
>>>  /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
>>>  static rtx
>>>  const_vector_from_tree (tree exp)
>>> @@ -11335,6 +11369,9 @@ const_vector_from_tree (tree exp)
>>>    if (initializer_zerop (exp))
>>>      return CONST0_RTX (mode);
>>>
>>> +  if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp)))
>>> +      return const_vector_mask_from_tree (exp);
>>> +
>>>    units = GET_MODE_NUNITS (mode);
>>>    inner = GET_MODE_INNER (mode);
>>>
>>> diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
>>> index 6949c71..337ea7b 100644
>>> --- a/gcc/tree-vect-stmts.c
>>> +++ b/gcc/tree-vect-stmts.c
>>> @@ -1308,27 +1308,61 @@ vect_init_vector_1 (gimple *stmt, gimple *new_stmt, gimple_stmt_iterator *gsi)
>>>  tree
>>>  vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>>>  {
>>> +  tree val_type = TREE_TYPE (val);
>>> +  machine_mode mode = TYPE_MODE (type);
>>> +  machine_mode val_mode = TYPE_MODE(val_type);
>>>    tree new_var;
>>>    gimple *init_stmt;
>>>    tree vec_oprnd;
>>>    tree new_temp;
>>>
>>>    if (TREE_CODE (type) == VECTOR_TYPE
>>> -      && TREE_CODE (TREE_TYPE (val)) != VECTOR_TYPE)
>>> -    {
>>> -      if (!types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
>>> +      && TREE_CODE (val_type) != VECTOR_TYPE)
>>> +    {
>>> +      /* Handle vector of bool represented as a vector of
>>> +        integers here rather than on expand because it is
>>> +        a default mask type for targets.  Vector mask is
>>> +        built in a following way:
>>> +
>>> +        tmp = (int)val
>>> +        vec_tmp = {tmp, ..., tmp}
>>> +        vec_cst = VIEW_CONVERT_EXPR<vector(N) _Bool>(vec_tmp);  */
>>> +      if (TREE_CODE (val_type) == BOOLEAN_TYPE
>>> +         && VECTOR_MODE_P (mode)
>>> +         && SCALAR_INT_MODE_P (GET_MODE_INNER (mode))
>>> +         && GET_MODE_INNER (mode) != val_mode)
>>>         {
>>> -         if (CONSTANT_CLASS_P (val))
>>> -           val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
>>> -         else
>>> +         unsigned size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
>>> +         tree stype = build_nonstandard_integer_type (size, 1);
>>> +         tree vectype = get_vectype_for_scalar_type (stype);
>>> +
>>> +         new_temp = make_ssa_name (stype);
>>> +         init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>>> +         vect_init_vector_1 (stmt, init_stmt, gsi);
>>> +
>>> +         val = make_ssa_name (vectype);
>>> +         new_temp = build_vector_from_val (vectype, new_temp);
>>> +         init_stmt = gimple_build_assign (val, new_temp);
>>> +         vect_init_vector_1 (stmt, init_stmt, gsi);
>>> +
>>> +         val = build1 (VIEW_CONVERT_EXPR, type, val);
>>l
>> So I don't quite understand - why don't we want to build
>>
>>    tmp = (bool-element-type)val;
>>    vec_cst = {tmp, tmp, tmp ... };
>>
>> ?
>
> This code was written at a time boolean vector elements always had
> bitsize 1. I'll rework it in accordance with new boolean types.
>
>>
>>> +       }
>>> +      else
>>> +       {
>>> +         if (!types_compatible_p (TREE_TYPE (type), val_type))
>>>             {
>>> -             new_temp = make_ssa_name (TREE_TYPE (type));
>>> -             init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>>> -             vect_init_vector_1 (stmt, init_stmt, gsi);
>>> -             val = new_temp;
>>> +             if (CONSTANT_CLASS_P (val))
>>> +               val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
>>> +             else
>>> +               {
>>> +                 new_temp = make_ssa_name (TREE_TYPE (type));
>>> +                 init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
>>> +                 vect_init_vector_1 (stmt, init_stmt, gsi);
>>> +                 val = new_temp;
>>> +               }
>>>             }
>>> +         val = build_vector_from_val (type, val);
>>>         }
>>> -      val = build_vector_from_val (type, val);
>>>      }
>>>
>>>    new_var = vect_get_new_vect_var (type, vect_simple_var, "cst_");
>>> @@ -1350,16 +1384,19 @@ vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
>>>     STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def.
>>>
>>>     In case OP is an invariant or constant, a new stmt that creates a vector def
>>> -   needs to be introduced.  */
>>> +   needs to be introduced.  VECTYPE may be used to specify a required type for
>>> +   vector invariant.  */
>>>
>>>  tree
>>> -vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>>> +vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def,
>>> +                             tree vectype)
>>>  {
>>>    tree vec_oprnd;
>>>    gimple *vec_stmt;
>>>    gimple *def_stmt;
>>>    stmt_vec_info def_stmt_info = NULL;
>>>    stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
>>> +  tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
>>>    unsigned int nunits;
>>>    loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
>>>    tree def;
>>> @@ -1403,7 +1440,14 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>>>      /* Case 1: operand is a constant.  */
>>>      case vect_constant_def:
>>>        {
>>> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
>>> +       if (vectype)
>>> +         vector_type = vectype;
>>> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
>>> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
>>> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
>>> +       else
>>> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
>>
>> Rather than this...
>>
>>> +
>>>         gcc_assert (vector_type);
>>>         nunits = TYPE_VECTOR_SUBPARTS (vector_type);
>>>
>>> @@ -1421,7 +1465,13 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
>>>      /* Case 2: operand is defined outside the loop - loop invariant.  */
>>>      case vect_external_def:
>>>        {
>>> -       vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
>>> +       if (vectype)
>>> +         vector_type = vectype;
>>> +       else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
>>> +                && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
>>> +         vector_type = build_same_sized_truth_vector_type (stmt_vectype);
>>> +       else
>>> +         vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
>>>         gcc_assert (vector_type);
>>
>> and this ...
>>
>>>         if (scalar_def)
>>> @@ -7437,13 +7487,13 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi,
>>>               gimple *gtemp;
>>>               vec_cond_lhs =
>>>               vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0),
>>> -                                           stmt, NULL);
>>> +                                           stmt, NULL, comp_vectype);
>>>               vect_is_simple_use (TREE_OPERAND (cond_expr, 0), stmt,
>>>                                   loop_vinfo, NULL, &gtemp, &def, &dts[0]);
>>>
>>>               vec_cond_rhs =
>>>                 vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
>>> -                                               stmt, NULL);
>>> +                                             stmt, NULL, comp_vectype);
>>>               vect_is_simple_use (TREE_OPERAND (cond_expr, 1), stmt,
>>>                                   loop_vinfo, NULL, &gtemp, &def, &dts[1]);
>>
>> I'd simply open-code this here?
>
> I don't understand what you mean. vect_get_vec_def_for_operand has two
> changes made.
> 1. For boolean invariants use build_same_sized_truth_vector_type
> instead of get_vectype_for_scalar_type in case statement produces a
> boolean vector. This covers cases when we use invariants in
> comparison, AND, IOR, XOR.

Yes, I understand we need this special-casing to differentiate between
the vector type
used for boolean-typed loads/stores and the type for boolean typed constants.
What happens if we mix them btw, like with

  _Bool b = bools[i];
  _Bool c = b || d;
  ...

?

> 2. COND_EXPR is an exception because it has built-in boolean vector
> result not reflected in its vecinfo. Thus I added additional operand
> for vect_get_vec_def_for_operand to directly specify vectype for
> vector definition in case it is a loop invariant.
> So what do you propose to do with these changes?

This is the change I don't like and don't see why we need it.  It works today
and the comparison operands should be of appropriate type already?

Richard.

> Thanks,
> Ilya
Ilya Enkovich Oct. 14, 2015, 10:50 a.m. UTC | #4
2015-10-14 11:49 GMT+03:00 Richard Biener <richard.guenther@gmail.com>:
> On Tue, Oct 13, 2015 at 4:52 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>> I don't understand what you mean. vect_get_vec_def_for_operand has two
>> changes made.
>> 1. For boolean invariants use build_same_sized_truth_vector_type
>> instead of get_vectype_for_scalar_type in case statement produces a
>> boolean vector. This covers cases when we use invariants in
>> comparison, AND, IOR, XOR.
>
> Yes, I understand we need this special-casing to differentiate between
> the vector type
> used for boolean-typed loads/stores and the type for boolean typed constants.
> What happens if we mix them btw, like with
>
>   _Bool b = bools[i];
>   _Bool c = b || d;
>   ...
>
> ?

Here both statements should get vector of char as a vectype and we
never go VECTOR_BOOLEAN_TYPE_P way for them

>
>> 2. COND_EXPR is an exception because it has built-in boolean vector
>> result not reflected in its vecinfo. Thus I added additional operand
>> for vect_get_vec_def_for_operand to directly specify vectype for
>> vector definition in case it is a loop invariant.
>> So what do you propose to do with these changes?
>
> This is the change I don't like and don't see why we need it.  It works today
> and the comparison operands should be of appropriate type already?

Today it works because we always create vector of integer constant.
With boolean vectors it may be either integer vector or boolean vector
depending on context. Consider:

_Bool _1;
int _2;

_2 = _1 != 0 ? 0 : 1

We have two zero constants here requiring different vectypes.

Ilya

>
> Richard.
>
>> Thanks,
>> Ilya
diff mbox

Patch

diff --git a/gcc/expr.c b/gcc/expr.c
index 88da8cb..a624a34 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -11320,6 +11320,40 @@  try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
   return 1;
 }
 
+/* Return a CONST_VECTOR rtx representing vector mask for
+   a VECTOR_CST of booleans.  */
+static rtx
+const_vector_mask_from_tree (tree exp)
+{
+  rtvec v;
+  unsigned i;
+  int units;
+  tree elt;
+  machine_mode inner, mode;
+
+  mode = TYPE_MODE (TREE_TYPE (exp));
+  units = GET_MODE_NUNITS (mode);
+  inner = GET_MODE_INNER (mode);
+
+  v = rtvec_alloc (units);
+
+  for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
+    {
+      elt = VECTOR_CST_ELT (exp, i);
+
+      gcc_assert (TREE_CODE (elt) == INTEGER_CST);
+      if (integer_zerop (elt))
+	RTVEC_ELT (v, i) = CONST0_RTX (inner);
+      else if (integer_onep (elt)
+	       || integer_minus_onep (elt))
+	RTVEC_ELT (v, i) = CONSTM1_RTX (inner);
+      else
+	gcc_unreachable ();
+    }
+
+  return gen_rtx_CONST_VECTOR (mode, v);
+}
+
 /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
 static rtx
 const_vector_from_tree (tree exp)
@@ -11335,6 +11369,9 @@  const_vector_from_tree (tree exp)
   if (initializer_zerop (exp))
     return CONST0_RTX (mode);
 
+  if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp)))
+      return const_vector_mask_from_tree (exp);
+
   units = GET_MODE_NUNITS (mode);
   inner = GET_MODE_INNER (mode);
 
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 6949c71..337ea7b 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -1308,27 +1308,61 @@  vect_init_vector_1 (gimple *stmt, gimple *new_stmt, gimple_stmt_iterator *gsi)
 tree
 vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
 {
+  tree val_type = TREE_TYPE (val);
+  machine_mode mode = TYPE_MODE (type);
+  machine_mode val_mode = TYPE_MODE(val_type);
   tree new_var;
   gimple *init_stmt;
   tree vec_oprnd;
   tree new_temp;
 
   if (TREE_CODE (type) == VECTOR_TYPE
-      && TREE_CODE (TREE_TYPE (val)) != VECTOR_TYPE)
-    {
-      if (!types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
+      && TREE_CODE (val_type) != VECTOR_TYPE)
+    {
+      /* Handle vector of bool represented as a vector of
+	 integers here rather than on expand because it is
+	 a default mask type for targets.  Vector mask is
+	 built in a following way:
+
+	 tmp = (int)val
+	 vec_tmp = {tmp, ..., tmp}
+	 vec_cst = VIEW_CONVERT_EXPR<vector(N) _Bool>(vec_tmp);  */
+      if (TREE_CODE (val_type) == BOOLEAN_TYPE
+	  && VECTOR_MODE_P (mode)
+	  && SCALAR_INT_MODE_P (GET_MODE_INNER (mode))
+	  && GET_MODE_INNER (mode) != val_mode)
 	{
-	  if (CONSTANT_CLASS_P (val))
-	    val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
-	  else
+	  unsigned size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
+	  tree stype = build_nonstandard_integer_type (size, 1);
+	  tree vectype = get_vectype_for_scalar_type (stype);
+
+	  new_temp = make_ssa_name (stype);
+	  init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
+	  vect_init_vector_1 (stmt, init_stmt, gsi);
+
+	  val = make_ssa_name (vectype);
+	  new_temp = build_vector_from_val (vectype, new_temp);
+	  init_stmt = gimple_build_assign (val, new_temp);
+	  vect_init_vector_1 (stmt, init_stmt, gsi);
+
+	  val = build1 (VIEW_CONVERT_EXPR, type, val);
+	}
+      else
+	{
+	  if (!types_compatible_p (TREE_TYPE (type), val_type))
 	    {
-	      new_temp = make_ssa_name (TREE_TYPE (type));
-	      init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
-	      vect_init_vector_1 (stmt, init_stmt, gsi);
-	      val = new_temp;
+	      if (CONSTANT_CLASS_P (val))
+		val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val);
+	      else
+		{
+		  new_temp = make_ssa_name (TREE_TYPE (type));
+		  init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val);
+		  vect_init_vector_1 (stmt, init_stmt, gsi);
+		  val = new_temp;
+		}
 	    }
+	  val = build_vector_from_val (type, val);
 	}
-      val = build_vector_from_val (type, val);
     }
 
   new_var = vect_get_new_vect_var (type, vect_simple_var, "cst_");
@@ -1350,16 +1384,19 @@  vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi)
    STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def.
 
    In case OP is an invariant or constant, a new stmt that creates a vector def
-   needs to be introduced.  */
+   needs to be introduced.  VECTYPE may be used to specify a required type for
+   vector invariant.  */
 
 tree
-vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
+vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def,
+			      tree vectype)
 {
   tree vec_oprnd;
   gimple *vec_stmt;
   gimple *def_stmt;
   stmt_vec_info def_stmt_info = NULL;
   stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
+  tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
   unsigned int nunits;
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
   tree def;
@@ -1403,7 +1440,14 @@  vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
     /* Case 1: operand is a constant.  */
     case vect_constant_def:
       {
-	vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
+	if (vectype)
+	  vector_type = vectype;
+	else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
+		 && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
+	  vector_type = build_same_sized_truth_vector_type (stmt_vectype);
+	else
+	  vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
+
 	gcc_assert (vector_type);
 	nunits = TYPE_VECTOR_SUBPARTS (vector_type);
 
@@ -1421,7 +1465,13 @@  vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def)
     /* Case 2: operand is defined outside the loop - loop invariant.  */
     case vect_external_def:
       {
-	vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
+	if (vectype)
+	  vector_type = vectype;
+	else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
+		 && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
+	  vector_type = build_same_sized_truth_vector_type (stmt_vectype);
+	else
+	  vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
 	gcc_assert (vector_type);
 
 	if (scalar_def)
@@ -7437,13 +7487,13 @@  vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi,
 	      gimple *gtemp;
 	      vec_cond_lhs =
 	      vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0),
-					    stmt, NULL);
+					    stmt, NULL, comp_vectype);
 	      vect_is_simple_use (TREE_OPERAND (cond_expr, 0), stmt,
 				  loop_vinfo, NULL, &gtemp, &def, &dts[0]);
 
 	      vec_cond_rhs =
 		vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
-						stmt, NULL);
+					      stmt, NULL, comp_vectype);
 	      vect_is_simple_use (TREE_OPERAND (cond_expr, 1), stmt,
 				  loop_vinfo, NULL, &gtemp, &def, &dts[1]);
 	      if (reduc_index == 1)
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 23a82ee..1a1e509 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1032,7 +1032,7 @@  extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
 extern void vect_finish_stmt_generation (gimple *, gimple *,
                                          gimple_stmt_iterator *);
 extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
-extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *);
+extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *, tree = NULL);
 extern tree vect_init_vector (gimple *, tree, tree,
                               gimple_stmt_iterator *);
 extern tree vect_get_vec_def_for_stmt_copy (enum vect_def_type, tree);