The question asks about branch avoidance, so doing that while retaining comparison is still fair play(*).
Checking if some scalar or vector equals its
clamped version is a terse, intuitive option:
float(clampN(d, dMin, dMax) == d), which yields 0.0 if false or 1.0 if true, with whatever way you use this resulting value, for example,
d can be scalar or any vector, while
dMax are either scalars, or whatever
< needs to be distinguished from
<=, it gets a bit more tedious as additional comparisons are needed for the min/max values or subtracting the value from an extremum and getting a
sign, unless one can safely use some other approach such as introducing an epsilon value.
For either case, performance may differ (or match) other solutions; in part, because...
(*) I'm not aware of anything that'd prevent the shader compiler from introducing its own branching if it feels like so; conversely, nothing prevents the shader compiler from converting branching (if) into single-track code, if it can tackle the data flow to the extent to be certain that the results are the same. IIRC the latter is actually done for at least simple cases.
ifstatements are compiled to parallel evaluation with a multiply-add to select the desired output. You should check with the profiling tool that goes with your target GPU. $\endgroup$