[next,resend,1/5] minmax: Add min_unsigned(a, b) and max_unsigned(a, b)

Message ID 62d82a41b94c475bacceb0f6b11583a1@AcuMS.aculab.com
State New
Headers
Series minmax: Relax type checks in min() and max(). |

Commit Message

David Laight July 25, 2023, 11:48 a.m. UTC
  These can be used when min()/max() errors a signed v unsigned
compare when the signed value is known to be non-negative.

Unlike min_t(some_unsigned_type, a, b) min_unsigned() will never
mask off high bits if an inappropriate type is selected.

Signed-off-by: David Laight <david.laight@aculab.com>
---
 include/linux/minmax.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
  

Comments

Matthew Wilcox July 25, 2023, 12:38 p.m. UTC | #1
On Tue, Jul 25, 2023 at 11:48:14AM +0000, David Laight wrote:
> +#define min_unsigned(x, y)	\
> +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)

What is the point of "+ 0u + 0ul + 0ull"?  How is that any different
from "+ 0ull"?  And why force the compiler to do a 64-bit comparison
when it could do a 32-bit comparison?
  
David Laight July 25, 2023, 1:20 p.m. UTC | #2
From: Matthew Wilcox
> Sent: 25 July 2023 13:39
> 
> On Tue, Jul 25, 2023 at 11:48:14AM +0000, David Laight wrote:
> > +#define min_unsigned(x, y)	\
> > +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
> 
> What is the point of "+ 0u + 0ul + 0ull"?  How is that any different
> from "+ 0ull"?  And why force the compiler to do a 64-bit comparison
> when it could do a 32-bit comparison?

The "+ 0u + 0ul + 0ull" causes a signed 32bit value to be zero extended
to 64bit. This is significantly cheaper than the sign extension.
(Adding 0ull first converts a signed 32bit value to a signed
64bit one - the same as a cast.)

The compiler also then knows that the high 32bit are zero and
optimises away any associated compares.
So you get a 32bit compare (on both 32bit and 64bit) if both
arguments are 32bit.
This happens even at -O0.

It also has no effect on pointer types.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
  

Patch

diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 396df1121bff..531860e9cc55 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -73,6 +73,23 @@ 
  */
 #define max(x, y)	__careful_cmp(x, y, >)
 
+/**
+ * min_unsigned - return minimum of two non-negative values
+ *   Signed types are zero extended to match a larger unsigned type.
+ * @x: first value
+ * @y: second value
+ */
+#define min_unsigned(x, y)	\
+	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
+
+/**
+ * max_unsigned - return maximum of two non-negative values
+ * @x: first value
+ * @y: second value
+ */
+#define max_unsigned(x, y)	\
+	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, >)
+
 /**
  * min3 - return minimum of three values
  * @x: first value