diff mbox series

[v3,1/9] Allow COND_EXPR and VEC_COND_EXPR condtions to trap

Message ID 20190905111019.8951-2-iii@linux.ibm.com
State New
Headers show
Series S/390: Use signaling FP comparison instructions | expand

Commit Message

Ilya Leoshkevich Sept. 5, 2019, 11:10 a.m. UTC
Right now gimplifier does not allow VEC_COND_EXPR's condition to trap
and introduces a temporary if this could happen, for example, generating

  _5 = _4 > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 };
  _6 = VEC_COND_EXPR <_5, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>;

from GENERIC

  VEC_COND_EXPR < (*b > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 }) ,
                  { -1, -1, -1, -1 } ,
		  { 0, 0, 0, 0 } >

This is not necessary and makes the resulting GIMPLE harder to analyze.
In particular, one of the next patches in series needs to get to
VEC_COND_EXPR's comparison code, which is not possible when a temporary
is introduced.

This patch takes special care to avoid introducing trapping comparisons
in GIMPLE_COND.  They are not allowed, because they would require 3
outgoing edges (then, else and EH), which is awkward to say the least.
Therefore, computations of such conditions should live in their own basic
blocks.

gcc/ChangeLog:

2019-09-03  Ilya Leoshkevich  <iii@linux.ibm.com>

	PR target/77918
	* gimple-expr.c (gimple_cond_get_ops_from_tree): Assert that the
	caller passes a non-trapping condition.
	(is_gimple_condexpr): Allow trapping conditions.
	(is_gimple_condexpr_1): New helper function.
	(is_gimple_condexpr_for_cond): New function, acts like old
	is_gimple_condexpr.
	* gimple-expr.h (is_gimple_condexpr_for_cond): New function.
	(gimple_ternary_operands_ok_p): New function to remove code
	duplication i verify_gimple_assign_ternary and
	valid_gimple_rhs_p.
	* gimple.c (gimple_could_trap_p_1): Handle COND_EXPR and
	VEC_COND_EXPR.
	* gimplify.c (gimplify_cond_expr): Use
	is_gimple_condexpr_for_cond.
	(gimplify_expr): Allow is_gimple_condexpr_for_cond.
	* tree-cfg.c (verify_gimple_assign_ternary): Use
	gimple_ternary_operands_ok_p.
	* tree-eh.c (operation_could_trap_p): Assert on COND_EXPR and
	VEC_COND_EXPR.
	(tree_could_trap_p): Handle COND_EXPR and VEC_COND_EXPR.
	* tree-ssa-forwprop.c (forward_propagate_into_gimple_cond): Use
	is_gimple_condexpr_for_cond, remove pointless tmp check
	(forward_propagate_into_cond): Remove pointless tmp check.
	* tree-ssa-propagate.c (valid_gimple_rhs_p): Use
	gimple_ternary_operands_ok_p.
---
 gcc/gimple-expr.c        | 25 +++++++++++++++++++++----
 gcc/gimple-expr.h        | 11 +++++++++++
 gcc/gimple.c             |  2 ++
 gcc/gimplify.c           |  5 +++--
 gcc/tree-cfg.c           |  5 +----
 gcc/tree-eh.c            |  8 ++++++++
 gcc/tree-ssa-forwprop.c  |  7 ++++---
 gcc/tree-ssa-propagate.c |  9 ++++-----
 8 files changed, 54 insertions(+), 18 deletions(-)

Comments

Richard Biener Sept. 6, 2019, 11:07 a.m. UTC | #1
On Thu, Sep 5, 2019 at 1:10 PM Ilya Leoshkevich <iii@linux.ibm.com> wrote:
>
> Right now gimplifier does not allow VEC_COND_EXPR's condition to trap
> and introduces a temporary if this could happen, for example, generating
>
>   _5 = _4 > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 };
>   _6 = VEC_COND_EXPR <_5, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>;
>
> from GENERIC
>
>   VEC_COND_EXPR < (*b > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 }) ,
>                   { -1, -1, -1, -1 } ,
>                   { 0, 0, 0, 0 } >
>
> This is not necessary and makes the resulting GIMPLE harder to analyze.
> In particular, one of the next patches in series needs to get to
> VEC_COND_EXPR's comparison code, which is not possible when a temporary
> is introduced.
>
> This patch takes special care to avoid introducing trapping comparisons
> in GIMPLE_COND.  They are not allowed, because they would require 3
> outgoing edges (then, else and EH), which is awkward to say the least.
> Therefore, computations of such conditions should live in their own basic
> blocks.

Comments inline (thanks for the work btw)

> gcc/ChangeLog:
>
> 2019-09-03  Ilya Leoshkevich  <iii@linux.ibm.com>
>
>         PR target/77918
>         * gimple-expr.c (gimple_cond_get_ops_from_tree): Assert that the
>         caller passes a non-trapping condition.
>         (is_gimple_condexpr): Allow trapping conditions.
>         (is_gimple_condexpr_1): New helper function.
>         (is_gimple_condexpr_for_cond): New function, acts like old
>         is_gimple_condexpr.
>         * gimple-expr.h (is_gimple_condexpr_for_cond): New function.
>         (gimple_ternary_operands_ok_p): New function to remove code
>         duplication i verify_gimple_assign_ternary and
>         valid_gimple_rhs_p.
>         * gimple.c (gimple_could_trap_p_1): Handle COND_EXPR and
>         VEC_COND_EXPR.
>         * gimplify.c (gimplify_cond_expr): Use
>         is_gimple_condexpr_for_cond.
>         (gimplify_expr): Allow is_gimple_condexpr_for_cond.
>         * tree-cfg.c (verify_gimple_assign_ternary): Use
>         gimple_ternary_operands_ok_p.
>         * tree-eh.c (operation_could_trap_p): Assert on COND_EXPR and
>         VEC_COND_EXPR.
>         (tree_could_trap_p): Handle COND_EXPR and VEC_COND_EXPR.
>         * tree-ssa-forwprop.c (forward_propagate_into_gimple_cond): Use
>         is_gimple_condexpr_for_cond, remove pointless tmp check
>         (forward_propagate_into_cond): Remove pointless tmp check.
>         * tree-ssa-propagate.c (valid_gimple_rhs_p): Use
>         gimple_ternary_operands_ok_p.
> ---
>  gcc/gimple-expr.c        | 25 +++++++++++++++++++++----
>  gcc/gimple-expr.h        | 11 +++++++++++
>  gcc/gimple.c             |  2 ++
>  gcc/gimplify.c           |  5 +++--
>  gcc/tree-cfg.c           |  5 +----
>  gcc/tree-eh.c            |  8 ++++++++
>  gcc/tree-ssa-forwprop.c  |  7 ++++---
>  gcc/tree-ssa-propagate.c |  9 ++++-----
>  8 files changed, 54 insertions(+), 18 deletions(-)
>
> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
> index b0c9f9b671a..46e5f000580 100644
> --- a/gcc/gimple-expr.c
> +++ b/gcc/gimple-expr.c
> @@ -571,6 +571,7 @@ gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
>               || TREE_CODE (cond) == TRUTH_NOT_EXPR
>               || is_gimple_min_invariant (cond)
>               || SSA_VAR_P (cond));
> +  gcc_assert (!tree_could_throw_p (cond));

make this gcc_checking_assert ()

>    extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
>
> @@ -602,17 +603,33 @@ is_gimple_lvalue (tree t)
>           || TREE_CODE (t) == BIT_FIELD_REF);
>  }
>
> -/*  Return true if T is a GIMPLE condition.  */
> +/* Helper for is_gimple_condexpr and is_gimple_condexpr_for_cond.  */
>
> -bool
> -is_gimple_condexpr (tree t)
> +static bool
> +is_gimple_condexpr_1 (tree t, bool allow_traps)
>  {
>    return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
> -                               && !tree_could_throw_p (t)
> +                               && (allow_traps || !tree_could_throw_p (t))
>                                 && is_gimple_val (TREE_OPERAND (t, 0))
>                                 && is_gimple_val (TREE_OPERAND (t, 1))));
>  }
>
> +/*  Return true if T is a GIMPLE condition.  */
> +
> +bool
> +is_gimple_condexpr (tree t)
> +{
> +  return is_gimple_condexpr_1 (t, true);
> +}
> +
> +/* Like is_gimple_condexpr, but does not allow T to trap.  */
> +
> +bool
> +is_gimple_condexpr_for_cond (tree t)
> +{
> +  return is_gimple_condexpr_1 (t, false);
> +}
> +
>  /* Return true if T is a gimple address.  */
>
>  bool
> diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
> index 1ad1432bd17..27190b1e5fe 100644
> --- a/gcc/gimple-expr.h
> +++ b/gcc/gimple-expr.h
> @@ -41,6 +41,7 @@ extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
>                                            tree *);
>  extern bool is_gimple_lvalue (tree);
>  extern bool is_gimple_condexpr (tree);
> +extern bool is_gimple_condexpr_for_cond (tree);
>  extern bool is_gimple_address (const_tree);
>  extern bool is_gimple_invariant_address (const_tree);
>  extern bool is_gimple_ip_invariant_address (const_tree);
> @@ -175,4 +176,14 @@ gimple_call_addr_fndecl (const_tree fn)
>    return NULL_TREE;
>  }
>
> +static inline bool
> +gimple_ternary_operands_ok_p (enum tree_code code, tree op1, tree op2, tree op3)
> +{
> +  return ((code == VEC_COND_EXPR || code == COND_EXPR)
> +         ? is_gimple_condexpr (op1)
> +         : is_gimple_val (op1))
> +        && is_gimple_val (op2)
> +        && is_gimple_val (op3);
> +}

Hmm, I don't like this too much, please simply adjust the
two places you use it (there's actually nothign to adjust?)

>  #endif /* GCC_GIMPLE_EXPR_H */
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 633ef512a19..fd14fbec15e 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -2144,6 +2144,8 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
>        op = gimple_assign_rhs_code (s);
>        if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
>         div = gimple_assign_rhs2 (s);
> +      else if (op == COND_EXPR || op == VEC_COND_EXPR)
> +       op = TREE_CODE (gimple_assign_rhs1 (s));

I think this is not correct since we can have

int i = fp > 1. ? intval1 : intval2

and thus FLOAT_TYPE_P (t)  is wrong.  You need to do

  t = TREE_TYPE (op);

as well I think.

OK with those changes - you can apply this independently of the rest of the
series btw.

Thanks,
Richard.

>        return (operation_could_trap_p (op, FLOAT_TYPE_P (t),
>                                       (INTEGRAL_TYPE_P (t)
>                                        && TYPE_OVERFLOW_TRAPS (t)),
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index daa0b71c191..920e423381c 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -4141,8 +4141,8 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
>    /* Now do the normal gimplification.  */
>
>    /* Gimplify condition.  */
> -  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, is_gimple_condexpr,
> -                      fb_rvalue);
> +  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
> +                      is_gimple_condexpr_for_cond, fb_rvalue);
>    if (ret == GS_ERROR)
>      return GS_ERROR;
>    gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE);
> @@ -12973,6 +12973,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>    else if (gimple_test_f == is_gimple_val
>             || gimple_test_f == is_gimple_call_addr
>             || gimple_test_f == is_gimple_condexpr
> +          || gimple_test_f == is_gimple_condexpr_for_cond
>             || gimple_test_f == is_gimple_mem_rhs
>             || gimple_test_f == is_gimple_mem_rhs_or_call
>             || gimple_test_f == is_gimple_reg_rhs
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index b75fdb2e63f..4d2239e9d2f 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -4121,10 +4121,7 @@ verify_gimple_assign_ternary (gassign *stmt)
>        return true;
>      }
>
> -  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
> -       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
> -      || !is_gimple_val (rhs2)
> -      || !is_gimple_val (rhs3))
> +  if (!gimple_ternary_operands_ok_p (rhs_code, rhs1, rhs2, rhs3))
>      {
>        error ("invalid operands in ternary operation");
>        return true;
> diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
> index 5bb07e49d28..98dc95a07cd 100644
> --- a/gcc/tree-eh.c
> +++ b/gcc/tree-eh.c
> @@ -2523,6 +2523,10 @@ operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
>    bool honor_snans = fp_operation && flag_signaling_nans != 0;
>    bool handled;
>
> +  /* This function cannot tell whether or not COND_EXPR and VEC_COND_EXPR could
> +     trap, because that depends on the respective condition op.  */
> +  gcc_assert (op != COND_EXPR && op != VEC_COND_EXPR);
> +
>    if (TREE_CODE_CLASS (op) != tcc_comparison
>        && TREE_CODE_CLASS (op) != tcc_unary
>        && TREE_CODE_CLASS (op) != tcc_binary)
> @@ -2610,6 +2614,10 @@ tree_could_trap_p (tree expr)
>    if (!expr)
>      return false;
>
> +  /* For COND_EXPR and VEC_COND_EXPR, only the condition may trap.  */
> +  if (TREE_CODE (expr) == COND_EXPR || TREE_CODE (expr) == VEC_COND_EXPR)
> +    expr = TREE_OPERAND (expr, 0);
> +
>    code = TREE_CODE (expr);
>    t = TREE_TYPE (expr);
>
> diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
> index c464c899586..edc5417f455 100644
> --- a/gcc/tree-ssa-forwprop.c
> +++ b/gcc/tree-ssa-forwprop.c
> @@ -524,9 +524,10 @@ forward_propagate_into_gimple_cond (gcond *stmt)
>    tmp = forward_propagate_into_comparison_1 (stmt, code,
>                                              boolean_type_node,
>                                              rhs1, rhs2);
> -  if (tmp)
> +  if (tmp
> +      && is_gimple_condexpr_for_cond (tmp))
>      {
> -      if (dump_file && tmp)
> +      if (dump_file)
>         {
>           fprintf (dump_file, "  Replaced '");
>           print_gimple_expr (dump_file, stmt, 0);
> @@ -604,7 +605,7 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
>    if (tmp
>        && is_gimple_condexpr (tmp))
>      {
> -      if (dump_file && tmp)
> +      if (dump_file)
>         {
>           fprintf (dump_file, "  Replaced '");
>           print_generic_expr (dump_file, cond);
> diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
> index 7172ef8b4e6..be34e25fc40 100644
> --- a/gcc/tree-ssa-propagate.c
> +++ b/gcc/tree-ssa-propagate.c
> @@ -523,11 +523,10 @@ valid_gimple_rhs_p (tree expr)
>         default:
>           if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS)
>             {
> -             if (((code == VEC_COND_EXPR || code == COND_EXPR)
> -                  ? !is_gimple_condexpr (TREE_OPERAND (expr, 0))
> -                  : !is_gimple_val (TREE_OPERAND (expr, 0)))
> -                 || !is_gimple_val (TREE_OPERAND (expr, 1))
> -                 || !is_gimple_val (TREE_OPERAND (expr, 2)))
> +             if (!gimple_ternary_operands_ok_p (code,
> +                                                TREE_OPERAND (expr, 0),
> +                                                TREE_OPERAND (expr, 1),
> +                                                TREE_OPERAND (expr, 2)))
>                 return false;
>               break;
>             }
> --
> 2.21.0
>
Ilya Leoshkevich Sept. 6, 2019, 3:45 p.m. UTC | #2
> Am 06.09.2019 um 13:07 schrieb Richard Biener <richard.guenther@gmail.com>:
> 
> On Thu, Sep 5, 2019 at 1:10 PM Ilya Leoshkevich <iii@linux.ibm.com> wrote:
>> 
>> Right now gimplifier does not allow VEC_COND_EXPR's condition to trap
>> and introduces a temporary if this could happen, for example, generating
>> 
>>  _5 = _4 > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 };
>>  _6 = VEC_COND_EXPR <_5, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>;
>> 
>> from GENERIC
>> 
>>  VEC_COND_EXPR < (*b > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 }) ,
>>                  { -1, -1, -1, -1 } ,
>>                  { 0, 0, 0, 0 } >
>> 
>> This is not necessary and makes the resulting GIMPLE harder to analyze.
>> In particular, one of the next patches in series needs to get to
>> VEC_COND_EXPR's comparison code, which is not possible when a temporary
>> is introduced.
>> 
>> This patch takes special care to avoid introducing trapping comparisons
>> in GIMPLE_COND.  They are not allowed, because they would require 3
>> outgoing edges (then, else and EH), which is awkward to say the least.
>> Therefore, computations of such conditions should live in their own basic
>> blocks.
> 
> Comments inline (thanks for the work btw)
> 
>> #endif /* GCC_GIMPLE_EXPR_H */
>> diff --git a/gcc/gimple.c b/gcc/gimple.c
>> index 633ef512a19..fd14fbec15e 100644
>> --- a/gcc/gimple.c
>> +++ b/gcc/gimple.c
>> @@ -2144,6 +2144,8 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
>>       op = gimple_assign_rhs_code (s);
>>       if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
>>        div = gimple_assign_rhs2 (s);
>> +      else if (op == COND_EXPR || op == VEC_COND_EXPR)
>> +       op = TREE_CODE (gimple_assign_rhs1 (s));
> 
> I think this is not correct since we can have
> 
> int i = fp > 1. ? intval1 : intval2
> 
> and thus FLOAT_TYPE_P (t)  is wrong.  You need to do
> 
>  t = TREE_TYPE (op);
> 
> as well I think.

Doesn't this mean there is a problem with the existing logic too? If `s`
is

    int i = fp > 1.;

then

    t = gimple_expr_type (s);

would give us BOOLEAN_TYPE instead of REAL_TYPE.


Also, the new logic will probably be a bit more complicated, since I
will first have to do:

    tree cond = gimple_assign_rhs1 (s);

then see if `cond` is not e.g. an SSA_NAME, but rather a tcc_comparison,
and only then

    t = TREE_TYPE (TREE_OPERAND (cond, 0))

So I'd rather send a new version before merging this :-)
Richard Biener Sept. 9, 2019, 8:43 a.m. UTC | #3
On Fri, Sep 6, 2019 at 5:45 PM Ilya Leoshkevich <iii@linux.ibm.com> wrote:
>
> > Am 06.09.2019 um 13:07 schrieb Richard Biener <richard.guenther@gmail.com>:
> >
> > On Thu, Sep 5, 2019 at 1:10 PM Ilya Leoshkevich <iii@linux.ibm.com> wrote:
> >>
> >> Right now gimplifier does not allow VEC_COND_EXPR's condition to trap
> >> and introduces a temporary if this could happen, for example, generating
> >>
> >>  _5 = _4 > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 };
> >>  _6 = VEC_COND_EXPR <_5, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>;
> >>
> >> from GENERIC
> >>
> >>  VEC_COND_EXPR < (*b > { 2.0e+0, 2.0e+0, 2.0e+0, 2.0e+0 }) ,
> >>                  { -1, -1, -1, -1 } ,
> >>                  { 0, 0, 0, 0 } >
> >>
> >> This is not necessary and makes the resulting GIMPLE harder to analyze.
> >> In particular, one of the next patches in series needs to get to
> >> VEC_COND_EXPR's comparison code, which is not possible when a temporary
> >> is introduced.
> >>
> >> This patch takes special care to avoid introducing trapping comparisons
> >> in GIMPLE_COND.  They are not allowed, because they would require 3
> >> outgoing edges (then, else and EH), which is awkward to say the least.
> >> Therefore, computations of such conditions should live in their own basic
> >> blocks.
> >
> > Comments inline (thanks for the work btw)
> >
> >> #endif /* GCC_GIMPLE_EXPR_H */
> >> diff --git a/gcc/gimple.c b/gcc/gimple.c
> >> index 633ef512a19..fd14fbec15e 100644
> >> --- a/gcc/gimple.c
> >> +++ b/gcc/gimple.c
> >> @@ -2144,6 +2144,8 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
> >>       op = gimple_assign_rhs_code (s);
> >>       if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
> >>        div = gimple_assign_rhs2 (s);
> >> +      else if (op == COND_EXPR || op == VEC_COND_EXPR)
> >> +       op = TREE_CODE (gimple_assign_rhs1 (s));
> >
> > I think this is not correct since we can have
> >
> > int i = fp > 1. ? intval1 : intval2
> >
> > and thus FLOAT_TYPE_P (t)  is wrong.  You need to do
> >
> >  t = TREE_TYPE (op);
> >
> > as well I think.
>
> Doesn't this mean there is a problem with the existing logic too? If `s`
> is
>
>     int i = fp > 1.;
>
> then
>
>     t = gimple_expr_type (s);
>
> would give us BOOLEAN_TYPE instead of REAL_TYPE.

Yeah, that looks broken as well.

>
> Also, the new logic will probably be a bit more complicated, since I
> will first have to do:
>
>     tree cond = gimple_assign_rhs1 (s);
>
> then see if `cond` is not e.g. an SSA_NAME, but rather a tcc_comparison,
> and only then
>
>     t = TREE_TYPE (TREE_OPERAND (cond, 0))
>
> So I'd rather send a new version before merging this :-)

Fine with me ;)

Richard.
diff mbox series

Patch

diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index b0c9f9b671a..46e5f000580 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -571,6 +571,7 @@  gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
 	      || TREE_CODE (cond) == TRUTH_NOT_EXPR
 	      || is_gimple_min_invariant (cond)
 	      || SSA_VAR_P (cond));
+  gcc_assert (!tree_could_throw_p (cond));
 
   extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
 
@@ -602,17 +603,33 @@  is_gimple_lvalue (tree t)
 	  || TREE_CODE (t) == BIT_FIELD_REF);
 }
 
-/*  Return true if T is a GIMPLE condition.  */
+/* Helper for is_gimple_condexpr and is_gimple_condexpr_for_cond.  */
 
-bool
-is_gimple_condexpr (tree t)
+static bool
+is_gimple_condexpr_1 (tree t, bool allow_traps)
 {
   return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
-				&& !tree_could_throw_p (t)
+				&& (allow_traps || !tree_could_throw_p (t))
 				&& is_gimple_val (TREE_OPERAND (t, 0))
 				&& is_gimple_val (TREE_OPERAND (t, 1))));
 }
 
+/*  Return true if T is a GIMPLE condition.  */
+
+bool
+is_gimple_condexpr (tree t)
+{
+  return is_gimple_condexpr_1 (t, true);
+}
+
+/* Like is_gimple_condexpr, but does not allow T to trap.  */
+
+bool
+is_gimple_condexpr_for_cond (tree t)
+{
+  return is_gimple_condexpr_1 (t, false);
+}
+
 /* Return true if T is a gimple address.  */
 
 bool
diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
index 1ad1432bd17..27190b1e5fe 100644
--- a/gcc/gimple-expr.h
+++ b/gcc/gimple-expr.h
@@ -41,6 +41,7 @@  extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
 					   tree *);
 extern bool is_gimple_lvalue (tree);
 extern bool is_gimple_condexpr (tree);
+extern bool is_gimple_condexpr_for_cond (tree);
 extern bool is_gimple_address (const_tree);
 extern bool is_gimple_invariant_address (const_tree);
 extern bool is_gimple_ip_invariant_address (const_tree);
@@ -175,4 +176,14 @@  gimple_call_addr_fndecl (const_tree fn)
   return NULL_TREE;
 }
 
+static inline bool
+gimple_ternary_operands_ok_p (enum tree_code code, tree op1, tree op2, tree op3)
+{
+  return ((code == VEC_COND_EXPR || code == COND_EXPR)
+	  ? is_gimple_condexpr (op1)
+	  : is_gimple_val (op1))
+	 && is_gimple_val (op2)
+	 && is_gimple_val (op3);
+}
+
 #endif /* GCC_GIMPLE_EXPR_H */
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..fd14fbec15e 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2144,6 +2144,8 @@  gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
       op = gimple_assign_rhs_code (s);
       if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
 	div = gimple_assign_rhs2 (s);
+      else if (op == COND_EXPR || op == VEC_COND_EXPR)
+	op = TREE_CODE (gimple_assign_rhs1 (s));
       return (operation_could_trap_p (op, FLOAT_TYPE_P (t),
 				      (INTEGRAL_TYPE_P (t)
 				       && TYPE_OVERFLOW_TRAPS (t)),
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index daa0b71c191..920e423381c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -4141,8 +4141,8 @@  gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   /* Now do the normal gimplification.  */
 
   /* Gimplify condition.  */
-  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, is_gimple_condexpr,
-		       fb_rvalue);
+  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+		       is_gimple_condexpr_for_cond, fb_rvalue);
   if (ret == GS_ERROR)
     return GS_ERROR;
   gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE);
@@ -12973,6 +12973,7 @@  gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   else if (gimple_test_f == is_gimple_val
            || gimple_test_f == is_gimple_call_addr
            || gimple_test_f == is_gimple_condexpr
+	   || gimple_test_f == is_gimple_condexpr_for_cond
            || gimple_test_f == is_gimple_mem_rhs
            || gimple_test_f == is_gimple_mem_rhs_or_call
            || gimple_test_f == is_gimple_reg_rhs
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index b75fdb2e63f..4d2239e9d2f 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4121,10 +4121,7 @@  verify_gimple_assign_ternary (gassign *stmt)
       return true;
     }
 
-  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
-       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
-      || !is_gimple_val (rhs2)
-      || !is_gimple_val (rhs3))
+  if (!gimple_ternary_operands_ok_p (rhs_code, rhs1, rhs2, rhs3))
     {
       error ("invalid operands in ternary operation");
       return true;
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 5bb07e49d28..98dc95a07cd 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -2523,6 +2523,10 @@  operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
   bool honor_snans = fp_operation && flag_signaling_nans != 0;
   bool handled;
 
+  /* This function cannot tell whether or not COND_EXPR and VEC_COND_EXPR could
+     trap, because that depends on the respective condition op.  */
+  gcc_assert (op != COND_EXPR && op != VEC_COND_EXPR);
+
   if (TREE_CODE_CLASS (op) != tcc_comparison
       && TREE_CODE_CLASS (op) != tcc_unary
       && TREE_CODE_CLASS (op) != tcc_binary)
@@ -2610,6 +2614,10 @@  tree_could_trap_p (tree expr)
   if (!expr)
     return false;
 
+  /* For COND_EXPR and VEC_COND_EXPR, only the condition may trap.  */
+  if (TREE_CODE (expr) == COND_EXPR || TREE_CODE (expr) == VEC_COND_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+
   code = TREE_CODE (expr);
   t = TREE_TYPE (expr);
 
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index c464c899586..edc5417f455 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -524,9 +524,10 @@  forward_propagate_into_gimple_cond (gcond *stmt)
   tmp = forward_propagate_into_comparison_1 (stmt, code,
 					     boolean_type_node,
 					     rhs1, rhs2);
-  if (tmp)
+  if (tmp
+      && is_gimple_condexpr_for_cond (tmp))
     {
-      if (dump_file && tmp)
+      if (dump_file)
 	{
 	  fprintf (dump_file, "  Replaced '");
 	  print_gimple_expr (dump_file, stmt, 0);
@@ -604,7 +605,7 @@  forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
   if (tmp
       && is_gimple_condexpr (tmp))
     {
-      if (dump_file && tmp)
+      if (dump_file)
 	{
 	  fprintf (dump_file, "  Replaced '");
 	  print_generic_expr (dump_file, cond);
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index 7172ef8b4e6..be34e25fc40 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -523,11 +523,10 @@  valid_gimple_rhs_p (tree expr)
 	default:
 	  if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS)
 	    {
-	      if (((code == VEC_COND_EXPR || code == COND_EXPR)
-		   ? !is_gimple_condexpr (TREE_OPERAND (expr, 0))
-		   : !is_gimple_val (TREE_OPERAND (expr, 0)))
-		  || !is_gimple_val (TREE_OPERAND (expr, 1))
-		  || !is_gimple_val (TREE_OPERAND (expr, 2)))
+	      if (!gimple_ternary_operands_ok_p (code,
+	                                         TREE_OPERAND (expr, 0),
+	                                         TREE_OPERAND (expr, 1),
+	                                         TREE_OPERAND (expr, 2)))
 		return false;
 	      break;
 	    }