diff options
author | Yvan Roux <yvan.roux@linaro.org> | 2015-10-27 21:12:49 +0100 |
---|---|---|
committer | Linaro Code Review <review@review.linaro.org> | 2015-11-26 18:11:45 +0000 |
commit | 5b9b542276ad2a6649af97dc77daa8cfb6b57be0 (patch) | |
tree | 9e5d719d1ef8494d5926de86df205a968ea288a1 /gcc | |
parent | b3e73b30518c07e84d552d08dfbf9f932eec14c2 (diff) | |
download | gcc-5b9b542276ad2a6649af97dc77daa8cfb6b57be0.tar.gz |
gcc/
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/aarch64/aarch64.c | 19 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.md | 58 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 18 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 131 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/mod_2.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/mod_2.x | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/mod_256.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/mod_256.x | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/mod_2.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/mod_256.c | 8 |
10 files changed, 241 insertions, 24 deletions
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 86037544dc2..0eba6a9372e 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -6592,6 +6592,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 0c2067d7d4e..9751999ccfc 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -313,6 +313,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)]) @@ -2439,7 +2495,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 57cb49a6b41..6c6ce4ab28b 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -9598,6 +9598,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\]*" } } */ + |