public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [KERNEL]: Avoid divide in IS_ALIGN
@ 2007-11-20 13:56 Herbert Xu
  2007-11-20 18:17 ` Joe Perches
  2007-11-20 21:43 ` linux-os (Dick Johnson)
  0 siblings, 2 replies; 6+ messages in thread
From: Herbert Xu @ 2007-11-20 13:56 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton, Linux Kernel Mailing List

Hi:

[KERNEL]: Avoid divide in IS_ALIGN

I was happy to discover the brand new IS_ALIGN macro and quickly
used it in my code.  To my dismay I found that the generated code
used division to perform the test.

This patch fixes it by changing the % test to an &.  This avoids
the division.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 94bc996..39b3fa6 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -35,7 +35,7 @@ extern const char linux_proc_banner[];
 #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
 #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
-#define IS_ALIGNED(x,a)		(((x) % ((typeof(x))(a))) == 0)
+#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [KERNEL]: Avoid divide in IS_ALIGN
  2007-11-20 13:56 [KERNEL]: Avoid divide in IS_ALIGN Herbert Xu
@ 2007-11-20 18:17 ` Joe Perches
  2007-11-20 20:22   ` Andrew Morton
  2007-11-20 21:43 ` linux-os (Dick Johnson)
  1 sibling, 1 reply; 6+ messages in thread
From: Joe Perches @ 2007-11-20 18:17 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Linus Torvalds, Andrew Morton, Linux Kernel Mailing List

On Tue, 2007-11-20 at 21:56 +0800, Herbert Xu wrote:
> [KERNEL]: Avoid divide in IS_ALIGN
> I was happy to discover the brand new IS_ALIGN macro and quickly
> used it in my code.  To my dismay I found that the generated code
> used division to perform the test.
> This patch fixes it by changing the % test to an &.  This avoids
> the division.

Perhaps this should use is_power_of_2?

#define IS_ALIGNED(x, a) 				\
	({ typeof(x) _a = (typeof(x))(a); 		\
	   is_power_of_2(_a) ? (((x) & (_a - 1)) == 0)	\
			     : (((x) % _a == 0); })

gcc -o2/oS seems to do the right thing.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [KERNEL]: Avoid divide in IS_ALIGN
  2007-11-20 18:17 ` Joe Perches
@ 2007-11-20 20:22   ` Andrew Morton
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Morton @ 2007-11-20 20:22 UTC (permalink / raw)
  To: Joe Perches; +Cc: herbert, torvalds, linux-kernel

On Tue, 20 Nov 2007 10:17:15 -0800
Joe Perches <joe@perches.com> wrote:

> On Tue, 2007-11-20 at 21:56 +0800, Herbert Xu wrote:
> > [KERNEL]: Avoid divide in IS_ALIGN
> > I was happy to discover the brand new IS_ALIGN macro and quickly
> > used it in my code.  To my dismay I found that the generated code
> > used division to perform the test.
> > This patch fixes it by changing the % test to an &.  This avoids
> > the division.
> 
> Perhaps this should use is_power_of_2?
> 
> #define IS_ALIGNED(x, a) 				\
> 	({ typeof(x) _a = (typeof(x))(a); 		\
> 	   is_power_of_2(_a) ? (((x) & (_a - 1)) == 0)	\
> 			     : (((x) % _a == 0); })
> 
> gcc -o2/oS seems to do the right thing.

The other *ALIGN* macros in there are only good for power-of-2 alignments
so I guess Herbert's change is OK.

The whole thing's a bit crufty really - there's no reason why it _can't_
work on non-power-of-2 numbers 9via an implementation such as you suggest)
and there's no commentary in there explaining that this will presently
break things.

Those macros are sufficiently obscure, risky and undocumented as to make
them of dubious value IMO.  I mean, anything which forces you to go and
stare at the definition for a while when reviewing a callsite isn't worth
it.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [KERNEL]: Avoid divide in IS_ALIGN
  2007-11-20 13:56 [KERNEL]: Avoid divide in IS_ALIGN Herbert Xu
  2007-11-20 18:17 ` Joe Perches
@ 2007-11-20 21:43 ` linux-os (Dick Johnson)
  2007-11-21 13:06   ` linux-os (Dick Johnson)
  1 sibling, 1 reply; 6+ messages in thread
From: linux-os (Dick Johnson) @ 2007-11-20 21:43 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Linus Torvalds, Andrew Morton, Linux Kernel Mailing List


On Tue, 20 Nov 2007, Herbert Xu wrote:

> Hi:
>
> [KERNEL]: Avoid divide in IS_ALIGN
>
> I was happy to discover the brand new IS_ALIGN macro and quickly
> used it in my code.  To my dismay I found that the generated code
> used division to perform the test.
>
> This patch fixes it by changing the % test to an &.  This avoids
> the division.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> Cheers,
> -- 
> Visit Openswan at http://www.openswan.org/
> Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
> --
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> index 94bc996..39b3fa6 100644
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -35,7 +35,7 @@ extern const char linux_proc_banner[];
> #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
> #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
> #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
> -#define IS_ALIGNED(x,a)		(((x) % ((typeof(x))(a))) == 0)
> +#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
>

Your macro modification is wrong.

Take 0x12345600, which is aligned on a 16-byte boundary.
Now, with your macro, we have for a 0x10 alignment:
      (0x12345600 & 0x0f) = (0x00 == 0) == TRUE (correct)
For an 0x20 alignment:
      (0x12345600 & 0x1f) = (0x00 == 0) == TRUE (incorrect)

In other words, the macro may work for some alignments, but
not all. It is therefore wrong. You need the modulus, the
remainder after division. Anything else is broken.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.22.1 on an i686 machine (5588.30 BogoMips).
My book : http://www.AbominableFirebug.com/
_


****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [KERNEL]: Avoid divide in IS_ALIGN
  2007-11-20 21:43 ` linux-os (Dick Johnson)
@ 2007-11-21 13:06   ` linux-os (Dick Johnson)
  2007-11-21 13:35     ` Andreas Schwab
  0 siblings, 1 reply; 6+ messages in thread
From: linux-os (Dick Johnson) @ 2007-11-21 13:06 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Linus Torvalds, Andrew Morton, Linux Kernel Mailing List


On Tue, 20 Nov 2007, Richard B. Johnson wrote:

> On Tue, 20 Nov 2007, Herbert Xu wrote:
>
>> Hi:
>> 
>> [KERNEL]: Avoid divide in IS_ALIGN
>> 
>> I was happy to discover the brand new IS_ALIGN macro and quickly
>> used it in my code.  To my dismay I found that the generated code
>> used division to perform the test.
>> 
>> This patch fixes it by changing the % test to an &.  This avoids
>> the division.
>> 
>> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>> 
>> Cheers,
>> -- 
>> Visit Openswan at http://www.openswan.org/
>> Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
>> Home Page: http://gondor.apana.org.au/~herbert/
>> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
>> --
>> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>> index 94bc996..39b3fa6 100644
>> --- a/include/linux/kernel.h
>> +++ b/include/linux/kernel.h
>> @@ -35,7 +35,7 @@ extern const char linux_proc_banner[];
>> #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
>> #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
>> #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), 
>> (a)))
>> -#define IS_ALIGNED(x,a)		(((x) % ((typeof(x))(a))) == 0)
>> +#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
>> 
>
> Your macro modification is wrong.

There was a brain fart on the explaination of why it's wrong.
Here is a better explaination.

Executing this script.............

cat <<EOF >/tmp/xxx.c
#include <stdio.h>

#define IS_ALIGNED(x,a)		(((x) % ((typeof(x))(a))) == 0)
#define _IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)

int main()
{
    int i;
    long p = 0x12345678;
    for(i=1; i< 0x11; i++)
        printf("Old = %d, new = %d\n", IS_ALIGNED(p, i), _IS_ALIGNED(p, i));
     return 0;
}
EOF
gcc -Wall -o /tmp/xxx /tmp/xxx.c
/tmp/xxx

... produces:
Old = 1, new = 1
Old = 1, new = 1
Old = 1, new = 1
Old = 1, new = 1
Old = 0, new = 1
Old = 1, new = 1
Old = 0, new = 1
Old = 1, new = 1
Old = 1, new = 0
Old = 0, new = 0
Old = 0, new = 0
Old = 1, new = 0
Old = 0, new = 0
Old = 0, new = 0
Old = 0, new = 0
Old = 0, new = 0

Which is clearly different.


Cheers,
Dick Johnson
Penguin : Linux version 2.6.22.1 on an i686 machine (5588.30 BogoMips).
My book : http://www.AbominableFirebug.com/
_


****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [KERNEL]: Avoid divide in IS_ALIGN
  2007-11-21 13:06   ` linux-os (Dick Johnson)
@ 2007-11-21 13:35     ` Andreas Schwab
  0 siblings, 0 replies; 6+ messages in thread
From: Andreas Schwab @ 2007-11-21 13:35 UTC (permalink / raw)
  To: linux-os (Dick Johnson)
  Cc: Herbert Xu, Linus Torvalds, Andrew Morton,
	Linux Kernel Mailing List

"linux-os (Dick Johnson)" <linux-os@analogic.com> writes:

> Executing this script.............
>
> cat <<EOF >/tmp/xxx.c
> #include <stdio.h>
>
> #define IS_ALIGNED(x,a)		(((x) % ((typeof(x))(a))) == 0)
> #define _IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
>
> int main()
> {
>     int i;
>     long p = 0x12345678;
>     for(i=1; i< 0x11; i++)
>         printf("Old = %d, new = %d\n", IS_ALIGNED(p, i), _IS_ALIGNED(p, i));

Alignment is only defined for powers of two.

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-11-21 13:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-20 13:56 [KERNEL]: Avoid divide in IS_ALIGN Herbert Xu
2007-11-20 18:17 ` Joe Perches
2007-11-20 20:22   ` Andrew Morton
2007-11-20 21:43 ` linux-os (Dick Johnson)
2007-11-21 13:06   ` linux-os (Dick Johnson)
2007-11-21 13:35     ` Andreas Schwab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox