[PATCH v2 1/5] powerpc/lib/sstep: Add cmpb instruction emulation

Subsystems: linux for powerpc (32-bit and 64-bit), the rest

STALE3297d

8 messages, 3 authors, 2017-07-25 · open the first message on its own page

[PATCH v2 1/5] powerpc/lib/sstep: Add cmpb instruction emulation

From: Matt Brown <hidden>
Date: 2017-07-24 01:01:25

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

Signed-off-by: Matt Brown <redacted>
---
v2: 
	- fixed opcode
	- fixed mask typecasting
---
 arch/powerpc/lib/sstep.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 33117f8..87d277f 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -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
  */
-- 
2.9.3

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

From: Matt Brown <hidden>
Date: 2017-07-24 01:01:27

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

Signed-off-by: Matt Brown <redacted>
---
v2:
	- fixed opcodes
	- fixed typecasting
	- fixed bitshifting error for both 32 and 64bit arch
---
 arch/powerpc/lib/sstep.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 87d277f..e6a16a3 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -612,6 +612,35 @@ 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 high, low, mask;
+	unsigned int n;
+	int i, j;
+
+	high = 0;
+	low = 0;
+
+	for (i = 0; i < (64 / size); i++) {
+		n = 0;
+		for (j = 0; j < size; j++) {
+			mask = 1UL << (j + (i * size));
+			if (v1 & mask)
+				n++;
+		}
+		if ((i * size) < 32)
+			low |= n << (i * size);
+		else
+			high |= n << ((i * size) - 32);
+	}
+	regs->gpr[ra] = (high << 32) | low;
+}
+
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
 	int ret = 0;
@@ -1194,6 +1223,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 +1239,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 +1254,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;
-- 
2.9.3

[PATCH v2 3/5] powerpc/lib/sstep: Add bpermd instruction emulation

From: Matt Brown <hidden>
Date: 2017-07-24 01:01:29

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

Signed-off-by: Matt Brown <redacted>
---
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(-)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index e6a16a3..a756f44 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -641,6 +641,24 @@ static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
 	regs->gpr[ra] = (high << 32) | low;
 }
 
+#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;
@@ -1230,7 +1248,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;
-- 
2.9.3

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

From: Matt Brown <hidden>
Date: 2017-07-24 01:01:30

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

Signed-off-by: Matt Brown <redacted>
---
v2:
	- fixed opcodes
	- fixed bitshifting and typecast errors
	- merged do_prtyw and do_prtyd into single function
---
 arch/powerpc/lib/sstep.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index a756f44..1820fd6 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -658,6 +658,29 @@ 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 high, low;
+	unsigned int i;
+
+	high = 0;
+	low = 0;
+
+	for (i = 0; i < 8; i++) {
+		if (v & (1UL << (i * 8)))
+			(i < 4) ? (low++) : (high++);
+	}
+
+	if (size == 32)
+		regs->gpr[ra] = ((high & 1) << 32) | (low & 1);
+	else
+		regs->gpr[ra] = (high + low) & 1;
+}
 
 static nokprobe_inline int trap_compare(long v1, long v2)
 {
@@ -1248,6 +1271,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);
-- 
2.9.3

[PATCH v2 5/5] powerpc/lib/sstep: Add isel instruction emulation

From: Matt Brown <hidden>
Date: 2017-07-24 01:01:31

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

Signed-off-by: Matt Brown <redacted>
---
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(+)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index b08eb96..e1f4ec6 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -1246,6 +1246,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]));
-- 
2.9.3

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

From: Segher Boessenkool <hidden>
Date: 2017-07-24 07:37:02

Hi Matt,

On Mon, Jul 24, 2017 at 11:01:06AM +1000, Matt Brown wrote:
+	for (i = 0; i < (64 / size); i++) {
If you do

  for (i = 0; i < 64; i += size)

things are slightly nicer.
+		if ((i * size) < 32)
+			low |= n << (i * size);
+		else
+			high |= n << ((i * size) - 32);
+	}
+	regs->gpr[ra] = (high << 32) | low;
Why have separate high and low vars?

And there are much better ways to calculate popcount, of course.


Segher

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

From: Balbir Singh <bsingharora@gmail.com>
Date: 2017-07-24 10:28:27

On Mon, Jul 24, 2017 at 11:01 AM, Matt Brown
[off-list ref] wrote:
quoted hunk
This adds emulations for the popcntb, popcntw, and popcntd instructions.
Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

Signed-off-by: Matt Brown <redacted>
---
v2:
        - fixed opcodes
        - fixed typecasting
        - fixed bitshifting error for both 32 and 64bit arch
---
 arch/powerpc/lib/sstep.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 87d277f..e6a16a3 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -612,6 +612,35 @@ 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 high, low, mask;
+       unsigned int n;
+       int i, j;
+
+       high = 0;
+       low = 0;
+
+       for (i = 0; i < (64 / size); i++) {
+               n = 0;
+               for (j = 0; j < size; j++) {
+                       mask = 1UL << (j + (i * size));
+                       if (v1 & mask)
+                               n++;
+               }
+               if ((i * size) < 32)
+                       low |= n << (i * size);
+               else
+                       high |= n << ((i * size) - 32);
+       }
+       regs->gpr[ra] = (high << 32) | low;
+}
There's a way to do it in very efficient way via the Giles-Miller
method of side-ways addition

Please see

http://opensourceforu.com/2012/06/power-programming-bitwise-tips-tricks/
and lib/hweight.c, you can reuse the code from lib/hweight.c

Balbir Singh

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

From: Matt Brown <hidden>
Date: 2017-07-25 00:53:46

On Mon, Jul 24, 2017 at 8:28 PM, Balbir Singh [off-list ref] wrote:
On Mon, Jul 24, 2017 at 11:01 AM, Matt Brown
[off-list ref] wrote:
quoted
This adds emulations for the popcntb, popcntw, and popcntd instructions.
Tested for correctness against the popcnt{b,w,d} instructions on ppc64le.

Signed-off-by: Matt Brown <redacted>
---
v2:
        - fixed opcodes
        - fixed typecasting
        - fixed bitshifting error for both 32 and 64bit arch
---
 arch/powerpc/lib/sstep.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 87d277f..e6a16a3 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -612,6 +612,35 @@ 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 high, low, mask;
+       unsigned int n;
+       int i, j;
+
+       high = 0;
+       low = 0;
+
+       for (i = 0; i < (64 / size); i++) {
+               n = 0;
+               for (j = 0; j < size; j++) {
+                       mask = 1UL << (j + (i * size));
+                       if (v1 & mask)
+                               n++;
+               }
+               if ((i * size) < 32)
+                       low |= n << (i * size);
+               else
+                       high |= n << ((i * size) - 32);
+       }
+       regs->gpr[ra] = (high << 32) | low;
+}
There's a way to do it in very efficient way via the Giles-Miller
method of side-ways addition

Please see

http://opensourceforu.com/2012/06/power-programming-bitwise-tips-tricks/
and lib/hweight.c, you can reuse the code from lib/hweight.c
Oh that's a really cool technique.
We could use that for the parity instructions too.
Balbir Singh
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help