Hi all,

This patch improves codegen for expressions of the form:
(x ? y + c1 : y + c2) when |c1 - c2| == 1

It matches the if_then_else of the two plus-immediates,
performs one of them, then generates a conditional increment
operation.

Thus, for the code in the testcase we generate a single add, compare
and cinc instruction rather than two adds, a compare and a csel.

Bootstrapped and tested on aarch64.

Ok for trunk?

Thanks,
Kyrill

2015-07-16  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    * config/aarch64/aarch64.md (*csel_plus<mode>6):
    New define_insn_and_split.
    (*csinc2<mode>_insn): Rename to...
    (csinc2<mode>_insn): ... This.

2015-07-16  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    * gcc.target/aarch64/cinc_common_1.c: New test.
commit a2dca37d3227ef4c9d3a8cc8277dd31529df74fd
Author: Kyrylo Tkachov <kyrylo.tkac...@arm.com>
Date:   Tue Jul 14 10:33:04 2015 +0100

    [AArch64] Use cinc for if_then_else of plus-immediates

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 381bb1d..39282b7 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2843,6 +2843,48 @@ (define_expand "cmov<mode>6"
   "
 )
 
+/* Catch cases where we do:
+   add x2, x1, #n
+   add x3, x1, #(n + 1)
+   csel x4, x2, x3, cond
+   and transform it into:
+   add x2, x1, #n
+   cinc x4, x2, !cond.  */
+
+(define_insn_and_split "*csel_plus<mode>6"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+	(if_then_else:GPI
+	 (match_operator 1 "aarch64_comparison_operator"
+	  [(match_operand 2 "cc_register" "") (const_int 0)])
+	 (plus:GPI (match_operand:GPI 3 "aarch64_reg_or_imm" "r")
+		   (match_operand:GPI 4 "aarch64_plus_immediate" "n"))
+	 (plus:GPI (match_dup 3)
+		   (match_operand:GPI 5 "aarch64_plus_immediate" "n"))))]
+  "optimize > 0
+   && ((INTVAL (operands[4]) == INTVAL (operands[5]) + 1)
+	|| (INTVAL (operands[5]) == INTVAL (operands[4]) + 1))"
+  "#"
+  "&& !reload_completed"
+  [(const_int 0)]
+  {
+    bool swap_p = INTVAL (operands[5]) > INTVAL (operands[4]);
+    enum rtx_code code = GET_CODE (operands[1]);
+    if (swap_p)
+      {
+	code = REVERSE_CONDITION (code, GET_MODE (operands[2]));
+	std::swap (operands[4], operands[5]);
+      }
+
+    rtx tmp = gen_reg_rtx (<MODE>mode);
+    emit_insn (gen_add<mode>3 (tmp, operands[3], operands[5]));
+    rtx comp = gen_rtx_fmt_ee (code, VOIDmode, operands[2], const0_rtx);
+
+    emit_insn (gen_csinc2<mode>_insn (operands[0], tmp, comp));
+    DONE;
+  }
+)
+
+
 (define_insn "*cmov<mode>_insn"
   [(set (match_operand:ALLI 0 "register_operand" "=r,r,r,r,r,r,r")
 	(if_then_else:ALLI
@@ -3030,7 +3072,7 @@ (define_insn "aarch64_<crc_variant>"
   [(set_attr "type" "crc")]
 )
 
-(define_insn "*csinc2<mode>_insn"
+(define_insn "csinc2<mode>_insn"
   [(set (match_operand:GPI 0 "register_operand" "=r")
         (plus:GPI (match_operand 2 "aarch64_comparison_operation" "")
                   (match_operand:GPI 1 "register_operand" "r")))]
diff --git a/gcc/testsuite/gcc.target/aarch64/cinc_common_1.c b/gcc/testsuite/gcc.target/aarch64/cinc_common_1.c
new file mode 100644
index 0000000..d041263
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cinc_common_1.c
@@ -0,0 +1,64 @@
+/* { dg-do run } */
+/* { dg-options "-save-temps -O2 -fno-inline" } */
+
+extern void abort (void);
+
+int
+foosi (int x)
+{
+  return x > 100 ? x - 2 : x - 1;
+}
+
+int
+barsi (int x)
+{
+  return x > 100 ? x + 4 : x + 3;
+}
+
+long
+foodi (long x)
+{
+  return x > 100 ? x - 2 : x - 1;
+}
+
+long
+bardi (long x)
+{
+  return x > 100 ? x + 4 : x + 3;
+}
+
+/* { dg-final { scan-assembler-times "cs?inc\tw\[0-9\]*" 2 } } */
+/* { dg-final { scan-assembler-times "cs?inc\tx\[0-9\]*" 2 } } */
+
+int
+main (void)
+{
+  if (foosi (105) != 103)
+    abort ();
+
+  if (foosi (95) != 94)
+    abort ();
+
+  if (barsi (105) != 109)
+    abort ();
+
+  if (barsi (95) != 98)
+    abort ();
+
+  if (foodi (105) != 103)
+    abort ();
+
+  if (foodi (95) != 94)
+    abort ();
+
+  if (bardi (105) != 109)
+    abort ();
+
+  if (bardi (95) != 98)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "csel\tx\[0-9\]*.*" } } */
+/* { dg-final { scan-assembler-not "csel\tw\[0-9\]*.*" } } */

Reply via email to