Skip to content

Commit dc1c803

Browse files
committed
minmax: simplify min()/max()/clamp() implementation
Now that we no longer have any C constant expression contexts (ie array size declarations or static initializers) that use min() or max(), we can simpify the implementation by not having to worry about the result staying as a C constant expression. So now we can unconditionally just use temporary variables of the right type, and get rid of the excessive expansion that used to come from the use of __builtin_choose_expr(__is_constexpr(...), .. to pick the specialized code for constant expressions. Another expansion simplification is to pass the temporary variables (in addition to the original expression) to our __types_ok() macro. That may superficially look like it complicates the macro, but when we only want the type of the expression, expanding the temporary variable names is much simpler and smaller than expanding the potentially complicated original expression. As a result, on my machine, doing a $ time make drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.i goes from real 0m16.621s user 0m15.360s sys 0m1.221s to real 0m2.532s user 0m2.091s sys 0m0.452s because the token expansion goes down dramatically. In particular, the longest line expansion (which was line 71 of that 'ia_css_ynr.host.c' file) shrinks from 23,338kB (yes, 23MB for one single line) to "just" 1,444kB (now "only" 1.4MB). And yes, that line is still the line from hell, because it's doing multiple levels of "min()/max()" expansion thanks to some of them being hidden inside the uDIGIT_FITTING() macro. Lorenzo has a nice cleanup patch that makes that driver use inline functions instead of macros for sDIGIT_FITTING() and uDIGIT_FITTING(), which will fix that line once and for all, but the 16-fold reduction in this case does show why we need to simplify these helpers. Cc: David Laight <[email protected]> Cc: Lorenzo Stoakes <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent cb04e8b commit dc1c803

File tree

1 file changed

+20
-23
lines changed

1 file changed

+20
-23
lines changed

include/linux/minmax.h

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
#define __is_noneg_int(x) \
3636
(__builtin_choose_expr(__is_constexpr(x) && __is_signed(x), x, -1) >= 0)
3737

38-
#define __types_ok(x, y) \
39-
(__is_signed(x) == __is_signed(y) || \
40-
__is_signed((x) + 0) == __is_signed((y) + 0) || \
41-
__is_noneg_int(x) || __is_noneg_int(y))
38+
#define __types_ok(x, y, ux, uy) \
39+
(__is_signed(ux) == __is_signed(uy) || \
40+
__is_signed((ux) + 0) == __is_signed((uy) + 0) || \
41+
__is_noneg_int(x) || __is_noneg_int(y))
4242

4343
#define __cmp_op_min <
4444
#define __cmp_op_max >
@@ -51,34 +51,31 @@
5151
#define __cmp_once(op, type, x, y) \
5252
__cmp_once_unique(op, type, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
5353

54-
#define __careful_cmp_once(op, x, y) ({ \
55-
static_assert(__types_ok(x, y), \
54+
#define __careful_cmp_once(op, x, y, ux, uy) ({ \
55+
__auto_type ux = (x); __auto_type uy = (y); \
56+
static_assert(__types_ok(x, y, ux, uy), \
5657
#op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \
57-
__cmp_once(op, __auto_type, x, y); })
58+
__cmp(op, ux, uy); })
5859

59-
#define __careful_cmp(op, x, y) \
60-
__builtin_choose_expr(__is_constexpr((x) - (y)), \
61-
__cmp(op, x, y), __careful_cmp_once(op, x, y))
60+
#define __careful_cmp(op, x, y) \
61+
__careful_cmp_once(op, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
6262

6363
#define __clamp(val, lo, hi) \
6464
((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val)))
6565

66-
#define __clamp_once(val, lo, hi, unique_val, unique_lo, unique_hi) ({ \
67-
typeof(val) unique_val = (val); \
68-
typeof(lo) unique_lo = (lo); \
69-
typeof(hi) unique_hi = (hi); \
66+
#define __clamp_once(val, lo, hi, uval, ulo, uhi) ({ \
67+
__auto_type uval = (val); \
68+
__auto_type ulo = (lo); \
69+
__auto_type uhi = (hi); \
7070
static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \
7171
(lo) <= (hi), true), \
7272
"clamp() low limit " #lo " greater than high limit " #hi); \
73-
static_assert(__types_ok(val, lo), "clamp() 'lo' signedness error"); \
74-
static_assert(__types_ok(val, hi), "clamp() 'hi' signedness error"); \
75-
__clamp(unique_val, unique_lo, unique_hi); })
76-
77-
#define __careful_clamp(val, lo, hi) ({ \
78-
__builtin_choose_expr(__is_constexpr((val) - (lo) + (hi)), \
79-
__clamp(val, lo, hi), \
80-
__clamp_once(val, lo, hi, __UNIQUE_ID(__val), \
81-
__UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); })
73+
static_assert(__types_ok(uval, lo, uval, ulo), "clamp() 'lo' signedness error"); \
74+
static_assert(__types_ok(uval, hi, uval, uhi), "clamp() 'hi' signedness error"); \
75+
__clamp(uval, ulo, uhi); })
76+
77+
#define __careful_clamp(val, lo, hi) \
78+
__clamp_once(val, lo, hi, __UNIQUE_ID(v_), __UNIQUE_ID(l_), __UNIQUE_ID(h_))
8279

8380
/**
8481
* min - return minimum of two values of the same or compatible types

0 commit comments

Comments
 (0)