diff mbox

Move some flag_unsafe_math_optimizations using simplify and match

Message ID SN2PR0701MB10245A87E9DE18E7EAECA0F98E660@SN2PR0701MB1024.namprd07.prod.outlook.com
State New
Headers show

Commit Message

Hurugalawadi, Naveen Aug. 20, 2015, 9:18 a.m. UTC
Hi,

>> Works for me if you specify -fno-math-errno.  I think that's a
>> "regression" we can accept.

Modified the pattern with "fno-math-errno" as a condition.

>> Can you re-post with the typo fix and the missing :s?

Please find attached the modified patch as per the review comments.
Please suggest if there should be any further modifications.

Thanks,
Naveen

ChangeLog

2015-08-20  Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>

	* fold-const.c (fold_binary_loc) : Move sqrt(x)*sqrt(x) as x
	to match.pd.
	Move Optimize pow(x,y)*pow(z,y) as pow(x*z,y)to match.pd.
	Move Optimize tan(x)*cos(x) as sin(x) to match.pd.
	Move Optimize x*pow(x,c) as pow(x,c+1) to match.pd.
	Move Optimize pow(x,c)*x as pow(x,c+1) to match.pd.
	Move Optimize sin(x)/cos(x) as tan(x) to match.pd.
	Move Optimize cos(x)/sin(x) as 1.0/tan(x) to match.pd.
	Move Optimize sin(x)/tan(x) as cos(x) to match.pd.
	Move Optimize tan(x)/sin(x) as 1.0/cos(x) to match.pd.
	Move Optimize pow(x,c)/x as pow(x,c-1) to match.pd.
	Move Optimize x/pow(y,z) into x*pow(y,-z) to match.pd.

	* match.pd (SIN ) : New Operator.
	(TAN) : New Operator.
	(mult (SQRT@1 @0) @1) : New simplifier.
	(mult (POW:s @0 @1) (POW:s @2 @1)) : New simplifier.
	(mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
	(mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
	(rdiv (SIN:s @0) (COS:s @0)) : New simplifier.
	(rdiv (COS:s @0) (SIN:s @0)) : New simplifier.
	(rdiv (SIN:s @0) (TAN:s @0)) : New simplifier.
	(rdiv (TAN:s @0) (SIN:s @0)) : New simplifier.
	(rdiv (POW:s @0 REAL_CST@1) @0) : New simplifier.
	(rdiv @0 (SQRT:s (rdiv:s @1 @2))) : New simplifier.
	(rdiv @0 (POW:s @1 @2)) : New simplifier.

Comments

Richard Biener Aug. 20, 2015, 10:58 a.m. UTC | #1
On Thu, Aug 20, 2015 at 11:18 AM, Hurugalawadi, Naveen
<Naveen.Hurugalawadi@caviumnetworks.com> wrote:
> Hi,
>
>>> Works for me if you specify -fno-math-errno.  I think that's a
>>> "regression" we can accept.
>
> Modified the pattern with "fno-math-errno" as a condition.
>
>>> Can you re-post with the typo fix and the missing :s?
>
> Please find attached the modified patch as per the review comments.
> Please suggest if there should be any further modifications.

You marked

+ /* Simplify x * pow(x,c) -> pow(x,c+1). */
+ (simplify
+  (mult @0 (POW:s @0 REAL_CST@1))
+  (if (!flag_errno_math
+       && !TREE_OVERFLOW (@1))
+   (POW @0 (plus @1 { build_one_cst (type); }))))

with !flag_errno_math to avoid ICEs when replacing a non-call with a call.
But ...

+ /* Simplify sin(x) / cos(x) -> tan(x). */
+ (simplify
+  (rdiv (SIN:s @0) (COS:s @0))
+   (TAN @0))

has exactly the same issue, so does the following (and maybe others)

+ /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
+ (simplify
+  (rdiv (COS:s @0) (SIN:s @0))
+   (rdiv { build_one_cst (type); } (TAN @0)))

so I presume those simply do not trigger late (on GIMPLE) for any existing
testcases.

So to not expose this (latent) issue please wait until I find the time to fix
the underlying issue in a more generic way.  I will have a look today.

Thanks,
Richard.

> Thanks,
> Naveen
>
> ChangeLog
>
> 2015-08-20  Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>
>
>         * fold-const.c (fold_binary_loc) : Move sqrt(x)*sqrt(x) as x
>         to match.pd.
>         Move Optimize pow(x,y)*pow(z,y) as pow(x*z,y)to match.pd.
>         Move Optimize tan(x)*cos(x) as sin(x) to match.pd.
>         Move Optimize x*pow(x,c) as pow(x,c+1) to match.pd.
>         Move Optimize pow(x,c)*x as pow(x,c+1) to match.pd.
>         Move Optimize sin(x)/cos(x) as tan(x) to match.pd.
>         Move Optimize cos(x)/sin(x) as 1.0/tan(x) to match.pd.
>         Move Optimize sin(x)/tan(x) as cos(x) to match.pd.
>         Move Optimize tan(x)/sin(x) as 1.0/cos(x) to match.pd.
>         Move Optimize pow(x,c)/x as pow(x,c-1) to match.pd.
>         Move Optimize x/pow(y,z) into x*pow(y,-z) to match.pd.
>
>         * match.pd (SIN ) : New Operator.
>         (TAN) : New Operator.
>         (mult (SQRT@1 @0) @1) : New simplifier.
>         (mult (POW:s @0 @1) (POW:s @2 @1)) : New simplifier.
>         (mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
>         (mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
>         (rdiv (SIN:s @0) (COS:s @0)) : New simplifier.
>         (rdiv (COS:s @0) (SIN:s @0)) : New simplifier.
>         (rdiv (SIN:s @0) (TAN:s @0)) : New simplifier.
>         (rdiv (TAN:s @0) (SIN:s @0)) : New simplifier.
>         (rdiv (POW:s @0 REAL_CST@1) @0) : New simplifier.
>         (rdiv @0 (SQRT:s (rdiv:s @1 @2))) : New simplifier.
>         (rdiv @0 (POW:s @1 @2)) : New simplifier.
Richard Biener Aug. 21, 2015, 8:38 a.m. UTC | #2
On Thu, Aug 20, 2015 at 12:58 PM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Thu, Aug 20, 2015 at 11:18 AM, Hurugalawadi, Naveen
> <Naveen.Hurugalawadi@caviumnetworks.com> wrote:
>> Hi,
>>
>>>> Works for me if you specify -fno-math-errno.  I think that's a
>>>> "regression" we can accept.
>>
>> Modified the pattern with "fno-math-errno" as a condition.
>>
>>>> Can you re-post with the typo fix and the missing :s?
>>
>> Please find attached the modified patch as per the review comments.
>> Please suggest if there should be any further modifications.
>
> You marked
>
> + /* Simplify x * pow(x,c) -> pow(x,c+1). */
> + (simplify
> +  (mult @0 (POW:s @0 REAL_CST@1))
> +  (if (!flag_errno_math
> +       && !TREE_OVERFLOW (@1))
> +   (POW @0 (plus @1 { build_one_cst (type); }))))
>
> with !flag_errno_math to avoid ICEs when replacing a non-call with a call.
> But ...

I have now committed a patch for PR67285 so your patch is ok now if
you remove that !flag_errno_math check above.

Thanks,
Richard.

> + /* Simplify sin(x) / cos(x) -> tan(x). */
> + (simplify
> +  (rdiv (SIN:s @0) (COS:s @0))
> +   (TAN @0))
>
> has exactly the same issue, so does the following (and maybe others)
>
> + /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
> + (simplify
> +  (rdiv (COS:s @0) (SIN:s @0))
> +   (rdiv { build_one_cst (type); } (TAN @0)))
>
> so I presume those simply do not trigger late (on GIMPLE) for any existing
> testcases.
>
> So to not expose this (latent) issue please wait until I find the time to fix
> the underlying issue in a more generic way.  I will have a look today.
>
> Thanks,
> Richard.
>
>> Thanks,
>> Naveen
>>
>> ChangeLog
>>
>> 2015-08-20  Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>
>>
>>         * fold-const.c (fold_binary_loc) : Move sqrt(x)*sqrt(x) as x
>>         to match.pd.
>>         Move Optimize pow(x,y)*pow(z,y) as pow(x*z,y)to match.pd.
>>         Move Optimize tan(x)*cos(x) as sin(x) to match.pd.
>>         Move Optimize x*pow(x,c) as pow(x,c+1) to match.pd.
>>         Move Optimize pow(x,c)*x as pow(x,c+1) to match.pd.
>>         Move Optimize sin(x)/cos(x) as tan(x) to match.pd.
>>         Move Optimize cos(x)/sin(x) as 1.0/tan(x) to match.pd.
>>         Move Optimize sin(x)/tan(x) as cos(x) to match.pd.
>>         Move Optimize tan(x)/sin(x) as 1.0/cos(x) to match.pd.
>>         Move Optimize pow(x,c)/x as pow(x,c-1) to match.pd.
>>         Move Optimize x/pow(y,z) into x*pow(y,-z) to match.pd.
>>
>>         * match.pd (SIN ) : New Operator.
>>         (TAN) : New Operator.
>>         (mult (SQRT@1 @0) @1) : New simplifier.
>>         (mult (POW:s @0 @1) (POW:s @2 @1)) : New simplifier.
>>         (mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
>>         (mult:c (TAN:s @0) (COS:s @0)) : New simplifier.
>>         (rdiv (SIN:s @0) (COS:s @0)) : New simplifier.
>>         (rdiv (COS:s @0) (SIN:s @0)) : New simplifier.
>>         (rdiv (SIN:s @0) (TAN:s @0)) : New simplifier.
>>         (rdiv (TAN:s @0) (SIN:s @0)) : New simplifier.
>>         (rdiv (POW:s @0 REAL_CST@1) @0) : New simplifier.
>>         (rdiv @0 (SQRT:s (rdiv:s @1 @2))) : New simplifier.
>>         (rdiv @0 (POW:s @1 @2)) : New simplifier.
diff mbox

Patch

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 93d6514..1e01726 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -9957,12 +9957,6 @@  fold_binary_loc (location_t loc,
 		  tree arg00 = CALL_EXPR_ARG (arg0, 0);
 		  tree arg10 = CALL_EXPR_ARG (arg1, 0);
 
-		  /* Optimize sqrt(x)*sqrt(x) as x.  */
-		  if (BUILTIN_SQRT_P (fcode0)
-		      && operand_equal_p (arg00, arg10, 0)
-		      && ! HONOR_SNANS (element_mode (type)))
-		    return arg00;
-
 	          /* Optimize root(x)*root(y) as root(x*y).  */
 		  rootfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
 		  arg = fold_build2_loc (loc, MULT_EXPR, type, arg00, arg10);
@@ -9989,15 +9983,6 @@  fold_binary_loc (location_t loc,
 		  tree arg10 = CALL_EXPR_ARG (arg1, 0);
 		  tree arg11 = CALL_EXPR_ARG (arg1, 1);
 
-		  /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y).  */
-		  if (operand_equal_p (arg01, arg11, 0))
-		    {
-		      tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
-		      tree arg = fold_build2_loc (loc, MULT_EXPR, type,
-					      arg00, arg10);
-		      return build_call_expr_loc (loc, powfn, 2, arg, arg01);
-		    }
-
 		  /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z).  */
 		  if (operand_equal_p (arg00, arg10, 0))
 		    {
@@ -10008,67 +9993,6 @@  fold_binary_loc (location_t loc,
 		    }
 		}
 
-	      /* Optimize tan(x)*cos(x) as sin(x).  */
-	      if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS)
-		   || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF)
-		   || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL)
-		   || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN)
-		   || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF)
-		   || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL))
-		  && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
-				      CALL_EXPR_ARG (arg1, 0), 0))
-		{
-		  tree sinfn = mathfn_built_in (type, BUILT_IN_SIN);
-
-		  if (sinfn != NULL_TREE)
-		    return build_call_expr_loc (loc, sinfn, 1,
-					    CALL_EXPR_ARG (arg0, 0));
-		}
-
-	      /* Optimize x*pow(x,c) as pow(x,c+1).  */
-	      if (fcode1 == BUILT_IN_POW
-		  || fcode1 == BUILT_IN_POWF
-		  || fcode1 == BUILT_IN_POWL)
-		{
-		  tree arg10 = CALL_EXPR_ARG (arg1, 0);
-		  tree arg11 = CALL_EXPR_ARG (arg1, 1);
-		  if (TREE_CODE (arg11) == REAL_CST
-		      && !TREE_OVERFLOW (arg11)
-		      && operand_equal_p (arg0, arg10, 0))
-		    {
-		      tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
-		      REAL_VALUE_TYPE c;
-		      tree arg;
-
-		      c = TREE_REAL_CST (arg11);
-		      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-		      arg = build_real (type, c);
-		      return build_call_expr_loc (loc, powfn, 2, arg0, arg);
-		    }
-		}
-
-	      /* Optimize pow(x,c)*x as pow(x,c+1).  */
-	      if (fcode0 == BUILT_IN_POW
-		  || fcode0 == BUILT_IN_POWF
-		  || fcode0 == BUILT_IN_POWL)
-		{
-		  tree arg00 = CALL_EXPR_ARG (arg0, 0);
-		  tree arg01 = CALL_EXPR_ARG (arg0, 1);
-		  if (TREE_CODE (arg01) == REAL_CST
-		      && !TREE_OVERFLOW (arg01)
-		      && operand_equal_p (arg1, arg00, 0))
-		    {
-		      tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
-		      REAL_VALUE_TYPE c;
-		      tree arg;
-
-		      c = TREE_REAL_CST (arg01);
-		      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-		      arg = build_real (type, c);
-		      return build_call_expr_loc (loc, powfn, 2, arg1, arg);
-		    }
-		}
-
 	      /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x.  */
 	      if (!in_gimple_form
 		  && optimize
@@ -10481,109 +10405,10 @@  fold_binary_loc (location_t loc,
 
       if (flag_unsafe_math_optimizations)
 	{
-	  enum built_in_function fcode0 = builtin_mathfn_code (arg0);
 	  enum built_in_function fcode1 = builtin_mathfn_code (arg1);
 
-	  /* Optimize sin(x)/cos(x) as tan(x).  */
-	  if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
-	       || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
-	       || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
-	      && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
-				  CALL_EXPR_ARG (arg1, 0), 0))
-	    {
-	      tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
-	      if (tanfn != NULL_TREE)
-		return build_call_expr_loc (loc, tanfn, 1, CALL_EXPR_ARG (arg0, 0));
-	    }
-
-	  /* Optimize cos(x)/sin(x) as 1.0/tan(x).  */
-	  if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
-	       || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
-	       || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
-	      && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
-				  CALL_EXPR_ARG (arg1, 0), 0))
-	    {
-	      tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
-	      if (tanfn != NULL_TREE)
-		{
-		  tree tmp = build_call_expr_loc (loc, tanfn, 1,
-					      CALL_EXPR_ARG (arg0, 0));
-		  return fold_build2_loc (loc, RDIV_EXPR, type,
-				      build_real (type, dconst1), tmp);
-		}
-	    }
-
- 	  /* Optimize sin(x)/tan(x) as cos(x) if we don't care about
-	     NaNs or Infinities.  */
- 	  if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN)
- 	       || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF)
- 	       || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL)))
-	    {
-	      tree arg00 = CALL_EXPR_ARG (arg0, 0);
-	      tree arg01 = CALL_EXPR_ARG (arg1, 0);
-
-	      if (! HONOR_NANS (arg00)
-		  && ! HONOR_INFINITIES (element_mode (arg00))
-		  && operand_equal_p (arg00, arg01, 0))
-		{
-		  tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
-
-		  if (cosfn != NULL_TREE)
-		    return build_call_expr_loc (loc, cosfn, 1, arg00);
-		}
-	    }
-
- 	  /* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about
-	     NaNs or Infinities.  */
- 	  if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN)
- 	       || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF)
- 	       || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL)))
-	    {
-	      tree arg00 = CALL_EXPR_ARG (arg0, 0);
-	      tree arg01 = CALL_EXPR_ARG (arg1, 0);
-
-	      if (! HONOR_NANS (arg00)
-		  && ! HONOR_INFINITIES (element_mode (arg00))
-		  && operand_equal_p (arg00, arg01, 0))
-		{
-		  tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
-
-		  if (cosfn != NULL_TREE)
-		    {
-		      tree tmp = build_call_expr_loc (loc, cosfn, 1, arg00);
-		      return fold_build2_loc (loc, RDIV_EXPR, type,
-					  build_real (type, dconst1),
-					  tmp);
-		    }
-		}
-	    }
-
-	  /* Optimize pow(x,c)/x as pow(x,c-1).  */
-	  if (fcode0 == BUILT_IN_POW
-	      || fcode0 == BUILT_IN_POWF
-	      || fcode0 == BUILT_IN_POWL)
-	    {
-	      tree arg00 = CALL_EXPR_ARG (arg0, 0);
-	      tree arg01 = CALL_EXPR_ARG (arg0, 1);
-	      if (TREE_CODE (arg01) == REAL_CST
-		  && !TREE_OVERFLOW (arg01)
-		  && operand_equal_p (arg1, arg00, 0))
-		{
-		  tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
-		  REAL_VALUE_TYPE c;
-		  tree arg;
-
-		  c = TREE_REAL_CST (arg01);
-		  real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
-		  arg = build_real (type, c);
-		  return build_call_expr_loc (loc, powfn, 2, arg1, arg);
-		}
-	    }
-
 	  /* Optimize a/root(b/c) into a*root(c/b).  */
-	  if (BUILTIN_ROOT_P (fcode1))
+	  if (BUILTIN_CBRT_P (fcode1))
 	    {
 	      tree rootarg = CALL_EXPR_ARG (arg1, 0);
 
@@ -10611,19 +10436,6 @@  fold_binary_loc (location_t loc,
 	      return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
 	    }
 
-	  /* Optimize x/pow(y,z) into x*pow(y,-z).  */
-	  if (fcode1 == BUILT_IN_POW
-	      || fcode1 == BUILT_IN_POWF
-	      || fcode1 == BUILT_IN_POWL)
-	    {
-	      tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
-	      tree arg10 = CALL_EXPR_ARG (arg1, 0);
-	      tree arg11 = CALL_EXPR_ARG (arg1, 1);
-	      tree neg11 = fold_convert_loc (loc, type,
-					     negate_expr (arg11));
-	      arg1 = build_call_expr_loc (loc, powfn, 2, arg10, neg11);
-	      return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
-	    }
 	}
       return NULL_TREE;
 
diff --git a/gcc/match.pd b/gcc/match.pd
index 71f4127..5b41813 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -55,10 +55,11 @@  along with GCC; see the file COPYING3.  If not see
 (define_operator_list POW10 BUILT_IN_POW10F BUILT_IN_POW10 BUILT_IN_POW10L)
 (define_operator_list SQRT BUILT_IN_SQRTF BUILT_IN_SQRT BUILT_IN_SQRTL)
 (define_operator_list CBRT BUILT_IN_CBRTF BUILT_IN_CBRT BUILT_IN_CBRTL)
+(define_operator_list SIN BUILT_IN_SIN BUILT_IN_SINL BUILT_IN_SINF)
 (define_operator_list COS BUILT_IN_COS BUILT_IN_COSL BUILT_IN_COSF)
+(define_operator_list TAN BUILT_IN_TAN BUILT_IN_TANL BUILT_IN_TANF)
 (define_operator_list COSH BUILT_IN_COSH BUILT_IN_COSHL BUILT_IN_COSHF)
 
-
 /* Simplifications of operations with one constant operand and
    simplifications to constants or single values.  */
 
@@ -2006,6 +2007,72 @@  along with GCC; see the file COPYING3.  If not see
 
 /* fold_builtin_logarithm */
 (if (flag_unsafe_math_optimizations)
+
+ /* Simplify sqrt(x) * sqrt(x) -> x.  */
+ (simplify
+  (mult (SQRT@1 @0) @1)
+  (if (!flag_errno_math
+       && !HONOR_SNANS (type))
+   @0))
+
+ /* Simplify pow(x,y) * pow(z,y) -> pow(x*z,y). */
+ (simplify
+  (mult (POW:s @0 @1) (POW:s @2 @1))
+   (POW (mult @0 @2) @1))
+
+ /* Simplify tan(x) * cos(x) -> sin(x). */
+ (simplify
+  (mult:c (TAN:s @0) (COS:s @0))
+   (SIN @0))
+
+ /* Simplify x * pow(x,c) -> pow(x,c+1). */
+ (simplify
+  (mult @0 (POW:s @0 REAL_CST@1))
+  (if (!flag_errno_math
+       && !TREE_OVERFLOW (@1))
+   (POW @0 (plus @1 { build_one_cst (type); }))))
+
+ /* Simplify sin(x) / cos(x) -> tan(x). */
+ (simplify
+  (rdiv (SIN:s @0) (COS:s @0))
+   (TAN @0))
+
+ /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
+ (simplify
+  (rdiv (COS:s @0) (SIN:s @0))
+   (rdiv { build_one_cst (type); } (TAN @0)))
+
+ /* Simplify sin(x) / tan(x) -> cos(x). */
+ (simplify
+  (rdiv (SIN:s @0) (TAN:s @0))
+  (if (! HONOR_NANS (@0)
+       && ! HONOR_INFINITIES (@0))
+   (cos @0)))
+
+ /* Simplify tan(x) / sin(x) -> 1.0 / cos(x). */
+ (simplify
+  (rdiv (TAN:s @0) (SIN:s @0))
+  (if (! HONOR_NANS (@0)
+       && ! HONOR_INFINITIES (@0))
+   (rdiv { build_one_cst (type); } (COS @0))))
+
+ /* Simplify pow(x,c) / x -> pow(x,c-1). */
+ (simplify
+  (rdiv (POW:s @0 REAL_CST@1) @0)
+  (if (! flag_errno_math
+       && !TREE_OVERFLOW (@1))
+   (POW @0 (minus @1 { build_one_cst (type); }))))
+
+ /* Simplify a/root(b/c) into a*root(c/b).  */
+ (simplify
+  (rdiv @0 (SQRT:s (rdiv:s @1 @2)))
+   (mult @0 (SQRT (rdiv @2 @1))))
+
+ /* Simplify x / pow (y,z) -> x * pow(y,-z). */
+ (simplify
+  (rdiv @0 (POW:s @1 @2))
+   (mult @0 (POW @1 (negate @2))))
+
  /* Special case, optimize logN(expN(x)) = x.  */
  (for logs (LOG LOG2 LOG10)
       exps (EXP EXP2 EXP10)