* config/rs6000/rs6000.md (popcount<mode>2): Rewrite.
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Feb 2007 17:29:44 +0000 (17:29 +0000)
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Feb 2007 17:29:44 +0000 (17:29 +0000)
(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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121653 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/testsuite/gcc.target/powerpc/parity-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/popcount-1.c [new file with mode: 0644]

index 52a1592..dd9e6f3 100644 (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.
index 3331c11..9ef454c 100644 (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);
index 18c00e0..6fa2b66 100644 (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
index ce774b1..75aef7c 100644 (file)
      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")]
   "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" ""))
diff --git a/gcc/testsuite/gcc.target/powerpc/parity-1.c b/gcc/testsuite/gcc.target/powerpc/parity-1.c
new file mode 100644 (file)
index 0000000..d767a81
--- /dev/null
@@ -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 (file)
index 0000000..320f922
--- /dev/null
@@ -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);
+}