From 565ef4bafb28d3b00ac62cc7b92f7a53f79df4b4 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Tue, 6 Feb 2007 17:29:44 +0000 Subject: [PATCH] rs6000.md (popcount2): Rewrite. * config/rs6000/rs6000.md (popcount2): Rewrite. (parity2): 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 --- gcc/ChangeLog | 9 ++ gcc/config/rs6000/rs6000-protos.h | 4 +- gcc/config/rs6000/rs6000.c | 96 +++++++++++++++++++ gcc/config/rs6000/rs6000.md | 38 ++++---- gcc/testsuite/gcc.target/powerpc/parity-1.c | 9 ++ gcc/testsuite/gcc.target/powerpc/popcount-1.c | 9 ++ 6 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/parity-1.c create mode 100644 gcc/testsuite/gcc.target/powerpc/popcount-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 52a15923fed..dd9e6f3cccf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2007-02-06 Roger Sayle + + * config/rs6000/rs6000.md (popcount2): Rewrite. + (parity2): 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 * lower-subreg.c (simple_move_operand): Reject CONST. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 3331c1137b7..9ef454c4499 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 18c00e0fafa..6fa2b661e49 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 ce774b187b2..75aef7ca5f6 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)); }) -(define_expand "popcount2" - [(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); - operands[3] = gen_reg_rtx (mode); - operands[4] = force_reg (mode, - mode == SImode - ? GEN_INT (0x01010101) - : GEN_INT ((HOST_WIDE_INT) - 0x01010101 << 32 | 0x01010101)); - operands[5] = GEN_INT (GET_MODE_BITSIZE (mode) - 8); - }) - (define_insn "popcntb2" [(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 "popcount2" + [(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 "parity2" + [(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" "")) diff --git a/gcc/testsuite/gcc.target/powerpc/parity-1.c b/gcc/testsuite/gcc.target/powerpc/parity-1.c new file mode 100644 index 00000000000..d767a816fad --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/parity-1.c @@ -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); +} diff --git a/gcc/testsuite/gcc.target/powerpc/popcount-1.c b/gcc/testsuite/gcc.target/powerpc/popcount-1.c new file mode 100644 index 00000000000..320f92285b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/popcount-1.c @@ -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); +}