* gcc.target/cris/cris.exp (check_effective_target_cc0): New.
+ PR target/93372
* gcc.target/cris/pr93372-1.c: New test.
* gcc.target/cris/pr93372-2.c, gcc.target/cris/pr93372-5.c,
gcc.target/cris/pr93372-8.c: New tests.
+ * gcc.target/cris/pr93372-3.c, gcc.target/cris/pr93372-4.c,
+ gcc.target/cris/pr93372-6.c, gcc.target/cris/pr93372-7.c,
+ gcc.target/cris/pr93372-9.c, gcc.target/cris/pr93372-10.c,
+ gcc.target/cris/pr93372-11.c, gcc.target/cris/pr93372-12.c,
+ gcc.target/cris/pr93372-13.c, gcc.target/cris/pr93372-14.c,
+ gcc.target/cris/pr93372-15.c, gcc.target/cris/pr93372-16.c,
+ gcc.target/cris/pr93372-17.c, gcc.target/cris/pr93372-18.c,
+ gcc.target/cris/pr93372-19.c, gcc.target/cris/pr93372-20.c,
+ gcc.target/cris/pr93372-21.c, gcc.target/cris/pr93372-22.c,
+ gcc.target/cris/pr93372-23.c, gcc.target/cris/pr93372-24.c,
+ gcc.target/cris/pr93372-25.c, gcc.target/cris/pr93372-26.c,
+ gcc.target/cris/pr93372-27.c, gcc.target/cris/pr93372-28.c,
+ gcc.target/cris/pr93372-29.c, gcc.target/cris/pr93372-30.c,
+ gcc.target/cris/pr93372-31.c, gcc.target/cris/pr93372-32.c,
+ gcc.target/cris/pr93372-33.c, gcc.target/cris/pr93372-34.c,
+ gcc.target/cris/pr93372-35.c: New tests.
2020-02-10 Jakub Jelinek <jakub@redhat.com>
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "\tcmp" 1 } } */
+/* { dg-final { scan-assembler-not "\ttest" } } */
+
+#define t char
+#include "pr93372-3.c"
+#include "pr93372-7.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#ifndef t
+#define t short int
+#endif
+#ifndef t2
+#define t2 int
+#endif
+
+#define eq_op(x) ((x) == 0)
+#define ne_op(x) ((x) != 0)
+#define gt_op(x) ((x) > 0)
+#define gtu_op(x) ((x) > 0)
+#define lt_op(x) ((x) < 0)
+#define ltu_op(x) ((x) < 0)
+#define ge_op(x) ((x) >= 0)
+#define geu_op(x) ((x) >= 0)
+#define le_op(x) ((x) <= 0)
+#define leu_op(x) ((x) <= 0)
+
+#define f(n, T, T2) \
+T2 f ## n(T *a, T *b, T2 *d) \
+{ \
+ T2 c = *a; \
+ *d = c; \
+ *b = n ## _op (c); \
+ return c; \
+}
+
+f(eq, t, t2)
+f(ne, t, t2)
+f(gt, t, t2)
+f(gtu, unsigned t, unsigned t2)
+f(lt, t, t2)
+#if 0
+f(ltu, unsigned t, unsigned t2)
+#endif
+f(ge, t, t2)
+#if 0
+f(geu, t, t2)
+#endif
+f(le, t, t2)
+f(leu, t, t2)
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t char
+#include "pr93372-11.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest|\tor" } } */
+
+extern void foo(void);
+
+void f(long long int a, long long int b)
+{
+ if (a + b == 0)
+ foo();
+}
+
+void g(long long int a, long long int b)
+{
+ if (a + b >= 0)
+ foo();
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "\tcmp|\ttest" 2 } } */
+
+extern void foo(void);
+
+void f(long long int a, long long int b)
+{
+ /* Trivial check that we don't eliminate a non-eliminable compare. */
+ if (a + b <= 0)
+ foo();
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "\tcmp|\ttest" 1 } } */
+
+int f(int a, int b, int *d)
+{
+ int c = a + b;
+
+ *d = (c == 0);
+
+ /* See also pr93372-6.c. We should get exactly one compare
+ instruction for this condition. */
+ return c <= 0;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#ifndef t
+#define t short int
+#endif
+#ifndef t2
+#define t2 t
+#endif
+#ifndef op
+#define op +
+#endif
+#ifndef do_f
+#define do_f 1
+#endif
+#ifndef do_g
+#define do_g 1
+#endif
+
+extern void foo(void);
+
+#if do_f
+void f(t a, t b)
+{
+ t2 c = a op b;
+
+ if (c == 0)
+ foo();
+}
+#endif
+
+#if do_g
+void g(t a, t b)
+{
+ t2 c = a op b;
+
+ if (c >= 0)
+ foo();
+}
+#endif
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t signed char
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest|\tor" } } */
+
+#ifndef t
+#define t long long
+#endif
+#ifndef t2
+#define t2 t
+#endif
+#ifndef op
+#define op -
+#endif
+
+extern void foo(t2);
+
+void g(t a, t b)
+{
+ t2 c = a op b;
+
+ if (c >= 0)
+ foo(c);
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t int
+#define op -
+#include "pr93372-18.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t short int
+#define op -
+#include "pr93372-18.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t signed char
+#define op -
+#include "pr93372-18.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t int
+#define op &
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* For the f2, we want an andq, not and.w. */
+/* { dg-final { scan-assembler "\tandq 20," } } */
+/* { dg-final { scan-assembler-not "\tand.w 20," } } */
+/* We don't want a move.w that sets condition codes, but it happens for
+ cc0, as the "andq" that is the last insn before the branch, is for an
+ alternative that matches -32..31 and thus marked as clobbering
+ condition codes. */
+/* { dg-final { scan-assembler-not "\tmove.w" { xfail cc0 } } } */
+
+#define op &
+#include "pr93372-16.c"
+
+#undef op
+#define op & 20 &
+#define f f2
+#define g g2
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* For the f2, we want an andq, not and.b. */
+/* { dg-final { scan-assembler "\tandq 20," } } */
+/* { dg-final { scan-assembler-not "\tand.b 20," } } */
+/* See pr93372-23.c regarding the xfail. */
+/* { dg-final { scan-assembler-not "\tmove.b" { xfail cc0 } } } */
+
+#define op &
+#define t signed char
+#include "pr93372-16.c"
+
+#undef op
+#define op & 20 &
+#define f f2
+#define g g2
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t int
+#define op |
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define op |
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define op |
+#define t signed char
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define op ^
+#define t int
+#include "pr93372-18.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#ifndef t
+#define t int
+#endif
+#ifndef t2
+#define t2 t
+#endif
+#ifndef op
+#define op(x) ~(x)
+#endif
+
+extern void foo(t2);
+
+t2 f(t a, t2 *b, t2 *d)
+{
+ t2 c = op(a);
+
+ *b = c;
+
+ if (c != 0)
+ *d = c;
+
+ return c;
+}
+
+t2 g(t a, t2 *b, t2 *d)
+{
+ t2 c = op(a);
+
+ *b = c;
+
+ if (c <= 0)
+ *d = c;
+
+ return c;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "\tcmp" 1 } } */
+
+#ifndef t
+#define t int
+#endif
+
+int ff(t a, t b, t *d)
+{
+ *d = (a == b);
+
+ return a > b;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#define t int
+#define op >>
+#define f ashrtf
+
+/* If we don't disable g, it will degenerate into a test of the
+ input. */
+#define do_g 0
+
+#include "pr93372-16.c"
+#undef do_g
+
+#undef t
+#define t unsigned int
+#undef f
+#undef g
+#define f lshrtf
+#define g lshrtg
+#include "pr93372-16.c"
+
+#undef f
+#undef g
+#undef op
+#define op <<
+#define f shlf
+#define g shlg
+#include "pr93372-16.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-skip-if "" { "*-*-*" } { "-march=v0" } { "" } } */
+/* { dg-options "-O2" { target march_option } } */
+/* { dg-options "-O2 -march=v10" { target { ! march_option } } } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#ifndef t
+#define t int
+#endif
+#ifndef t2
+#define t2 t
+#endif
+#ifndef t3
+#define t3 t
+#endif
+#ifndef op
+#define op(xx) __builtin_clz(xx)
+#endif
+
+extern t3 x;
+
+t2 f(t a, t2 *b, t2 *d)
+{
+ t2 c = op(a);
+
+ *b = c;
+
+ if (c != 0)
+ *d = c;
+
+ return c;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-skip-if "" { "*-*-*" } { "-march=*" } { "" } } */
+/* { dg-options "-O2 -march=v10" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* { dg-final { scan-assembler "\tswapwb " } } */
+
+#define op(xx) __builtin_bswap32(xx)
+
+#include "pr93372-31.c"
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* { dg-final { scan-assembler "\tbound" } } */
+
+#define t unsigned int
+#define op(xx) ((xx) < x ? (xx) : x)
+
+#include "pr93372-31.c"
--- /dev/null
+/* Check that btst/btstq other than a field starting at bit 0, is used. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tand" } } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* { dg-final { scan-assembler-times "\tbtstq" 3 } } */
+/* { dg-final { scan-assembler-times "\tbtst " 3 } } */
+
+void foo(void);
+
+void f(int *a)
+{
+ if ((*a & 32) != 0)
+ foo();
+}
+
+void g(short int *a)
+{
+ if ((*a & 128) == 0)
+ foo();
+}
+
+void h(char *a)
+{
+ if ((*a & 64) != 0)
+ foo();
+}
+
+void i(int *a, unsigned int n)
+{
+ if ((*a & (1 << n)) != 0)
+ foo();
+}
+
+void j(short int *a, unsigned int n)
+{
+ if ((*a & (1 << n)) == 0)
+ foo();
+}
+
+void k(char *a, unsigned int n)
+{
+ if ((*a & (1 << n)) != 0)
+ foo();
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* { dg-final { scan-assembler "\tneg" } } */
+
+void foo(void);
+
+#ifndef op
+#define op(x) -(x)
+#endif
+
+#define f(k, T, T2) \
+void f ## k (T *a, T2 *b) \
+{ \
+ T2 d = op(*a); \
+ *b = d; \
+ if (d != 0) \
+ foo(); \
+}
+
+#define ff(x, y) f(x, y, y)
+
+/* For NEG, gcc prefers to test the source (before the operation), but
+ will settle for the destination. For SImode, the destination is
+ allocated to a different register than the source. Not that
+ important; just skip the "int" variant for now. */
+#ifndef do_1
+#define do_1 0
+#endif
+
+#ifndef do_2
+#define do_2 1
+#endif
+#ifndef do_3
+#define do_3 1
+#endif
+
+#if do_1
+ff(1, int)
+#endif
+
+#if do_2
+ff(2, short int)
+#endif
+
+#if do_3
+ff(3, signed char)
+#endif
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+int f(int a, int *b)
+{
+ /* As seen in powisf2, the result of a shift is checked for zeroness. */
+ int c = a >> 1;
+ *b = (c == 0);
+ return c;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+/* { dg-final { scan-assembler "\tlsr|\tsmi" } } */
+
+/* Regarding the "lsr", see pr93372-2.c; we get a shift for the
+ sign-bit. For "<", that's equally optimal to smi; we just want this
+ test to be different with the "<" instead of ">=". */
+
+int f(int a, int b, int *d)
+{
+ int c = a + b;
+
+ *d = (c == 0);
+
+ return c < 0;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tcmp|\ttest" } } */
+
+#ifndef t
+#define t int
+#endif
+
+t feq(t *a, t *b)
+{
+ t c = *a;
+ *b = c == 0;
+ return c;
+}
+
+t fne(t *a, t *b)
+{
+ t c = *a;
+ *b = c != 0;
+ return c;
+}
+
+t fgt(t *a, t *b)
+{
+ t c = *a;
+ *b = c > 0;
+ return c;
+}
+
+unsigned t fgtu(unsigned t *a, unsigned t *b)
+{
+ unsigned t c = *a;
+ *b = c > 0;
+ return c;
+}
+
+t flt(t *a, t *b)
+{
+ t c = *a;
+ *b = c < 0;
+ return c;
+}
+
+#if 0
+/* Always false... */
+unsigned t fltu(unsigned t *a, unsigned t *b)
+{
+ unsigned t c = *a;
+ *b = c < 0;
+ return c;
+}
+#endif
+
+t fge(t *a, t *b)
+{
+ t c = *a;
+ *b = c >= 0;
+ return c;
+}
+
+#if 0
+/* Always true... */
+unsigned t fgeu(unsigned t *a, unsigned t *b)
+{
+ unsigned t c = *a;
+ *b = c > 0;
+ return c;
+}
+#endif
+
+t fle(t *a, t *b)
+{
+ t c = *a;
+ *b = c <= 0;
+ return c;
+}
+
+/* Same as eq... */
+unsigned t fleu(unsigned t *a, unsigned t *b)
+{
+ unsigned t c = *a;
+ *b = c <= 0;
+ return c;
+}
--- /dev/null
+/* Check that eliminable compare-instructions are eliminated. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "\tcmp" 1 } } */
+/* { dg-final { scan-assembler-not "\ttest" } } */
+
+#define t short int
+#include "pr93372-3.c"
+#include "pr93372-7.c"