Skip to content

Commit 2a6c045

Browse files
geertuYuryNorov
authored andcommitted
bitfield: Add less-checking __FIELD_{GET,PREP}()
The BUILD_BUG_ON_MSG() check against "~0ull" works only with "unsigned (long) long" _mask types. For constant masks, that condition is usually met, as GENMASK() yields an UL value. The few places where the constant mask is stored in an intermediate variable were fixed by changing the variable type to u64 (see e.g. [1] and [2]). However, for non-constant masks, smaller unsigned types should be valid, too, but currently lead to "result of comparison of constant 18446744073709551615 with expression of type ... is always false"-warnings with clang and W=1. Hence refactor the __BF_FIELD_CHECK() helper, and factor out __FIELD_{GET,PREP}(). The later lack the single problematic check, but are otherwise identical to FIELD_{GET,PREP}(), and are intended to be used in the fully non-const variants later. [1] commit 5c667d5 ("clk: sp7021: Adjust width of _m in HWM_FIELD_PREP()") [2] commit cfd6fb4 ("crypto: ccree - avoid out-of-range warnings from clang") Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://git.kernel.org/torvalds/c/5c667d5a5a3ec166 [1] Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
1 parent 85a8ff1 commit 2a6c045

1 file changed

Lines changed: 28 additions & 8 deletions

File tree

include/linux/bitfield.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060

6161
#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x))
6262

63-
#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \
63+
#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
6464
({ \
6565
BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
6666
_pfx "mask is not constant"); \
@@ -69,13 +69,33 @@
6969
~((_mask) >> __bf_shf(_mask)) & \
7070
(0 + (_val)) : 0, \
7171
_pfx "value too large for the field"); \
72-
BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \
73-
__bf_cast_unsigned(_reg, ~0ull), \
74-
_pfx "type of reg too small for mask"); \
7572
__BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
7673
(1ULL << __bf_shf(_mask))); \
7774
})
7875

76+
#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
77+
BUILD_BUG_ON_MSG(__bf_cast_unsigned(mask, mask) > \
78+
__bf_cast_unsigned(reg, ~0ull), \
79+
pfx "type of reg too small for mask")
80+
81+
#define __BF_FIELD_CHECK(mask, reg, val, pfx) \
82+
({ \
83+
__BF_FIELD_CHECK_MASK(mask, val, pfx); \
84+
__BF_FIELD_CHECK_REG(mask, reg, pfx); \
85+
})
86+
87+
#define __FIELD_PREP(mask, val, pfx) \
88+
({ \
89+
__BF_FIELD_CHECK_MASK(mask, val, pfx); \
90+
((typeof(mask))(val) << __bf_shf(mask)) & (mask); \
91+
})
92+
93+
#define __FIELD_GET(mask, reg, pfx) \
94+
({ \
95+
__BF_FIELD_CHECK_MASK(mask, 0U, pfx); \
96+
(typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \
97+
})
98+
7999
/**
80100
* FIELD_MAX() - produce the maximum value representable by a field
81101
* @_mask: shifted mask defining the field's length and position
@@ -112,8 +132,8 @@
112132
*/
113133
#define FIELD_PREP(_mask, _val) \
114134
({ \
115-
__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
116-
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
135+
__BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \
136+
__FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
117137
})
118138

119139
#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
@@ -152,8 +172,8 @@
152172
*/
153173
#define FIELD_GET(_mask, _reg) \
154174
({ \
155-
__BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \
156-
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
175+
__BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \
176+
__FIELD_GET(_mask, _reg, "FIELD_GET: "); \
157177
})
158178

159179
/**

0 commit comments

Comments
 (0)