Linux MIPS Architecture development
 help / color / mirror / Atom feed
From: James Hogan <james.hogan@mips.com>
To: Ralf Baechle <ralf@linux-mips.org>
Cc: Marcin Nowakowski <marcin.nowakowski@imgtec.com>,
	Linux MIPS Mailing List <linux-mips@linux-mips.org>
Subject: Re: [PATCH v2 2/2] MIPS: crypto: Add crc32 and crc32c hw accelerated module
Date: Thu, 16 Nov 2017 00:04:48 +0000	[thread overview]
Message-ID: <20171116000448.GC27409@jhogan-linux.mipstec.com> (raw)
In-Reply-To: <20171004153600.GB31821@linux-mips.org>

[-- Attachment #1: Type: text/plain, Size: 6233 bytes --]

(trim cc)

On Wed, Oct 04, 2017 at 05:36:00PM +0200, Ralf Baechle wrote:
> On Wed, Oct 04, 2017 at 12:48:53PM +0200, Marcin Nowakowski wrote:
> > +#define _CRC32(crc, value, size, type)						\
> > +do {										\
> > +	__asm__ __volatile__(							\
> > +	".set	push\n\t"							\
> > +	".set	noat\n\t"							\
> > +	"move	$at, %1\n\t"							\
> > +	"# " #type #size "	%0, $at, %0\n\t"				\
> > +	_ASM_INSN_IF_MIPS(0x7c00000f | (2 << 16) | (1 << 21) | (%2 << 6) | (%3 << 8))	\
> > +	_ASM_INSN32_IF_MM(0x00000030 | (1 << 16) | (2 << 21) | (%2 << 14) | (%3 << 3))	\
> > +	".set	pop"							\
> > +	: "+r" (crc)								\
> > +	: "r" (value), "i" (size), "i" (type)					\
> > +);										\
> > +} while(0)
> > +
> > +#define CRC_REGISTER __asm__("$2")
> > +#endif	/* !TOOLCHAIN_SUPPORTS_CRC */
> 
> Over there years we've added so many inlines for instructions not yet
> supported by gas and the simply approach always requires extra move
> instructions.  So I finally cooked up something better which only relies
> on things that are in gas for as long as I can remember.  This illustrates
> it:
> 
> 	.macro	parse var r
> 	.ifc	\r, $0
> \var	=	0
> 	.endif
> 	.ifc	\r, $1
> \var	=	1
> 	.endif
> 	.ifc	\r, $2
> \var	=	2
> 	.endif
> 	.ifc	\r, $3
> \var	=	3
> 	.endif
> 	.endm
> 
> 	.macro	definsn opcode r1 r2 r3
> 	parse	__definsn_r1 \r1
> 	parse	__definsn_r2 \r2
> 	parse	__definsn_r3 \r3
> 	.word	\opcode | (__definsn_r1 << 16) | (__definsn_r2 << 20) | (__definsn_r3 << 24)
> 	.endm
> 
> 	.macro	foo r1, r2, r3
> 	definsn	42, \r1, \r2, \r3
> 	.endm
> 
> 	foo	$1, $2, $3
> 	foo	$3, $0, $1
> 
> The advantages are obvious, the hypothetical instruction foo can be used
> just like it was actually supported by gas and no bloat by move
> instructions to shuffle operands in and results out.  Which for some
> very convoluted cases may also save you from an ICE.
> 
> Above skeleton still needs a little polish, either by extending the
> parsing of register numbers to all 32 registers or by implementing that
> using another loop which probably would be implemented using a recursive
> gas macro.

Very nice, e.g.

diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 6b1f1ad0542c..3a16fad43efb 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -1180,6 +1180,31 @@ static inline int mm_insn_16bit(u16 insn)
 #define _ASM_INSN_IF_MIPS(_enc)
 #endif
 
+/*
+ * Helper assembly macro for decoding a register name.
+ */
+#define _IFC_REG(n)			\
+	".ifc	\\r, $"#n"\n\t"		\
+	"\\var	="#n"\n\t"		\
+	".endif\n\t"
+
+__asm__(".macro	parse var r\n\t"
+	"\\var	= -1\n\t"
+	_IFC_REG( 0) _IFC_REG( 1) _IFC_REG( 2) _IFC_REG( 3)
+	_IFC_REG( 4) _IFC_REG( 5) _IFC_REG( 6) _IFC_REG( 7)
+	_IFC_REG( 8) _IFC_REG( 9) _IFC_REG(10) _IFC_REG(11)
+	_IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15)
+	_IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19)
+	_IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23)
+	_IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27)
+	_IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31)
+	".iflt	\\var\n\t"
+	".error \"Unable to parse register name \\r\"\n\t"
+	".endif\n\t"
+	".endm");
+
+#undef _IFC_REG
+
 /*
  * TLB Invalidate Flush
  */
@@ -1412,10 +1437,10 @@ do {									\
 	"	.set	push					\n"	\
 	"	.set	noat					\n"	\
 	"	.set	mips32r2				\n"	\
-	"	# mfhc0 $1, %1					\n"	\
-	_ASM_INSN_IF_MIPS(0x40410000 | ((%1 & 0x1f) << 11))		\
-	_ASM_INSN32_IF_MM(0x002000f4 | ((%1 & 0x1f) << 16))		\
-	"	move	%0, $1					\n"	\
+	"	# mfhc0 %0, %1					\n"	\
+	"	parse	__dst, %0				\n"	\
+	_ASM_INSN_IF_MIPS(0x40400000 | (__dst << 16) | ((%1 & 0x1f) << 11)) \
+	_ASM_INSN32_IF_MM(0x000000f4 | (__dst << 21) | ((%1 & 0x1f) << 16)) \
 	"	.set	pop					\n"	\
 	: "=r" (__res)							\
 	: "i" (source));						\

gives us this in arch/mips/lib/dump_tlb.o:

- 430:	40411000 	mfhc0	at,c0_entrylo0
- 434:	00203825 	move	a3,at
+ 430:	40471000 	mfhc0	a3,c0_entrylo0

And we can easily enough simplify a lot of mostly duplicated code by
doing something like this (can't do it with mfhc0 as we don't yet have a
case that uses the assembler):

@@ -1855,14 +1855,25 @@ do {									\
  * Macros to access the guest system control coprocessor
  */
 
-#ifdef TOOLCHAIN_SUPPORTS_VIRT
+#ifndef TOOLCHAIN_SUPPORTS_VIRT
+__asm__(".macro	mfgc0 rt, rs, sel\n\t"
+	"parse __rt, \\rt\n\t"
+	"parse __rs, \\rs\n\t"
+	"# mfgc0\t\\rt, \\rs, %2\n\t"
+	_ASM_INSN_IF_MIPS(0x40600000 | __rt << 16 | __rs << 11 | \\sel)
+	_ASM_INSN32_IF_MM(0x000004fc | __rt << 21 | __rs << 16 | \\sel << 11)
+	".endm");
+#define _ASM_SET_VIRT ""
+#else
+#define _ASM_SET_VIRT ".set\tvirt\n\t"
+#endif
 
 #define __read_32bit_gc0_register(source, sel)				\
 ({ int __res;								\
 	__asm__ __volatile__(						\
 		".set\tpush\n\t"					\
 		".set\tmips32r2\n\t"					\
-		".set\tvirt\n\t"					\
+		_ASM_SET_VIRT						\
 		"mfgc0\t%0, $%1, %2\n\t"				\
 		".set\tpop"						\
 		: "=r" (__res)						\
@@ -1870,6 +1881,8 @@ do {									\
 	__res;								\
 })
 
+#ifdef TOOLCHAIN_SUPPORTS_VIRT
+
 #define __read_64bit_gc0_register(source, sel)				\
 ({ unsigned long long __res;						\
 	__asm__ __volatile__(						\
@@ -1909,21 +1922,6 @@ do {									\
 
 #else	/* TOOLCHAIN_SUPPORTS_VIRT */
 
-#define __read_32bit_gc0_register(source, sel)				\
-({ int __res;								\
-	__asm__ __volatile__(						\
-		".set\tpush\n\t"					\
-		".set\tnoat\n\t"					\
-		"# mfgc0\t$1, $%1, %2\n\t"				\
-		_ASM_INSN_IF_MIPS(0x40610000 | %1 << 11 | %2)		\
-		_ASM_INSN32_IF_MM(0x002004fc | %1 << 16 | %2 << 11)	\
-		"move\t%0, $1\n\t"					\
-		".set\tpop"						\
-		: "=r" (__res)						\
-		: "i" (source), "i" (sel));				\
-	__res;								\
-})
-
 #define __read_64bit_gc0_register(source, sel)				\
 ({ unsigned long long __res;						\
 	__asm__ __volatile__(						\

A worthwhile cleanup IMO to fix all cases like this to use that parsing
macro, though it'll take a bit of care.

The use of __asm__ in global scope to define the macros to be accessible
from inline asm is slightly hacky.

Any comments / objections?

Cheers
James

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

      reply	other threads:[~2017-11-16  0:05 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-04 10:48 [PATCH v2 0/2] MIPS CRC instruction support Marcin Nowakowski
2017-10-04 10:48 ` [PATCH v2 1/2] MIPS: add crc instruction support flag to elf_hwcap Marcin Nowakowski
2017-10-04 10:48 ` [PATCH v2 2/2] MIPS: crypto: Add crc32 and crc32c hw accelerated module Marcin Nowakowski
2017-10-04 10:48   ` Marcin Nowakowski
2017-10-04 15:36   ` Ralf Baechle
2017-11-16  0:04     ` James Hogan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171116000448.GC27409@jhogan-linux.mipstec.com \
    --to=james.hogan@mips.com \
    --cc=linux-mips@linux-mips.org \
    --cc=marcin.nowakowski@imgtec.com \
    --cc=ralf@linux-mips.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox