Hopefully this isn't controversial :)
A an area where LLVM generates much better code than GCC today is in
optimization of VLA branches guarded by VLA constants.
Normally in GIMPLE POLY_INT_CSTs have no upport and lower bound because well,
they're poly. However SVE has defined minimum and maximum vector sizes in
the architecture[1] and so for us we do have bounds on these constants.
[1] https://developer.arm.com/documentation/102476/0101/Introducing-SVE
Today LLVM optimizes these simple expressions
#include <arm_sve.h>
int g (void)
{
unsigned int vl = svcntb ();
return vl < 257;
}
int h (void)
{
return svcntw () <= 64;
}
away to
g():
mov w0, #1
ret
h():
mov w0, #1
ret
which is right because both are always true for any SVE vector length.
while GCC generates:
g():
cntb x0
cmp w0, 257
cset w0, cc
ret
h():
cntw x0
cmp x0, 65
cset w0, cc
ret
This patch extends ranger with a target hook poly_int_cst_value_range which
is different from the current costing only hooks used in the vectorizer because
those hooks can't be relied upon for correctness.
This new hook allows us specify the minimum and maximum bounds of a POLY_INT_CST
and have ranger use it in range_query::get_tree_range.
This gets GCC to fold away many known true or known false comparisons in
codegen today and we generate much simpler loop pre-headers.
I have kept the AArch64 parts in this patch to get some extra eyes on it, but
will split them out on commit.
Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.
Ok for master?
Thanks,
Tamar
gcc/ChangeLog:
* config/aarch64/aarch64.cc (aarch64_poly_int_cst_value_range): New.
(TARGET_POLY_INT_CST_VALUE_RANGE): Implement hook using it.
* target.def (poly_int_cst_value_range): New.
* doc/tm.texi.in: Document it.
* doc/tm.texi: Regenerate.
* targhooks.cc (default_poly_int_cst_value_range): New.
* targhooks.h (default_poly_int_cst_value_range): New.
* value-query.cc (range_query::get_tree_range): Use it.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/slp_12.c: Update testcases
* gcc.target/aarch64/sve/cnt_fold_7.c: New test.
* gcc.target/aarch64/sve/cnt_fold_7_run.c: New test.
---
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index
72822ca621f52afee144bffa76bc75aac28adae1..7e12bb0e2c003b80008dd0f3c9fa304c7273ef39
100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -31053,6 +31053,27 @@ aarch64_estimated_poly_value (poly_int64 val,
return val.coeffs[0] + val.coeffs[1] * over_128 / 128;
}
+/* Implement TARGET_POLY_INT_CST_VALUE_RANGE. */
+
+static bool
+aarch64_poly_int_cst_value_range (poly_int64 val, HOST_WIDE_INT *min_val,
+ HOST_WIDE_INT *max_val)
+{
+ unsigned int const_vg;
+ if (aarch64_sve_vg.is_constant (&const_vg))
+ {
+ *min_val = val.coeffs[0];
+ *max_val = *min_val;
+ return true;
+ }
+
+ *min_val = val.coeffs[0];
+ *max_val = val.coeffs[0] + val.coeffs[1] * 15;
+ if (*min_val > *max_val)
+ std::swap (*min_val, *max_val);
+ return true;
+}
+
/* Return true for types that could be supported as SIMD return or
argument types. */
@@ -34370,6 +34391,9 @@ aarch64_libgcc_floating_mode_supported_p
#undef TARGET_ESTIMATED_POLY_VALUE
#define TARGET_ESTIMATED_POLY_VALUE aarch64_estimated_poly_value
+#undef TARGET_POLY_INT_CST_VALUE_RANGE
+#define TARGET_POLY_INT_CST_VALUE_RANGE aarch64_poly_int_cst_value_range
+
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index
6178db74d2fc5d14e8618ee655de05739cb3207c..bfb7e94cf163a75688e6f99473bad4864a57fb24
100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -7509,6 +7509,14 @@ the @code{POLY_VALUE_MIN}, @code{POLY_VALUE_MAX} and
implementation returns the lowest possible value of @var{val}.
@end deftypefn
+@deftypefn {Target Hook} bool TARGET_POLY_INT_CST_VALUE_RANGE (poly_int64
@var{val}, HOST_WIDE_INT *@var{min_val}, HOST_WIDE_INT *@var{max_val})
+Return true if the target can give a conservative inclusive range for
+the runtime value of @var{val}, storing the lower bound in @var{min_val}
+and the upper bound in @var{max_val}. This hook is used for correctness
+rather than for costing, so the returned bounds must be safe for all
+architecturally-valid runtime values.
+@end deftypefn
+
@deftypefn {Target Hook} bool TARGET_AVOID_STORE_FORWARDING_P
(vec<store_fwd_info>, @var{rtx}, @var{int}, @var{bool})
Given a list of stores and a load instruction that reads from the location
of the stores, this hook decides if it's profitable to emit additional code
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index
0a97b0fa2e44014fa9e27d07a06d407a25e1ecc4..3aae8b2de9a3ecee41803a5dcba8f31b4af55b93
100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4812,6 +4812,8 @@ Define this macro if a non-short-circuit operation
produced by
@hook TARGET_ESTIMATED_POLY_VALUE
+@hook TARGET_POLY_INT_CST_VALUE_RANGE
+
@hook TARGET_AVOID_STORE_FORWARDING_P
@node Scheduling
diff --git a/gcc/target.def b/gcc/target.def
index
884fe1bd57e17b3ae92cd052a340f02a2559da31..aab20e89bb16fd9bb7d70d1c403268a65990a3e4
100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4217,6 +4217,16 @@ implementation returns the lowest possible value of
@var{val}.",
HOST_WIDE_INT, (poly_int64 val, poly_value_estimate_kind kind),
default_estimated_poly_value)
+DEFHOOK
+(poly_int_cst_value_range,
+ "Return true if the target can give a conservative inclusive range for\n\
+the runtime value of @var{val}, storing the lower bound in @var{min_val}\n\
+and the upper bound in @var{max_val}. This hook is used for correctness\n\
+rather than for costing, so the returned bounds must be safe for all\n\
+architecturally-valid runtime values.",
+ bool, (poly_int64 val, HOST_WIDE_INT *min_val, HOST_WIDE_INT *max_val),
+ default_poly_int_cst_value_range)
+
/* Permit speculative instructions in delay slots during delayed-branch
scheduling. */
DEFHOOK
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index
388f696c8aa1050edbbc7efbdb01db60d84b4fe0..71f6f769e50298e32434ee94e87a1f3a3dfeef69
100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -2164,6 +2164,19 @@ default_estimated_poly_value (poly_int64 x,
poly_value_estimate_kind)
return x.coeffs[0];
}
+/* The default implementation of TARGET_POLY_INT_CST_VALUE_RANGE. */
+
+bool
+default_poly_int_cst_value_range (poly_int64 x, HOST_WIDE_INT *min_val,
+ HOST_WIDE_INT *max_val)
+{
+ if (!x.is_constant (min_val))
+ return false;
+
+ *max_val = *min_val;
+ return true;
+}
+
/* For hooks which use the MOVE_RATIO macro, this gives the legacy default
behavior. SPEED_P is true if we are compiling for speed. */
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index
86de6ef8a699d72a36c665c697c89ca58314f3fe..90ebc1f514d47ca736c14a641c69ab94f968bb1b
100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -246,6 +246,8 @@ extern int default_frame_allocation_cost (frame_cost_type,
extern bool default_slow_unaligned_access (machine_mode, unsigned int);
extern HOST_WIDE_INT default_estimated_poly_value (poly_int64,
poly_value_estimate_kind);
+extern bool default_poly_int_cst_value_range (poly_int64, HOST_WIDE_INT *,
+ HOST_WIDE_INT *);
extern bool default_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT,
unsigned int,
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c
b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c
new file mode 100644
index
0000000000000000000000000000000000000000..d64933527da7e3e85f37dc231355eb4cd30a1422
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c
@@ -0,0 +1,154 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sve.h>
+
+/*
+** b_lt_257:
+** mov w0, 1
+** ret
+*/
+int
+b_lt_257 (void)
+{
+ unsigned int vl = svcntb ();
+
+ return vl < 257;
+}
+
+/*
+** h_ge_8:
+** mov w0, 1
+** ret
+*/
+int
+h_ge_8 (void)
+{
+ return svcnth () >= 8;
+}
+
+/*
+** w_le_64:
+** mov w0, 1
+** ret
+*/
+int
+w_le_64 (void)
+{
+ return svcntw () <= 64;
+}
+
+/*
+** d_gt_1:
+** mov w0, 1
+** ret
+*/
+int
+d_gt_1 (void)
+{
+ return svcntd () > 1;
+}
+
+/*
+** b_ne_0:
+** mov w0, 1
+** ret
+*/
+int
+b_ne_0 (void)
+{
+ return svcntb () != 0;
+}
+
+/*
+** b_le_15:
+** mov w0, 0
+** ret
+*/
+int
+b_le_15 (void)
+{
+ return svcntb () <= 15;
+}
+
+/*
+** h_lt_8:
+** mov w0, 0
+** ret
+*/
+int
+h_lt_8 (void)
+{
+ return svcnth () < 8;
+}
+
+/*
+** w_gt_64:
+** mov w0, 0
+** ret
+*/
+int
+w_gt_64 (void)
+{
+ return svcntw () > 64;
+}
+
+/*
+** d_eq_0:
+** mov w0, 0
+** ret
+*/
+int
+d_eq_0 (void)
+{
+ return svcntd () == 0;
+}
+
+/*
+** b_lt_256:
+** cntb x0
+** cmp x0, 256
+** cset w0, cc
+** ret
+*/
+int
+b_lt_256 (void)
+{
+ return svcntb () < 256;
+}
+
+/*
+** w_gt_4:
+** cntw x0
+** cmp x0, 4
+** cset w0, hi
+** ret
+*/
+int
+w_gt_4 (void)
+{
+ return svcntw () > 4;
+}
+
+/*
+** b_pat_all_lt_257:
+** mov w0, 1
+** ret
+*/
+int
+b_pat_all_lt_257 (void)
+{
+ return svcntb_pat (SV_ALL) < 257;
+}
+
+/*
+** w_pat_all_le_64:
+** mov w0, 1
+** ret
+*/
+int
+w_pat_all_le_64 (void)
+{
+ return svcntw_pat (SV_ALL) <= 64;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c
b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c
new file mode 100644
index
0000000000000000000000000000000000000000..59217ab343ec03509bccc6d12098e6264adaa8b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c
@@ -0,0 +1,47 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+#define CHECK(EXPR) \
+ do \
+ { \
+ if (!(EXPR)) \
+ __builtin_abort (); \
+ } \
+ while (0)
+
+int
+main (void)
+{
+ unsigned int b = svcntb ();
+ unsigned int h = svcnth ();
+ unsigned int w = svcntw ();
+ unsigned int d = svcntd ();
+
+ CHECK (b >= 16 && b <= 256);
+ CHECK (h >= 8 && h <= 128);
+ CHECK (w >= 4 && w <= 64);
+ CHECK (d >= 2 && d <= 32);
+
+ CHECK (b < 257);
+ CHECK (h >= 8);
+ CHECK (w <= 64);
+ CHECK (d > 1);
+ CHECK (b != 0);
+
+ CHECK (!(b <= 15));
+ CHECK (!(h < 8));
+ CHECK (!(w > 64));
+ CHECK (!(d == 0));
+
+ CHECK ((svcntb () < 256) == (b < 256));
+ CHECK ((svcntw () > 4) == (w > 4));
+
+ CHECK (svcntb_pat (SV_ALL) == b);
+ CHECK (svcntw_pat (SV_ALL) == w);
+ CHECK (svcntb_pat (SV_ALL) < 257);
+ CHECK (svcntw_pat (SV_ALL) <= 64);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
index
0b9f8d9bdfaaf868ba0bd73ae83894c68e1613f8..0b1fef4d23a89b4fa46b45a2662924247eedce17
100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
@@ -47,14 +47,12 @@ TEST_ALL (VEC_PERM)
/* We should use WHILEs for all accesses. */
/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b} 20 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 20 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 30 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 30 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 18 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 24 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 21 } } */
/* 6 for the 8-bit types and 2 for the 16-bit types. */
/* { dg-final { scan-assembler-times {\tuqdecb\t} 8 } } */
-/* 4 for the 16-bit types and 3 for the 32-bit types. */
-/* { dg-final { scan-assembler-times {\tuqdech\t} 7 } } */
-/* 6 for the 32-bit types and 3 for the 64-bit types. */
-/* { dg-final { scan-assembler-times {\tuqdecw\t} 9 } } */
-/* { dg-final { scan-assembler-times {\tuqdecd\t} 6 } } */
+/* { dg-final { scan-assembler-times {\tuqdech\t} 2 } } */
+/* { dg-final { scan-assembler-times {\tuqdecw\t} 3 } } */
+/* { dg-final { scan-assembler-not {\tuqdecd\t} } } */
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index
decf4e4d0ac0eddb2dd6657072bf7c62c2e2ed00..5ce7fac4caeddccd62b587d11b2174a1d0979bac
100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "alloc-pool.h"
#include "gimple-range.h"
#include "value-range-storage.h"
+#include "target.h"
// range_query default methods.
@@ -404,7 +405,20 @@ range_query::get_tree_range (vrange &r, tree expr, gimple
*stmt,
if (POLY_INT_CST_P (expr))
{
unsigned int precision = TYPE_PRECISION (type);
- r.set_varying (type);
+ HOST_WIDE_INT min_val, max_val;
+ if (tree_fits_poly_int64_p (expr)
+ && targetm.poly_int_cst_value_range (tree_to_poly_int64 (expr),
+ &min_val, &max_val))
+ {
+ wide_int min = wi::shwi (min_val, precision);
+ wide_int max = wi::shwi (max_val, precision);
+ if (wi::le_p (min, max, TYPE_SIGN (type)))
+ as_a <irange> (r).set (type, min, max);
+ else
+ r.set_varying (type);
+ }
+ else
+ r.set_varying (type);
r.update_bitmask ({ wi::zero (precision), get_nonzero_bits (expr) });
return true;
}
--
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 72822ca621f52afee144bffa76bc75aac28adae1..7e12bb0e2c003b80008dd0f3c9fa304c7273ef39 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -31053,6 +31053,27 @@ aarch64_estimated_poly_value (poly_int64 val,
return val.coeffs[0] + val.coeffs[1] * over_128 / 128;
}
+/* Implement TARGET_POLY_INT_CST_VALUE_RANGE. */
+
+static bool
+aarch64_poly_int_cst_value_range (poly_int64 val, HOST_WIDE_INT *min_val,
+ HOST_WIDE_INT *max_val)
+{
+ unsigned int const_vg;
+ if (aarch64_sve_vg.is_constant (&const_vg))
+ {
+ *min_val = val.coeffs[0];
+ *max_val = *min_val;
+ return true;
+ }
+
+ *min_val = val.coeffs[0];
+ *max_val = val.coeffs[0] + val.coeffs[1] * 15;
+ if (*min_val > *max_val)
+ std::swap (*min_val, *max_val);
+ return true;
+}
+
/* Return true for types that could be supported as SIMD return or
argument types. */
@@ -34370,6 +34391,9 @@ aarch64_libgcc_floating_mode_supported_p
#undef TARGET_ESTIMATED_POLY_VALUE
#define TARGET_ESTIMATED_POLY_VALUE aarch64_estimated_poly_value
+#undef TARGET_POLY_INT_CST_VALUE_RANGE
+#define TARGET_POLY_INT_CST_VALUE_RANGE aarch64_poly_int_cst_value_range
+
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 6178db74d2fc5d14e8618ee655de05739cb3207c..bfb7e94cf163a75688e6f99473bad4864a57fb24 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -7509,6 +7509,14 @@ the @code{POLY_VALUE_MIN}, @code{POLY_VALUE_MAX} and
implementation returns the lowest possible value of @var{val}.
@end deftypefn
+@deftypefn {Target Hook} bool TARGET_POLY_INT_CST_VALUE_RANGE (poly_int64 @var{val}, HOST_WIDE_INT *@var{min_val}, HOST_WIDE_INT *@var{max_val})
+Return true if the target can give a conservative inclusive range for
+the runtime value of @var{val}, storing the lower bound in @var{min_val}
+and the upper bound in @var{max_val}. This hook is used for correctness
+rather than for costing, so the returned bounds must be safe for all
+architecturally-valid runtime values.
+@end deftypefn
+
@deftypefn {Target Hook} bool TARGET_AVOID_STORE_FORWARDING_P (vec<store_fwd_info>, @var{rtx}, @var{int}, @var{bool})
Given a list of stores and a load instruction that reads from the location
of the stores, this hook decides if it's profitable to emit additional code
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0a97b0fa2e44014fa9e27d07a06d407a25e1ecc4..3aae8b2de9a3ecee41803a5dcba8f31b4af55b93 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4812,6 +4812,8 @@ Define this macro if a non-short-circuit operation produced by
@hook TARGET_ESTIMATED_POLY_VALUE
+@hook TARGET_POLY_INT_CST_VALUE_RANGE
+
@hook TARGET_AVOID_STORE_FORWARDING_P
@node Scheduling
diff --git a/gcc/target.def b/gcc/target.def
index 884fe1bd57e17b3ae92cd052a340f02a2559da31..aab20e89bb16fd9bb7d70d1c403268a65990a3e4 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4217,6 +4217,16 @@ implementation returns the lowest possible value of @var{val}.",
HOST_WIDE_INT, (poly_int64 val, poly_value_estimate_kind kind),
default_estimated_poly_value)
+DEFHOOK
+(poly_int_cst_value_range,
+ "Return true if the target can give a conservative inclusive range for\n\
+the runtime value of @var{val}, storing the lower bound in @var{min_val}\n\
+and the upper bound in @var{max_val}. This hook is used for correctness\n\
+rather than for costing, so the returned bounds must be safe for all\n\
+architecturally-valid runtime values.",
+ bool, (poly_int64 val, HOST_WIDE_INT *min_val, HOST_WIDE_INT *max_val),
+ default_poly_int_cst_value_range)
+
/* Permit speculative instructions in delay slots during delayed-branch
scheduling. */
DEFHOOK
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 388f696c8aa1050edbbc7efbdb01db60d84b4fe0..71f6f769e50298e32434ee94e87a1f3a3dfeef69 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -2164,6 +2164,19 @@ default_estimated_poly_value (poly_int64 x, poly_value_estimate_kind)
return x.coeffs[0];
}
+/* The default implementation of TARGET_POLY_INT_CST_VALUE_RANGE. */
+
+bool
+default_poly_int_cst_value_range (poly_int64 x, HOST_WIDE_INT *min_val,
+ HOST_WIDE_INT *max_val)
+{
+ if (!x.is_constant (min_val))
+ return false;
+
+ *max_val = *min_val;
+ return true;
+}
+
/* For hooks which use the MOVE_RATIO macro, this gives the legacy default
behavior. SPEED_P is true if we are compiling for speed. */
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 86de6ef8a699d72a36c665c697c89ca58314f3fe..90ebc1f514d47ca736c14a641c69ab94f968bb1b 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -246,6 +246,8 @@ extern int default_frame_allocation_cost (frame_cost_type,
extern bool default_slow_unaligned_access (machine_mode, unsigned int);
extern HOST_WIDE_INT default_estimated_poly_value (poly_int64,
poly_value_estimate_kind);
+extern bool default_poly_int_cst_value_range (poly_int64, HOST_WIDE_INT *,
+ HOST_WIDE_INT *);
extern bool default_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT,
unsigned int,
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c
new file mode 100644
index 0000000000000000000000000000000000000000..d64933527da7e3e85f37dc231355eb4cd30a1422
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7.c
@@ -0,0 +1,154 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sve.h>
+
+/*
+** b_lt_257:
+** mov w0, 1
+** ret
+*/
+int
+b_lt_257 (void)
+{
+ unsigned int vl = svcntb ();
+
+ return vl < 257;
+}
+
+/*
+** h_ge_8:
+** mov w0, 1
+** ret
+*/
+int
+h_ge_8 (void)
+{
+ return svcnth () >= 8;
+}
+
+/*
+** w_le_64:
+** mov w0, 1
+** ret
+*/
+int
+w_le_64 (void)
+{
+ return svcntw () <= 64;
+}
+
+/*
+** d_gt_1:
+** mov w0, 1
+** ret
+*/
+int
+d_gt_1 (void)
+{
+ return svcntd () > 1;
+}
+
+/*
+** b_ne_0:
+** mov w0, 1
+** ret
+*/
+int
+b_ne_0 (void)
+{
+ return svcntb () != 0;
+}
+
+/*
+** b_le_15:
+** mov w0, 0
+** ret
+*/
+int
+b_le_15 (void)
+{
+ return svcntb () <= 15;
+}
+
+/*
+** h_lt_8:
+** mov w0, 0
+** ret
+*/
+int
+h_lt_8 (void)
+{
+ return svcnth () < 8;
+}
+
+/*
+** w_gt_64:
+** mov w0, 0
+** ret
+*/
+int
+w_gt_64 (void)
+{
+ return svcntw () > 64;
+}
+
+/*
+** d_eq_0:
+** mov w0, 0
+** ret
+*/
+int
+d_eq_0 (void)
+{
+ return svcntd () == 0;
+}
+
+/*
+** b_lt_256:
+** cntb x0
+** cmp x0, 256
+** cset w0, cc
+** ret
+*/
+int
+b_lt_256 (void)
+{
+ return svcntb () < 256;
+}
+
+/*
+** w_gt_4:
+** cntw x0
+** cmp x0, 4
+** cset w0, hi
+** ret
+*/
+int
+w_gt_4 (void)
+{
+ return svcntw () > 4;
+}
+
+/*
+** b_pat_all_lt_257:
+** mov w0, 1
+** ret
+*/
+int
+b_pat_all_lt_257 (void)
+{
+ return svcntb_pat (SV_ALL) < 257;
+}
+
+/*
+** w_pat_all_le_64:
+** mov w0, 1
+** ret
+*/
+int
+w_pat_all_le_64 (void)
+{
+ return svcntw_pat (SV_ALL) <= 64;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c
new file mode 100644
index 0000000000000000000000000000000000000000..59217ab343ec03509bccc6d12098e6264adaa8b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/cnt_fold_7_run.c
@@ -0,0 +1,47 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+#define CHECK(EXPR) \
+ do \
+ { \
+ if (!(EXPR)) \
+ __builtin_abort (); \
+ } \
+ while (0)
+
+int
+main (void)
+{
+ unsigned int b = svcntb ();
+ unsigned int h = svcnth ();
+ unsigned int w = svcntw ();
+ unsigned int d = svcntd ();
+
+ CHECK (b >= 16 && b <= 256);
+ CHECK (h >= 8 && h <= 128);
+ CHECK (w >= 4 && w <= 64);
+ CHECK (d >= 2 && d <= 32);
+
+ CHECK (b < 257);
+ CHECK (h >= 8);
+ CHECK (w <= 64);
+ CHECK (d > 1);
+ CHECK (b != 0);
+
+ CHECK (!(b <= 15));
+ CHECK (!(h < 8));
+ CHECK (!(w > 64));
+ CHECK (!(d == 0));
+
+ CHECK ((svcntb () < 256) == (b < 256));
+ CHECK ((svcntw () > 4) == (w > 4));
+
+ CHECK (svcntb_pat (SV_ALL) == b);
+ CHECK (svcntw_pat (SV_ALL) == w);
+ CHECK (svcntb_pat (SV_ALL) < 257);
+ CHECK (svcntw_pat (SV_ALL) <= 64);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
index 0b9f8d9bdfaaf868ba0bd73ae83894c68e1613f8..0b1fef4d23a89b4fa46b45a2662924247eedce17 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
@@ -47,14 +47,12 @@ TEST_ALL (VEC_PERM)
/* We should use WHILEs for all accesses. */
/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b} 20 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 20 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 30 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 30 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 18 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 24 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 21 } } */
/* 6 for the 8-bit types and 2 for the 16-bit types. */
/* { dg-final { scan-assembler-times {\tuqdecb\t} 8 } } */
-/* 4 for the 16-bit types and 3 for the 32-bit types. */
-/* { dg-final { scan-assembler-times {\tuqdech\t} 7 } } */
-/* 6 for the 32-bit types and 3 for the 64-bit types. */
-/* { dg-final { scan-assembler-times {\tuqdecw\t} 9 } } */
-/* { dg-final { scan-assembler-times {\tuqdecd\t} 6 } } */
+/* { dg-final { scan-assembler-times {\tuqdech\t} 2 } } */
+/* { dg-final { scan-assembler-times {\tuqdecw\t} 3 } } */
+/* { dg-final { scan-assembler-not {\tuqdecd\t} } } */
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index decf4e4d0ac0eddb2dd6657072bf7c62c2e2ed00..5ce7fac4caeddccd62b587d11b2174a1d0979bac 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "alloc-pool.h"
#include "gimple-range.h"
#include "value-range-storage.h"
+#include "target.h"
// range_query default methods.
@@ -404,7 +405,20 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
if (POLY_INT_CST_P (expr))
{
unsigned int precision = TYPE_PRECISION (type);
- r.set_varying (type);
+ HOST_WIDE_INT min_val, max_val;
+ if (tree_fits_poly_int64_p (expr)
+ && targetm.poly_int_cst_value_range (tree_to_poly_int64 (expr),
+ &min_val, &max_val))
+ {
+ wide_int min = wi::shwi (min_val, precision);
+ wide_int max = wi::shwi (max_val, precision);
+ if (wi::le_p (min, max, TYPE_SIGN (type)))
+ as_a <irange> (r).set (type, min, max);
+ else
+ r.set_varying (type);
+ }
+ else
+ r.set_varying (type);
r.update_bitmask ({ wi::zero (precision), get_nonzero_bits (expr) });
return true;
}