diff options
author | Roger Sayle <roger@eyesopen.com> | 2007-02-06 17:29:44 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2007-02-06 17:29:44 +0000 |
commit | 565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4 (patch) | |
tree | 3b0a683627d420dedb289b8f502bb2e97bd39aa2 /gcc/config | |
parent | 7e0c3f57e0bd40144eb662c221e284f3bbf1873c (diff) | |
download | gcc-565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4.zip gcc-565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4.tar.gz gcc-565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4.tar.bz2 |
rs6000.md (popcount<mode>2): Rewrite.
* config/rs6000/rs6000.md (popcount<mode>2): Rewrite.
(parity<mode>2): New define_expand using rs6000_emit_parity.
* config/rs6000/rs6000.c (rs6000_emit_popcount,
rs6000_emit_parity): New functions.
* config/rs6000/rs6000-protos.h (rs6000_emit_popcount,
rs6000_emit_parity): Prototype here.
* gcc.target/powerpc/popcount-1.c: New test case.
* gcc.target/powerpc/parity-1.c: Likewise.
From-SVN: r121653
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 96 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 38 |
3 files changed, 117 insertions, 21 deletions
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 3331c11..9ef454c 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler, for IBM RS/6000. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) @@ -106,6 +106,8 @@ extern bool rs6000_offsettable_memref_p (rtx); extern rtx rs6000_return_addr (int, rtx); extern void rs6000_output_symbol_ref (FILE*, rtx); extern HOST_WIDE_INT rs6000_initial_elimination_offset (int, int); +extern void rs6000_emit_popcount (rtx, rtx); +extern void rs6000_emit_parity (rtx, rtx); extern rtx rs6000_machopic_legitimize_pic_address (rtx, enum machine_mode, rtx); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 18c00e0..6fa2b66 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -20239,6 +20239,102 @@ rs6000_emit_swdivdf (rtx res, rtx n, rtx d) gen_rtx_MULT (DFmode, v0, y3), u0))); } + +/* Emit popcount intrinsic on TARGET_POPCNTB targets. DST is the + target, and SRC is the argument operand. */ + +void +rs6000_emit_popcount (rtx dst, rtx src) +{ + enum machine_mode mode = GET_MODE (dst); + rtx tmp1, tmp2; + + tmp1 = gen_reg_rtx (mode); + + if (mode == SImode) + { + emit_insn (gen_popcntbsi2 (tmp1, src)); + tmp2 = expand_mult (SImode, tmp1, GEN_INT (0x01010101), + NULL_RTX, 0); + tmp2 = force_reg (SImode, tmp2); + emit_insn (gen_lshrsi3 (dst, tmp2, GEN_INT (24))); + } + else + { + emit_insn (gen_popcntbdi2 (tmp1, src)); + tmp2 = expand_mult (DImode, tmp1, + GEN_INT ((HOST_WIDE_INT) + 0x01010101 << 32 | 0x01010101), + NULL_RTX, 0); + tmp2 = force_reg (DImode, tmp2); + emit_insn (gen_lshrdi3 (dst, tmp2, GEN_INT (56))); + } +} + + +/* Emit parity intrinsic on TARGET_POPCNTB targets. DST is the + target, and SRC is the argument operand. */ + +void +rs6000_emit_parity (rtx dst, rtx src) +{ + enum machine_mode mode = GET_MODE (dst); + rtx tmp; + + tmp = gen_reg_rtx (mode); + if (mode == SImode) + { + /* Is mult+shift >= shift+xor+shift+xor? */ + if (rs6000_cost->mulsi_const >= COSTS_N_INSNS (3)) + { + rtx tmp1, tmp2, tmp3, tmp4; + + tmp1 = gen_reg_rtx (SImode); + emit_insn (gen_popcntbsi2 (tmp1, src)); + + tmp2 = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (tmp2, tmp1, GEN_INT (16))); + tmp3 = gen_reg_rtx (SImode); + emit_insn (gen_xorsi3 (tmp3, tmp1, tmp2)); + + tmp4 = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (tmp4, tmp3, GEN_INT (8))); + emit_insn (gen_xorsi3 (tmp, tmp3, tmp4)); + } + else + rs6000_emit_popcount (tmp, src); + emit_insn (gen_andsi3 (dst, tmp, const1_rtx)); + } + else + { + /* Is mult+shift >= shift+xor+shift+xor+shift+xor? */ + if (rs6000_cost->muldi >= COSTS_N_INSNS (5)) + { + rtx tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + + tmp1 = gen_reg_rtx (DImode); + emit_insn (gen_popcntbdi2 (tmp1, src)); + + tmp2 = gen_reg_rtx (DImode); + emit_insn (gen_lshrdi3 (tmp2, tmp1, GEN_INT (32))); + tmp3 = gen_reg_rtx (DImode); + emit_insn (gen_xordi3 (tmp3, tmp1, tmp2)); + + tmp4 = gen_reg_rtx (DImode); + emit_insn (gen_lshrdi3 (tmp4, tmp3, GEN_INT (16))); + tmp5 = gen_reg_rtx (DImode); + emit_insn (gen_xordi3 (tmp5, tmp3, tmp4)); + + tmp6 = gen_reg_rtx (DImode); + emit_insn (gen_lshrdi3 (tmp6, tmp5, GEN_INT (8))); + emit_insn (gen_xordi3 (tmp, tmp5, tmp6)); + } + else + rs6000_emit_popcount (tmp, src); + emit_insn (gen_anddi3 (dst, tmp, const1_rtx)); + } +} + /* Return an RTX representing where to find the function value of a function returning MODE. */ static rtx diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index ce774b1..75aef7c 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -2161,26 +2161,6 @@ operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)); }) -(define_expand "popcount<mode>2" - [(set (match_dup 2) - (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] - UNSPEC_POPCNTB)) - (set (match_dup 3) - (mult:GPR (match_dup 2) (match_dup 4))) - (set (match_operand:GPR 0 "gpc_reg_operand" "=r") - (lshiftrt:GPR (match_dup 3) (match_dup 5)))] - "TARGET_POPCNTB" - { - operands[2] = gen_reg_rtx (<MODE>mode); - operands[3] = gen_reg_rtx (<MODE>mode); - operands[4] = force_reg (<MODE>mode, - <MODE>mode == SImode - ? GEN_INT (0x01010101) - : GEN_INT ((HOST_WIDE_INT) - 0x01010101 << 32 | 0x01010101)); - operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - 8); - }) - (define_insn "popcntb<mode>2" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] @@ -2188,6 +2168,24 @@ "TARGET_POPCNTB" "popcntb %0,%1") +(define_expand "popcount<mode>2" + [(use (match_operand:GPR 0 "gpc_reg_operand" "=r")) + (use (match_operand:GPR 1 "gpc_reg_operand" "r"))] + "TARGET_POPCNTB" + { + rs6000_emit_popcount (operands[0], operands[1]); + DONE; + }) + +(define_expand "parity<mode>2" + [(use (match_operand:GPR 0 "gpc_reg_operand" "=r")) + (use (match_operand:GPR 1 "gpc_reg_operand" "r"))] + "TARGET_POPCNTB" + { + rs6000_emit_parity (operands[0], operands[1]); + DONE; + }) + (define_expand "mulsi3" [(use (match_operand:SI 0 "gpc_reg_operand" "")) (use (match_operand:SI 1 "gpc_reg_operand" "")) |