[v2] tree-optimization: Canonicalize conditional signed narrow clips [PR127166]
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap |
fail
|
Patch failed to apply
|
Commit Message
From: Kyrylo Tkachov <ktkachov@nvidia.com>
The PR120378 RISC-V tests use this source form:
(NT) ((UT) x > NT_MAX ? (-x) >> (PREC - 1) : x)
For every defined execution, it is an unsigned saturating truncation of
MAX (x, 0). The signed negation is undefined at the signed minimum under
the default overflow rules.
Loop if-conversion changes the selected negation to unsigned arithmetic.
This loses the distinction between the signed source and the explicit
unsigned-negation form from PR126981, which must not become a saturating
truncation.
Canonicalize the signed form while its overflow semantics are still
available before loop if-conversion:
(NT) MIN ((UT) MAX (x, 0), NT_MAX)
Require an unsigned comparison, a signed right shift, undefined and
unsanitized negation overflow, exact constants, and no side effects. This
keeps the original form with -fwrapv, -ftrapv, sanitization, volatile
operands, and explicit unsigned negation.
With this patch the tests restore the RISC-V saturation patterns.
Update pr103771.c because the direct form is
canonicalized before phiopt.
Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill
gcc/ChangeLog:
PR tree-optimization/127166
* match.pd: Canonicalize conditional signed narrow clips before loop
if-conversion.
gcc/testsuite/ChangeLog:
PR tree-optimization/127166
* gcc.dg/tree-ssa/pr103771.c: Check the earlier canonicalization.
* gcc.dg/tree-ssa/pr127166.c: New test.
* gcc.dg/tree-ssa/pr127166-3.c: New test.
* gcc.dg/vect/pr127166.c: New test.
* gcc.target/riscv/rvv/autovec/pr120378-1.c: Update expected dump
counts.
* gcc.target/riscv/rvv/autovec/pr120378-2.c: Request an optimized dump.
* gcc.target/riscv/rvv/autovec/pr120378-3.c: Likewise. Update expected
dump counts.
* gcc.target/riscv/rvv/autovec/pr120378-4.c: Request an optimized dump.
Signed-off-by: Kyrylo Tkachov <ktkachov@nvidia.com>
---
gcc/match.pd | 37 +++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr103771.c | 5 +-
gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c | 15 ++++++
gcc/testsuite/gcc.dg/tree-ssa/pr127166.c | 53 +++++++++++++++++++
gcc/testsuite/gcc.dg/vect/pr127166.c | 50 +++++++++++++++++
.../gcc.target/riscv/rvv/autovec/pr120378-1.c | 4 +-
.../gcc.target/riscv/rvv/autovec/pr120378-2.c | 2 +-
.../gcc.target/riscv/rvv/autovec/pr120378-3.c | 6 +--
.../gcc.target/riscv/rvv/autovec/pr120378-4.c | 2 +-
9 files changed, 165 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr127166.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr127166.c
Comments
On Wed, 2 Sep 2026, ktkachov@nvidia.com wrote:
> From: Kyrylo Tkachov <ktkachov@nvidia.com>
>
> The PR120378 RISC-V tests use this source form:
>
> (NT) ((UT) x > NT_MAX ? (-x) >> (PREC - 1) : x)
>
> For every defined execution, it is an unsigned saturating truncation of
> MAX (x, 0). The signed negation is undefined at the signed minimum under
> the default overflow rules.
>
> Loop if-conversion changes the selected negation to unsigned arithmetic.
> This loses the distinction between the signed source and the explicit
> unsigned-negation form from PR126981, which must not become a saturating
> truncation.
>
> Canonicalize the signed form while its overflow semantics are still
> available before loop if-conversion:
>
> (NT) MIN ((UT) MAX (x, 0), NT_MAX)
>
> Require an unsigned comparison, a signed right shift, undefined and
> unsanitized negation overflow, exact constants, and no side effects. This
> keeps the original form with -fwrapv, -ftrapv, sanitization, volatile
> operands, and explicit unsigned negation.
>
> With this patch the tests restore the RISC-V saturation patterns.
> Update pr103771.c because the direct form is
> canonicalized before phiopt.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?
OK.
Thanks,
Richard.
> Thanks,
> Kyrill
>
> gcc/ChangeLog:
>
> PR tree-optimization/127166
> * match.pd: Canonicalize conditional signed narrow clips before loop
> if-conversion.
>
> gcc/testsuite/ChangeLog:
>
> PR tree-optimization/127166
> * gcc.dg/tree-ssa/pr103771.c: Check the earlier canonicalization.
> * gcc.dg/tree-ssa/pr127166.c: New test.
> * gcc.dg/tree-ssa/pr127166-3.c: New test.
> * gcc.dg/vect/pr127166.c: New test.
> * gcc.target/riscv/rvv/autovec/pr120378-1.c: Update expected dump
> counts.
> * gcc.target/riscv/rvv/autovec/pr120378-2.c: Request an optimized dump.
> * gcc.target/riscv/rvv/autovec/pr120378-3.c: Likewise. Update expected
> dump counts.
> * gcc.target/riscv/rvv/autovec/pr120378-4.c: Request an optimized dump.
>
> Signed-off-by: Kyrylo Tkachov <ktkachov@nvidia.com>
> ---
> gcc/match.pd | 37 +++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr103771.c | 5 +-
> gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c | 15 ++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr127166.c | 53 +++++++++++++++++++
> gcc/testsuite/gcc.dg/vect/pr127166.c | 50 +++++++++++++++++
> .../gcc.target/riscv/rvv/autovec/pr120378-1.c | 4 +-
> .../gcc.target/riscv/rvv/autovec/pr120378-2.c | 2 +-
> .../gcc.target/riscv/rvv/autovec/pr120378-3.c | 6 +--
> .../gcc.target/riscv/rvv/autovec/pr120378-4.c | 2 +-
> 9 files changed, 165 insertions(+), 9 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr127166.c
> create mode 100644 gcc/testsuite/gcc.dg/vect/pr127166.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 5777c833896..54cad1cd2bc 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -13372,6 +13372,43 @@ and,
> (BUILT_IN_CONSTANT_P (nop_convert@1 @0))
> (BUILT_IN_CONSTANT_P @0))
>
> +/* Canonicalize a conditional signed narrow clip while the signed negation
> + has its original overflow semantics:
> +
> + (NT) ((UT) X > NT_MAX ? (-X) >> (PREC - 1) : X)
> + -> (NT) MIN ((UT) MAX (X, 0), NT_MAX). */
> +(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
> + (simplify
> + (cond (gt (nop_convert@4 @0) INTEGER_CST@1)
> + (convert (rshift@5
> + (nop_convert? (negate@3 (nop_convert? @0)))
> + INTEGER_CST@2))
> + (convert @0))
> + (if (!TREE_SIDE_EFFECTS (@0)
> + && !TYPE_UNSIGNED (TREE_TYPE (@0))
> + && TYPE_UNSIGNED (TREE_TYPE (@4))
> + && !TYPE_UNSIGNED (TREE_TYPE (@5))
> + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
> + && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@3)))
> + (with
> + {
> + tree utype = TREE_TYPE (@4);
> + unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
> + unsigned otype_precision = TYPE_PRECISION (type);
> + wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
> + wide_int int_cst_1 = wi::to_wide (@1, itype_precision);
> + wide_int int_cst_2 = wi::to_wide (@2, itype_precision);
> + wide_int shift_amount = wi::uhwi (itype_precision - 1,
> + itype_precision);
> + }
> + (if (otype_precision < itype_precision
> + && wi::eq_p (trunc_max, int_cst_1)
> + && wi::eq_p (int_cst_2, shift_amount))
> + (convert (min:utype
> + (convert:utype
> + (max @0 { build_zero_cst (TREE_TYPE (@0)); }))
> + @1)))))))
> +
> #if GIMPLE
>
> /* Include the saturation alu match patterns. */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103771.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103771.c
> index 8061e2df79e..b3dde923281 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr103771.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103771.c
> @@ -1,6 +1,7 @@
> /* { dg-do compile } */
> -/* { dg-options "-O3 -fdump-tree-phiopt1-details" } */
> -/* { dg-final { scan-tree-dump-times "changed to factor operation out from COND_EXPR." 1 "phiopt1" } } */
> +/* { dg-options "-O3 -fdump-tree-gimple" } */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "gimple" } } */
> +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "gimple" } } */
>
> typedef unsigned char uint8_t;
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c
> new file mode 100644
> index 00000000000..266b0aac75a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr127166-3.c
> @@ -0,0 +1,15 @@
> +/* PR tree-optimization/127166 */
> +/* { dg-do compile } */
> +/* { dg-require-effective-target int32 } */
> +/* { dg-options "-O2 -fsanitize=signed-integer-overflow" } */
> +/* { dg-additional-options "-fdump-tree-optimized" } */
> +
> +unsigned short
> +f (int x)
> +{
> + return ((unsigned int) x > 65535u ? (-x) >> 31 : x);
> +}
> +
> +/* Keep the conditional signed negation so that it is checked at runtime. */
> +/* { dg-final { scan-tree-dump-not "MAX_EXPR|MIN_EXPR" "optimized" } } */
> +/* { dg-final { scan-tree-dump {\.UBSAN_CHECK_SUB} "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr127166.c b/gcc/testsuite/gcc.dg/tree-ssa/pr127166.c
> new file mode 100644
> index 00000000000..9bf89246dba
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr127166.c
> @@ -0,0 +1,53 @@
> +/* PR tree-optimization/127166 */
> +/* { dg-do compile } */
> +/* { dg-require-effective-target int32 } */
> +/* { dg-options "-O2 -fdump-tree-gimple -fdump-tree-phiopt2" } */
> +
> +unsigned short
> +signed_clip (int x)
> +{
> + return ((unsigned int) x > 65535u ? (-x) >> 31 : x);
> +}
> +
> +unsigned short
> +unsigned_clip (int x)
> +{
> + return ((unsigned int) x > 65535u
> + ? (int) (-(unsigned int) x) >> 31 : x);
> +}
> +
> +unsigned short
> +signed_split_clip (int x)
> +{
> + int neg = -x;
> + int sign = neg >> 31;
> + unsigned short high = sign;
> +
> + return ((unsigned int) x > 65535u ? high : x);
> +}
> +
> +unsigned short
> +unsigned_split_clip (int x)
> +{
> + unsigned int ux = x;
> + unsigned int neg = -ux;
> + int sign = (int) neg >> 31;
> + unsigned short high = sign;
> +
> + return (ux > 65535u ? high : x);
> +}
> +
> +volatile int v;
> +
> +unsigned short
> +volatile_clip (void)
> +{
> + return ((unsigned int) v > 65535u ? (-v) >> 31 : v);
> +}
> +
> +/* The direct signed form is canonicalized in GENERIC. The split signed form
> + is canonicalized in GIMPLE before loop if-conversion. */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "gimple" } } */
> +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "gimple" } } */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt2" } } */
> diff --git a/gcc/testsuite/gcc.dg/vect/pr127166.c b/gcc/testsuite/gcc.dg/vect/pr127166.c
> new file mode 100644
> index 00000000000..5bc59ad3769
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/pr127166.c
> @@ -0,0 +1,50 @@
> +/* PR tree-optimization/127166 */
> +/* { dg-additional-options "-fwrapv" } */
> +/* { dg-require-effective-target int32 } */
> +/* { dg-require-effective-target vect_int } */
> +
> +#include "tree-vect.h"
> +
> +#define N 64
> +
> +__attribute__ ((noipa)) void
> +clip (unsigned short *__restrict out, const int *__restrict in, int n)
> +{
> + for (int i = 0; i < n; ++i)
> + {
> + int x = in[i];
> + out[i] = ((unsigned int) x > 65535u ? (-x) >> 31 : x);
> + }
> +}
> +
> +int
> +main (void)
> +{
> + int in[N];
> + unsigned short out[N];
> +
> + check_vect ();
> +
> + for (int i = 0; i < N; ++i)
> + in[i] = (i & 3) == 0 ? (-__INT_MAX__ - 1) : i * 12345 - 30000;
> +
> + clip (out, in, N);
> +
> +#pragma GCC novector
> + for (int i = 0; i < N; ++i)
> + {
> + int x = in[i];
> + unsigned short ref;
> +
> + if (x == (-__INT_MAX__ - 1) || x > 65535)
> + ref = 65535;
> + else if (x < 0)
> + ref = 0;
> + else
> + ref = x;
> + if (out[i] != ref)
> + abort ();
> + }
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
> index 54f25e0ceaa..f5a9acec858 100644
> --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
> @@ -16,6 +16,6 @@ clip_loop (uint8_t *res, int *x, int w)
> res[i] = clip_uint8 (x[i]);
> }
>
> -/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 1 "optimized" } } */
> -/* { dg-final { scan-tree-dump-times "MAX_EXPR " 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 2 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR " 2 "optimized" } } */
> /* { dg-final { scan-assembler-times {vnclipu\.wi} 2 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
> index 9a880e0f67b..2208e954242 100644
> --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile } */
> -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
>
> #include <stdint.h>
>
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
> index d6b2ddd3f8d..5941b3b7543 100644
> --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile } */
> -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
>
> #include <stdint.h>
>
> @@ -16,6 +16,6 @@ clip_loop (uint8_t *res, int64_t *x, int w)
> res[i] = clip_uint8 (x[i]);
> }
>
> -/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 1 "optimized" } } */
> -/* { dg-final { scan-tree-dump-times "MAX_EXPR " 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 2 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR " 2 "optimized" } } */
> /* { dg-final { scan-assembler-times {vnclipu\.wi} 3 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
> index 4657e52f883..57cca4504ba 100644
> --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile } */
> -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
>
> #include <stdint.h>
>
>
@@ -13372,6 +13372,43 @@ and,
(BUILT_IN_CONSTANT_P (nop_convert@1 @0))
(BUILT_IN_CONSTANT_P @0))
+/* Canonicalize a conditional signed narrow clip while the signed negation
+ has its original overflow semantics:
+
+ (NT) ((UT) X > NT_MAX ? (-X) >> (PREC - 1) : X)
+ -> (NT) MIN ((UT) MAX (X, 0), NT_MAX). */
+(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (simplify
+ (cond (gt (nop_convert@4 @0) INTEGER_CST@1)
+ (convert (rshift@5
+ (nop_convert? (negate@3 (nop_convert? @0)))
+ INTEGER_CST@2))
+ (convert @0))
+ (if (!TREE_SIDE_EFFECTS (@0)
+ && !TYPE_UNSIGNED (TREE_TYPE (@0))
+ && TYPE_UNSIGNED (TREE_TYPE (@4))
+ && !TYPE_UNSIGNED (TREE_TYPE (@5))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@3)))
+ (with
+ {
+ tree utype = TREE_TYPE (@4);
+ unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
+ unsigned otype_precision = TYPE_PRECISION (type);
+ wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
+ wide_int int_cst_1 = wi::to_wide (@1, itype_precision);
+ wide_int int_cst_2 = wi::to_wide (@2, itype_precision);
+ wide_int shift_amount = wi::uhwi (itype_precision - 1,
+ itype_precision);
+ }
+ (if (otype_precision < itype_precision
+ && wi::eq_p (trunc_max, int_cst_1)
+ && wi::eq_p (int_cst_2, shift_amount))
+ (convert (min:utype
+ (convert:utype
+ (max @0 { build_zero_cst (TREE_TYPE (@0)); }))
+ @1)))))))
+
#if GIMPLE
/* Include the saturation alu match patterns. */
@@ -1,6 +1,7 @@
/* { dg-do compile } */
-/* { dg-options "-O3 -fdump-tree-phiopt1-details" } */
-/* { dg-final { scan-tree-dump-times "changed to factor operation out from COND_EXPR." 1 "phiopt1" } } */
+/* { dg-options "-O3 -fdump-tree-gimple" } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "gimple" } } */
typedef unsigned char uint8_t;
new file mode 100644
@@ -0,0 +1,15 @@
+/* PR tree-optimization/127166 */
+/* { dg-do compile } */
+/* { dg-require-effective-target int32 } */
+/* { dg-options "-O2 -fsanitize=signed-integer-overflow" } */
+/* { dg-additional-options "-fdump-tree-optimized" } */
+
+unsigned short
+f (int x)
+{
+ return ((unsigned int) x > 65535u ? (-x) >> 31 : x);
+}
+
+/* Keep the conditional signed negation so that it is checked at runtime. */
+/* { dg-final { scan-tree-dump-not "MAX_EXPR|MIN_EXPR" "optimized" } } */
+/* { dg-final { scan-tree-dump {\.UBSAN_CHECK_SUB} "optimized" } } */
new file mode 100644
@@ -0,0 +1,53 @@
+/* PR tree-optimization/127166 */
+/* { dg-do compile } */
+/* { dg-require-effective-target int32 } */
+/* { dg-options "-O2 -fdump-tree-gimple -fdump-tree-phiopt2" } */
+
+unsigned short
+signed_clip (int x)
+{
+ return ((unsigned int) x > 65535u ? (-x) >> 31 : x);
+}
+
+unsigned short
+unsigned_clip (int x)
+{
+ return ((unsigned int) x > 65535u
+ ? (int) (-(unsigned int) x) >> 31 : x);
+}
+
+unsigned short
+signed_split_clip (int x)
+{
+ int neg = -x;
+ int sign = neg >> 31;
+ unsigned short high = sign;
+
+ return ((unsigned int) x > 65535u ? high : x);
+}
+
+unsigned short
+unsigned_split_clip (int x)
+{
+ unsigned int ux = x;
+ unsigned int neg = -ux;
+ int sign = (int) neg >> 31;
+ unsigned short high = sign;
+
+ return (ux > 65535u ? high : x);
+}
+
+volatile int v;
+
+unsigned short
+volatile_clip (void)
+{
+ return ((unsigned int) v > 65535u ? (-v) >> 31 : v);
+}
+
+/* The direct signed form is canonicalized in GENERIC. The split signed form
+ is canonicalized in GIMPLE before loop if-conversion. */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt2" } } */
new file mode 100644
@@ -0,0 +1,50 @@
+/* PR tree-optimization/127166 */
+/* { dg-additional-options "-fwrapv" } */
+/* { dg-require-effective-target int32 } */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#define N 64
+
+__attribute__ ((noipa)) void
+clip (unsigned short *__restrict out, const int *__restrict in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int x = in[i];
+ out[i] = ((unsigned int) x > 65535u ? (-x) >> 31 : x);
+ }
+}
+
+int
+main (void)
+{
+ int in[N];
+ unsigned short out[N];
+
+ check_vect ();
+
+ for (int i = 0; i < N; ++i)
+ in[i] = (i & 3) == 0 ? (-__INT_MAX__ - 1) : i * 12345 - 30000;
+
+ clip (out, in, N);
+
+#pragma GCC novector
+ for (int i = 0; i < N; ++i)
+ {
+ int x = in[i];
+ unsigned short ref;
+
+ if (x == (-__INT_MAX__ - 1) || x > 65535)
+ ref = 65535;
+ else if (x < 0)
+ ref = 0;
+ else
+ ref = x;
+ if (out[i] != ref)
+ abort ();
+ }
+
+ return 0;
+}
@@ -16,6 +16,6 @@ clip_loop (uint8_t *res, int *x, int w)
res[i] = clip_uint8 (x[i]);
}
-/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 1 "optimized" } } */
-/* { dg-final { scan-tree-dump-times "MAX_EXPR " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR " 2 "optimized" } } */
/* { dg-final { scan-assembler-times {vnclipu\.wi} 2 } } */
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
#include <stdint.h>
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
#include <stdint.h>
@@ -16,6 +16,6 @@ clip_loop (uint8_t *res, int64_t *x, int w)
res[i] = clip_uint8 (x[i]);
}
-/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 1 "optimized" } } */
-/* { dg-final { scan-tree-dump-times "MAX_EXPR " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times ".SAT_TRUNC " 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR " 2 "optimized" } } */
/* { dg-final { scan-assembler-times {vnclipu\.wi} 3 } } */
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
#include <stdint.h>