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.bol...@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. ------------------------------------- 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) +{ + return (a == b) ? 7 : 1; + /* { dg-final { scan-assembler "csinc\tx\[0-9\].*xzr" } } */ +}