Messages in this thread | | | From | "Jason A. Donenfeld" <> | Date | Fri, 23 Sep 2022 18:42:56 +0200 | Subject | Re: [PATCH v2] minmax: clamp more efficiently by avoiding extra comparison |
| |
On Fri, Sep 23, 2022 at 6:41 PM Kees Cook <keescook@chromium.org> wrote: > > On Fri, Sep 23, 2022 at 05:40:01PM +0200, Jason A. Donenfeld wrote: > > Currently the clamp algorithm does: > > > > if (val > hi) > > val = hi; > > if (val < lo) > > val = lo; > > > > But since hi > lo by definition, this can be made more efficient with: > > > > if (val > hi) > > val = hi; > > else if (val < lo) > > val = lo; > > > > So fix up the clamp and clamp_t functions to do this, adding the same > > argument checking as for min and min_t. > > > > Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> > > Cc: Andrew Morton <akpm@linux-foundation.org> > > Cc: Kees Cook <keescook@chromium.org> > > Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> > > --- > > include/linux/minmax.h | 25 +++++++++++++++++++++++-- > > 1 file changed, 23 insertions(+), 2 deletions(-) > > > > diff --git a/include/linux/minmax.h b/include/linux/minmax.h > > index 5433c08fcc68..30e2e2cd0f44 100644 > > --- a/include/linux/minmax.h > > +++ b/include/linux/minmax.h > > @@ -37,6 +37,27 @@ > > __cmp(x, y, op), \ > > __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op)) > > > > +#define __clamp(val, lo, hi) \ > > + ((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val))) > > + > > +#define __clamp_once(val, lo, hi, unique_val, unique_lo, unique_hi) ({ \ > > + typeof(val) unique_val = (val); \ > > + typeof(lo) unique_lo = (lo); \ > > + typeof(hi) unique_hi = (hi); \ > > + __clamp(unique_val, unique_lo, unique_hi); }) > > + > > +#define __clamp_input_check(lo, hi) \ > > + (BUILD_BUG_ON_ZERO(__builtin_choose_expr( \ > > + __is_constexpr((lo) > (hi)), (lo) > (hi), false))) > > Nice. :) > > > + > > +#define __careful_clamp(val, lo, hi) ({ \ > > + __clamp_input_check(lo, hi) + \ > > + __builtin_choose_expr(__typecheck(val, lo) && __typecheck(val, hi) && \ > > + __typecheck(hi, lo) && __is_constexpr(val) && \ > > + __is_constexpr(lo) && __is_constexpr(hi), \ > > I really like it! I might have used: > > __safe_cmp(val, lo) && __safe_cmp(val, hi) > > instead of the "open coded" __typecheck()s and __is_constexpr()s, but > it's the same result. > > > + __clamp(val, lo, hi), \ > > + __clamp_once(val, lo, hi, __UNIQUE_ID(__val), __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); }) > > *complaint about line being >100 characters, but I don't really care* If > anyone is really bothered, this looks fine, too: > > __clamp_once(val, lo, hi, \ > __UNIQUE_ID(__val), __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); }) > > *shrug* > > > + > > /** > > * min - return minimum of two values of the same or compatible types > > * @x: first value > > @@ -86,7 +107,7 @@ > > * This macro does strict typechecking of @lo/@hi to make sure they are of the > > * same type as @val. See the unnecessary pointer comparisons. > > */ > > -#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) > > +#define clamp(val, lo, hi) __careful_clamp(val, lo, hi) > > > > /* > > * ..and if you can't take the strict > > @@ -121,7 +142,7 @@ > > * This macro does no typechecking and uses temporary variables of type > > * @type to make all the comparisons. > > */ > > -#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi) > > +#define clamp_t(type, val, lo, hi) __careful_clamp((type)(val), (type)(lo), (type)(hi)) > > > > /** > > * clamp_val - return a value clamped to a given range using val's type > > -- > > 2.37.3 > > > > Reviewed-by: Kees Cook <keescook@chromium.org> > > I can take this unless akpm wants it?
Fine by me.
| |