aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2015-10-27 21:12:49 +0100
committerYvan Roux <yvan.roux@linaro.org>2015-11-02 07:29:50 +0000
commit8807136680ef211be484f570127b58e0723bee05 (patch)
treedea30d3272fb671158036449abb560fc8ff9dc50
parentb03dcc81dbade55971f5afcc55caeda2a71b90ad (diff)
Backport from trunk r226447. 2015-07-31 Kyrylo Tkachov <kyrylo.tkachov@arm.com> * config/arm/arm.md (*if_neg_move): Convert to insn_and_split. Enable for TARGET_32BIT. (*if_move_neg): Likewise. gcc/ Backport from trunk r227585. 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. * config/aarch64/aarch64.c (aarch64_rtx_costs, MOD case): Move check for speed inside the if-then-elses. Reflect CSNEG sequence in MOD by power of 2 case. gcc/ Backport from trunk r227586. 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. gcc/testsuite/ Backport from trunk r227586. 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. Change-Id: I025cd7c4cc8d8f8c11fb578e71506064cc013267
-rw-r--r--gcc/config/aarch64/aarch64.c19
-rw-r--r--gcc/config/aarch64/aarch64.md58
-rw-r--r--gcc/config/arm/arm.c18
-rw-r--r--gcc/config/arm/arm.md131
-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, 241 insertions, 24 deletions
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 8b215ea3042..5db9aa3e30d 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -6381,6 +6381,25 @@ cost_plus:
return true;
case MOD:
+ /* We can expand signed mod by power of 2 using a NEGS, two parallel
+ ANDs and a CSNEG. Assume here that CSNEG is the same as the cost of
+ an unconditional negate. This case should only ever be reached through
+ the set_smod_pow2_cheap check in expmed.c. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && exact_log2 (INTVAL (XEXP (x, 1))) > 0
+ && (mode == SImode || mode == DImode))
+ {
+ /* We expand to 4 instructions. Reset the baseline. */
+ *cost = COSTS_N_INSNS (4);
+
+ if (speed)
+ *cost += 2 * extra_cost->alu.logical
+ + 2 * extra_cost->alu.arith;
+
+ return true;
+ }
+
+ /* Fall-through. */
case UMOD:
if (speed)
{
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index c21298f4b0d..45ef9335b50 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -301,6 +301,62 @@
}
)
+;; Expansion of signed mod by a power of 2 using CSNEG.
+;; For x0 % n where n is a power of 2 produce:
+;; negs x1, x0
+;; and x0, x0, #(n - 1)
+;; and x1, x1, #(n - 1)
+;; csneg x0, x0, x1, mi
+
+(define_expand "mod<mode>3"
+ [(match_operand:GPI 0 "register_operand" "")
+ (match_operand:GPI 1 "register_operand" "")
+ (match_operand:GPI 2 "const_int_operand" "")]
+ ""
+ {
+ HOST_WIDE_INT val = INTVAL (operands[2]);
+
+ if (val <= 0
+ || exact_log2 (val) <= 0
+ || !aarch64_bitmask_imm (val - 1, <MODE>mode))
+ FAIL;
+
+ rtx mask = GEN_INT (val - 1);
+
+ /* In the special case of x0 % 2 we can do the even shorter:
+ cmp x0, xzr
+ and x0, x0, 1
+ cneg x0, x0, lt. */
+ if (val == 2)
+ {
+ rtx masked = gen_reg_rtx (<MODE>mode);
+ rtx ccreg = aarch64_gen_compare_reg (LT, operands[1], const0_rtx);
+ emit_insn (gen_and<mode>3 (masked, operands[1], mask));
+ rtx x = gen_rtx_LT (VOIDmode, ccreg, const0_rtx);
+ emit_insn (gen_csneg3<mode>_insn (operands[0], x, masked, masked));
+ DONE;
+ }
+
+ rtx neg_op = gen_reg_rtx (<MODE>mode);
+ rtx_insn *insn = emit_insn (gen_neg<mode>2_compare0 (neg_op, 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 (VOIDmode, cc_reg, const0_rtx);
+
+ rtx masked_pos = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_and<mode>3 (masked_pos, operands[1], mask));
+
+ rtx masked_neg = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_and<mode>3 (masked_neg, neg_op, mask));
+
+ emit_insn (gen_csneg3<mode>_insn (operands[0], cond,
+ masked_neg, masked_pos));
+ DONE;
+ }
+)
+
(define_insn "*condjump"
[(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator"
[(match_operand 1 "cc_register" "") (const_int 0)])
@@ -2373,7 +2429,7 @@
[(set_attr "type" "adc_reg")]
)
-(define_insn "*neg<mode>2_compare0"
+(define_insn "neg<mode>2_compare0"
[(set (reg:CC_NZ CC_REGNUM)
(compare:CC_NZ (neg:GPI (match_operand:GPI 1 "register_operand" "r"))
(const_int 0)))
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f973ef80faa..38ff0439150 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -9599,6 +9599,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 7f5a6d704c1..3fe95264524 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")
@@ -10084,21 +10084,24 @@
(set_attr "type" "multiple")]
)
-(define_insn "*if_neg_move"
- [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+(define_insn_and_split "*if_neg_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
(if_then_else:SI
(match_operator 4 "arm_comparison_operator"
[(match_operand 3 "cc_register" "") (const_int 0)])
- (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
- (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
- "TARGET_ARM"
- "@
- rsb%d4\\t%0, %2, #0
- mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0
- mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0"
+ (neg:SI (match_operand:SI 2 "s_register_operand" "l,r"))
+ (match_operand:SI 1 "s_register_operand" "0,0")))]
+ "TARGET_32BIT"
+ "#"
+ "&& reload_completed"
+ [(cond_exec (match_op_dup 4 [(match_dup 3) (const_int 0)])
+ (set (match_dup 0) (neg:SI (match_dup 2))))]
+ ""
[(set_attr "conds" "use")
- (set_attr "length" "4,8,8")
- (set_attr "type" "logic_shift_imm,multiple,multiple")]
+ (set_attr "length" "4")
+ (set_attr "arch" "t2,32")
+ (set_attr "enabled_for_depr_it" "yes,no")
+ (set_attr "type" "logic_shift_imm")]
)
(define_insn "*ifcompare_move_neg"
@@ -10117,21 +10120,34 @@
(set_attr "type" "multiple")]
)
-(define_insn "*if_move_neg"
- [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+(define_insn_and_split "*if_move_neg"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
(if_then_else:SI
(match_operator 4 "arm_comparison_operator"
[(match_operand 3 "cc_register" "") (const_int 0)])
- (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
- (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
- "TARGET_ARM"
- "@
- rsb%D4\\t%0, %2, #0
- mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0
- mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0"
+ (match_operand:SI 1 "s_register_operand" "0,0")
+ (neg:SI (match_operand:SI 2 "s_register_operand" "l,r"))))]
+ "TARGET_32BIT"
+ "#"
+ "&& reload_completed"
+ [(cond_exec (match_dup 5)
+ (set (match_dup 0) (neg:SI (match_dup 2))))]
+ {
+ machine_mode mode = GET_MODE (operands[3]);
+ rtx_code rc = GET_CODE (operands[4]);
+
+ if (mode == CCFPmode || mode == CCFPEmode)
+ rc = reverse_condition_maybe_unordered (rc);
+ else
+ rc = reverse_condition (rc);
+
+ operands[5] = gen_rtx_fmt_ee (rc, VOIDmode, operands[3], const0_rtx);
+ }
[(set_attr "conds" "use")
- (set_attr "length" "4,8,8")
- (set_attr "type" "logic_shift_imm,multiple,multiple")]
+ (set_attr "length" "4")
+ (set_attr "arch" "t2,32")
+ (set_attr "enabled_for_depr_it" "yes,no")
+ (set_attr "type" "logic_shift_imm")]
)
(define_insn "*arith_adjacentmem"
@@ -11109,6 +11125,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/gcc.target/aarch64/mod_2.c b/gcc/testsuite/gcc.target/aarch64/mod_2.c
new file mode 100644
index 00000000000..2645c18e741
--- /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 00000000000..2b079a4b883
--- /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 00000000000..567332c04e1
--- /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 00000000000..c1de42ce389
--- /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 00000000000..93017a10683
--- /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 00000000000..ccb7f3cf68d
--- /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\]*" } } */
+