The following as promised adds a 'switch' statement.  This way

 (if (A)
  B
  (if (B)
   C
   (if (C)
    D
    E)))

can now be written as

 (switch
  (if (A)
   B)
  (if (B)
   C)
  (if (C)
   D)
  E)

the ifs immediately nested in the switch cannot have else clauses and
I reject switches that can be expressed as single if.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

I know Micha detests the extra 'if' as much as the extra braces thus
would have prefered

 (switch
  (A) B
  (B) C
  (C) D
  E)

but that's hard to unambiguously parse and adding a keyword
without braces like

 (switch
  if (A) B
  if (B) C
  if (C) D
  E)

looked too inconsistent with all the rest of the language.

Thus - barring any comments I plan to commit this tomorrow
and then (being done with IL changes) will update the internals
documentation to reflect recent changes.

Note that internally the switch statement is represented as
a if () { } else { if () {} else { if () .... chain.

Thanks,
Richard.

2015-07-14  Richard Biener  <rguent...@suse.de>

        * genmatch.c (parser::peek, parser::peek_ident): Add argument
        to tell how many tokens to peek ahead (default 1).
        (parser::eat_token, parser::eat_ident): Return token consumed.
        (parser::parse_result): Parse new switch statement.
        * match.pd: Use case statements where appropriate.

Index: gcc/genmatch.c
===================================================================
*** gcc/genmatch.c      (revision 225765)
--- gcc/genmatch.c      (working copy)
*************** public:
*** 3014,3026 ****
  
  private:
    const cpp_token *next ();
!   const cpp_token *peek ();
!   const cpp_token *peek_ident (const char * = NULL);
    const cpp_token *expect (enum cpp_ttype);
!   void eat_token (enum cpp_ttype);
    const char *get_string ();
    const char *get_ident ();
!   void eat_ident (const char *);
    const char *get_number ();
  
    id_base *parse_operation ();
--- 3014,3026 ----
  
  private:
    const cpp_token *next ();
!   const cpp_token *peek (unsigned = 1);
!   const cpp_token *peek_ident (const char * = NULL, unsigned = 1);
    const cpp_token *expect (enum cpp_ttype);
!   const cpp_token *eat_token (enum cpp_ttype);
    const char *get_string ();
    const char *get_ident ();
!   const cpp_token *eat_ident (const char *);
    const char *get_number ();
  
    id_base *parse_operation ();
*************** parser::next ()
*** 3078,3084 ****
  /* Peek at the next non-whitespace token from R.  */
  
  const cpp_token *
! parser::peek ()
  {
    const cpp_token *token;
    unsigned i = 0;
--- 3078,3084 ----
  /* Peek at the next non-whitespace token from R.  */
  
  const cpp_token *
! parser::peek (unsigned num)
  {
    const cpp_token *token;
    unsigned i = 0;
*************** parser::peek ()
*** 3086,3093 ****
      {
        token = cpp_peek_token (r, i++);
      }
!   while (token->type == CPP_PADDING
!        && token->type != CPP_EOF);
    /* If we peek at EOF this is a fatal error as it leaves the
       cpp_reader in unusable state.  Assume we really wanted a
       token and thus this EOF is unexpected.  */
--- 3086,3094 ----
      {
        token = cpp_peek_token (r, i++);
      }
!   while ((token->type == CPP_PADDING
!         && token->type != CPP_EOF)
!        || (--num > 0));
    /* If we peek at EOF this is a fatal error as it leaves the
       cpp_reader in unusable state.  Assume we really wanted a
       token and thus this EOF is unexpected.  */
*************** parser::peek ()
*** 3100,3108 ****
     token is not an identifier or equal to ID if supplied).  */
  
  const cpp_token *
! parser::peek_ident (const char *id)
  {
!   const cpp_token *token = peek ();
    if (token->type != CPP_NAME)
      return 0;
  
--- 3101,3109 ----
     token is not an identifier or equal to ID if supplied).  */
  
  const cpp_token *
! parser::peek_ident (const char *id, unsigned num)
  {
!   const cpp_token *token = peek (num);
    if (token->type != CPP_NAME)
      return 0;
  
*************** parser::expect (enum cpp_ttype tk)
*** 3131,3140 ****
  
  /* Consume the next token from R and assert it is of type TK.  */
  
! void
  parser::eat_token (enum cpp_ttype tk)
  {
!   expect (tk);
  }
  
  /* Read the next token from R and assert it is of type CPP_STRING and
--- 3132,3141 ----
  
  /* Consume the next token from R and assert it is of type TK.  */
  
! const cpp_token *
  parser::eat_token (enum cpp_ttype tk)
  {
!   return expect (tk);
  }
  
  /* Read the next token from R and assert it is of type CPP_STRING and
*************** parser::get_ident ()
*** 3159,3171 ****
  
  /* Eat an identifier token with value S from R.  */
  
! void
  parser::eat_ident (const char *s)
  {
    const cpp_token *token = peek ();
    const char *t = get_ident ();
    if (strcmp (s, t) != 0)
      fatal_at (token, "expected '%s' got '%s'\n", s, t);
  }
  
  /* Read the next token from R and assert it is of type CPP_NUMBER and
--- 3160,3173 ----
  
  /* Eat an identifier token with value S from R.  */
  
! const cpp_token *
  parser::eat_ident (const char *s)
  {
    const cpp_token *token = peek ();
    const char *t = get_ident ();
    if (strcmp (s, t) != 0)
      fatal_at (token, "expected '%s' got '%s'\n", s, t);
+   return token;
  }
  
  /* Read the next token from R and assert it is of type CPP_NUMBER and
*************** parser::parse_result (operand *result, p
*** 3557,3562 ****
--- 3559,3616 ----
        eat_token (CPP_CLOSE_PAREN);
        return withe;
      }
+   else if (peek_ident ("switch"))
+     {
+       token = eat_ident ("switch");
+       eat_token (CPP_OPEN_PAREN);
+       eat_ident ("if");
+       if_expr *ife = new if_expr ();
+       operand *res = ife;
+       ife->cond = parse_c_expr (CPP_OPEN_PAREN);
+       if (peek ()->type == CPP_OPEN_PAREN)
+       ife->trueexpr = parse_result (result, matcher);
+       else
+       ife->trueexpr = parse_op ();
+       eat_token (CPP_CLOSE_PAREN);
+       if (peek ()->type != CPP_OPEN_PAREN
+         || !peek_ident ("if", 2))
+       fatal_at (token, "switch can be implemented with a single if");
+       while  (peek ()->type != CPP_CLOSE_PAREN)
+       {
+         if (peek ()->type == CPP_OPEN_PAREN)
+           {
+             if (peek_ident ("if", 2))
+               {
+                 eat_token (CPP_OPEN_PAREN);
+                 eat_ident ("if");
+                 ife->falseexpr = new if_expr ();
+                 ife = as_a <if_expr *> (ife->falseexpr);
+                 ife->cond = parse_c_expr (CPP_OPEN_PAREN);
+                 if (peek ()->type == CPP_OPEN_PAREN)
+                   ife->trueexpr = parse_result (result, matcher);
+                 else
+                   ife->trueexpr = parse_op ();
+                 eat_token (CPP_CLOSE_PAREN);
+               }
+             else
+               {
+                 /* switch default clause */
+                 ife->falseexpr = parse_result (result, matcher);
+                 eat_token (CPP_CLOSE_PAREN);
+                 return res;
+               }
+           }
+         else
+           {
+             /* switch default clause */
+             ife->falseexpr = parse_op ();
+             eat_token (CPP_CLOSE_PAREN);
+             return res;
+           }
+       }
+       eat_token (CPP_CLOSE_PAREN);
+       return res;
+     }
    else
      {
        operand *op = result;
Index: gcc/match.pd
===================================================================
*** gcc/match.pd        (revision 225764)
--- gcc/match.pd        (working copy)
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1107,1149 ****
        unsigned int final_prec = TYPE_PRECISION (type);
        int final_unsignedp = TYPE_UNSIGNED (type);
      }
!    /* In addition to the cases of two conversions in a row
!       handled below, if we are converting something to its own
!       type via an object of identical or wider precision, neither
!       conversion is needed.  */
!    (if (((GIMPLE && useless_type_conversion_p (type, inside_type))
!        || (GENERIC
!            && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type)))
!       && (((inter_int || inter_ptr) && final_int)
!           || (inter_float && final_float))
!       && inter_prec >= final_prec)
!     (ocvt @0)
! 
!    /* Likewise, if the intermediate and initial types are either both
!       float or both integer, we don't need the middle conversion if the
!       former is wider than the latter and doesn't change the signedness
!       (for integers).  Avoid this if the final type is a pointer since
!       then we sometimes need the middle conversion.  Likewise if the
!       final type has a precision not equal to the size of its mode.  */
!    (if (((inter_int && inside_int) || (inter_float && inside_float))
!       && (final_int || final_float)
!       && inter_prec >= inside_prec
!       && (inter_float || inter_unsignedp == inside_unsignedp)
!       && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
!             && TYPE_MODE (type) == TYPE_MODE (inter_type)))
!     (ocvt @0)
! 
!    /* If we have a sign-extension of a zero-extended value, we can
!       replace that by a single zero-extension.  Likewise if the
!       final conversion does not change precision we can drop the
!       intermediate conversion.  */
!    (if (inside_int && inter_int && final_int
!       && ((inside_prec < inter_prec && inter_prec < final_prec
!            && inside_unsignedp && !inter_unsignedp)
!           || final_prec == inter_prec))
!     (ocvt @0)
  
!    /* Two conversions in a row are not needed unless:
        - some conversion is floating-point (overstrict for now), or
        - some conversion is a vector (overstrict for now), or
        - the intermediate type is narrower than both initial and
--- 1167,1210 ----
        unsigned int final_prec = TYPE_PRECISION (type);
        int final_unsignedp = TYPE_UNSIGNED (type);
      }
!    (switch
!     /* In addition to the cases of two conversions in a row
!        handled below, if we are converting something to its own
!        type via an object of identical or wider precision, neither
!        conversion is needed.  */
!     (if (((GIMPLE && useless_type_conversion_p (type, inside_type))
!         || (GENERIC
!             && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type)))
!        && (((inter_int || inter_ptr) && final_int)
!            || (inter_float && final_float))
!        && inter_prec >= final_prec)
!      (ocvt @0))
! 
!     /* Likewise, if the intermediate and initial types are either both
!        float or both integer, we don't need the middle conversion if the
!        former is wider than the latter and doesn't change the signedness
!        (for integers).  Avoid this if the final type is a pointer since
!        then we sometimes need the middle conversion.  Likewise if the
!        final type has a precision not equal to the size of its mode.  */
!     (if (((inter_int && inside_int) || (inter_float && inside_float))
!        && (final_int || final_float)
!        && inter_prec >= inside_prec
!        && (inter_float || inter_unsignedp == inside_unsignedp)
!        && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
!              && TYPE_MODE (type) == TYPE_MODE (inter_type)))
!      (ocvt @0))
! 
!     /* If we have a sign-extension of a zero-extended value, we can
!        replace that by a single zero-extension.  Likewise if the
!        final conversion does not change precision we can drop the
!        intermediate conversion.  */
!     (if (inside_int && inter_int && final_int
!        && ((inside_prec < inter_prec && inter_prec < final_prec
!             && inside_unsignedp && !inter_unsignedp)
!            || final_prec == inter_prec))
!      (ocvt @0))
  
!     /* Two conversions in a row are not needed unless:
        - some conversion is floating-point (overstrict for now), or
        - some conversion is a vector (overstrict for now), or
        - the intermediate type is narrower than both initial and
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1154,1192 ****
          intermediate and final types differ, or
        - the final type is a pointer type and the precisions of the
          initial and intermediate types differ.  */
!    (if (! inside_float && ! inter_float && ! final_float
!       && ! inside_vec && ! inter_vec && ! final_vec
!       && (inter_prec >= inside_prec || inter_prec >= final_prec)
!       && ! (inside_int && inter_int
!             && inter_unsignedp != inside_unsignedp
!             && inter_prec < final_prec)
!       && ((inter_unsignedp && inter_prec > inside_prec)
!           == (final_unsignedp && final_prec > inter_prec))
!       && ! (inside_ptr && inter_prec != final_prec)
!       && ! (final_ptr && inside_prec != inter_prec)
!       && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
!             && TYPE_MODE (type) == TYPE_MODE (inter_type)))
!     (ocvt @0)
! 
!    /* A truncation to an unsigned type (a zero-extension) should be
!       canonicalized as bitwise and of a mask.  */
!    (if (final_int && inter_int && inside_int
!       && final_prec == inside_prec
!       && final_prec > inter_prec
!       && inter_unsignedp)
!     (convert (bit_and @0 { wide_int_to_tree
!                            (inside_type,
!                             wi::mask (inter_prec, false,
!                                       TYPE_PRECISION (inside_type))); }))
! 
!    /* If we are converting an integer to a floating-point that can
!       represent it exactly and back to an integer, we can skip the
!       floating-point conversion.  */
!    (if (GIMPLE /* PR66211 */
!       && inside_int && inter_float && final_int &&
!       (unsigned) significand_size (TYPE_MODE (inter_type))
!       >= inside_prec - !inside_unsignedp)
!     (convert @0)))))))))))
  
  /* If we have a narrowing conversion to an integral type that is fed by a
     BIT_AND_EXPR, we might be able to remove the BIT_AND_EXPR if it merely
--- 1215,1253 ----
          intermediate and final types differ, or
        - the final type is a pointer type and the precisions of the
          initial and intermediate types differ.  */
!     (if (! inside_float && ! inter_float && ! final_float
!        && ! inside_vec && ! inter_vec && ! final_vec
!        && (inter_prec >= inside_prec || inter_prec >= final_prec)
!        && ! (inside_int && inter_int
!              && inter_unsignedp != inside_unsignedp
!              && inter_prec < final_prec)
!        && ((inter_unsignedp && inter_prec > inside_prec)
!            == (final_unsignedp && final_prec > inter_prec))
!        && ! (inside_ptr && inter_prec != final_prec)
!        && ! (final_ptr && inside_prec != inter_prec)
!        && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
!              && TYPE_MODE (type) == TYPE_MODE (inter_type)))
!      (ocvt @0))
! 
!     /* A truncation to an unsigned type (a zero-extension) should be
!        canonicalized as bitwise and of a mask.  */
!     (if (final_int && inter_int && inside_int
!        && final_prec == inside_prec
!        && final_prec > inter_prec
!        && inter_unsignedp)
!      (convert (bit_and @0 { wide_int_to_tree
!                             (inside_type,
!                              wi::mask (inter_prec, false,
!                                        TYPE_PRECISION (inside_type))); })))
! 
!     /* If we are converting an integer to a floating-point that can
!        represent it exactly and back to an integer, we can skip the
!        floating-point conversion.  */
!     (if (GIMPLE /* PR66211 */
!        && inside_int && inter_float && final_int &&
!        (unsigned) significand_size (TYPE_MODE (inter_type))
!        >= inside_prec - !inside_unsignedp)
!      (convert @0)))))))
  
  /* If we have a narrowing conversion to an integral type that is fed by a
     BIT_AND_EXPR, we might be able to remove the BIT_AND_EXPR if it merely
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1463,1520 ****
   (simplify
    (cmp @0 REAL_CST@1)
    /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
!   /* a CMP (-0) -> a CMP 0  */
!   (if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)))
!    (cmp @0 { build_real (TREE_TYPE (@1), dconst0); })
!   /* x != NaN is always true, other ops are always false.  */
!   (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
!        && ! HONOR_SNANS (@1))
!    { constant_boolean_node (cmp == NE_EXPR, type); }
!   /* Fold comparisons against infinity.  */
!   (if (REAL_VALUE_ISINF (TREE_REAL_CST (@1))
!        && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (@1))))
!    (with
!     {
!       REAL_VALUE_TYPE max;
!       enum tree_code code = cmp;
!       bool neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1));
!       if (neg)
!         code = swap_tree_comparison (code);
!     }
!     /* x > +Inf is always false, if with ignore sNANs.  */
!     (if (code == GT_EXPR
!        && ! HONOR_SNANS (@0))
!      { constant_boolean_node (false, type); }
!     (if (code == LE_EXPR)
!      /* x <= +Inf is always true, if we don't case about NaNs.  */
!      (if (! HONOR_NANS (@0))
!       { constant_boolean_node (true, type); }
!       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
!       (eq @0 @0))
!     /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX.  */
!     (if (code == EQ_EXPR || code == GE_EXPR)
!      (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (neg)
!        (lt @0 { build_real (TREE_TYPE (@0), max); })
!        (gt @0 { build_real (TREE_TYPE (@0), max); })))
!     /* x < +Inf is always equal to x <= DBL_MAX.  */
!     (if (code == LT_EXPR)
!      (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (neg)
!        (ge @0 { build_real (TREE_TYPE (@0), max); })
!        (le @0 { build_real (TREE_TYPE (@0), max); })))
!     /* x != +Inf is always equal to !(x > DBL_MAX).  */
!     (if (code == NE_EXPR)
!      (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (! HONOR_NANS (@0))
!        (if (neg)
!         (ge @0 { build_real (TREE_TYPE (@0), max); })
!       (le @0 { build_real (TREE_TYPE (@0), max); }))
!        (if (neg)
!       (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
!                       { build_one_cst (type); })
!       (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
!                       { build_one_cst (type); }))))))))))))))
  
   /* If this is a comparison of a real constant with a PLUS_EXPR
      or a MINUS_EXPR of a real constant, we can convert it into a
--- 1537,1596 ----
   (simplify
    (cmp @0 REAL_CST@1)
    /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
!   (switch
!    /* a CMP (-0) -> a CMP 0  */
!    (if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)))
!     (cmp @0 { build_real (TREE_TYPE (@1), dconst0); }))
!    /* x != NaN is always true, other ops are always false.  */
!    (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
!       && ! HONOR_SNANS (@1))
!     { constant_boolean_node (cmp == NE_EXPR, type); })
!    /* Fold comparisons against infinity.  */
!    (if (REAL_VALUE_ISINF (TREE_REAL_CST (@1))
!       && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (@1))))
!     (with
!      {
!        REAL_VALUE_TYPE max;
!        enum tree_code code = cmp;
!        bool neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1));
!        if (neg)
!          code = swap_tree_comparison (code);
!      }
!      (switch
!       /* x > +Inf is always false, if with ignore sNANs.  */
!       (if (code == GT_EXPR
!          && ! HONOR_SNANS (@0))
!        { constant_boolean_node (false, type); })
!       (if (code == LE_EXPR)
!        /* x <= +Inf is always true, if we don't case about NaNs.  */
!        (if (! HONOR_NANS (@0))
!       { constant_boolean_node (true, type); }
!       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
!       (eq @0 @0)))
!       /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX.  */
!       (if (code == EQ_EXPR || code == GE_EXPR)
!        (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (neg)
!        (lt @0 { build_real (TREE_TYPE (@0), max); })
!        (gt @0 { build_real (TREE_TYPE (@0), max); }))))
!       /* x < +Inf is always equal to x <= DBL_MAX.  */
!       (if (code == LT_EXPR)
!        (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (neg)
!        (ge @0 { build_real (TREE_TYPE (@0), max); })
!        (le @0 { build_real (TREE_TYPE (@0), max); }))))
!       /* x != +Inf is always equal to !(x > DBL_MAX).  */
!       (if (code == NE_EXPR)
!        (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
!       (if (! HONOR_NANS (@0))
!        (if (neg)
!         (ge @0 { build_real (TREE_TYPE (@0), max); })
!         (le @0 { build_real (TREE_TYPE (@0), max); }))
!        (if (neg)
!         (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
!          { build_one_cst (type); })
!         (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
!          { build_one_cst (type); }))))))))))
  
   /* If this is a comparison of a real constant with a PLUS_EXPR
      or a MINUS_EXPR of a real constant, we can convert it into a
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1549,1613 ****
    (for sq (SQRT)
     (simplify
      (cmp (sq @0) REAL_CST@1)
!     (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
!      /* sqrt(x) < y is always false, if y is negative.  */
!      (if (cmp == EQ_EXPR || cmp == LT_EXPR || cmp == LE_EXPR)
!       { constant_boolean_node (false, type); }
!      /* sqrt(x) > y is always true, if y is negative and we
!       don't care about NaNs, i.e. negative values of x.  */
!      (if (cmp == NE_EXPR || !HONOR_NANS (@0))
!       { constant_boolean_node (true, type); }
!      /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
!      (ge @0 { build_real (TREE_TYPE (@0), dconst0); })))
!     (if (cmp == GT_EXPR || cmp == GE_EXPR)
!      (with
!       {
!               REAL_VALUE_TYPE c2;
!       REAL_ARITHMETIC (c2, MULT_EXPR, TREE_REAL_CST (@1), TREE_REAL_CST (@1));
!       real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
!       }
!       (if (REAL_VALUE_ISINF (c2))
!        /* sqrt(x) > y is x == +Inf, when y is very large.  */
!        (if (HONOR_INFINITIES (@0))
!         (eq @0 { build_real (TREE_TYPE (@0), c2); })
        { constant_boolean_node (false, type); })
!        /* sqrt(x) > c is the same as x > c*c.  */
!        (cmp @0 { build_real (TREE_TYPE (@0), c2); })))
!     (if (cmp == LT_EXPR || cmp == LE_EXPR)
!      (with
!       {
!               REAL_VALUE_TYPE c2;
!       REAL_ARITHMETIC (c2, MULT_EXPR, TREE_REAL_CST (@1), TREE_REAL_CST (@1));
!       real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
!       }
!       (if (REAL_VALUE_ISINF (c2))
!        /* sqrt(x) < y is always true, when y is a very large
!         value and we don't care about NaNs or Infinities.  */
!        (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
!         { constant_boolean_node (true, type); }
!        /* sqrt(x) < y is x != +Inf when y is very large and we
!         don't care about NaNs.  */
!        (if (! HONOR_NANS (@0))
!         (ne @0 { build_real (TREE_TYPE (@0), c2); })
!        /* sqrt(x) < y is x >= 0 when y is very large and we
!         don't care about Infinities.  */
!        (if (! HONOR_INFINITIES (@0))
!         (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
!        /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
!        (if (GENERIC)
!         (truth_andif
!        (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
!        (ne @0 { build_real (TREE_TYPE (@0), c2); }))))))
!       /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
!       (if (! REAL_VALUE_ISINF (c2)
!            && ! HONOR_NANS (@0))
!        (cmp @0 { build_real (TREE_TYPE (@0), c2); })
!       /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
!       (if (! REAL_VALUE_ISINF (c2)
!            && GENERIC)
!        (truth_andif
!         (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
!       (cmp @0 { build_real (TREE_TYPE (@0), c2); })))))))))))))
  
  /* Unordered tests if either argument is a NaN.  */
  (simplify
--- 1625,1692 ----
    (for sq (SQRT)
     (simplify
      (cmp (sq @0) REAL_CST@1)
!     (switch
!      (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
!       (switch
!        /* sqrt(x) < y is always false, if y is negative.  */
!        (if (cmp == EQ_EXPR || cmp == LT_EXPR || cmp == LE_EXPR)
        { constant_boolean_node (false, type); })
!        /* sqrt(x) > y is always true, if y is negative and we
!         don't care about NaNs, i.e. negative values of x.  */
!        (if (cmp == NE_EXPR || !HONOR_NANS (@0))
!       { constant_boolean_node (true, type); })
!        /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
!        (ge @0 { build_real (TREE_TYPE (@0), dconst0); })))
!      (if (cmp == GT_EXPR || cmp == GE_EXPR)
!       (with
!        {
!          REAL_VALUE_TYPE c2;
!        REAL_ARITHMETIC (c2, MULT_EXPR,
!                         TREE_REAL_CST (@1), TREE_REAL_CST (@1));
!        real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
!        }
!        (if (REAL_VALUE_ISINF (c2))
!       /* sqrt(x) > y is x == +Inf, when y is very large.  */
!       (if (HONOR_INFINITIES (@0))
!        (eq @0 { build_real (TREE_TYPE (@0), c2); })
!        { constant_boolean_node (false, type); })
!       /* sqrt(x) > c is the same as x > c*c.  */
!       (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))
!      (if (cmp == LT_EXPR || cmp == LE_EXPR)
!       (with
!        {
!                REAL_VALUE_TYPE c2;
!        REAL_ARITHMETIC (c2, MULT_EXPR,
!                         TREE_REAL_CST (@1), TREE_REAL_CST (@1));
!        real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
!        }
!        (if (REAL_VALUE_ISINF (c2))
!         (switch
!        /* sqrt(x) < y is always true, when y is a very large
!           value and we don't care about NaNs or Infinities.  */
!        (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
!         { constant_boolean_node (true, type); })
!        /* sqrt(x) < y is x != +Inf when y is very large and we
!           don't care about NaNs.  */
!        (if (! HONOR_NANS (@0))
!         (ne @0 { build_real (TREE_TYPE (@0), c2); }))
!        /* sqrt(x) < y is x >= 0 when y is very large and we
!           don't care about Infinities.  */
!        (if (! HONOR_INFINITIES (@0))
!         (ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
!        /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
!        (if (GENERIC)
!         (truth_andif
!          (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
!          (ne @0 { build_real (TREE_TYPE (@0), c2); }))))
!       /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
!       (if (! HONOR_NANS (@0))
!        (cmp @0 { build_real (TREE_TYPE (@0), c2); })
!        /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
!        (if (GENERIC)
!         (truth_andif
!          (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
!          (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))))))))))
  
  /* Unordered tests if either argument is a NaN.  */
  (simplify

Reply via email to