Skip to contentSkip to conversation

powerpc/lib/sstep: Add cmpb instruction emulation

PATCH Superseded Matt Brown 6 participants 17 messages Jul 25, 2017 – Jul 28, 2017 PowerPC

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Matt Brown

author
#0 lore raw

PATCH v3 1/5 powerpc/lib/sstep: Add cmpb instruction emulation

This patch adds emulation of the cmpb instruction, enabling xmon to emulate this instruction.
Tested for correctness against the cmpb asm instruction on ppc64le.

---
v2:
- fixed opcode
- fixed mask typecasting

---
 arch/powerpc/lib/sstep.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
arch/powerpc/lib/sstep.c +20 -0
index 33117f8..87d277f 100644
@@ -596,6 +596,22 @@ static nokprobe_inline void do_cmp_unsigned(struct pt_regs *regs, unsigned long
 	regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
 }
 
+static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
+				unsigned long v2, int rd)
+{
+	unsigned long long out_val, mask;
+	int i;
+
+	out_val = 0;
+	for (i = 0; i < 8; i++) {
+		mask = 0xffUL << (i * 8);
+		if ((v1 & mask) == (v2 & mask))
+			out_val |= mask;
+	}
+
+	regs->gpr[rd] = out_val;
+}
+
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
 	int ret = 0;
@@ -1049,6 +1065,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			do_cmp_unsigned(regs, val, val2, rd >> 2);
 			goto instr_done;
 
+		case 508: /* cmpb */
+			do_cmpb(regs, regs->gpr[rd], regs->gpr[rb], ra);
+			goto instr_done;
+
 /*
  * Arithmetic instructions
  */
Signature · 1 line
2.9.3
author
#1 lore raw

PATCH v3 2/5 powerpc/lib/sstep: Add popcnt instruction emulation

This adds emulations for the popcntb, popcntw, and popcntd instructions. Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed typecasting
- fixed bitshifting error for both 32 and 64bit arch

---
 arch/powerpc/lib/sstep.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)
arch/powerpc/lib/sstep.c +39 -1
index 87d277f..c1f9cdb 100644
@@ -612,6 +612,32 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[rd] = out_val;
 }
 
+/*
+ * The size parameter is used to adjust the equivalent popcnt instruction.
+ * popcntb = 8, popcntw = 32, popcntd = 64
+ */
+static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
+				int size, int ra)
+{
+	unsigned long long out = v1;
+
+	out = (0x5555555555555555 & out) + (0x5555555555555555 & (out >> 1));
+	out = (0x3333333333333333 & out) + (0x3333333333333333 & (out >> 2));
+	out = (0x0f0f0f0f0f0f0f0f & out) + (0x0f0f0f0f0f0f0f0f & (out >> 4));
+	if (size == 8) {	/* popcntb */
+		regs->gpr[ra] = out;
+		return;
+	}
+	out = (0x001f001f001f001f & out) + (0x001f001f001f001f & (out >> 8));
+	out = (0x0000003f0000003f & out) + (0x0000003f0000003f & (out >> 16));
+	if (size == 32) {	/* popcntw */
+		regs->gpr[ra] = out;
+		return;
+	}
+	out = (0x000000000000007f & out) + (0x000000000000007f & (out >> 32));
+	regs->gpr[ra] = out;	/* popcntd */
+}
+
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
 	int ret = 0;
@@ -1194,6 +1220,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			regs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb];
 			goto logical_done;
 
+		case 122:	/* popcntb */
+			do_popcnt(regs, regs->gpr[rd], 8, ra);
+			goto logical_done;
+
 		case 124:	/* nor */
 			regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
 			goto logical_done;
@@ -1206,6 +1236,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			regs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb];
 			goto logical_done;
 
+		case 378:	/* popcntw */
+			do_popcnt(regs, regs->gpr[rd], 32, ra);
+			goto logical_done;
+
 		case 412:	/* orc */
 			regs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb];
 			goto logical_done;
@@ -1217,7 +1251,11 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		case 476:	/* nand */
 			regs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]);
 			goto logical_done;
-
+#ifdef __powerpc64__
+		case 506:	/* popcntd */
+			do_popcnt(regs, regs->gpr[rd], 64, ra);
+			goto logical_done;
+#endif
 		case 922:	/* extsh */
 			regs->gpr[ra] = (signed short) regs->gpr[rd];
 			goto logical_done;
Signature · 1 line
2.9.3
author
#6 lore raw

PATCH v3 3/5 powerpc/lib/sstep: Add bpermd instruction emulation

In reply to Matt Brown

This adds emulation for the bpermd instruction.
Tested for correctness against the bpermd instruction on ppc64le.

---
v2:
- fixed opcode
- added ifdef tags to do_bpermd func
- fixed bitshifting errors

---
 arch/powerpc/lib/sstep.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
arch/powerpc/lib/sstep.c +23 -1
index c1f9cdb..6a79618 100644
@@ -638,6 +638,24 @@ static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[ra] = out;	/* popcntd */
 }
 
+#ifdef __powerpc64__
+static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
+				unsigned long v2, int ra)
+{
+	unsigned char perm, idx;
+	unsigned int i;
+
+	perm = 0;
+	for (i = 0; i < 8; i++) {
+		idx = (v1 >> (i * 8)) & 0xff;
+		if (idx < 64)
+			if (v2 & PPC_BIT(idx))
+				perm |= 1 << i;
+	}
+	regs->gpr[ra] = perm;
+}
+#endif /* __powerpc64__ */
+
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
 	int ret = 0;
@@ -1227,7 +1245,11 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		case 124:	/* nor */
 			regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
 			goto logical_done;
-
+#ifdef __powerpc64__
+		case 252:	/* bpermd */
+			do_bpermd(regs, regs->gpr[rd], regs->gpr[rb], ra);
+			goto logical_done;
+#endif
 		case 284:	/* xor */
 			regs->gpr[ra] = ~(regs->gpr[rd] ^ regs->gpr[rb]);
 			goto logical_done;
Signature · 1 line
2.9.3
author
#7 lore raw

PATCH v3 4/5 powerpc/lib/sstep: Add prty instruction emulation

In reply to Matt Brown

This adds emulation for the prtyw and prtyd instructions. Tested for logical correctness against the prtyw and prtyd instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed bitshifting and typecast errors
- merged do_prtyw and do_prtyd into single function

---
 arch/powerpc/lib/sstep.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
arch/powerpc/lib/sstep.c +27 -0
index 6a79618..0bcf631 100644
@@ -655,6 +655,25 @@ static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[ra] = perm;
 }
 #endif /* __powerpc64__ */
+/*
+ * The size parameter adjusts the equivalent prty instruction.
+ * prtyw = 32, prtyd = 64
+ */
+static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
+				int size, int ra)
+{
+	unsigned long long res = v;
+
+	res = (0x0001000100010001 & res) + (0x0001000100010001 & (res >> 8));
+	res = (0x0000000700000007 & res) + (0x0000000700000007 & (res >> 16));
+	if (size == 32) {		/* prtyw */
+		regs->gpr[ra] = (0x0000000100000001 & res);
+		return;
+	}
+
+	res = (0x000000000000000f & res) + (0x000000000000000f & (res >> 32));
+	regs->gpr[ra] = res & 1;	/*prtyd */
+}
 
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
@@ -1245,6 +1264,14 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		case 124:	/* nor */
 			regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
 			goto logical_done;
+
+		case 154:	/* prtyw */
+			do_prty(regs, regs->gpr[rd], 32, ra);
+			goto logical_done;
+
+		case 186:	/* prtyd */
+			do_prty(regs, regs->gpr[rd], 64, ra);
+			goto logical_done;
 #ifdef __powerpc64__
 		case 252:	/* bpermd */
 			do_bpermd(regs, regs->gpr[rd], regs->gpr[rb], ra);
Signature · 1 line
2.9.3
author
#16 lore raw

PATCH v3 5/5 powerpc/lib/sstep: Add isel instruction emulation

In reply to Matt Brown

This adds emulation for the isel instruction.
Tested for correctness against the isel instruction and its extended mnemonics (lt, gt, eq) on ppc64le.

---
v2:
- fixed opcode
- fixed definition to include the 'if RA=0, a=0' clause
- fixed ccr bitshifting error

---
 arch/powerpc/lib/sstep.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
arch/powerpc/lib/sstep.c +11 -0
index 0bcf631..de3d558 100644
@@ -1239,6 +1239,17 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 /*
  * Logical instructions
  */
+		case 15:	/* isel */
+			mb = (instr >> 6) & 0x1f; /* bc */
+			val = (regs->ccr >> (31 - mb)) & 1;
+			val2 = (ra) ? regs->gpr[ra] : 0;
+
+			if (val)
+				regs->gpr[rd] = val2;
+			else
+				regs->gpr[rd] = regs->gpr[rb];
+			goto logical_done;
+
 		case 26:	/* cntlzw */
 			asm("cntlzw %0,%1" : "=r" (regs->gpr[ra]) :
 			    "r" (regs->gpr[rd]));
Signature · 1 line
2.9.3
#2 lore raw

Re: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulation

In reply to Matt Brown
Quoted 30 lines · Matt Brown

This adds emulations for the popcntb, popcntw, and popcntd instructions. Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed typecasting
- fixed bitshifting error for both 32 and 64bit arch

---
 arch/powerpc/lib/sstep.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)
arch/powerpc/lib/sstep.c +7 -0
index 87d277f..c1f9cdb 100644
@@ -612,6 +612,32 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[rd] = out_val;
 }
 
+/*
+ * The size parameter is used to adjust the equivalent popcnt instruction.
+ * popcntb = 8, popcntw = 32, popcntd = 64
+ */
+static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
+				int size, int ra)
+{

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 631

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+	unsigned long long out = v1;
+
+	out = (0x5555555555555555 & out) + (0x5555555555555555 & (out >> 1));
+	out = (0x3333333333333333 & out) + (0x3333333333333333 & (out >> 2));
+	out = (0x0f0f0f0f0f0f0f0f & out) + (0x0f0f0f0f0f0f0f0f & (out >> 4));
+	if (size == 8) {	/* popcntb */
+		regs->gpr[ra] = out;
+		return;
+	}
+	out = (0x001f001f001f001f & out) + (0x001f001f001f001f & (out >> 8));

Why are we using 0x001f001f here? Now that we've got things in the bytes with 0's prefixing, we can directly use

out = out + out >> 8

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 632

Quoted 1 line
arch/powerpc/lib/sstep.c +1 -0
+	out = (0x0000003f0000003f & out) + (0x0000003f0000003f & (out >> 16));

Same as above

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 638

Quoted 6 lines
arch/powerpc/lib/sstep.c +6 -0
+	if (size == 32) {	/* popcntw */
+		regs->gpr[ra] = out;
+		return;
+	}
+	out = (0x000000000000007f & out) + (0x000000000000007f & (out >> 32));
+	regs->gpr[ra] = out;	/* popcntd */

Ditto

Otherwise looks good!

Balbir Singh.

#8 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

In reply to Matt Brown
Quoted 32 lines · Matt Brown

This adds emulation for the prtyw and prtyd instructions. Tested for logical correctness against the prtyw and prtyd instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed bitshifting and typecast errors
- merged do_prtyw and do_prtyd into single function

---
 arch/powerpc/lib/sstep.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
arch/powerpc/lib/sstep.c +8 -0
index 6a79618..0bcf631 100644
@@ -655,6 +655,25 @@ static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[ra] = perm;
 }
 #endif /* __powerpc64__ */
+/*
+ * The size parameter adjusts the equivalent prty instruction.
+ * prtyw = 32, prtyd = 64
+ */
+static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
+				int size, int ra)
+{
+	unsigned long long res = v;

arch/powerpc/lib/sstep.c static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1, · line 675

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+
+	res = (0x0001000100010001 & res) + (0x0001000100010001 & (res >> 8));
+	res = (0x0000000700000007 & res) + (0x0000000700000007 & (res >> 16));
+	if (size == 32) {		/* prtyw */
+		regs->gpr[ra] = (0x0000000100000001 & res);
+		return;
+	}
+
+	res = (0x000000000000000f & res) + (0x000000000000000f & (res >> 32));
+	regs->gpr[ra] = res & 1;	/*prtyd */

Looks good, you can also xor instead of adding, but the masks would need to change in that case.

Balbir Singh.

#3 lore raw

RE: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulation

In reply to Matt Brown

From: Linuxppc-dev [mailto:linuxppc-dev-bounces+david.laight=3Daculab.com@l= ists.ozlabs.org] On Behalf Of

Quoted 4 lines

Matt Brown
Sent: 25 July 2017 04:33
To: [email protected]
Subject: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulati=

on

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *=

Quoted 21 lines

=20
This adds emulations for the popcntb, popcntw, and popcntd instructions. Tested for correctness against the popcnt{b,w,d} instructions on ppc64le. =20

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed typecasting
- fixed bitshifting error for both 32 and 64bit arch

---
 arch/powerpc/lib/sstep.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

=20

arch/powerpc/lib/sstep.c +0 -0
index 87d277f..c1f9cdb 100644
@@ -612,6 +612,32 @@ static nokprobe_inline void do_cmpb(struct pt_regs *=

regs, unsigned long v1,

Quoted 5 lines
arch/powerpc/lib/sstep.c +0 -0
 	regs->gpr[rd] =3D out_val;
 }

=20
+/*
+ * The size parameter is used to adjust the equivalent popcnt instructio=

n.

Quoted 3 lines

+ * popcntb =3D 8, popcntw =3D 32, popcntd =3D 64
+ */
+static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned lon=

g v1,

arch/powerpc/lib/sstep.c

Quoted 9 lines
arch/powerpc/lib/sstep.c +9 -0
+				int size, int ra)
+{
+	unsigned long long out =3D v1;
+
+	out =3D (0x5555555555555555 & out) + (0x5555555555555555 & (out >> 1));
+	out =3D (0x3333333333333333 & out) + (0x3333333333333333 & (out >> 2));
+	out =3D (0x0f0f0f0f0f0f0f0f & out) + (0x0f0f0f0f0f0f0f0f & (out >> 4));
+	if (size =3D=3D 8) {	/* popcntb */
+		regs->gpr[ra] =3D out;

I'm pretty sure you need to mask the result with 7.

David

#4 lore raw

Re: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulation

Quoted 29 lines · David Laight

From: Linuxppc-dev [mailto:[email protected]] On Behalf Of

Quoted 28 lines

Matt Brown
Sent: 25 July 2017 04:33
To: [email protected]
Subject: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulation

This adds emulations for the popcntb, popcntw, and popcntd instructions. Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed typecasting
- fixed bitshifting error for both 32 and 64bit arch

---
 arch/powerpc/lib/sstep.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)
arch/powerpc/lib/sstep.c +0 -0
index 87d277f..c1f9cdb 100644
@@ -612,6 +612,32 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
      regs->gpr[rd] = out_val;
 }
 
Quoted 17 lines
Quoted 4 lines
arch/powerpc/lib/sstep.c +4 -0
+/*
+ * The size parameter is used to adjust the equivalent popcnt instruction.
+ * popcntb = 8, popcntw = 32, popcntd = 64
+ */

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 628

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
+                             int size, int ra)
+{
+     unsigned long long out = v1;
+
+     out = (0x5555555555555555 & out) + (0x5555555555555555 & (out >> 1));
+     out = (0x3333333333333333 & out) + (0x3333333333333333 & (out >> 2));
+     out = (0x0f0f0f0f0f0f0f0f & out) + (0x0f0f0f0f0f0f0f0f & (out >> 4));
+     if (size == 8) {        /* popcntb */
+             regs->gpr[ra] = out;

I'm pretty sure you need to mask the result with 7.

Absolutely! Good catch!

Balbir Singh.

#10 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

In reply to Matt Brown
Quoted 5 lines · Matt Brown
arch/powerpc/lib/sstep.c +5 -0
+static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
+				int size, int ra)
+{
+	unsigned long long res = v;
+

arch/powerpc/lib/sstep.c static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1, · line 676

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+	res = (0x0001000100010001 & res) + (0x0001000100010001 & (res >> 8));
+	res = (0x0000000700000007 & res) + (0x0000000700000007 & (res >> 16));
+	if (size == 32) {		/* prtyw */
+		regs->gpr[ra] = (0x0000000100000001 & res);
+		return;
+	}
+
+	res = (0x000000000000000f & res) + (0x000000000000000f & (res >> 32));
+	regs->gpr[ra] = res & 1;	/*prtyd */
+}

Does 7's and 0xf look strange (since the top bit in the values there is always 0). You always "and" the values with 1 later, you could do that immediately (and change + to ^).

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Segher

#5 lore raw

Re: [PATCH v3 2/5] powerpc/lib/sstep: Add popcnt instruction emulation

In reply to Matt Brown
Quoted 23 lines · Matt Brown

This adds emulations for the popcntb, popcntw, and popcntd instructions. Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed typecasting
- fixed bitshifting error for both 32 and 64bit arch

---
 arch/powerpc/lib/sstep.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)
arch/powerpc/lib/sstep.c +0 -0
index 87d277f..c1f9cdb 100644
@@ -612,6 +612,32 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[rd] = out_val;
 }
 

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 624

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+/*
+ * The size parameter is used to adjust the equivalent popcnt instruction.
+ * popcntb = 8, popcntw = 32, popcntd = 64
+ */
+static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
+				int size, int ra)
+{
+	unsigned long long out = v1;
+
+	out = (0x5555555555555555 & out) + (0x5555555555555555 & (out >> 1));

This can be simplified in a less obvious way as:

	out -= (out >> 1) & 0x5555555555555555;

which maps each pair of bits according to the following:
00 -> 00
01 -> 01
10 -> 01
11 -> 10

This should save one instruction.

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 625

Quoted 1 line
arch/powerpc/lib/sstep.c +1 -0
+	out = (0x3333333333333333 & out) + (0x3333333333333333 & (out >> 2));

Ok, but now each nibble is between 0 and 4, so the addition of two nibbles can't overflow or generate carry into the higher one.

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 626

Quoted 1 line
arch/powerpc/lib/sstep.c +1 -0
+	out = (0x0f0f0f0f0f0f0f0f & out) + (0x0f0f0f0f0f0f0f0f & (out >> 4));
	out += out >> 4;
	out &= 0x0f0f0f0f0f0f0f0f;

which should also save one instruction

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 630

Quoted 4 lines
arch/powerpc/lib/sstep.c +4 -0
+	if (size == 8) {	/* popcntb */
+		regs->gpr[ra] = out;
+		return;
+	}

At this point each count occupies at least one byte and can no more overflow, so masking is only needed before returning.

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 631

Quoted 1 line
arch/powerpc/lib/sstep.c +1 -0
+	out = (0x001f001f001f001f & out) + (0x001f001f001f001f & (out >> 8));
	out += out >> 8;

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 632

Quoted 1 line
arch/powerpc/lib/sstep.c +1 -0
+	out = (0x0000003f0000003f & out) + (0x0000003f0000003f & (out >> 16));
	out += out >> 16;

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 634

Quoted 2 lines
arch/powerpc/lib/sstep.c +2 -0
+	if (size == 32) {	/* popcntw */
+		regs->gpr[ra] = out;
		regs->gpr[ra] = out & 0x0000003f0000003f;

arch/powerpc/lib/sstep.c static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1, · line 637

Quoted 3 lines
arch/powerpc/lib/sstep.c +3 -0
+		return;
+	}
+	out = (0x000000000000007f & out) + (0x000000000000007f & (out >> 32));
	out = (out + (out >> 32)) & 0x7f;


	Gabriel
Quoted 43 lines
arch/powerpc/lib/sstep.c +16 -1
+	regs->gpr[ra] = out;	/* popcntd */
+}
+
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
 	int ret = 0;
@@ -1194,6 +1220,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			regs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb];
 			goto logical_done;
 
+		case 122:	/* popcntb */
+			do_popcnt(regs, regs->gpr[rd], 8, ra);
+			goto logical_done;
+
 		case 124:	/* nor */
 			regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
 			goto logical_done;
@@ -1206,6 +1236,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			regs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb];
 			goto logical_done;
 
+		case 378:	/* popcntw */
+			do_popcnt(regs, regs->gpr[rd], 32, ra);
+			goto logical_done;
+
 		case 412:	/* orc */
 			regs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb];
 			goto logical_done;
@@ -1217,7 +1251,11 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		case 476:	/* nand */
 			regs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]);
 			goto logical_done;
-
+#ifdef __powerpc64__
+		case 506:	/* popcntd */
+			do_popcnt(regs, regs->gpr[rd], 64, ra);
+			goto logical_done;
+#endif
 		case 922:	/* extsh */
 			regs->gpr[ra] = (signed short) regs->gpr[rd];
 			goto logical_done;
Signature · 1 line
2.9.3
#9 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

In reply to Balbir Singh
Quoted 38 lines · Balbir Singh
Quoted 37 lines · Matt Brown

This adds emulation for the prtyw and prtyd instructions. Tested for logical correctness against the prtyw and prtyd instructions on ppc64le.

---
v3:
- optimised using the Giles-Miller method of side-ways addition
v2:
- fixed opcodes
- fixed bitshifting and typecast errors
- merged do_prtyw and do_prtyd into single function

---
 arch/powerpc/lib/sstep.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
arch/powerpc/lib/sstep.c +13 -0
index 6a79618..0bcf631 100644
@@ -655,6 +655,25 @@ static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[ra] = perm;
 }
 #endif /* __powerpc64__ */
+/*
+ * The size parameter adjusts the equivalent prty instruction.
+ * prtyw = 32, prtyd = 64
+ */
+static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
+				int size, int ra)
+{
+	unsigned long long res = v;
+
+	res = (0x0001000100010001 & res) + (0x0001000100010001 & (res >> 8));
+	res = (0x0000000700000007 & res) + (0x0000000700000007 & (res >> 16));
+	if (size == 32) {		/* prtyw */
+		regs->gpr[ra] = (0x0000000100000001 & res);
Quoted 8 lines

arch/powerpc/lib/sstep.c static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1, · line 675

Quoted 5 lines
arch/powerpc/lib/sstep.c +5 -0
+		return;
+	}
+
+	res = (0x000000000000000f & res) + (0x000000000000000f & (res >> 32));
+	regs->gpr[ra] = res & 1;	/*prtyd */

Looks good, you can also xor instead of adding, but the masks would need to change in that case.

Actually, I'd prefer to use xor for this case, since you hardly ever need any mask, except at the end. Most masks are only needed because of carry propagation, which the xor completely avoid.

In other words:

	unsigned long long res = v ^ (v >> 8);
	res ^= res >> 16; 
	if (size == 32) {
		regs->gpr[ra] = res & 0x0000000100000001;
		return;
	}
	res ^= res >> 32;
	regs-> gpr[ra] = res & 1;

should work, but I've not even compiled it.

Gabriel

#11 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

In reply to Segher Boessenkool
Quoted 21 lines · Segher Boessenkool
Quoted 5 lines · Matt Brown
arch/powerpc/lib/sstep.c +5 -0
+static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
+				int size, int ra)
+{
+	unsigned long long res = v;
+

arch/powerpc/lib/sstep.c static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1, · line 676

Quoted 10 lines
arch/powerpc/lib/sstep.c +10 -0
+	res = (0x0001000100010001 & res) + (0x0001000100010001 & (res >> 8));
+	res = (0x0000000700000007 & res) + (0x0000000700000007 & (res >> 16));
+	if (size == 32) {		/* prtyw */
+		regs->gpr[ra] = (0x0000000100000001 & res);
+		return;
+	}
+
+	res = (0x000000000000000f & res) + (0x000000000000000f & (res >> 32));
+	regs->gpr[ra] = res & 1;	/*prtyd */
+}

Does 7's and 0xf look strange (since the top bit in the values there is always 0). You always "and" the values with 1 later, you could do that immediately (and change + to ^).

Quoted 3 lines

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Why is it the wrong macro? Because we tend to use CONFIG_PPC64 you mean?

I thought the reason some are #ifdef'ed is that some are 64-bit only. ie. bpermd is 64-bit only ?

cheers

#12 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

Quoted 6 lines · Michael Ellerman
Quoted 3 lines · Segher Boessenkool

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Why is it the wrong macro? Because we tend to use CONFIG_PPC64 you mean?

Yeah. But I see sstep.c already mixes those two at will (or if there is a distinction, I'm not seeing it :-) )

Quoted 2 lines

I thought the reason some are #ifdef'ed is that some are 64-bit only. ie. bpermd is 64-bit only ?

64-bit only, in what way? It's not clear what the rules are.

It's not instructions that can only run in 64-bit mode. It's not instructions that only give a usable result with 64-bit regs implemented.
It's not instructions only implemented on 64-bit CPUs. It's not even "all instructions that would not give a correct result in the low 32 bits of GPRs if the high 32 bits are not implemented".

Segher

#13 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

Quoted 10 lines · Segher Boessenkool
Quoted 6 lines · Michael Ellerman
Quoted 3 lines · Segher Boessenkool

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Why is it the wrong macro? Because we tend to use CONFIG_PPC64 you mean?

Yeah. But I see sstep.c already mixes those two at will (or if there is a distinction, I'm not seeing it :-) )

Yeah OK. In practice they're equivalent, if CONFIG_PPC64=y then the kernel is built 64-bit and therefore __powerpc64__ is defined.

But I agree it's a mess, we should use CONFIG_PPC64 exclusively unless there's some reason not to (which I don't think there ever is).

Quoted 4 lines
Quoted 2 lines

I thought the reason some are #ifdef'ed is that some are 64-bit only. ie. bpermd is 64-bit only ?

64-bit only, in what way? It's not clear what the rules are.

Instructions that have "d" in the name? :P

Quoted 4 lines

It's not instructions that can only run in 64-bit mode. It's not instructions that only give a usable result with 64-bit regs implemented.
It's not instructions only implemented on 64-bit CPUs.

I think it's trying to be that ^

If you build a 32-bit kernel then instructions that are only defined on 64-bit CPUs should be treated as illegal, so the easiest way to achieve that is to #ifdef off the code for those instructions.

cheers

author
#14 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

Quoted 31 lines · Michael Ellerman
Quoted 10 lines · Segher Boessenkool
Quoted 6 lines · Michael Ellerman
Quoted 3 lines · Segher Boessenkool

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Why is it the wrong macro? Because we tend to use CONFIG_PPC64 you mean?

Yeah. But I see sstep.c already mixes those two at will (or if there is a distinction, I'm not seeing it :-) )

Yeah OK. In practice they're equivalent, if CONFIG_PPC64=y then the kernel is built 64-bit and therefore __powerpc64__ is defined.

But I agree it's a mess, we should use CONFIG_PPC64 exclusively unless there's some reason not to (which I don't think there ever is).

Quoted 4 lines
Quoted 2 lines

I thought the reason some are #ifdef'ed is that some are 64-bit only. ie. bpermd is 64-bit only ?

64-bit only, in what way? It's not clear what the rules are.

Instructions that have "d" in the name? :P

Quoted 4 lines

It's not instructions that can only run in 64-bit mode. It's not instructions that only give a usable result with 64-bit regs implemented.
It's not instructions only implemented on 64-bit CPUs.

Quoted 6 lines

I think it's trying to be that ^

If you build a 32-bit kernel then instructions that are only defined on 64-bit CPUs should be treated as illegal, so the easiest way to achieve that is to #ifdef off the code for those instructions.

I'll fixup this up to use the xor implementation, and change the series to use CONFIG_PPC64 for the ifdef.

Thanks,
Matt

Quoted 1 line

cheers

#15 lore raw

Re: [PATCH v3 4/5] powerpc/lib/sstep: Add prty instruction emulation

Quoted 32 lines · Matt Brown
Quoted 31 lines · Michael Ellerman
Quoted 10 lines · Segher Boessenkool
Quoted 6 lines · Michael Ellerman
Quoted 3 lines · Segher Boessenkool

A general question about these patches: some things are inside #ifdef __powerpc64__, some are not. It seems it is the wrong macro, and it should be used (or not used) consistently?

Why is it the wrong macro? Because we tend to use CONFIG_PPC64 you mean?

Yeah. But I see sstep.c already mixes those two at will (or if there is a distinction, I'm not seeing it :-) )

Yeah OK. In practice they're equivalent, if CONFIG_PPC64=y then the kernel is built 64-bit and therefore __powerpc64__ is defined.

But I agree it's a mess, we should use CONFIG_PPC64 exclusively unless there's some reason not to (which I don't think there ever is).

Quoted 4 lines
Quoted 2 lines

I thought the reason some are #ifdef'ed is that some are 64-bit only. ie. bpermd is 64-bit only ?

64-bit only, in what way? It's not clear what the rules are.

Instructions that have "d" in the name? :P

Quoted 4 lines

It's not instructions that can only run in 64-bit mode. It's not instructions that only give a usable result with 64-bit regs implemented.
It's not instructions only implemented on 64-bit CPUs.

Quoted 8 lines
Quoted 5 lines

I think it's trying to be that ^

If you build a 32-bit kernel then instructions that are only defined on 64-bit CPUs should be treated as illegal, so the easiest way to achieve that is to #ifdef off the code for those instructions.

I'll fixup this up to use the xor implementation, and change the series to use CONFIG_PPC64 for the ifdef.

Thanks.

In terms of the actual algorithms, we want to use something reasonably efficient, but don't sweat too much on the performance. The overhead of the emulation is in the exception we took to get there. So readable and obviously correct source is the main goal.

cheers