aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>2015-09-09 08:41:41 +0000
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>2015-09-09 08:41:41 +0000
commit956db28eb5782cc4f86f146d9250ca5f0f16e3ce (patch)
tree0c03de8ce8a7cae4d68322f00c6d68e7ced44bb1 /gcc
parent4f58fe36c141c2a328b6081be7d9cdf203cf2fcf (diff)
downloadgcc-956db28eb5782cc4f86f146d9250ca5f0f16e3ce.zip
gcc-956db28eb5782cc4f86f146d9250ca5f0f16e3ce.tar.gz
gcc-956db28eb5782cc4f86f146d9250ca5f0f16e3ce.tar.bz2
[ARM][3/3] Expand mod by power of 2
* config/arm/arm.md (*subsi3_compare0): Rename to... (subsi3_compare0): ... This. (modsi3): New define_expand. * config/arm/arm.c (arm_new_rtx_costs, MOD case): Handle case when operand is power of 2. * gcc.target/aarch64/mod_2.x: New file. * gcc.target/aarch64/mod_256.x: Likewise. * gcc.target/arm/mod_2.c: New test. * gcc.target/arm/mod_256.c: Likewise. * gcc.target/aarch64/mod_2.c: Likewise. * gcc.target/aarch64/mod_256.c: Likewise. From-SVN: r227586
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/arm/arm.c18
-rw-r--r--gcc/config/arm/arm.md71
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/gcc.target/aarch64/mod_2.c7
-rw-r--r--gcc/testsuite/gcc.target/aarch64/mod_2.x5
-rw-r--r--gcc/testsuite/gcc.target/aarch64/mod_256.c6
-rw-r--r--gcc/testsuite/gcc.target/aarch64/mod_256.x5
-rw-r--r--gcc/testsuite/gcc.target/arm/mod_2.c8
-rw-r--r--gcc/testsuite/gcc.target/arm/mod_256.c8
10 files changed, 144 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 25ecf5a..618bbe6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,13 @@
2015-09-09 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+ * config/arm/arm.md (*subsi3_compare0): Rename to...
+ (subsi3_compare0): ... This.
+ (modsi3): New define_expand.
+ * config/arm/arm.c (arm_new_rtx_costs, MOD case): Handle case
+ when operand is power of 2.
+
+2015-09-09 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
* config/aarch64/aarch64.md (mod<mode>3): New define_expand.
(*neg<mode>2_compare0): Rename to...
(neg<mode>2_compare0): ... This.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f343d53..5f3180d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -9580,6 +9580,24 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
return false; /* All arguments must be in registers. */
case MOD:
+ /* MOD by a power of 2 can be expanded as:
+ rsbs r1, r0, #0
+ and r0, r0, #(n - 1)
+ and r1, r1, #(n - 1)
+ rsbpl r0, r1, #0. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && exact_log2 (INTVAL (XEXP (x, 1))) > 0
+ && mode == SImode)
+ {
+ *cost += COSTS_N_INSNS (3);
+
+ if (speed_p)
+ *cost += 2 * extra_cost->alu.logical
+ + extra_cost->alu.arith;
+ return true;
+ }
+
+ /* Fall-through. */
case UMOD:
*cost = LIBCALL_COST (2);
return false; /* All arguments must be in registers. */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index b6c2047..775ca25 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -1229,7 +1229,7 @@
""
)
-(define_insn "*subsi3_compare0"
+(define_insn "subsi3_compare0"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV
(minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,r,I")
@@ -11142,6 +11142,75 @@
""
)
+;; ARM-specific expansion of signed mod by power of 2
+;; using conditional negate.
+;; For r0 % n where n is a power of 2 produce:
+;; rsbs r1, r0, #0
+;; and r0, r0, #(n - 1)
+;; and r1, r1, #(n - 1)
+;; rsbpl r0, r1, #0
+
+(define_expand "modsi3"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")]
+ "TARGET_32BIT"
+ {
+ HOST_WIDE_INT val = INTVAL (operands[2]);
+
+ if (val <= 0
+ || exact_log2 (val) <= 0)
+ FAIL;
+
+ rtx mask = GEN_INT (val - 1);
+
+ /* In the special case of x0 % 2 we can do the even shorter:
+ cmp r0, #0
+ and r0, r0, #1
+ rsblt r0, r0, #0. */
+
+ if (val == 2)
+ {
+ rtx cc_reg = arm_gen_compare_reg (LT,
+ operands[1], const0_rtx, NULL_RTX);
+ rtx cond = gen_rtx_LT (SImode, cc_reg, const0_rtx);
+ rtx masked = gen_reg_rtx (SImode);
+
+ emit_insn (gen_andsi3 (masked, operands[1], mask));
+ emit_move_insn (operands[0],
+ gen_rtx_IF_THEN_ELSE (SImode, cond,
+ gen_rtx_NEG (SImode,
+ masked),
+ masked));
+ DONE;
+ }
+
+ rtx neg_op = gen_reg_rtx (SImode);
+ rtx_insn *insn = emit_insn (gen_subsi3_compare0 (neg_op, const0_rtx,
+ operands[1]));
+
+ /* Extract the condition register and mode. */
+ rtx cmp = XVECEXP (PATTERN (insn), 0, 0);
+ rtx cc_reg = SET_DEST (cmp);
+ rtx cond = gen_rtx_GE (SImode, cc_reg, const0_rtx);
+
+ emit_insn (gen_andsi3 (operands[0], operands[1], mask));
+
+ rtx masked_neg = gen_reg_rtx (SImode);
+ emit_insn (gen_andsi3 (masked_neg, neg_op, mask));
+
+ /* We want a conditional negate here, but emitting COND_EXEC rtxes
+ during expand does not always work. Do an IF_THEN_ELSE instead. */
+ emit_move_insn (operands[0],
+ gen_rtx_IF_THEN_ELSE (SImode, cond,
+ gen_rtx_NEG (SImode, masked_neg),
+ operands[0]));
+
+
+ DONE;
+ }
+)
+
(define_expand "bswapsi2"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(bswap:SI (match_operand:SI 1 "s_register_operand" "r")))]
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3506d4a..360fe70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2015-09-09 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gcc.target/aarch64/mod_2.x: New file.
+ * gcc.target/aarch64/mod_256.x: Likewise.
+ * gcc.target/arm/mod_2.c: New test.
+ * gcc.target/arm/mod_256.c: Likewise.
+ * gcc.target/aarch64/mod_2.c: Likewise.
+ * gcc.target/aarch64/mod_256.c: Likewise.
+
2015-09-09 Jakub Jelinek <jakub@redhat.com>
PR c++/67504
diff --git a/gcc/testsuite/gcc.target/aarch64/mod_2.c b/gcc/testsuite/gcc.target/aarch64/mod_2.c
new file mode 100644
index 0000000..2645c18
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mod_2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=cortex-a57 -save-temps" } */
+
+#include "mod_2.x"
+
+/* { dg-final { scan-assembler "csneg\t\[wx\]\[0-9\]*" } } */
+/* { dg-final { scan-assembler-times "and\t\[wx\]\[0-9\]*" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mod_2.x b/gcc/testsuite/gcc.target/aarch64/mod_2.x
new file mode 100644
index 0000000..2b079a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mod_2.x
@@ -0,0 +1,5 @@
+int
+f (int x)
+{
+ return x % 2;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/mod_256.c b/gcc/testsuite/gcc.target/aarch64/mod_256.c
new file mode 100644
index 0000000..567332c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mod_256.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=cortex-a57 -save-temps" } */
+
+#include "mod_256.x"
+
+/* { dg-final { scan-assembler "csneg\t\[wx\]\[0-9\]*" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mod_256.x b/gcc/testsuite/gcc.target/aarch64/mod_256.x
new file mode 100644
index 0000000..c1de42c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mod_256.x
@@ -0,0 +1,5 @@
+int
+f (int x)
+{
+ return x % 256;
+}
diff --git a/gcc/testsuite/gcc.target/arm/mod_2.c b/gcc/testsuite/gcc.target/arm/mod_2.c
new file mode 100644
index 0000000..93017a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mod_2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2 -mcpu=cortex-a57 -save-temps" } */
+
+#include "../aarch64/mod_2.x"
+
+/* { dg-final { scan-assembler "rsblt\tr\[0-9\]*" } } */
+/* { dg-final { scan-assembler-times "and\tr\[0-9\].*1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/mod_256.c b/gcc/testsuite/gcc.target/arm/mod_256.c
new file mode 100644
index 0000000..ccb7f3c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mod_256.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2 -mcpu=cortex-a57 -save-temps" } */
+
+#include "../aarch64/mod_256.x"
+
+/* { dg-final { scan-assembler "rsbpl\tr\[0-9\]*" } } */
+