[AArch64] Improve bit tests [PR105773]

Message ID AS4PR08MB7901314F7E77FB81A079AE5F835D9@AS4PR08MB7901.eurprd08.prod.outlook.com
State Accepted, archived
Headers
Series [AArch64] Improve bit tests [PR105773] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Wilco Dijkstra Oct. 5, 2022, 12:30 p.m. UTC
  Since AArch64 sets all flags on logical operations, comparisons with zero
can be combined into an AND even if the condition is LE or GT.

Passes regress, OK for commit?

gcc:
	PR target/105773
	* config/aarch64/aarch64.cc (aarch64_select_cc_mode): Allow
	GT/LE for merging compare with zero into AND.
	(aarch64_get_condition_code_1): Support GT and LE in CC_NZmode.

gcc/testsuite:
	PR target/105773
	* gcc.target/aarch64/ands_2.c: Test for ANDS.
	* gcc.target/aarch64/bics_2.c: Test for BICS.
	* gcc.target/aarch64/tst_2.c: Test for TST.
	* gcc.target/aarch64/tst_imm_split_1.c: Fix test.

---
  

Comments

Richard Sandiford Oct. 5, 2022, 4:54 p.m. UTC | #1
Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> Since AArch64 sets all flags on logical operations, comparisons with zero
> can be combined into an AND even if the condition is LE or GT.
>
> Passes regress, OK for commit?
>
> gcc:
>         PR target/105773
>         * config/aarch64/aarch64.cc (aarch64_select_cc_mode): Allow
>         GT/LE for merging compare with zero into AND.
>         (aarch64_get_condition_code_1): Support GT and LE in CC_NZmode.

Realise this is awkward, but: CC_NZmode is for operations that set only
the N and Z flags to useful values.  If we want to take advantage of V
being zero then I think we need a different mode.

We can't go all the way to CCmode because the carry flag has the opposite
value compared to subtraction.  But we could have either:

* CC_INVC (inverted carry) that handles all comparisons, including the
  redundant unsigned comparisons

* CC_NZV

Guess I've got a slight preference for CC_INVC, but either would be OK IMO.

Thanks,
Richard

>
> gcc/testsuite:
>         PR target/105773
>         * gcc.target/aarch64/ands_2.c: Test for ANDS.
>         * gcc.target/aarch64/bics_2.c: Test for BICS.
>         * gcc.target/aarch64/tst_2.c: Test for TST.
>         * gcc.target/aarch64/tst_imm_split_1.c: Fix test.
>
> ---
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 1601d11710cb6132c80a77bb4fe2f8429519aa5a..00876b08d8fbb1329a37a0ea73d3abf09d28b829 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -11323,7 +11323,8 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
>
>    if ((mode_x == SImode || mode_x == DImode)
>        && y == const0_rtx
> -      && (code == EQ || code == NE || code == LT || code == GE)
> +      && (code == EQ || code == NE || code == LT || code == GE
> +         || (code_x == AND && (code == GT || code == LE)))
>        && (code_x == PLUS || code_x == MINUS || code_x == AND
>           || code_x == NEG
>           || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
> @@ -11471,6 +11472,8 @@ aarch64_get_condition_code_1 (machine_mode mode, enum rtx_code comp_code)
>         case EQ: return AARCH64_EQ;
>         case GE: return AARCH64_PL;
>         case LT: return AARCH64_MI;
> +       case GT: return AARCH64_GT;
> +       case LE: return AARCH64_LE;
>         default: return -1;
>         }
>        break;
> diff --git a/gcc/testsuite/gcc.target/aarch64/ands_2.c b/gcc/testsuite/gcc.target/aarch64/ands_2.c
> index b061b1dfc59c1847cb799a1e49f8e5fc53bf2f14..c8763f234c5f7d19ef9c222756ab5e8a6eaae6fe 100644
> --- a/gcc/testsuite/gcc.target/aarch64/ands_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/ands_2.c
> @@ -8,8 +8,7 @@ ands_si_test1 (int a, int b, int c)
>  {
>    int d = a & b;
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -21,12 +20,11 @@ ands_si_test2 (int a, int b, int c)
>  {
>    int d = a & 0x99999999;
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  int
> @@ -34,8 +32,7 @@ ands_si_test3 (int a, int b, int c)
>  {
>    int d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -49,8 +46,7 @@ ands_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & b;
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -62,12 +58,11 @@ ands_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & 0xaaaaaaaaaaaaaaaall;
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  s64
> @@ -75,8 +70,7 @@ ands_di_test3 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return a + c;
>    else
> diff --git a/gcc/testsuite/gcc.target/aarch64/bics_2.c b/gcc/testsuite/gcc.target/aarch64/bics_2.c
> index 9ccae368c1276618bad691c78fb621a9c82794b7..c1f7e87a6121f7b067b7b37b149da64aa63ebd1a 100644
> --- a/gcc/testsuite/gcc.target/aarch64/bics_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/bics_2.c
> @@ -8,8 +8,7 @@ bics_si_test1 (int a, int b, int c)
>  {
>    int d = a & ~b;
>
> -  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -21,12 +20,11 @@ bics_si_test2 (int a, int b, int c)
>  {
>    int d = a & ~(b << 3);
>
> -  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  typedef long long s64;
> @@ -36,8 +34,7 @@ bics_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & ~b;
>
> -  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -49,12 +46,11 @@ bics_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & ~(b << 3);
>
> -  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  int
> diff --git a/gcc/testsuite/gcc.target/aarch64/tst_2.c b/gcc/testsuite/gcc.target/aarch64/tst_2.c
> index c8b28fc5620a9140fee29c4455294af708642d69..3c9bdfd05c4a19e83150f84f454c3e875c7757d1 100644
> --- a/gcc/testsuite/gcc.target/aarch64/tst_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/tst_2.c
> @@ -8,8 +8,7 @@ tst_si_test1 (int a, int b, int c)
>  {
>    int d = a & b;
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -21,12 +20,11 @@ tst_si_test2 (int a, int b, int c)
>  {
>    int d = a & 0x99999999;
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  if (d <= 0)
> -    return 12;
> -  else
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, -1717986919" } } */
> +  if (d > 0)
>      return 18;
> +  else
> +    return 12;
>  }
>
>  int
> @@ -34,8 +32,7 @@ tst_si_test3 (int a, int b, int c)
>  {
>    int d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -49,8 +46,7 @@ tst_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & b;
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -62,8 +58,7 @@ tst_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & 0xaaaaaaaaaaaaaaaall;
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, -6148914691236517206" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -75,12 +70,11 @@ tst_di_test3 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return 12;
> -  else
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return 18;
> +  else
> +    return 12;
>  }
>
>  int
> diff --git a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> index 33a2c0f45afadb8fc9488f847f296ec0e690c049..e456e823593fbe507a8a67b5115a45712e40f80e 100644
> --- a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> +++ b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> @@ -14,5 +14,4 @@ g (unsigned char *p)
>  }
>
>  /* { dg-final { scan-assembler-not "and\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+.*" } } */
> -/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" } } */
> -/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+, lsr 4" } } */
> +/* { dg-final { scan-assembler-times "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" 2 } } */
  
Wilco Dijkstra Oct. 12, 2022, 2:38 p.m. UTC | #2
Hi Richard,

> Realise this is awkward, but: CC_NZmode is for operations that set only
> the N and Z flags to useful values.  If we want to take advantage of V
> being zero then I think we need a different mode.
>
> We can't go all the way to CCmode because the carry flag has the opposite
> value compared to subtraction.  But we could have either:
> 
> * CC_INVC (inverted carry) that handles all comparisons, including the
>   redundant unsigned comparisons
>
> * CC_NZV
>
> Guess I've got a slight preference for CC_INVC, but either would be OK IMO.

I've added CC_NZV since that's easier to understand and unsigned comparisons
with zero are always changed into equality comparisons. There were a few cases
where CC_NZ mode was used rather than CC_Z, so I changed those too.

Cheers,
Wilco

v2: Add new CC_NZV mode for cmp+and.

Since AArch64 sets all flags on logical operations, comparisons with zero
can be combined into an AND even if the condition is LE or GT. Add a new
CC_NZV mode used by ANDS/BICS/TST instructions.

Passes regress, OK for commit?

gcc/ChangeLog:

	PR target/105773
	* config/aarch64/aarch64.cc (aarch64_select_cc_mode): Allow
	GT/LE for merging compare with zero into AND.
	(aarch64_get_condition_code_1): Add CC_NZVmode support.
        * config/aarch64/aarch64-modes.def: Add CC_NZV.
        * config/aarch64/aarch64.md: Use CC_NZV in cmp+and patterns.

gcc/testsuite:
	PR target/105773
	* gcc.target/aarch64/ands_2.c: Test for ANDS.
	* gcc.target/aarch64/bics_2.c: Test for BICS.
	* gcc.target/aarch64/tst_2.c: Test for TST.
	* gcc.target/aarch64/tst_imm_split_1.c: Fix test.

---

diff --git a/gcc/config/aarch64/aarch64-modes.def b/gcc/config/aarch64/aarch64-modes.def
index d3c9b74434cd2c0d0cb1a2fd26af8c0bf38a4cfa..0fd4c32ad0bd09f8651d1b8a77378fa4504ff488 100644
--- a/gcc/config/aarch64/aarch64-modes.def
+++ b/gcc/config/aarch64/aarch64-modes.def
@@ -35,6 +35,7 @@ CC_MODE (CCFPE);
 CC_MODE (CC_SWP);
 CC_MODE (CC_NZC);   /* Only N, Z and C bits of condition flags are valid.
 		       (Used with SVE predicate tests.)  */
+CC_MODE (CC_NZV);   /* Only N, Z and V bits of condition flags are valid.  */
 CC_MODE (CC_NZ);    /* Only N and Z bits of condition flags are valid.  */
 CC_MODE (CC_Z);     /* Only Z bit of condition flags is valid.  */
 CC_MODE (CC_C);     /* C represents unsigned overflow of a simple addition.  */
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 3a4b1f6987487e959648a343bb25180ea419f397..600e0f41d51242a6f100b3643ce8421ea116ec5c 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -11284,7 +11284,7 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
   if (y == const0_rtx && (REG_P (x) || SUBREG_P (x))
       && (code == EQ || code == NE)
       && (mode_x == HImode || mode_x == QImode))
-    return CC_NZmode;
+    return CC_Zmode;
 
   /* Similarly, comparisons of zero_extends from shorter modes can
      be performed using an ANDS with an immediate mask.  */
@@ -11292,15 +11292,22 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
       && (mode_x == SImode || mode_x == DImode)
       && (GET_MODE (XEXP (x, 0)) == HImode || GET_MODE (XEXP (x, 0)) == QImode)
       && (code == EQ || code == NE))
-    return CC_NZmode;
+    return CC_Zmode;
+
+  /* ANDS/BICS/TST support equality and all signed comparisons.  */
+  if ((mode_x == SImode || mode_x == DImode)
+      && y == const0_rtx
+      && (code_x == AND || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
+			    && CONST_INT_P (XEXP (x, 2))))
+      && (code == EQ || code == NE || code == LT || code == GE
+	  || code == GT || code == LE))
+    return CC_NZVmode;
 
+  /* ADDS/SUBS correctly set N and Z flags.  */
   if ((mode_x == SImode || mode_x == DImode)
       && y == const0_rtx
       && (code == EQ || code == NE || code == LT || code == GE)
-      && (code_x == PLUS || code_x == MINUS || code_x == AND
-	  || code_x == NEG
-	  || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
-	      && CONST_INT_P (XEXP (x, 2)))))
+      && (code_x == PLUS || code_x == MINUS || code_x == NEG))
     return CC_NZmode;
 
   /* A compare with a shifted operand.  Because of canonicalization,
@@ -11437,6 +11444,19 @@ aarch64_get_condition_code_1 (machine_mode mode, enum rtx_code comp_code)
 	}
       break;
 
+    case E_CC_NZVmode:
+      switch (comp_code)
+	{
+	case NE: return AARCH64_NE;
+	case EQ: return AARCH64_EQ;
+	case GE: return AARCH64_PL;
+	case LT: return AARCH64_MI;
+	case GT: return AARCH64_GT;
+	case LE: return AARCH64_LE;
+	default: return -1;
+	}
+      break;
+
     case E_CC_NZmode:
       switch (comp_code)
 	{
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 23ceca48543d23b85beea1f0bf98ef83051d80b6..cc58373144890c617ff6ce16ca37d14e0617bf3b 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -4513,8 +4513,8 @@ (define_insn "*<optab>si3_uxtw"
 )
 
 (define_insn "*and<mode>3_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (match_operand:GPI 1 "register_operand" "%r,r")
 		  (match_operand:GPI 2 "aarch64_logical_operand" "r,<lconst>"))
 	 (const_int 0)))
@@ -4529,8 +4529,8 @@ (define_insn "*and<mode>3_compare0"
 
 ;; zero_extend version of above
 (define_insn "*andsi3_compare0_uxtw"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:SI (match_operand:SI 1 "register_operand" "%r,r")
 		 (match_operand:SI 2 "aarch64_logical_operand" "r,K"))
 	 (const_int 0)))
@@ -4544,8 +4544,8 @@ (define_insn "*andsi3_compare0_uxtw"
 )
 
 (define_insn "*and_<SHIFT:optab><mode>3_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (SHIFT:GPI
 		   (match_operand:GPI 1 "register_operand" "r")
 		   (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
@@ -4564,8 +4564,8 @@ (define_insn "*and_<SHIFT:optab><mode>3_compare0"
 
 ;; zero_extend version of above
 (define_insn "*and_<SHIFT:optab>si3_compare0_uxtw"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:SI (SHIFT:SI
 		  (match_operand:SI 1 "register_operand" "r")
 		  (match_operand:QI 2 "aarch64_shift_imm_si" "n"))
@@ -4769,8 +4769,8 @@ (define_insn_and_split "*xor_one_cmpl<mode>3"
 )
 
 (define_insn "*and_one_cmpl<mode>3_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (not:GPI
 		   (match_operand:GPI 1 "register_operand" "r"))
 		  (match_operand:GPI 2 "register_operand" "r"))
@@ -4784,8 +4784,8 @@ (define_insn "*and_one_cmpl<mode>3_compare0"
 
 ;; zero_extend version of above
 (define_insn "*and_one_cmplsi3_compare0_uxtw"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:SI (not:SI
 		  (match_operand:SI 1 "register_operand" "r"))
 		 (match_operand:SI 2 "register_operand" "r"))
@@ -4798,8 +4798,8 @@ (define_insn "*and_one_cmplsi3_compare0_uxtw"
 )
 
 (define_insn "*and_one_cmpl<mode>3_compare0_no_reuse"
-  [(set (reg:CC_NZ CC_REGNUM)
-    (compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+    (compare:CC_NZV
      (and:GPI (not:GPI
            (match_operand:GPI 0 "register_operand" "r"))
           (match_operand:GPI 1 "register_operand" "r"))
@@ -4877,8 +4877,8 @@ (define_insn "*eor_one_cmpl_<SHIFT:optab>sidi3_alt_ze"
 )
 
 (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (not:GPI
 		   (SHIFT:GPI
 		    (match_operand:GPI 1 "register_operand" "r")
@@ -4900,8 +4900,8 @@ (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0"
 
 ;; zero_extend version of above
 (define_insn "*and_one_cmpl_<SHIFT:optab>si3_compare0_uxtw"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:SI (not:SI
 		  (SHIFT:SI
 		   (match_operand:SI 1 "register_operand" "r")
@@ -4922,8 +4922,8 @@ (define_insn "*and_one_cmpl_<SHIFT:optab>si3_compare0_uxtw"
 )
 
 (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0_no_reuse"
-  [(set (reg:CC_NZ CC_REGNUM)
-    (compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+    (compare:CC_NZV
      (and:GPI (not:GPI
            (SHIFT:GPI
             (match_operand:GPI 0 "register_operand" "r")
@@ -5028,8 +5028,8 @@ (define_insn_and_split "ctz<mode>2"
 ")
 
 (define_insn "*and<mode>_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_Z CC_REGNUM)
+	(compare:CC_Z
 	 (match_operand:SHORT 0 "register_operand" "r")
 	 (const_int 0)))]
   ""
@@ -5038,8 +5038,8 @@ (define_insn "*and<mode>_compare0"
 )
 
 (define_insn "*ands<GPI:mode>_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_Z CC_REGNUM)
+	(compare:CC_Z
 	 (zero_extend:GPI (match_operand:SHORT 1 "register_operand" "r"))
 	 (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r")
@@ -5050,8 +5050,8 @@ (define_insn "*ands<GPI:mode>_compare0"
 )
 
 (define_insn "*and<mode>3nr_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (match_operand:GPI 0 "register_operand" "%r,r")
 		  (match_operand:GPI 1 "aarch64_logical_operand" "r,<lconst>"))
 	 (const_int 0)))]
@@ -5063,24 +5063,24 @@ (define_insn "*and<mode>3nr_compare0"
 )
 
 (define_split
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (match_operand:GPI 0 "register_operand")
 		  (match_operand:GPI 1 "aarch64_mov_imm_operand"))
 	 (const_int 0)))
    (clobber (match_operand:SI 2 "register_operand"))]
   ""
   [(set (match_dup 2) (match_dup 1))
-   (set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+   (set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (match_dup 0)
 		  (match_dup 2))
 	 (const_int 0)))]
 )
 
 (define_insn "*and<mode>3nr_compare0_zextract"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (zero_extract:GPI (match_operand:GPI 0 "register_operand" "r")
 		  (match_operand:GPI 1 "const_int_operand" "n")
 		  (match_operand:GPI 2 "const_int_operand" "n"))
@@ -5101,8 +5101,8 @@ (define_insn "*and<mode>3nr_compare0_zextract"
 )
 
 (define_insn "*and_<SHIFT:optab><mode>3nr_compare0"
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (SHIFT:GPI
 		   (match_operand:GPI 0 "register_operand" "r")
 		   (match_operand:QI 1 "aarch64_shift_imm_<mode>" "n"))
@@ -5118,8 +5118,8 @@ (define_insn "*and_<SHIFT:optab><mode>3nr_compare0"
 )
 
 (define_split
-  [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+  [(set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (SHIFT:GPI
 		   (match_operand:GPI 0 "register_operand")
 		   (match_operand:QI 1 "aarch64_shift_imm_<mode>"))
@@ -5128,8 +5128,8 @@ (define_split
     (clobber (match_operand:SI 3 "register_operand"))]
   ""
   [(set (match_dup 3) (match_dup 2))
-   (set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ
+   (set (reg:CC_NZV CC_REGNUM)
+	(compare:CC_NZV
 	 (and:GPI (SHIFT:GPI
 		   (match_dup 0)
 		   (match_dup 1))
diff --git a/gcc/testsuite/gcc.target/aarch64/ands_2.c b/gcc/testsuite/gcc.target/aarch64/ands_2.c
index b061b1dfc59c1847cb799a1e49f8e5fc53bf2f14..c8763f234c5f7d19ef9c222756ab5e8a6eaae6fe 100644
--- a/gcc/testsuite/gcc.target/aarch64/ands_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/ands_2.c
@@ -8,8 +8,7 @@ ands_si_test1 (int a, int b, int c)
 {
   int d = a & b;
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -21,12 +20,11 @@ ands_si_test2 (int a, int b, int c)
 {
   int d = a & 0x99999999;
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 int
@@ -34,8 +32,7 @@ ands_si_test3 (int a, int b, int c)
 {
   int d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return a + c;
   else
@@ -49,8 +46,7 @@ ands_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & b;
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -62,12 +58,11 @@ ands_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & 0xaaaaaaaaaaaaaaaall;
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 s64
@@ -75,8 +70,7 @@ ands_di_test3 (s64 a, s64 b, s64 c)
 {
   s64 d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return a + c;
   else
diff --git a/gcc/testsuite/gcc.target/aarch64/bics_2.c b/gcc/testsuite/gcc.target/aarch64/bics_2.c
index 9ccae368c1276618bad691c78fb621a9c82794b7..c1f7e87a6121f7b067b7b37b149da64aa63ebd1a 100644
--- a/gcc/testsuite/gcc.target/aarch64/bics_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/bics_2.c
@@ -8,8 +8,7 @@ bics_si_test1 (int a, int b, int c)
 {
   int d = a & ~b;
 
-  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -21,12 +20,11 @@ bics_si_test2 (int a, int b, int c)
 {
   int d = a & ~(b << 3);
 
-  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 typedef long long s64;
@@ -36,8 +34,7 @@ bics_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & ~b;
 
-  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -49,12 +46,11 @@ bics_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & ~(b << 3);
 
-  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 int
diff --git a/gcc/testsuite/gcc.target/aarch64/tst_2.c b/gcc/testsuite/gcc.target/aarch64/tst_2.c
index c8b28fc5620a9140fee29c4455294af708642d69..3c9bdfd05c4a19e83150f84f454c3e875c7757d1 100644
--- a/gcc/testsuite/gcc.target/aarch64/tst_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/tst_2.c
@@ -8,8 +8,7 @@ tst_si_test1 (int a, int b, int c)
 {
   int d = a & b;
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return 12;
   else
@@ -21,12 +20,11 @@ tst_si_test2 (int a, int b, int c)
 {
   int d = a & 0x99999999;
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  if (d <= 0)
-    return 12;
-  else
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, -1717986919" } } */
+  if (d > 0)
     return 18;
+  else
+    return 12;
 }
 
 int
@@ -34,8 +32,7 @@ tst_si_test3 (int a, int b, int c)
 {
   int d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return 12;
   else
@@ -49,8 +46,7 @@ tst_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & b;
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return 12;
   else
@@ -62,8 +58,7 @@ tst_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & 0xaaaaaaaaaaaaaaaall;
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, -6148914691236517206" } } */
   if (d <= 0)
     return 12;
   else
@@ -75,12 +70,11 @@ tst_di_test3 (s64 a, s64 b, s64 c)
 {
   s64 d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return 12;
-  else
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return 18;
+  else
+    return 12;
 }
 
 int
diff --git a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
index 33a2c0f45afadb8fc9488f847f296ec0e690c049..e456e823593fbe507a8a67b5115a45712e40f80e 100644
--- a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
@@ -14,5 +14,4 @@ g (unsigned char *p)
 }
 
 /* { dg-final { scan-assembler-not "and\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+.*" } } */
-/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" } } */
-/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+, lsr 4" } } */
+/* { dg-final { scan-assembler-times "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" 2 } } */
  
Richard Sandiford Oct. 12, 2022, 4:04 p.m. UTC | #3
Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> Hi Richard,
>
>> Realise this is awkward, but: CC_NZmode is for operations that set only
>> the N and Z flags to useful values.  If we want to take advantage of V
>> being zero then I think we need a different mode.
>>
>> We can't go all the way to CCmode because the carry flag has the opposite
>> value compared to subtraction.  But we could have either:
>>
>> * CC_INVC (inverted carry) that handles all comparisons, including the
>>   redundant unsigned comparisons
>>
>> * CC_NZV
>>
>> Guess I've got a slight preference for CC_INVC, but either would be OK IMO.
>
> I've added CC_NZV since that's easier to understand and unsigned comparisons
> with zero are always changed into equality comparisons. There were a few cases
> where CC_NZ mode was used rather than CC_Z, so I changed those too.

Thanks, sounds good.

One comment below...

>
> Cheers,
> Wilco
>
> v2: Add new CC_NZV mode for cmp+and.
>
> Since AArch64 sets all flags on logical operations, comparisons with zero
> can be combined into an AND even if the condition is LE or GT. Add a new
> CC_NZV mode used by ANDS/BICS/TST instructions.
>
> Passes regress, OK for commit?
>
> gcc/ChangeLog:
>
>         PR target/105773
>         * config/aarch64/aarch64.cc (aarch64_select_cc_mode): Allow
>         GT/LE for merging compare with zero into AND.
>         (aarch64_get_condition_code_1): Add CC_NZVmode support.
>         * config/aarch64/aarch64-modes.def: Add CC_NZV.
>         * config/aarch64/aarch64.md: Use CC_NZV in cmp+and patterns.
>
> gcc/testsuite:
>         PR target/105773
>         * gcc.target/aarch64/ands_2.c: Test for ANDS.
>         * gcc.target/aarch64/bics_2.c: Test for BICS.
>         * gcc.target/aarch64/tst_2.c: Test for TST.
>         * gcc.target/aarch64/tst_imm_split_1.c: Fix test.
>
> ---
>
> diff --git a/gcc/config/aarch64/aarch64-modes.def b/gcc/config/aarch64/aarch64-modes.def
> index d3c9b74434cd2c0d0cb1a2fd26af8c0bf38a4cfa..0fd4c32ad0bd09f8651d1b8a77378fa4504ff488 100644
> --- a/gcc/config/aarch64/aarch64-modes.def
> +++ b/gcc/config/aarch64/aarch64-modes.def
> @@ -35,6 +35,7 @@ CC_MODE (CCFPE);
>  CC_MODE (CC_SWP);
>  CC_MODE (CC_NZC);   /* Only N, Z and C bits of condition flags are valid.
>                        (Used with SVE predicate tests.)  */
> +CC_MODE (CC_NZV);   /* Only N, Z and V bits of condition flags are valid.  */
>  CC_MODE (CC_NZ);    /* Only N and Z bits of condition flags are valid.  */
>  CC_MODE (CC_Z);     /* Only Z bit of condition flags is valid.  */
>  CC_MODE (CC_C);     /* C represents unsigned overflow of a simple addition.  */
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 3a4b1f6987487e959648a343bb25180ea419f397..600e0f41d51242a6f100b3643ce8421ea116ec5c 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -11284,7 +11284,7 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
>    if (y == const0_rtx && (REG_P (x) || SUBREG_P (x))
>        && (code == EQ || code == NE)
>        && (mode_x == HImode || mode_x == QImode))
> -    return CC_NZmode;
> +    return CC_Zmode;
>
>    /* Similarly, comparisons of zero_extends from shorter modes can
>       be performed using an ANDS with an immediate mask.  */
> @@ -11292,15 +11292,22 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
>        && (mode_x == SImode || mode_x == DImode)
>        && (GET_MODE (XEXP (x, 0)) == HImode || GET_MODE (XEXP (x, 0)) == QImode)
>        && (code == EQ || code == NE))
> -    return CC_NZmode;
> +    return CC_Zmode;
> +
> +  /* ANDS/BICS/TST support equality and all signed comparisons.  */
> +  if ((mode_x == SImode || mode_x == DImode)
> +      && y == const0_rtx
> +      && (code_x == AND || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
> +                           && CONST_INT_P (XEXP (x, 2))))

Maybe pre-existing, but are ordered comparisons safe for the
ZERO_EXTRACT case?  If we extract the top 8 bits (say), zero extend,
and compare with zero, the result should be >= 0, whereas TST would
set N to the top bit.

Perhaps this needs to be sign_extract if it involves the top bit and
zero_extract otherwise?

If that's right, the patch is OK with just a test for AND.  We can fix
the ZERO_EXTRACT as a separate patch.

Let me know if I've missed something though.

Thanks,
Richard

> +      && (code == EQ || code == NE || code == LT || code == GE
> +         || code == GT || code == LE))
> +    return CC_NZVmode;
>
> +  /* ADDS/SUBS correctly set N and Z flags.  */
>    if ((mode_x == SImode || mode_x == DImode)
>        && y == const0_rtx
>        && (code == EQ || code == NE || code == LT || code == GE)
> -      && (code_x == PLUS || code_x == MINUS || code_x == AND
> -         || code_x == NEG
> -         || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
> -             && CONST_INT_P (XEXP (x, 2)))))
> +      && (code_x == PLUS || code_x == MINUS || code_x == NEG))
>      return CC_NZmode;
>
>    /* A compare with a shifted operand.  Because of canonicalization,
> @@ -11437,6 +11444,19 @@ aarch64_get_condition_code_1 (machine_mode mode, enum rtx_code comp_code)
>         }
>        break;
>
> +    case E_CC_NZVmode:
> +      switch (comp_code)
> +       {
> +       case NE: return AARCH64_NE;
> +       case EQ: return AARCH64_EQ;
> +       case GE: return AARCH64_PL;
> +       case LT: return AARCH64_MI;
> +       case GT: return AARCH64_GT;
> +       case LE: return AARCH64_LE;
> +       default: return -1;
> +       }
> +      break;
> +
>      case E_CC_NZmode:
>        switch (comp_code)
>         {
> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
> index 23ceca48543d23b85beea1f0bf98ef83051d80b6..cc58373144890c617ff6ce16ca37d14e0617bf3b 100644
> --- a/gcc/config/aarch64/aarch64.md
> +++ b/gcc/config/aarch64/aarch64.md
> @@ -4513,8 +4513,8 @@ (define_insn "*<optab>si3_uxtw"
>  )
>
>  (define_insn "*and<mode>3_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (match_operand:GPI 1 "register_operand" "%r,r")
>                   (match_operand:GPI 2 "aarch64_logical_operand" "r,<lconst>"))
>          (const_int 0)))
> @@ -4529,8 +4529,8 @@ (define_insn "*and<mode>3_compare0"
>
>  ;; zero_extend version of above
>  (define_insn "*andsi3_compare0_uxtw"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:SI (match_operand:SI 1 "register_operand" "%r,r")
>                  (match_operand:SI 2 "aarch64_logical_operand" "r,K"))
>          (const_int 0)))
> @@ -4544,8 +4544,8 @@ (define_insn "*andsi3_compare0_uxtw"
>  )
>
>  (define_insn "*and_<SHIFT:optab><mode>3_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (SHIFT:GPI
>                    (match_operand:GPI 1 "register_operand" "r")
>                    (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
> @@ -4564,8 +4564,8 @@ (define_insn "*and_<SHIFT:optab><mode>3_compare0"
>
>  ;; zero_extend version of above
>  (define_insn "*and_<SHIFT:optab>si3_compare0_uxtw"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:SI (SHIFT:SI
>                   (match_operand:SI 1 "register_operand" "r")
>                   (match_operand:QI 2 "aarch64_shift_imm_si" "n"))
> @@ -4769,8 +4769,8 @@ (define_insn_and_split "*xor_one_cmpl<mode>3"
>  )
>
>  (define_insn "*and_one_cmpl<mode>3_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (not:GPI
>                    (match_operand:GPI 1 "register_operand" "r"))
>                   (match_operand:GPI 2 "register_operand" "r"))
> @@ -4784,8 +4784,8 @@ (define_insn "*and_one_cmpl<mode>3_compare0"
>
>  ;; zero_extend version of above
>  (define_insn "*and_one_cmplsi3_compare0_uxtw"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:SI (not:SI
>                   (match_operand:SI 1 "register_operand" "r"))
>                  (match_operand:SI 2 "register_operand" "r"))
> @@ -4798,8 +4798,8 @@ (define_insn "*and_one_cmplsi3_compare0_uxtw"
>  )
>
>  (define_insn "*and_one_cmpl<mode>3_compare0_no_reuse"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -    (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +    (compare:CC_NZV
>       (and:GPI (not:GPI
>             (match_operand:GPI 0 "register_operand" "r"))
>            (match_operand:GPI 1 "register_operand" "r"))
> @@ -4877,8 +4877,8 @@ (define_insn "*eor_one_cmpl_<SHIFT:optab>sidi3_alt_ze"
>  )
>
>  (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (not:GPI
>                    (SHIFT:GPI
>                     (match_operand:GPI 1 "register_operand" "r")
> @@ -4900,8 +4900,8 @@ (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0"
>
>  ;; zero_extend version of above
>  (define_insn "*and_one_cmpl_<SHIFT:optab>si3_compare0_uxtw"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:SI (not:SI
>                   (SHIFT:SI
>                    (match_operand:SI 1 "register_operand" "r")
> @@ -4922,8 +4922,8 @@ (define_insn "*and_one_cmpl_<SHIFT:optab>si3_compare0_uxtw"
>  )
>
>  (define_insn "*and_one_cmpl_<SHIFT:optab><mode>3_compare0_no_reuse"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -    (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +    (compare:CC_NZV
>       (and:GPI (not:GPI
>             (SHIFT:GPI
>              (match_operand:GPI 0 "register_operand" "r")
> @@ -5028,8 +5028,8 @@ (define_insn_and_split "ctz<mode>2"
>  ")
>
>  (define_insn "*and<mode>_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_Z CC_REGNUM)
> +       (compare:CC_Z
>          (match_operand:SHORT 0 "register_operand" "r")
>          (const_int 0)))]
>    ""
> @@ -5038,8 +5038,8 @@ (define_insn "*and<mode>_compare0"
>  )
>
>  (define_insn "*ands<GPI:mode>_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_Z CC_REGNUM)
> +       (compare:CC_Z
>          (zero_extend:GPI (match_operand:SHORT 1 "register_operand" "r"))
>          (const_int 0)))
>     (set (match_operand:GPI 0 "register_operand" "=r")
> @@ -5050,8 +5050,8 @@ (define_insn "*ands<GPI:mode>_compare0"
>  )
>
>  (define_insn "*and<mode>3nr_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (match_operand:GPI 0 "register_operand" "%r,r")
>                   (match_operand:GPI 1 "aarch64_logical_operand" "r,<lconst>"))
>          (const_int 0)))]
> @@ -5063,24 +5063,24 @@ (define_insn "*and<mode>3nr_compare0"
>  )
>
>  (define_split
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (match_operand:GPI 0 "register_operand")
>                   (match_operand:GPI 1 "aarch64_mov_imm_operand"))
>          (const_int 0)))
>     (clobber (match_operand:SI 2 "register_operand"))]
>    ""
>    [(set (match_dup 2) (match_dup 1))
> -   (set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +   (set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (match_dup 0)
>                   (match_dup 2))
>          (const_int 0)))]
>  )
>
>  (define_insn "*and<mode>3nr_compare0_zextract"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (zero_extract:GPI (match_operand:GPI 0 "register_operand" "r")
>                   (match_operand:GPI 1 "const_int_operand" "n")
>                   (match_operand:GPI 2 "const_int_operand" "n"))
> @@ -5101,8 +5101,8 @@ (define_insn "*and<mode>3nr_compare0_zextract"
>  )
>
>  (define_insn "*and_<SHIFT:optab><mode>3nr_compare0"
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (SHIFT:GPI
>                    (match_operand:GPI 0 "register_operand" "r")
>                    (match_operand:QI 1 "aarch64_shift_imm_<mode>" "n"))
> @@ -5118,8 +5118,8 @@ (define_insn "*and_<SHIFT:optab><mode>3nr_compare0"
>  )
>
>  (define_split
> -  [(set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +  [(set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (SHIFT:GPI
>                    (match_operand:GPI 0 "register_operand")
>                    (match_operand:QI 1 "aarch64_shift_imm_<mode>"))
> @@ -5128,8 +5128,8 @@ (define_split
>      (clobber (match_operand:SI 3 "register_operand"))]
>    ""
>    [(set (match_dup 3) (match_dup 2))
> -   (set (reg:CC_NZ CC_REGNUM)
> -       (compare:CC_NZ
> +   (set (reg:CC_NZV CC_REGNUM)
> +       (compare:CC_NZV
>          (and:GPI (SHIFT:GPI
>                    (match_dup 0)
>                    (match_dup 1))
> diff --git a/gcc/testsuite/gcc.target/aarch64/ands_2.c b/gcc/testsuite/gcc.target/aarch64/ands_2.c
> index b061b1dfc59c1847cb799a1e49f8e5fc53bf2f14..c8763f234c5f7d19ef9c222756ab5e8a6eaae6fe 100644
> --- a/gcc/testsuite/gcc.target/aarch64/ands_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/ands_2.c
> @@ -8,8 +8,7 @@ ands_si_test1 (int a, int b, int c)
>  {
>    int d = a & b;
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -21,12 +20,11 @@ ands_si_test2 (int a, int b, int c)
>  {
>    int d = a & 0x99999999;
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  int
> @@ -34,8 +32,7 @@ ands_si_test3 (int a, int b, int c)
>  {
>    int d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -49,8 +46,7 @@ ands_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & b;
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -62,12 +58,11 @@ ands_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & 0xaaaaaaaaaaaaaaaall;
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  s64
> @@ -75,8 +70,7 @@ ands_di_test3 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return a + c;
>    else
> diff --git a/gcc/testsuite/gcc.target/aarch64/bics_2.c b/gcc/testsuite/gcc.target/aarch64/bics_2.c
> index 9ccae368c1276618bad691c78fb621a9c82794b7..c1f7e87a6121f7b067b7b37b149da64aa63ebd1a 100644
> --- a/gcc/testsuite/gcc.target/aarch64/bics_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/bics_2.c
> @@ -8,8 +8,7 @@ bics_si_test1 (int a, int b, int c)
>  {
>    int d = a & ~b;
>
> -  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -21,12 +20,11 @@ bics_si_test2 (int a, int b, int c)
>  {
>    int d = a & ~(b << 3);
>
> -  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  typedef long long s64;
> @@ -36,8 +34,7 @@ bics_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & ~b;
>
> -  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return a + c;
>    else
> @@ -49,12 +46,11 @@ bics_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & ~(b << 3);
>
> -  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return a + c;
> -  else
> +  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return b + d + c;
> +  else
> +    return a + c;
>  }
>
>  int
> diff --git a/gcc/testsuite/gcc.target/aarch64/tst_2.c b/gcc/testsuite/gcc.target/aarch64/tst_2.c
> index c8b28fc5620a9140fee29c4455294af708642d69..3c9bdfd05c4a19e83150f84f454c3e875c7757d1 100644
> --- a/gcc/testsuite/gcc.target/aarch64/tst_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/tst_2.c
> @@ -8,8 +8,7 @@ tst_si_test1 (int a, int b, int c)
>  {
>    int d = a & b;
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -21,12 +20,11 @@ tst_si_test2 (int a, int b, int c)
>  {
>    int d = a & 0x99999999;
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
> -  if (d <= 0)
> -    return 12;
> -  else
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, -1717986919" } } */
> +  if (d > 0)
>      return 18;
> +  else
> +    return 12;
>  }
>
>  int
> @@ -34,8 +32,7 @@ tst_si_test3 (int a, int b, int c)
>  {
>    int d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
> +  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, lsl 3" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -49,8 +46,7 @@ tst_di_test1 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & b;
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
> -  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -62,8 +58,7 @@ tst_di_test2 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & 0xaaaaaaaaaaaaaaaall;
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, -6148914691236517206" } } */
>    if (d <= 0)
>      return 12;
>    else
> @@ -75,12 +70,11 @@ tst_di_test3 (s64 a, s64 b, s64 c)
>  {
>    s64 d = a & (b << 3);
>
> -  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> -  if (d <= 0)
> -    return 12;
> -  else
> +  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, lsl 3" } } */
> +  if (d > 0)
>      return 18;
> +  else
> +    return 12;
>  }
>
>  int
> diff --git a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> index 33a2c0f45afadb8fc9488f847f296ec0e690c049..e456e823593fbe507a8a67b5115a45712e40f80e 100644
> --- a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> +++ b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
> @@ -14,5 +14,4 @@ g (unsigned char *p)
>  }
>
>  /* { dg-final { scan-assembler-not "and\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+.*" } } */
> -/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" } } */
> -/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+, lsr 4" } } */
> +/* { dg-final { scan-assembler-times "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" 2 } } */
  
Wilco Dijkstra Oct. 13, 2022, 1:40 p.m. UTC | #4
Hi Richard,

> Maybe pre-existing, but are ordered comparisons safe for the
> ZERO_EXTRACT case?  If we extract the top 8 bits (say), zero extend,
> and compare with zero, the result should be >= 0, whereas TST would
> set N to the top bit.

Yes in principle zero extract should always be positive assuming we never
extract all bits (= nop). GCC never generates a zero extend of the top bits
(it becomes a shift), so I don't think it can be generated.

However I'll change it to use CC_Z in the commit since signed comparisons
of zero extend seem to be folded to equality (or true/false), so there is no
point in supporting anything but equality comparisons anyway.

Cheers,
Wilco
  

Patch

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 1601d11710cb6132c80a77bb4fe2f8429519aa5a..00876b08d8fbb1329a37a0ea73d3abf09d28b829 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -11323,7 +11323,8 @@  aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
 
   if ((mode_x == SImode || mode_x == DImode)
       && y == const0_rtx
-      && (code == EQ || code == NE || code == LT || code == GE)
+      && (code == EQ || code == NE || code == LT || code == GE
+	  || (code_x == AND && (code == GT || code == LE)))
       && (code_x == PLUS || code_x == MINUS || code_x == AND
 	  || code_x == NEG
 	  || (code_x == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1))
@@ -11471,6 +11472,8 @@  aarch64_get_condition_code_1 (machine_mode mode, enum rtx_code comp_code)
 	case EQ: return AARCH64_EQ;
 	case GE: return AARCH64_PL;
 	case LT: return AARCH64_MI;
+	case GT: return AARCH64_GT;
+	case LE: return AARCH64_LE;
 	default: return -1;
 	}
       break;
diff --git a/gcc/testsuite/gcc.target/aarch64/ands_2.c b/gcc/testsuite/gcc.target/aarch64/ands_2.c
index b061b1dfc59c1847cb799a1e49f8e5fc53bf2f14..c8763f234c5f7d19ef9c222756ab5e8a6eaae6fe 100644
--- a/gcc/testsuite/gcc.target/aarch64/ands_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/ands_2.c
@@ -8,8 +8,7 @@  ands_si_test1 (int a, int b, int c)
 {
   int d = a & b;
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -21,12 +20,11 @@  ands_si_test2 (int a, int b, int c)
 {
   int d = a & 0x99999999;
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 int
@@ -34,8 +32,7 @@  ands_si_test3 (int a, int b, int c)
 {
   int d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return a + c;
   else
@@ -49,8 +46,7 @@  ands_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & b;
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -62,12 +58,11 @@  ands_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & 0xaaaaaaaaaaaaaaaall;
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 s64
@@ -75,8 +70,7 @@  ands_di_test3 (s64 a, s64 b, s64 c)
 {
   s64 d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return a + c;
   else
diff --git a/gcc/testsuite/gcc.target/aarch64/bics_2.c b/gcc/testsuite/gcc.target/aarch64/bics_2.c
index 9ccae368c1276618bad691c78fb621a9c82794b7..c1f7e87a6121f7b067b7b37b149da64aa63ebd1a 100644
--- a/gcc/testsuite/gcc.target/aarch64/bics_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/bics_2.c
@@ -8,8 +8,7 @@  bics_si_test1 (int a, int b, int c)
 {
   int d = a & ~b;
 
-  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -21,12 +20,11 @@  bics_si_test2 (int a, int b, int c)
 {
   int d = a & ~(b << 3);
 
-  /* { dg-final { scan-assembler-not "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "bics\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 typedef long long s64;
@@ -36,8 +34,7 @@  bics_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & ~b;
 
-  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return a + c;
   else
@@ -49,12 +46,11 @@  bics_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & ~(b << 3);
 
-  /* { dg-final { scan-assembler-not "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return a + c;
-  else
+  /* { dg-final { scan-assembler "bics\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return b + d + c;
+  else
+    return a + c;
 }
 
 int
diff --git a/gcc/testsuite/gcc.target/aarch64/tst_2.c b/gcc/testsuite/gcc.target/aarch64/tst_2.c
index c8b28fc5620a9140fee29c4455294af708642d69..3c9bdfd05c4a19e83150f84f454c3e875c7757d1 100644
--- a/gcc/testsuite/gcc.target/aarch64/tst_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/tst_2.c
@@ -8,8 +8,7 @@  tst_si_test1 (int a, int b, int c)
 {
   int d = a & b;
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+" } } */
   if (d <= 0)
     return 12;
   else
@@ -21,12 +20,11 @@  tst_si_test2 (int a, int b, int c)
 {
   int d = a & 0x99999999;
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, -1717986919" } } */
-  if (d <= 0)
-    return 12;
-  else
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, -1717986919" } } */
+  if (d > 0)
     return 18;
+  else
+    return 12;
 }
 
 int
@@ -34,8 +32,7 @@  tst_si_test3 (int a, int b, int c)
 {
   int d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "tst\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, lsl 3" } } */
   if (d <= 0)
     return 12;
   else
@@ -49,8 +46,7 @@  tst_di_test1 (s64 a, s64 b, s64 c)
 {
   s64 d = a & b;
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
-  /* { dg-final { scan-assembler-times "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" 2 } } */
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+" } } */
   if (d <= 0)
     return 12;
   else
@@ -62,8 +58,7 @@  tst_di_test2 (s64 a, s64 b, s64 c)
 {
   s64 d = a & 0xaaaaaaaaaaaaaaaall;
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -6148914691236517206" } } */
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, -6148914691236517206" } } */
   if (d <= 0)
     return 12;
   else
@@ -75,12 +70,11 @@  tst_di_test3 (s64 a, s64 b, s64 c)
 {
   s64 d = a & (b << 3);
 
-  /* { dg-final { scan-assembler-not "tst\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
-  if (d <= 0)
-    return 12;
-  else
+  /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d > 0)
     return 18;
+  else
+    return 12;
 }
 
 int
diff --git a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
index 33a2c0f45afadb8fc9488f847f296ec0e690c049..e456e823593fbe507a8a67b5115a45712e40f80e 100644
--- a/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/tst_imm_split_1.c
@@ -14,5 +14,4 @@  g (unsigned char *p)
 }
 
 /* { dg-final { scan-assembler-not "and\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+.*" } } */
-/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" } } */
-/* { dg-final { scan-assembler "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+, lsr 4" } } */
+/* { dg-final { scan-assembler-times "tst\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+" 2 } } */