Add a pattern for `(trunc)copysign ((extend)x, CST)`. Only the sign of
CST matters, not its value, so it can be simplified to
`copysign (x, +-0.0)` depending on the sign of CST. When signed zeros
are not honored their sign may be lost, so `copysign (x, +-1.0)` is used
instead.
PR tree-optimization/112472
gcc/ChangeLog:
* match.pd ((trunc)copysign ((extend)x, CST) --> copysign (x,
+-0.0/1.0)):
New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr112472.c: New test.
Signed-off-by: Eikansh Gupta <[email protected]>
---
gcc/match.pd | 20 +++++++++++++++++++-
gcc/testsuite/gcc.dg/tree-ssa/pr112472.c | 24 ++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 8c410c2f3b3..e050ecdf6d6 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9293,7 +9293,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@2))
&& direct_internal_fn_supported_p (IFN_COPYSIGN,
type, OPTIMIZE_FOR_BOTH))
- (IFN_COPYSIGN @0 @1))))
+ (IFN_COPYSIGN @0 @1)))
+ /* Simplify (trunc)copysign ((extend)x, CST) to copysign (x, +-0.0/1.0). */
+ (simplify
+ (convert (copysigns (convert@2 @0) REAL_CST@1))
+ (if (optimize
+ && !HONOR_SNANS (@2)
+ && types_match (type, TREE_TYPE (@0))
+ && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@2))
+ && direct_internal_fn_supported_p (IFN_COPYSIGN,
+ type, OPTIMIZE_FOR_BOTH))
+ (with { bool neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1));
+ /* Use +-0.0 if possible. When signed zeros are not honored,
+ use +-1.0 instead. */
+ tree cst = HONOR_SIGNED_ZEROS (type)
+ ? (neg ? build_real (type, dconstm0)
+ : build_zero_cst (type))
+ : (neg ? build_minus_one_cst (type)
+ : build_one_cst (type)); }
+ (IFN_COPYSIGN @0 { cst; })))))
(for froms (BUILT_IN_FMAF BUILT_IN_FMA BUILT_IN_FMAL)
tos (IFN_FMA IFN_FMA IFN_FMA)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
new file mode 100644
index 00000000000..0112b4a2b61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/112472 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+/* (trunc)copysign ((extend)a, negative CST) is simplified to
+ .COPYSIGN (a, -0.0). */
+float f(float a)
+{
+ return (float)__builtin_copysign(a, -3.0);
+}
+
+/* When signed zeros are not honored, .COPYSIGN (a, -1.0) is used
+ instead. */
+__attribute__((optimize("no-signed-zeros")))
+float g(float a)
+{
+ return (float)__builtin_copysign(a, -3.0);
+}
+
+/* { dg-final { scan-tree-dump-not "= __builtin_copysign" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " double " "optimized" { target
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times ".COPYSIGN" 2 "optimized" { target
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times "-0\\.0" 1 "optimized" { target
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times "-1\\.0e\\+0" 1 "optimized" { target
ifn_copysign } } } */
--
2.34.1
>From 208e5c41a71f0900d37ba3d51a57911a32931de4 Mon Sep 17 00:00:00 2001
From: Eikansh Gupta <[email protected]>
Date: Mon, 15 Jun 2026 12:19:45 +0530
Subject: [PATCH v2 2/2] MATCH: Simplify `(trunc)abs ((extend)x)` to `abs (x)`
[PR112472]
When the second argument of copysign is a non-negative constant, the
inner copysign is canonicalized to abs before the copysign pattern can
match, leaving (trunc)abs ((extend)x) with a redundant extend/truncate.
Add a pattern so the non-negative-constant copysign case is fully optimized too.
PR tree-optimization/112472
gcc/ChangeLog:
* match.pd ((trunc)abs (extend x) --> abs (x)): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr112472.c: Add non-negative constant case.
Signed-off-by: Eikansh Gupta <[email protected]>
---
gcc/match.pd | 9 +++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr112472.c | 9 +++++++++
2 files changed, 18 insertions(+)
diff --git a/gcc/match.pd b/gcc/match.pd
index e050ecdf6d6..7f540aa1c4e 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9313,6 +9313,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
: build_one_cst (type)); }
(IFN_COPYSIGN @0 { cst; })))))
+/* (trunc)abs (extend x) --> abs (x) */
+(simplify
+ (convert (abs (convert@1 @0)))
+ (if (optimize
+ && !HONOR_SNANS (@1)
+ && types_match (type, TREE_TYPE (@0))
+ && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@1)))
+ (abs @0)))
+
(for froms (BUILT_IN_FMAF BUILT_IN_FMA BUILT_IN_FMAL)
tos (IFN_FMA IFN_FMA IFN_FMA)
(simplify
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
index 0112b4a2b61..6aa905497bc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112472.c
@@ -17,8 +17,17 @@ float g(float a)
return (float)__builtin_copysign(a, -3.0);
}
+/* With a non-negative CST, copysign is canonicalized to abs, so this
+ becomes (float)abs((double)a) and is then simplified to abs(a),
+ dropping the wider type. */
+float f2(float a)
+{
+ return (float)__builtin_copysign(a, 5.0);
+}
+
/* { dg-final { scan-tree-dump-not "= __builtin_copysign" "optimized" } } */
/* { dg-final { scan-tree-dump-not " double " "optimized" { target
ifn_copysign } } } */
/* { dg-final { scan-tree-dump-times ".COPYSIGN" 2 "optimized" { target
ifn_copysign } } } */
/* { dg-final { scan-tree-dump-times "-0\\.0" 1 "optimized" { target
ifn_copysign } } } */
/* { dg-final { scan-tree-dump-times "-1\\.0e\\+0" 1 "optimized" { target
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times " ABS_EXPR " 1 "optimized" { target
ifn_copysign } } } */
--
2.34.1