aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2007-02-06 17:29:44 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2007-02-06 17:29:44 +0000
commit565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4 (patch)
tree3b0a683627d420dedb289b8f502bb2e97bd39aa2 /gcc/config
parent7e0c3f57e0bd40144eb662c221e284f3bbf1873c (diff)
downloadgcc-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.h4
-rw-r--r--gcc/config/rs6000/rs6000.c96
-rw-r--r--gcc/config/rs6000/rs6000.md38
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" ""))