[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Pine.LNX.4.64.0801292154540.14907@fbirervta.pbzchgretzou.qr>
Date:	Tue, 29 Jan 2008 22:26:11 +0100 (CET)
From:	Jan Engelhardt <jengelh@...putergmbh.de>
To:	monstr@...str.eu
cc:	linux-kernel@...r.kernel.org, stephen.neuendorffer@...inx.com,
	john.williams@...alogix.com, microblaze-uclinux@...e.uq.edu.au
Subject: Re: [PATCH 16/52] [microblaze] supported function for memory -
 kernel/lib
On Jan 24 2008 16:02, monstr@...str.eu wrote:
>diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
>new file mode 100644
>index 0000000..cc13ebd
>--- /dev/null
>+++ b/arch/microblaze/lib/memcpy.c
>@@ -0,0 +1,159 @@
>+/* Filename: memcpy.c
>+ *
Please, no such filenames in files. It is redundant and hard to keep
uptodate, should things move at one point in time.
>+#define BYTE_BLIT_STEP(d, s, h, o) \
>+	{ register unsigned _v_; _v_ = *((unsigned *)(s))++; \
>+	 *((unsigned *)(d))++ = (h) | _v_ >> (32-(o)); \
>+	 (h) = _v_ << (o); \
>+	}
'register' is a relict from 30 years ago. Compilers likely ignore it
these days, so it can jsut be removed anyway.
>+	/* This code was put into place as we transitioned from gcc3 to gcc4.
>+	 * gcc4 does not support the syntax *((char *)d)++ which causes the
Of course not, because (char *)d is not an lvalue - and if you ask
me, it is ambiguous and bogus code.
Assuming 'd' was int*, d++ would cause it to be incremented by 4.
If you incremented 'd' with char* semantics, it would be incremented
by 1. But since 'd' is still int*, you now have an unaligned pointer,
which is a problem in itself. We do not need more pitfalls than C
already provides.
>+	if (c >= 4) {
>+		unsigned x, a, h, align;
You will be wanting to use unsigned long since you are working with
pointers.
>+		/* Align the destination to a word boundry. */
>+		/* This is done in an endian independant manner. */
>+		switch ((unsigned) d & 3) {
>+		case 1:
>+			*((char *) d)++ = *((char *) s)++;
>+			c--;
>+		case 2:
>+			*((char *) d)++ = *((char *) s)++;
>+			c--;
>+		case 3:
>+			*((char *) d)++ = *((char *) s)++;
>+			c--;
>+		}
This gets my strongest NAK. Please rewrite it in a sane manner.
In other words, like this:
+void *memcpy(void *v_dest, const void *v_src, __kernel_size_t c)
+{
+	const char *src = v_src;
+	char *dest = v_dest;
+
+	const uint32_t *i_src;
+	uint32_t *i_dest;
+
+	if (c >= 4) {
+		unsigned x, a, h, align;
+
+		/* Align the destination to a word boundry. */
+		/* This is done in an endian independant manner. */
+		switch ((unsigned long)dest & 3) {
+		case 1:
+			*dest++ = *src++;
+			--c;
+		case 2:
+			*dest++ = *src++;
+			--c;
+		case 3:
+			*dest++ = *src++;
+			--c;
+		}
+		/* Choose a copy scheme based on the source */
+		/* alignment relative to destination. */
+		switch ((unsigned long)src & 3) {
+		case 0x0:	/* Both byte offsets are aligned */
+
+			i_src  = (const void *)src;
+			i_dest = (void *)dest;
+
+			for (; c >= 4; c -= 4)
+				*i_dest++ = *i_src++;
+
+			src  = (const void *)i_src;
+			dest = (void *)i_dest;
+
+			break;
+
+		case 0x1:	/* Unaligned - Off by 1 */
			...
The BYTE_BLIT_ macros need reworking. The suggestions
so far should provide everything needed.
+		}
+
+	}
+
+	/* Finish off any remaining bytes */
+	/* simple fast copy, ... unless a cache boundry is crossed */
+	switch (c) {
+	case 3:
+		*dest++ = *src++;
+	case 2:
+		*dest++ = *src++;
+	case 1:
+		*dest++ = *src++;
+	}
+
+	return r;
+#endif
+}
 - and voilĂ , you can use it even with gcc4.
The same goes for memmove.c and memset.c.
By the way, I think you should just replace lib/string.c's memcpy,
etc. (which still do per-byte copying) with this optimized variant
instead, so everyone can benefit.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Powered by blists - more mailing lists