#include <asm-generic/bitops/generic-non-atomic.h>
 
+/*
+ * Many architecture-specific non-atomic bitops contain inline asm code and due
+ * to that the compiler can't optimize them to compile-time expressions or
+ * constants. In contrary, generic_*() helpers are defined in pure C and
+ * compilers optimize them just well.
+ * Therefore, to make `unsigned long foo = 0; __set_bit(BAR, &foo)` effectively
+ * equal to `unsigned long foo = BIT(BAR)`, pick the generic C alternative when
+ * the arguments can be resolved at compile time. That expression itself is a
+ * constant and doesn't bring any functional changes to the rest of cases.
+ * The casts to `uintptr_t` are needed to mitigate `-Waddress` warnings when
+ * passing a bitmap from .bss or .data (-> `!!addr` is always true).
+ */
 #define bitop(op, nr, addr)                                            \
-       op(nr, addr)
+       ((__builtin_constant_p(nr) &&                                   \
+         __builtin_constant_p((uintptr_t)(addr) != (uintptr_t)NULL) && \
+         (uintptr_t)(addr) != (uintptr_t)NULL &&                       \
+         __builtin_constant_p(*(const unsigned long *)(addr))) ?       \
+        const##op(nr, addr) : op(nr, addr))
 
 #define __set_bit(nr, addr)            bitop(___set_bit, nr, addr)
 #define __clear_bit(nr, addr)          bitop(___clear_bit, nr, addr)