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
This commit is contained in:
Roger Sayle 2007-02-06 17:29:44 +00:00 committed by Roger Sayle
parent 7e0c3f57e0
commit 565ef4bafb
6 changed files with 144 additions and 21 deletions

View File

@ -1,3 +1,12 @@
2007-02-06 Roger Sayle <roger@eyesopen.com>
* 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.
2007-02-06 Ian Lance Taylor <iant@google.com>
* lower-subreg.c (simple_move_operand): Reject CONST.

View File

@ -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);

View File

@ -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

View File

@ -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" ""))

View File

@ -0,0 +1,9 @@
/* { dg-do compile { target { ilp32 } } } */
/* { dg-options "-O2 -mcpu=power6" } */
/* { dg-final { scan-assembler "popcntb" } } */
/* { dg-final { scan-assembler-not "mullw" } } */
int foo(int x)
{
return __builtin_parity(x);
}

View File

@ -0,0 +1,9 @@
/* { dg-do compile { target { ilp32 } } } */
/* { dg-options "-O2 -mcpu=power6" } */
/* { dg-final { scan-assembler "popcntb" } } */
/* { dg-final { scan-assembler-not "mullw" } } */
int foo(int x)
{
return __builtin_popcount(x);
}