Subject: Re: [PATCH] powerpc: emulate power5 popcntb instruction

From: Will Schmidt <[email-masked]>
Date: Wed, 30 Aug 2006 13:11:38 -0500

On Tue, 2006-29-08 at 08:43 +0200, Segher Boessenkool wrote:
> >> I just did a patch to fix the existing masks.
> 
> Thanks Paul.
> 
> >> Could you do a new
> >> version of this patch that doesn't include the unrelated mask fixes
> >> please?  Also it would be really nice if you could figure out a  
> >> way to
> >> avoid doing the unnecessary 64-bit logical operations on 32-bit
> >> machines - i.e. using an unsigned long for tmp, but then the  
> >> constants
> >> become problematic.  Maybe you need something like
> >>
> >> #define LCONST(x)	((unsigned long)(x##ULL))
> >
> > Ok, how about this..
> 
> Hrm.  The LCONST() thing is butt ugly though; you can just write
> 0x3333333333333333ULL etc. and GCC will do the right thing (i.e.
> efficient code), and not warn (don't need the "ULL" even when in
> C99/gnu99 mode, as we should be but aren't, heh).
> 
> You want to make tmp and unsigned long instead of an u64...

Ok, so back to unsigned-long to let the 32-bit stuff be happy..

Now a bit of a tangent question:  As far as just 64-bit is concerned, is
there actually any difference between u64 and unsigned long?   Am
wondering why you suggested that change to u64 from unsigned long
earlier in the thread.

this version looks to build clean with arch=ppc (32-bit). 

This provides emulation of the power5 instruction popcntb.

Signed-off-by: Will Schmidt <[email-masked]>

---
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 2105767..4014d71 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -588,6 +588,9 @@ #define INST_LSWX		0x7c00042a
 #define INST_STSWI		0x7c0005aa
 #define INST_STSWX		0x7c00052a
 
+#define INST_POPCNTB		0x7c0000f4
+#define INST_POPCNTB_MASK	0xfc0007fe
+
 static int emulate_string_inst(struct pt_regs *regs, u32 instword)
 {
 	u8 rT = (instword >> 21) & 0x1f;
@@ -656,6 +659,23 @@ static int emulate_string_inst(struct pt
 	return 0;
 }
 
+static int emulate_popcntb_inst(struct pt_regs *regs, u32 instword)
+{
+	u32 ra,rs;
+	unsigned long tmp;
+
+	ra = (instword >> 16) & 0x1f;
+	rs = (instword >> 21) & 0x1f;
+
+	tmp = regs->gpr[rs];
+	tmp = tmp - ((tmp >> 1) & 0x5555555555555555ULL);
+	tmp = (tmp & 0x3333333333333333ULL) + ((tmp >> 2) & 0x3333333333333333ULL);
+	tmp = (tmp + (tmp >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+	regs->gpr[ra] = tmp;
+
+	return 0;
+}
+
 static int emulate_instruction(struct pt_regs *regs)
 {
 	u32 instword;
@@ -693,6 +713,11 @@ static int emulate_instruction(struct pt
 	if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
 		return emulate_string_inst(regs, instword);
 
+	/* Emulate the popcntb (Population Count Bytes) instruction. */
+	if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
+		return emulate_popcntb_inst(regs, instword);
+	}
+
 	return -EINVAL;
 }