All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Add kabs()
@ 2012-04-23 13:11 Alexey Dobriyan
  2012-04-23 13:22 ` [PATCH v2] " Alexey Dobriyan
  2012-04-25 17:20 ` [PATCH] " Ben Pfaff
  0 siblings, 2 replies; 4+ messages in thread
From: Alexey Dobriyan @ 2012-04-23 13:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

There is abs() and abs64().
They have following unwanted or suprising properties:
1) They return signed value
	in math norms et al are unsigned

2) In finest Unix tradition they do not work reliably.
   Quoting abs(3).
	"Trying to take the absolute value of the most negative integer is not defined."

3) They expand type needlessly

4) There are 2 of them with different names
	with gcc extensions __builtin_choose_expr(),
	__builtin_types_compatible_p() we can mimic type dispatch as found
	in modern programming languages.

Enter kabs().

kabs() has the following nice properties which should have been there
from day 1.

kabs() return unsigned value.
kabs() works for all integer types and return correct result.
sizeof(kabs(x)) == sizeof(x)

Mention kabs() in checkpatch.pl so people would gradually convert.
abs() and abs64() will eventually dissapear.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 include/linux/kernel.h |   29 +++++++++++++++++++++++++++++
 scripts/checkpatch.pl  |    6 ++++++
 2 files changed, 35 insertions(+)

--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -188,6 +188,35 @@ extern int _cond_resched(void);
 		(__x < 0) ? -__x : __x;		\
 	})
 
+#define kabs(x)								\
+({									\
+	typeof(x) _x = (x);						\
+									\
+	/*								\
+	 * "char", "signed char", "unsigned char" aren't compatible	\
+	 * regardless of -f{un,}signed-char.				\
+	 */
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), signed char),	\
+		(unsigned char)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), char),		\
+		(unsigned char)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), short),	\
+		(unsigned short)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), int),		\
+		(unsigned int)({ _x < 0 ? -_x : _x; }),			\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), long),		\
+		(unsigned long)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), long long),	\
+		(unsigned long long)({ _x < 0 ? -_x : _x; }),		\
+	_x))))));							\
+})
+
 #ifdef CONFIG_PROVE_LOCKING
 void might_fault(void);
 #else
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -3347,6 +3347,12 @@ sub process {
 			     "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
 		}
 
+# check for abs(), abs64()
+		if ($line =~ /\b(abs64|abs)\s*\(/) {
+			WARN("CONSIDER_KABS",
+			     "$1 is obsolete, use kabs\n" . $herecurr);
+		}
+
 # check for use of yield()
 		if ($line =~ /\byield\s*\(\s*\)/) {
 			WARN("YIELD",

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

* [PATCH v2] Add kabs()
  2012-04-23 13:11 [PATCH] Add kabs() Alexey Dobriyan
@ 2012-04-23 13:22 ` Alexey Dobriyan
  2012-04-23 18:18   ` Nick Bowler
  2012-04-25 17:20 ` [PATCH] " Ben Pfaff
  1 sibling, 1 reply; 4+ messages in thread
From: Alexey Dobriyan @ 2012-04-23 13:22 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

There is abs() and abs64().
They have following unwanted or suprising properties:
1) They return signed value
	in math norms et al are unsigned

2) In finest Unix tradition they do not work reliably.
   Quoting abs(3).
	"Trying to take the absolute value of the most negative integer is not defined."

3) They expand type needlessly

4) There are 2 of them with different names
	with gcc extensions __builtin_choose_expr(),
	__builtin_types_compatible_p() we can mimic type dispatch as found
	in modern programming languages.

Enter kabs().

kabs() has the following nice properties which should have been there
from day 1.

kabs() return unsigned value.
kabs() works for all integer types and return correct result.
sizeof(kabs(x)) == sizeof(x)

Mention kabs() in checkpatch.pl so people would gradually convert.
abs() and abs64() will eventually dissapear.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 This one will actually compile.

 include/linux/kernel.h |   29 +++++++++++++++++++++++++++++
 scripts/checkpatch.pl  |    6 ++++++
 2 files changed, 35 insertions(+)

--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -188,6 +188,35 @@ extern int _cond_resched(void);
 		(__x < 0) ? -__x : __x;		\
 	})
 
+#define kabs(x)								\
+({									\
+	typeof(x) _x = (x);						\
+									\
+	/*								\
+	 * "char", "signed char", "unsigned char" aren't compatible	\
+	 * regardless of -f{un,}signed-char.				\
+	 */								\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), signed char),	\
+		(unsigned char)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), char),		\
+		(unsigned char)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), short),	\
+		(unsigned short)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), int),		\
+		(unsigned int)({ _x < 0 ? -_x : _x; }),			\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), long),		\
+		(unsigned long)({ _x < 0 ? -_x : _x; }),		\
+	__builtin_choose_expr(						\
+		__builtin_types_compatible_p(typeof(_x), long long),	\
+		(unsigned long long)({ _x < 0 ? -_x : _x; }),		\
+	_x))))));							\
+})
+
 #ifdef CONFIG_PROVE_LOCKING
 void might_fault(void);
 #else
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -3347,6 +3347,12 @@ sub process {
 			     "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
 		}
 
+# check for abs(), abs64()
+		if ($line =~ /\b(abs64|abs)\s*\(/) {
+			WARN("CONSIDER_KABS",
+			     "$1 is obsolete, use kabs\n" . $herecurr);
+		}
+
 # check for use of yield()
 		if ($line =~ /\byield\s*\(\s*\)/) {
 			WARN("YIELD",

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

* Re: [PATCH v2] Add kabs()
  2012-04-23 13:22 ` [PATCH v2] " Alexey Dobriyan
@ 2012-04-23 18:18   ` Nick Bowler
  0 siblings, 0 replies; 4+ messages in thread
From: Nick Bowler @ 2012-04-23 18:18 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: akpm, linux-kernel

On 2012-04-23 16:22 +0300, Alexey Dobriyan wrote:
> There is abs() and abs64().
> They have following unwanted or suprising properties:
[...]
> 2) In finest Unix tradition they do not work reliably.
>    Quoting abs(3).
> 	"Trying to take the absolute value of the most negative integer is not defined."

Unforunately, your version does not actually fix this problem,
because...

> +#define kabs(x)								\
> +({									\
> +	typeof(x) _x = (x);						\
> +									\
[...]
> +		__builtin_types_compatible_p(typeof(_x), int),		\
> +		(unsigned int)({ _x < 0 ? -_x : _x; }),			\

... here, if x == INT_MIN, then evaluating -x results in signed overflow
and thus undefined behaviour.  The problem is that the conversion to
unsigned int happens too late.

It needs to be (untested):

  _x == INT_MIN ? (unsigned)_x : (unsigned)(_x < 0 ? -_x : _x)

This version assumes a couple things about the representation of
signed/unsigned types, in particular that INT_MIN is exactly one less
than -INT_MAX, and that UINT_MAX is exactly one more than 2u*INT_MAX.
I presume this is true for everything that Linux targets.

Ditto for the other types, although types "smaller" than int will be
promoted to int before being negated, so the overflow probably won't
happen for them.

[...]
> +	_x))))));							\
> +})

Cheers,
-- 
Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)


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

* Re: [PATCH] Add kabs()
  2012-04-23 13:11 [PATCH] Add kabs() Alexey Dobriyan
  2012-04-23 13:22 ` [PATCH v2] " Alexey Dobriyan
@ 2012-04-25 17:20 ` Ben Pfaff
  1 sibling, 0 replies; 4+ messages in thread
From: Ben Pfaff @ 2012-04-25 17:20 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: akpm, linux-kernel

Alexey Dobriyan <adobriyan@gmail.com> writes:

> kabs() has the following nice properties which should have been there
> from day 1.
>
> kabs() return unsigned value.
> kabs() works for all integer types and return correct result.
> sizeof(kabs(x)) == sizeof(x)

It would be nice to document these properties in a source code
comment, as well as in the commit message.

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

end of thread, other threads:[~2012-04-25 17:42 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-23 13:11 [PATCH] Add kabs() Alexey Dobriyan
2012-04-23 13:22 ` [PATCH v2] " Alexey Dobriyan
2012-04-23 18:18   ` Nick Bowler
2012-04-25 17:20 ` [PATCH] " Ben Pfaff

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.