Patchwork [AArch64] Use CSINC instead of CSEL to return 1

login
register
mail settings
Submitter Ian Bolton
Date Nov. 6, 2012, 6:56 p.m.
Message ID <000101cdbc50$5f815750$1e8405f0$@bolton@arm.com>
Download mbox | patch
Permalink /patch/197536/
State New
Headers show

Comments

Ian Bolton - Nov. 6, 2012, 6:56 p.m.
Where a CSEL can return the value 1 as one of the alternatives,
it is usually more efficient to use a CSINC than a CSEL (and
never less efficient), since the value of 1 can be derived from
wzr, rather than needing to set it up in a register first.

This patch enables this capability.

It has been regression tested on trunk.

OK for commit?

Cheers,
Ian



2012-11-06  Ian Bolton  <ian.bolton@arm.com>

	* gcc/config/aarch64/aarch64.md (cmov<mode>_insn): Emit
	CSINC when one of the alternatives is constant 1.
	* gcc/config/aarch64/constraints.md: New constraint.
	* gcc/config/aarch64/predicates.md: Rename predicate
	aarch64_reg_zero_or_m1 to aarch64_reg_zero_or_m1_or_1.

	* gcc/testsuite/gcc.target/aarch64/csinc-2.c: New test.



-------------------------------------

+{
+  return (a == b) ? 7 : 1;
+  /* { dg-final { scan-assembler "csinc\tx\[0-9\].*xzr" } } */
+}
Marcus Shawcroft - Nov. 12, 2012, 9:06 a.m.
On 06/11/12 18:56, Ian Bolton wrote:
> Where a CSEL can return the value 1 as one of the alternatives,
> it is usually more efficient to use a CSINC than a CSEL (and
> never less efficient), since the value of 1 can be derived from
> wzr, rather than needing to set it up in a register first.
>
> This patch enables this capability.
>
> It has been regression tested on trunk.
>
> OK for commit?
>
> Cheers,
> Ian

OK, and please backport to ARM/aarch64-4.7-branch

Thanks
/Marcus

Patch

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 6935192..038465e 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -1877,19 +1877,23 @@ 
 )
 
 (define_insn "*cmov<mode>_insn"
-  [(set (match_operand:ALLI 0 "register_operand" "=r,r,r,r")
+  [(set (match_operand:ALLI 0 "register_operand" "=r,r,r,r,r,r,r")
 	(if_then_else:ALLI
 	 (match_operator 1 "aarch64_comparison_operator"
 	  [(match_operand 2 "cc_register" "") (const_int 0)])
-	 (match_operand:ALLI 3 "aarch64_reg_zero_or_m1" "rZ,rZ,UsM,UsM")
-	 (match_operand:ALLI 4 "aarch64_reg_zero_or_m1" "rZ,UsM,rZ,UsM")))]
-  ""
-  ;; Final alternative should be unreachable, but included for completeness
+	 (match_operand:ALLI 3 "aarch64_reg_zero_or_m1_or_1"
"rZ,rZ,UsM,rZ,Ui1,UsM,Ui1")
+	 (match_operand:ALLI 4 "aarch64_reg_zero_or_m1_or_1"
"rZ,UsM,rZ,Ui1,rZ,UsM,Ui1")))]
+  "!((operands[3] == const1_rtx && operands[4] == constm1_rtx)
+     || (operands[3] == constm1_rtx && operands[4] == const1_rtx))"
+  ;; Final two alternatives should be unreachable, but included for
completeness
   "@
    csel\\t%<w>0, %<w>3, %<w>4, %m1
    csinv\\t%<w>0, %<w>3, <w>zr, %m1
    csinv\\t%<w>0, %<w>4, <w>zr, %M1
-   mov\\t%<w>0, -1"
+   csinc\\t%<w>0, %<w>3, <w>zr, %m1
+   csinc\\t%<w>0, %<w>4, <w>zr, %M1
+   mov\\t%<w>0, -1
+   mov\\t%<w>0, 1"
   [(set_attr "v8type" "csel")
    (set_attr "mode" "<MODE>")]
 )
diff --git a/gcc/config/aarch64/constraints.md
b/gcc/config/aarch64/constraints.md
index da50a47..780faaa 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -102,6 +102,11 @@ 
   A constraint that matches the immediate constant -1."
   (match_test "op == constm1_rtx"))
 
+(define_constraint "Ui1"
+  "@internal
+  A constraint that matches the immediate constant +1."
+  (match_test "op == const1_rtx"))
+
 (define_constraint "Ui3"
   "@internal
   A constraint that matches the integers 0...4."
diff --git a/gcc/config/aarch64/predicates.md
b/gcc/config/aarch64/predicates.md
index 328e5cf..aae71c1 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -31,11 +31,12 @@ 
        (ior (match_operand 0 "register_operand")
 	    (match_test "op == const0_rtx"))))
 
-(define_predicate "aarch64_reg_zero_or_m1"
+(define_predicate "aarch64_reg_zero_or_m1_or_1"
   (and (match_code "reg,subreg,const_int")
        (ior (match_operand 0 "register_operand")
 	    (ior (match_test "op == const0_rtx")
-		 (match_test "op == constm1_rtx")))))
+		 (ior (match_test "op == constm1_rtx")
+		      (match_test "op == const1_rtx"))))))
 
 (define_predicate "aarch64_fp_compare_operand"
   (ior (match_operand 0 "register_operand")
diff --git a/gcc/testsuite/gcc.target/aarch64/csinc-2.c
b/gcc/testsuite/gcc.target/aarch64/csinc-2.c
new file mode 100644
index 0000000..6ed9080
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/csinc-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int
+foo (int a, int b)
+{
+  return (a < b) ? 1 : 7;
+  /* { dg-final { scan-assembler "csinc\tw\[0-9\].*wzr" } } */
+}
+
+typedef long long s64;
+
+s64
+foo2 (s64 a, s64 b)