@@ -437,25 +437,24 @@ along with GCC; see the file COPYING3. If not see
(negate (nop_convert? (convert (lt @0 integer_zerop)))))
INTEGER_CST@3)
(convert @0))
- /* The comparison has to be the unsigned reinterpretation of X, and the
- conversion has to narrow, otherwise the constants below do not have the
- precision the comparison is carried out at. */
- (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@4))
- && TYPE_PRECISION (TREE_TYPE (@4)) == TYPE_PRECISION (TREE_TYPE (@0))
- && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))
+ /* The comparison type has to be unsigned and at least as wide as X. A
+ narrower type would examine only the low bits of X. The result
+ conversion has to narrow X. */
+ (if (!TYPE_UNSIGNED (TREE_TYPE (@0))
+ && TYPE_UNSIGNED (TREE_TYPE (@4))
+ && (TYPE_PRECISION (TREE_TYPE (@4))
+ >= TYPE_PRECISION (TREE_TYPE (@0)))
+ && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))
(with
{
- unsigned itype_prec = TYPE_PRECISION (TREE_TYPE (@0));
unsigned otype_prec = TYPE_PRECISION (type);
- wide_int offset = wi::uhwi (HOST_WIDE_INT_1U << (otype_prec - 1),
- itype_prec); // Aka 128 for int8_t
- wide_int limit_0 = wi::mask (otype_prec, false, itype_prec); // Aka 255
- wide_int limit_1 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 3,
- itype_prec); // Aka 253
- wide_int limit_2 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 2,
- itype_prec); // Aka 254
+ unsigned range_prec = TYPE_PRECISION (TREE_TYPE (@4));
+ wide_int offset = wi::set_bit_in_zero (otype_prec - 1, range_prec);
+ wide_int limit_0 = wi::mask (otype_prec, false, range_prec); // Aka 255
+ wide_int limit_1 = limit_0 - 2; // Aka 253
+ wide_int limit_2 = limit_0 - 1; // Aka 254
wide_int otype_max = wi::mask (otype_prec - 1, false, otype_prec);
- wide_int itype_max = wi::mask (otype_prec - 1, false, itype_prec);
+ wide_int itype_max = wi::mask (otype_prec - 1, false, range_prec);
wide_int int_cst_1 = wi::to_wide (@1);
wide_int int_cst_2 = wi::to_wide (@2);
wide_int int_cst_3 = wi::to_wide (@3);
new file mode 100644
@@ -0,0 +1,122 @@
+/* { dg-do run { target bitint } } */
+/* { dg-additional-options "-O3 -fvect-cost-model=unlimited" } */
+
+typedef __INT8_TYPE__ int8_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __INT32_TYPE__ int32_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef signed _BitInt(16) int16b_t;
+typedef unsigned _BitInt(17) uint17_t;
+
+#define N 259
+#define SAT_VALUE(OUT, X, MAX) ((OUT) (-((OUT) ((X) < 0)) ^ (OUT) MAX))
+
+__attribute__((noipa))
+static void
+wide_range (int8_t *__restrict out, const int16b_t *__restrict in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int16b_t source = in[i];
+ uint32_t range = (uint32_t) source + 128U;
+ out[i] = (range > 255U
+ ? SAT_VALUE (int8_t, source, 127) : (int8_t) source);
+ }
+}
+
+__attribute__((noipa))
+static void
+narrow_range (int16_t *__restrict out, const int32_t *__restrict in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int32_t source = in[i];
+ uint17_t range = (uint17_t) source + (uint17_t) 32768;
+ out[i] = (range > (uint17_t) 65535
+ ? SAT_VALUE (int16_t, source, 32767) : (int16_t) source);
+ }
+}
+
+__attribute__((noipa, optimize ("O0")))
+static void
+wide_range_ref (int8_t *out, const int16b_t *in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int16b_t source = in[i];
+ if (source < -128)
+ out[i] = -128;
+ else if (source > 127)
+ out[i] = 127;
+ else
+ out[i] = (int8_t) source;
+ }
+}
+
+__attribute__((noipa, optimize ("O0")))
+static void
+narrow_range_ref (int16_t *out, const int32_t *in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int32_t source = in[i];
+ uint17_t range = (uint17_t) source + (uint17_t) 32768;
+ out[i] = (range > (uint17_t) 65535
+ ? SAT_VALUE (int16_t, source, 32767) : (int16_t) source);
+ }
+}
+
+static void
+check_wide_range (void)
+{
+ int8_t out[N];
+ int8_t ref[N];
+ int16b_t in[N];
+
+ for (int i = 0; i < N; ++i)
+ in[i] = (uint16_t) i * 40503U + 97U;
+
+ for (int n = 0; n <= N; ++n)
+ {
+ for (int i = 0; i < N; ++i)
+ out[i] = ref[i] = 23;
+ wide_range (out, in, n);
+ wide_range_ref (ref, in, n);
+ for (int i = 0; i < N; ++i)
+ if (out[i] != ref[i])
+ __builtin_abort ();
+ }
+}
+
+static void
+check_narrow_range (void)
+{
+ int16_t out[N];
+ int16_t ref[N];
+ int32_t in[N];
+
+ for (int i = 0; i < N; ++i)
+ in[i] = (int32_t) ((uint32_t) i * 2654435761U + 1013904223U);
+ in[0] = 131072;
+
+ for (int n = 0; n <= N; ++n)
+ {
+ for (int i = 0; i < N; ++i)
+ out[i] = ref[i] = 23;
+ narrow_range (out, in, n);
+ narrow_range_ref (ref, in, n);
+ for (int i = 0; i < N; ++i)
+ if (out[i] != ref[i])
+ __builtin_abort ();
+ }
+}
+
+int
+main (void)
+{
+ check_wide_range ();
+ check_narrow_range ();
+ return 0;
+}
+
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-O3 -march=armv8-a" } */
+/* { dg-additional-options "-mmax-vectorization --param=vect-epilogues-nomask=0 -fdump-tree-vect-details" } */
+
+#include "../../gcc.dg/vect/vect-sat-trunc-range-precision-1.c"
+
+/* { dg-final { scan-tree-dump-times "sat_trunc pattern recognized" 1 "vect" } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-O3 -march=armv8-a" } */
+/* { dg-additional-options "-mmax-vectorization --param=vect-epilogues-nomask=0 -fdump-tree-vect-details" } */
+
+typedef __INT16_TYPE__ int16_t;
+typedef __INT32_TYPE__ int32_t;
+typedef unsigned _BitInt(17) uint17_t;
+
+#define SAT_VALUE(X) ((int16_t) (-((int16_t) ((X) < 0)) ^ 32767))
+
+__attribute__((noipa))
+void
+narrow_range (int16_t *__restrict out, const int32_t *__restrict in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int32_t source = in[i];
+ uint17_t range = (uint17_t) source + (uint17_t) 32768;
+ out[i] = (range > (uint17_t) 65535
+ ? SAT_VALUE (source) : (int16_t) source);
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "sat_trunc pattern recognized" "vect" } } */