linux/include
Andrew Morton 71a9048448 include/linux/kernel.h: abs(): fix handling of 32-bit unsigneds on 64-bit
Michal reports:

In the framebuffer subsystem the abs() macro is often used as a part of
the calculation of a Manhattan metric, which in turn is used as a measure
of similarity between video modes.  The arguments of abs() are sometimes
unsigned numbers.  This worked fine until commit a49c59c0 ("Make sure the
value in abs() does not get truncated if it is greater than 2^32:) , which
changed the definition of abs() to prevent truncation.  As a result of
this change, in the following piece of code:

u32 a = 0, b = 1;
u32 c = abs(a - b);

'c' will end up with a value of 0xffffffff instead of the expected 0x1.

A problem caused by this change and visible by the end user is that
framebuffer drivers relying on functions from modedb.c will fail to find
high resolution video modes similar to that explicitly requested by the
user if an exact match cannot be found (see e.g.

Fix this by special-casing `long' types within abs().

This patch reduces x86_64 code size a bit - drivers/video/uvesafb.o shrunk
by 15 bytes, presumably because it is doing abs() on 4-byte quantities,
and expanding those to 8-byte longs adds code.

testcase:

#define oldabs(x) ({				\
		long __x = (x);			\
		(__x < 0) ? -__x : __x;		\
	})

#define newabs(x) ({						\
		long ret;					\
		if (sizeof(x) == sizeof(long)) {		\
			long __x = (x);				\
			ret = (__x < 0) ? -__x : __x;		\
		} else {					\
			int __x = (x);				\
			ret = (__x < 0) ? -__x : __x;		\
		}						\
		ret;						\
	})

typedef unsigned int u32;

main()
{
	u32 a = 0;
	u32 b = 1;
	u32 oldc = oldabs(a - b);
	u32 newc = newabs(a - b);

	printf("%u %u\n", oldc, newc);
}

akpm:/home/akpm> gcc t.c
akpm:/home/akpm> ./a.out
4294967295 1

Reported-by: Michal Januszewski <michalj@gmail.com>
Cc: Rolf Eike Beer <eike-kernel@sf-tec.de
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-01-13 08:03:07 -08:00
..
acpi ACPI: video: fix build for CONFIG_ACPI=n 2010-12-11 02:01:46 -05:00
asm-generic Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/vapier/blackfin 2011-01-10 17:06:08 -08:00
crypto
drm Merge branch 'drm-radeon-ni' of ../drm-radeon-next into drm-core-next 2011-01-10 09:27:06 +10:00
keys keys: add new key-type encrypted 2010-11-29 08:55:29 +11:00
linux include/linux/kernel.h: abs(): fix handling of 32-bit unsigneds on 64-bit 2011-01-13 08:03:07 -08:00
math-emu
media Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6 2011-01-06 18:32:12 -08:00
mtd
net ah: update maximum truncated ICV length 2011-01-11 14:03:10 -08:00
pcmcia
rdma
rxrpc
scsi [SCSI] libiscsi: do not take host lock in queuecommand 2010-12-31 09:52:44 -06:00
sound ARM: mach-shmobile: ap4evb: FSI clock use proper process for HDMI 2010-11-24 15:29:56 +09:00
trace tracing: remove duplicate null-pointer check in skb tracepoint 2011-01-07 20:55:42 -05:00
video Merge branch 'fbdev/udlfb' 2011-01-06 18:10:09 +09:00
xen Merge branch 'stable/xenbus' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen 2011-01-12 08:37:35 -08:00
Kbuild