This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add 'switch' statement to match.pd language


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  <rguenther@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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]