lkml.org 
[lkml]   [2015]   [Sep]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] kernel.h: make abs() work with 64-bit types
Date
For 64-bit arguments, abs macro casts it to an int which leads to lost
precision and may cause incorrect results. To deal with 64-bit types
abs64 macro has been introduced but still there are places where abs
macro is used incorrectly.

To deal with the problem, expand abs macro such that it operates on s64
type when dealing with 64-bit types while still returning long when
dealing with smaller types.

Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
---
include/linux/kernel.h | 45 ++++++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 21 deletions(-)

On Tue, Sep 15 2015, Linus Torvalds wrote:
> So I think the "auto-expand to 's64' using __builtin_choose_expr()" is
> the preferable model, and get rid of abs64() entirely. It has very few
> uses.

Compile tested (with ‘make allmodconfig && make bzImage modules’ on
x86_64) only.

The 32-bit case could be further ‘simplified’ with:

typeof(__builtin_choose_expr(sizeof(x) == sizeof(long), \
1L, 1)) __x = (x); \
(long)(__x < 0 ? -__x : __x);

but I don’t suppose the few saved lines (and hacker-cred ;) ) are worth
added confusion or risk of angry developer attacking me with a blunt
instrument after they had to debug the code for previous fortnight.

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 5582410..f985d16 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -200,28 +200,31 @@ extern int _cond_resched(void);

#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)

-/*
- * abs() handles unsigned and signed longs, ints, shorts and chars. For all
- * input types abs() returns a signed long.
- * abs() should not be used for 64-bit types (s64, u64, long long) - use abs64()
- * for those.
+/**
+ * abs - return absolute value of an argument
+ * @x: the value. If it is unsigned type, it is converted to signed type first
+ * (s64, long or int depending on its size).
+ *
+ * Return: an absolute value of x. If x is 64-bit, macro's return type is s64,
+ * otherwise it is signed long.
*/
-#define abs(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; \
- })
-
-#define abs64(x) ({ \
- s64 __x = (x); \
- (__x < 0) ? -__x : __x; \
- })
+#define abs(x) __builtin_choose_expr(sizeof(x) == sizeof(s64), ({ \
+ s64 __x = (x); \
+ (__x < 0) ? -__x : __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; \
+ }))
+
+/* Deprecated, use abs instead. */
+#define abs64(x) abs((s64)(x))

/**
* reciprocal_scale - "scale" a value into range [0, ep_ro)
--
2.6.0.rc0.131.gf624c3d


\
 
 \ /
  Last update: 2015-09-16 15:21    [W:0.083 / U:0.148 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site