diff options
author | Kyrylo Tkachov <kyrylo.tkachov@arm.com> | 2015-09-09 08:39:13 +0000 |
---|---|---|
committer | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2015-09-09 08:39:13 +0000 |
commit | 4f58fe36c141c2a328b6081be7d9cdf203cf2fcf (patch) | |
tree | 029f6807ac622b179c0baa4c28b32bfe41ca019e /gcc | |
parent | 6cbf37c3d58bd0dbd5f79c6b2e24b35764e6fb0a (diff) | |
download | gcc-4f58fe36c141c2a328b6081be7d9cdf203cf2fcf.zip gcc-4f58fe36c141c2a328b6081be7d9cdf203cf2fcf.tar.gz gcc-4f58fe36c141c2a328b6081be7d9cdf203cf2fcf.tar.bz2 |
[AArch64][1/3] Expand signed mod by power of 2 using CSNEG
* 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.
From-SVN: r227585
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.c | 19 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.md | 58 |
3 files changed, 85 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 542abcf..25ecf5a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +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. + 2015-09-09 Alan Modra <amodra@gmail.com> PR target/67378 diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index feb7b28..b2a481b 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -6769,6 +6769,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 25229824..594bef0 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)]) @@ -2457,7 +2513,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))) |