diff mbox

vec_cond_expr adjustments

Message ID alpine.DEB.2.02.1209272348070.14099@stedding.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse Sept. 27, 2012, 10:42 p.m. UTC
Hello,

I have been experimenting with generating VEC_COND_EXPR from the 
front-end, and these are just a couple things I noticed.

1) optabs.c requires that the first argument of vec_cond_expr be a 
comparison, but verify_gimple_assign_ternary only checks 
is_gimple_condexpr, like for COND_EXPR. In the long term, it seems better 
to also allow ssa_name and vector_cst (thus match the is_gimple_condexpr 
condition), but for now I just want to know early if I created an invalid 
vec_cond_expr.

2) a little refactoring of the code to find a suitable vector type for 
comparison results, and one more place where it should be used (no 
testcase yet because I don't know if that path can be taken without 
front-end changes first). I did wonder, for tree-ssa-forwprop, about using 
directly TREE_TYPE (cond) without truth_type_for.

Hmm, now I am wondering whether I should have waited until I had front-end 
vec_cond_expr support to submit everything at once...

2012-09-27  Marc Glisse  <marc.glisse@inria.fr>

 	* tree-cfg.c (verify_gimple_assign_ternary): Stricter check on
 	first argument of VEC_COND_EXPR.
 	* tree.c (truth_type_for): New function.
 	* tree.h (truth_type_for): Declare.
 	* gimple-fold.c (and_comparisons_1): Call it.
 	(or_comparisons_1): Likewise.
 	* tree-ssa-forwprop.c (forward_propagate_into_cond): Likewise.

Comments

Richard Biener Sept. 28, 2012, 8:49 a.m. UTC | #1
On Fri, Sep 28, 2012 at 12:42 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> I have been experimenting with generating VEC_COND_EXPR from the front-end,
> and these are just a couple things I noticed.
>
> 1) optabs.c requires that the first argument of vec_cond_expr be a
> comparison, but verify_gimple_assign_ternary only checks is_gimple_condexpr,
> like for COND_EXPR. In the long term, it seems better to also allow ssa_name
> and vector_cst (thus match the is_gimple_condexpr condition), but for now I
> just want to know early if I created an invalid vec_cond_expr.

optabs should be fixed instead, an is_gimple_val condition is implicitely
val != 0.

> 2) a little refactoring of the code to find a suitable vector type for
> comparison results, and one more place where it should be used (no testcase
> yet because I don't know if that path can be taken without front-end changes
> first).

Yes, it looks fine to me.

> I did wonder, for tree-ssa-forwprop, about using directly TREE_TYPE
> (cond) without truth_type_for.

Yes, that should work.

> Hmm, now I am wondering whether I should have waited until I had front-end
> vec_cond_expr support to submit everything at once...

;)

The tree.[ch] and gimple-fold.c hunks are ok if tested properly, the
tree-ssa-forwprop.c idea of using TREE_TYPE (cond), too.

I don't like the tree-cfg.c change, instead re-factor optabs.c to
get a decomposed cond for vector_compare_rtx and appropriately
"decompose" a non-comparison-class cond in expand_vec_cond_expr.

If we for example have

 predicate = a < b;
 x = predicate ? d : e;
 y = predicate ? f : g;

we ideally want to re-use the predicate computation on targets where
that would be optimal (and combine should be able to recover the
case where it is not).

Thanks,
Richard.

> 2012-09-27  Marc Glisse  <marc.glisse@inria.fr>
>
>         * tree-cfg.c (verify_gimple_assign_ternary): Stricter check on
>         first argument of VEC_COND_EXPR.
>         * tree.c (truth_type_for): New function.
>         * tree.h (truth_type_for): Declare.
>         * gimple-fold.c (and_comparisons_1): Call it.
>         (or_comparisons_1): Likewise.
>         * tree-ssa-forwprop.c (forward_propagate_into_cond): Likewise.
>
> --
> Marc Glisse
> Index: gcc/tree-ssa-forwprop.c
> ===================================================================
> --- gcc/tree-ssa-forwprop.c     (revision 191810)
> +++ gcc/tree-ssa-forwprop.c     (working copy)
> @@ -549,21 +549,22 @@ static bool
>  forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
>  {
>    gimple stmt = gsi_stmt (*gsi_p);
>    tree tmp = NULL_TREE;
>    tree cond = gimple_assign_rhs1 (stmt);
>    bool swap = false;
>
>    /* We can do tree combining on SSA_NAME and comparison expressions.  */
>    if (COMPARISON_CLASS_P (cond))
>      tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
> -                                              boolean_type_node,
> +                                              truth_type_for
> +                                                (TREE_TYPE (cond)),
>                                                TREE_OPERAND (cond, 0),
>                                                TREE_OPERAND (cond, 1));
>    else if (TREE_CODE (cond) == SSA_NAME)
>      {
>        enum tree_code code;
>        tree name = cond;
>        gimple def_stmt = get_prop_source_stmt (name, true, NULL);
>        if (!def_stmt || !can_propagate_from (def_stmt))
>         return 0;
>
> Index: gcc/tree-cfg.c
> ===================================================================
> --- gcc/tree-cfg.c      (revision 191810)
> +++ gcc/tree-cfg.c      (working copy)
> @@ -3758,22 +3758,24 @@ verify_gimple_assign_ternary (gimple stm
>    tree rhs2_type = TREE_TYPE (rhs2);
>    tree rhs3 = gimple_assign_rhs3 (stmt);
>    tree rhs3_type = TREE_TYPE (rhs3);
>
>    if (!is_gimple_reg (lhs))
>      {
>        error ("non-register as LHS of ternary operation");
>        return true;
>      }
>
> -  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
> -       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
> +  if (((rhs_code == COND_EXPR) ? !is_gimple_condexpr (rhs1)
> +       : (rhs_code == VEC_COND_EXPR) ? (!is_gimple_condexpr (rhs1)
> +                                       || is_gimple_val (rhs1))
> +       : !is_gimple_val (rhs1))
>        || !is_gimple_val (rhs2)
>        || !is_gimple_val (rhs3))
>      {
>        error ("invalid operands in ternary operation");
>        return true;
>      }
>
>    /* First handle operations that involve different types.  */
>    switch (rhs_code)
>      {
> Index: gcc/gimple-fold.c
> ===================================================================
> --- gcc/gimple-fold.c   (revision 191810)
> +++ gcc/gimple-fold.c   (working copy)
> @@ -23,21 +23,20 @@ along with GCC; see the file COPYING3.
>  #include "coretypes.h"
>  #include "tm.h"
>  #include "tree.h"
>  #include "flags.h"
>  #include "function.h"
>  #include "dumpfile.h"
>  #include "tree-flow.h"
>  #include "tree-ssa-propagate.h"
>  #include "target.h"
>  #include "gimple-fold.h"
> -#include "langhooks.h"
>
>  /* Return true when DECL can be referenced from current unit.
>     FROM_DECL (if non-null) specify constructor of variable DECL was taken
> from.
>     We can get declarations that are not possible to reference for various
>     reasons:
>
>       1) When analyzing C++ virtual tables.
>         C++ virtual tables do have known constructors even
>         when they are keyed to other compilation unit.
>         Those tables can contain pointers to methods and vars
> @@ -1686,29 +1685,21 @@ and_var_with_comparison_1 (gimple stmt,
>     (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
>     If this can be done without constructing an intermediate value,
>     return the resulting tree; otherwise NULL_TREE is returned.
>     This function is deliberately asymmetric as it recurses on SSA_DEFs
>     in the first comparison but not the second.  */
>
>  static tree
>  and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
>                    enum tree_code code2, tree op2a, tree op2b)
>  {
> -  tree truth_type = boolean_type_node;
> -  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
> -    {
> -      tree vec_type = TREE_TYPE (op1a);
> -      tree elem = lang_hooks.types.type_for_size
> -       (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
> -      truth_type = build_opaque_vector_type (elem,
> -                                            TYPE_VECTOR_SUBPARTS
> (vec_type));
> -    }
> +  tree truth_type = truth_type_for (TREE_TYPE (op1a));
>
>    /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
>    if (operand_equal_p (op1a, op2a, 0)
>        && operand_equal_p (op1b, op2b, 0))
>      {
>        /* Result will be either NULL_TREE, or a combined comparison.  */
>        tree t = combine_comparisons (UNKNOWN_LOCATION,
>                                     TRUTH_ANDIF_EXPR, code1, code2,
>                                     truth_type, op1a, op1b);
>        if (t)
> @@ -2158,29 +2149,21 @@ or_var_with_comparison_1 (gimple stmt,
>     (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
>     If this can be done without constructing an intermediate value,
>     return the resulting tree; otherwise NULL_TREE is returned.
>     This function is deliberately asymmetric as it recurses on SSA_DEFs
>     in the first comparison but not the second.  */
>
>  static tree
>  or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
>                   enum tree_code code2, tree op2a, tree op2b)
>  {
> -  tree truth_type = boolean_type_node;
> -  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
> -    {
> -      tree vec_type = TREE_TYPE (op1a);
> -      tree elem = lang_hooks.types.type_for_size
> -       (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
> -      truth_type = build_opaque_vector_type (elem,
> -                                            TYPE_VECTOR_SUBPARTS
> (vec_type));
> -    }
> +  tree truth_type = truth_type_for (TREE_TYPE (op1a));
>
>    /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
>    if (operand_equal_p (op1a, op2a, 0)
>        && operand_equal_p (op1b, op2b, 0))
>      {
>        /* Result will be either NULL_TREE, or a combined comparison.  */
>        tree t = combine_comparisons (UNKNOWN_LOCATION,
>                                     TRUTH_ORIF_EXPR, code1, code2,
>                                     truth_type, op1a, op1b);
>        if (t)
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c  (revision 191810)
> +++ gcc/tree.c  (working copy)
> @@ -10243,20 +10243,36 @@ unsigned_type_for (tree type)
>  /* If TYPE is an integral or pointer type, return an integer type with
>     the same precision which is signed, or itself if TYPE is already a
>     signed integer type.  */
>
>  tree
>  signed_type_for (tree type)
>  {
>    return signed_or_unsigned_type_for (0, type);
>  }
>
> +/* If TYPE is a vector type, return a signed integer vector type with the
> +   same width and number of subparts. Otherwise return boolean_type_node.
> */
> +
> +tree
> +truth_type_for (tree type)
> +{
> +  if (TREE_CODE (type) == VECTOR_TYPE)
> +    {
> +      tree elem = lang_hooks.types.type_for_size
> +        (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (type))), 0);
> +      return build_opaque_vector_type (elem, TYPE_VECTOR_SUBPARTS (type));
> +    }
> +  else
> +    return boolean_type_node;
> +}
> +
>  /* Returns the largest value obtainable by casting something in INNER type
> to
>     OUTER type.  */
>
>  tree
>  upper_bound_in_type (tree outer, tree inner)
>  {
>    double_int high;
>    unsigned int det = 0;
>    unsigned oprec = TYPE_PRECISION (outer);
>    unsigned iprec = TYPE_PRECISION (inner);
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h  (revision 191810)
> +++ gcc/tree.h  (working copy)
> @@ -4762,20 +4762,21 @@ extern tree build_call_valist (tree, tre
>  extern tree build_call_array_loc (location_t, tree, tree, int, const tree
> *);
>  extern tree build_call_vec (tree, tree, VEC(tree,gc) *);
>
>  /* Construct various nodes representing data types.  */
>
>  extern tree make_signed_type (int);
>  extern tree make_unsigned_type (int);
>  extern tree signed_or_unsigned_type_for (int, tree);
>  extern tree signed_type_for (tree);
>  extern tree unsigned_type_for (tree);
> +extern tree truth_type_for (tree);
>  extern void initialize_sizetypes (void);
>  extern void fixup_unsigned_type (tree);
>  extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool);
>  extern tree build_pointer_type (tree);
>  extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
>  extern tree build_reference_type (tree);
>  extern tree build_vector_type_for_mode (tree, enum machine_mode);
>  extern tree build_vector_type (tree innertype, int nunits);
>  extern tree build_opaque_vector_type (tree innertype, int nunits);
>  extern tree build_type_no_quals (tree);
>
Marc Glisse Sept. 28, 2012, 4:55 p.m. UTC | #2
On Fri, 28 Sep 2012, Richard Guenther wrote:

> On Fri, Sep 28, 2012 at 12:42 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
>> Hello,
>>
>> I have been experimenting with generating VEC_COND_EXPR from the front-end,
>> and these are just a couple things I noticed.
>>
>> 1) optabs.c requires that the first argument of vec_cond_expr be a
>> comparison, but verify_gimple_assign_ternary only checks is_gimple_condexpr,
>> like for COND_EXPR. In the long term, it seems better to also allow ssa_name
>> and vector_cst (thus match the is_gimple_condexpr condition), but for now I
>> just want to know early if I created an invalid vec_cond_expr.
>
> optabs should be fixed instead, an is_gimple_val condition is implicitely
> val != 0.

For vectors, I think it should be val < 0 (with an appropriate cast of val 
to a signed integer vector type if necessary). Or (val & highbit) != 0, 
but that's longer.

> The tree.[ch] and gimple-fold.c hunks are ok if tested properly, the
> tree-ssa-forwprop.c idea of using TREE_TYPE (cond), too.

Ok, I will retest that way.

> I don't like the tree-cfg.c change, instead re-factor optabs.c to
> get a decomposed cond for vector_compare_rtx and appropriately
> "decompose" a non-comparison-class cond in expand_vec_cond_expr.

So vector_compare_rtx will take as arguments rcode, t_op0, t_op1 instead 
of cond. And in expand_vec_cond_expr, if I have a condition, I pass its 
elements to vector_compare_rtx, and otherwise I use 0 and the code for 
LT_EXPR as the other arguments.

> If we for example have
>
> predicate = a < b;
> x = predicate ? d : e;
> y = predicate ? f : g;
>
> we ideally want to re-use the predicate computation on targets where
> that would be optimal (and combine should be able to recover the
> case where it is not).

That I don't understand. The vcond instruction implemented by targets 
takes as arguments d, e, cmp, a, b and emits the comparison itself. I 
don't see how I can avoid sending to the targets both (d,e,<,a,b) and 
(f,g,<,a,b). They will notice eventually that a<b is computed twice and 
remove one of the two, but I don't see how to do that in optabs.c. Or I 
can compute x = a < b, use x < 0 as the comparison passed to the targets, 
and expect targets (those for which it is true) to recognize that < 0 is 
useless in a vector condition (PR54700), or is useless on a comparison 
result.

Thanks for the comments,
Richard Biener Oct. 1, 2012, 9:30 a.m. UTC | #3
On Fri, Sep 28, 2012 at 6:55 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> On Fri, 28 Sep 2012, Richard Guenther wrote:
>
>> On Fri, Sep 28, 2012 at 12:42 AM, Marc Glisse <marc.glisse@inria.fr>
>> wrote:
>>>
>>> Hello,
>>>
>>> I have been experimenting with generating VEC_COND_EXPR from the
>>> front-end,
>>> and these are just a couple things I noticed.
>>>
>>> 1) optabs.c requires that the first argument of vec_cond_expr be a
>>> comparison, but verify_gimple_assign_ternary only checks
>>> is_gimple_condexpr,
>>> like for COND_EXPR. In the long term, it seems better to also allow
>>> ssa_name
>>> and vector_cst (thus match the is_gimple_condexpr condition), but for now
>>> I
>>> just want to know early if I created an invalid vec_cond_expr.
>>
>>
>> optabs should be fixed instead, an is_gimple_val condition is implicitely
>> val != 0.
>
>
> For vectors, I think it should be val < 0 (with an appropriate cast of val
> to a signed integer vector type if necessary). Or (val & highbit) != 0, but
> that's longer.

I don't think so.  Throughout the compiler we generally assume false == 0
and anything else is true.  (yes, for FP there is STORE_FLAG_VALUE, but
it's scope is quite limited - if we want sth similar for vectors we'd have to
invent it).

>> The tree.[ch] and gimple-fold.c hunks are ok if tested properly, the
>> tree-ssa-forwprop.c idea of using TREE_TYPE (cond), too.
>
>
> Ok, I will retest that way.
>
>
>> I don't like the tree-cfg.c change, instead re-factor optabs.c to
>> get a decomposed cond for vector_compare_rtx and appropriately
>> "decompose" a non-comparison-class cond in expand_vec_cond_expr.
>
>
> So vector_compare_rtx will take as arguments rcode, t_op0, t_op1 instead of
> cond.

Yes.

> And in expand_vec_cond_expr, if I have a condition, I pass its
> elements to vector_compare_rtx, and otherwise I use 0 and the code for
> LT_EXPR as the other arguments.

Yes, but NE_EXPR and 0 (see above).

>
>> If we for example have
>>
>> predicate = a < b;
>> x = predicate ? d : e;
>> y = predicate ? f : g;
>>
>> we ideally want to re-use the predicate computation on targets where
>> that would be optimal (and combine should be able to recover the
>> case where it is not).
>
>
> That I don't understand. The vcond instruction implemented by targets takes
> as arguments d, e, cmp, a, b and emits the comparison itself. I don't see
> how I can avoid sending to the targets both (d,e,<,a,b) and (f,g,<,a,b).
> They will notice eventually that a<b is computed twice and remove one of the
> two, but I don't see how to do that in optabs.c. Or I can compute x = a < b,
> use x < 0 as the comparison passed to the targets, and expect targets (those
> for which it is true) to recognize that < 0 is useless in a vector condition
> (PR54700), or is useless on a comparison result.

But that's a limitation of how vcond works.  ISTR there is/was a vselect
instruction as well, taking a "mask" and two vectors to select from.  At least
that's how vcond works internally for some sub-targets.

Richard.

> Thanks for the comments,
>
> --
> Marc Glisse
diff mbox

Patch

Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c	(revision 191810)
+++ gcc/tree-ssa-forwprop.c	(working copy)
@@ -549,21 +549,22 @@  static bool
 forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
 {
   gimple stmt = gsi_stmt (*gsi_p);
   tree tmp = NULL_TREE;
   tree cond = gimple_assign_rhs1 (stmt);
   bool swap = false;
 
   /* We can do tree combining on SSA_NAME and comparison expressions.  */
   if (COMPARISON_CLASS_P (cond))
     tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
-					       boolean_type_node,
+					       truth_type_for
+						 (TREE_TYPE (cond)),
 					       TREE_OPERAND (cond, 0),
 					       TREE_OPERAND (cond, 1));
   else if (TREE_CODE (cond) == SSA_NAME)
     {
       enum tree_code code;
       tree name = cond;
       gimple def_stmt = get_prop_source_stmt (name, true, NULL);
       if (!def_stmt || !can_propagate_from (def_stmt))
 	return 0;
 
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(revision 191810)
+++ gcc/tree-cfg.c	(working copy)
@@ -3758,22 +3758,24 @@  verify_gimple_assign_ternary (gimple stm
   tree rhs2_type = TREE_TYPE (rhs2);
   tree rhs3 = gimple_assign_rhs3 (stmt);
   tree rhs3_type = TREE_TYPE (rhs3);
 
   if (!is_gimple_reg (lhs))
     {
       error ("non-register as LHS of ternary operation");
       return true;
     }
 
-  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
-       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
+  if (((rhs_code == COND_EXPR) ? !is_gimple_condexpr (rhs1)
+       : (rhs_code == VEC_COND_EXPR) ? (!is_gimple_condexpr (rhs1)
+					|| is_gimple_val (rhs1))
+       : !is_gimple_val (rhs1))
       || !is_gimple_val (rhs2)
       || !is_gimple_val (rhs3))
     {
       error ("invalid operands in ternary operation");
       return true;
     }
 
   /* First handle operations that involve different types.  */
   switch (rhs_code)
     {
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 191810)
+++ gcc/gimple-fold.c	(working copy)
@@ -23,21 +23,20 @@  along with GCC; see the file COPYING3.
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
 #include "function.h"
 #include "dumpfile.h"
 #include "tree-flow.h"
 #include "tree-ssa-propagate.h"
 #include "target.h"
 #include "gimple-fold.h"
-#include "langhooks.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
    We can get declarations that are not possible to reference for various
    reasons:
 
      1) When analyzing C++ virtual tables.
 	C++ virtual tables do have known constructors even
 	when they are keyed to other compilation unit.
 	Those tables can contain pointers to methods and vars
@@ -1686,29 +1685,21 @@  and_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree truth_type = boolean_type_node;
-  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
-    {
-      tree vec_type = TREE_TYPE (op1a);
-      tree elem = lang_hooks.types.type_for_size
-	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
-      truth_type = build_opaque_vector_type (elem,
-					     TYPE_VECTOR_SUBPARTS (vec_type));
-    }
+  tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ANDIF_EXPR, code1, code2,
 				    truth_type, op1a, op1b);
       if (t)
@@ -2158,29 +2149,21 @@  or_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
-  tree truth_type = boolean_type_node;
-  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
-    {
-      tree vec_type = TREE_TYPE (op1a);
-      tree elem = lang_hooks.types.type_for_size
-	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
-      truth_type = build_opaque_vector_type (elem,
-					     TYPE_VECTOR_SUBPARTS (vec_type));
-    }
+  tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ORIF_EXPR, code1, code2,
 				    truth_type, op1a, op1b);
       if (t)
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 191810)
+++ gcc/tree.c	(working copy)
@@ -10243,20 +10243,36 @@  unsigned_type_for (tree type)
 /* If TYPE is an integral or pointer type, return an integer type with
    the same precision which is signed, or itself if TYPE is already a
    signed integer type.  */
 
 tree
 signed_type_for (tree type)
 {
   return signed_or_unsigned_type_for (0, type);
 }
 
+/* If TYPE is a vector type, return a signed integer vector type with the
+   same width and number of subparts. Otherwise return boolean_type_node.  */
+
+tree
+truth_type_for (tree type)
+{
+  if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      tree elem = lang_hooks.types.type_for_size
+        (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (type))), 0);
+      return build_opaque_vector_type (elem, TYPE_VECTOR_SUBPARTS (type));
+    }
+  else
+    return boolean_type_node;
+}
+
 /* Returns the largest value obtainable by casting something in INNER type to
    OUTER type.  */
 
 tree
 upper_bound_in_type (tree outer, tree inner)
 {
   double_int high;
   unsigned int det = 0;
   unsigned oprec = TYPE_PRECISION (outer);
   unsigned iprec = TYPE_PRECISION (inner);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 191810)
+++ gcc/tree.h	(working copy)
@@ -4762,20 +4762,21 @@  extern tree build_call_valist (tree, tre
 extern tree build_call_array_loc (location_t, tree, tree, int, const tree *);
 extern tree build_call_vec (tree, tree, VEC(tree,gc) *);
 
 /* Construct various nodes representing data types.  */
 
 extern tree make_signed_type (int);
 extern tree make_unsigned_type (int);
 extern tree signed_or_unsigned_type_for (int, tree);
 extern tree signed_type_for (tree);
 extern tree unsigned_type_for (tree);
+extern tree truth_type_for (tree);
 extern void initialize_sizetypes (void);
 extern void fixup_unsigned_type (tree);
 extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_pointer_type (tree);
 extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_reference_type (tree);
 extern tree build_vector_type_for_mode (tree, enum machine_mode);
 extern tree build_vector_type (tree innertype, int nunits);
 extern tree build_opaque_vector_type (tree innertype, int nunits);
 extern tree build_type_no_quals (tree);