From 399012a911b3d69e453aa2d4e4031b290d2ef94f Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 25 Feb 2023 10:49:29 -0800 Subject: [PATCH] freedreno/common: Replace or_mask() with BitsetEnum Use template and operator overloading to make dealing with bitmask enums shared between C and C++ easier. Signed-off-by: Rob Clark Part-of: --- src/freedreno/common/freedreno_common.h | 87 +++++++++++++++++++--- src/gallium/drivers/freedreno/freedreno_batch.h | 2 +- src/gallium/drivers/freedreno/freedreno_context.h | 18 +++-- src/gallium/drivers/freedreno/freedreno_resource.h | 4 +- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/freedreno/common/freedreno_common.h b/src/freedreno/common/freedreno_common.h index a083807..d275bf7 100644 --- a/src/freedreno/common/freedreno_common.h +++ b/src/freedreno/common/freedreno_common.h @@ -26,20 +26,83 @@ #include "util/u_atomic.h" -/** - * Helper macro to get around c++ being cranky about an enum that is a bitmask - */ #ifdef __cplusplus -#define or_mask(d, mask) \ - do { \ - decltype(mask) _d = (d); \ - d = (decltype(mask))(_d | (mask)); \ - } while (0) +template +struct BitmaskEnum { + E value; + + using underlying = typename std::underlying_type_t; + +#define FOREACH_TYPE(M, ...) \ + M(E, ##__VA_ARGS__) \ + M(bool, ##__VA_ARGS__) \ + M(uint8_t, ##__VA_ARGS__) \ + M(int8_t, ##__VA_ARGS__) \ + M(uint16_t, ##__VA_ARGS__) \ + M(int16_t, ##__VA_ARGS__) \ + M(uint32_t, ##__VA_ARGS__) \ + M(int32_t, ##__VA_ARGS__) + +#define CONSTRUCTOR(T) BitmaskEnum(T value) : value(static_cast(value)) {} + FOREACH_TYPE(CONSTRUCTOR) +#undef CONSTRUCTOR + +#define CAST(T) inline operator T() const { return static_cast(value); } + FOREACH_TYPE(CAST) +#undef CAST + +#define BOP(T, OP) \ + inline E operator OP(T rhs) const { \ + return static_cast ( \ + static_cast(value) OP \ + static_cast(rhs) \ + ); \ + } + FOREACH_TYPE(BOP, |) + FOREACH_TYPE(BOP, &) +#undef BOP + +#if defined(__GNUC__) && !defined(__clang) && (__GNUC__ <= 10) +/* + * Silence: + * + * ../src/freedreno/common/freedreno_common.h: In instantiation of 'E& BitmaskEnum::operator|=(BitmaskEnum::underlying) [with E = fd_dirty_3d_state; BitmaskEnum::underlying = unsigned int]': + * ../src/gallium/drivers/freedreno/freedreno_context.h:620:16: required from here + * ../src/freedreno/common/freedreno_common.h:68:39: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing] + * 68 | reinterpret_cast(value) OP static_cast(rhs) ); \ + * | ^~~~~ + * + * I cannot reproduce on gcc 12.2.1 or with clang 14.0.5 so I'm going to assume + * this is a bug with gcc 10.x + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + +#define UOP(T, OP) \ + inline E& operator OP(T rhs) { \ + return reinterpret_cast( \ + reinterpret_cast(value) OP static_cast(rhs) ); \ + } + UOP(underlying, |=) + UOP(underlying, &=) +#undef UOP + +#if defined(__GNUC__) && !defined(__clang) && (__GNUC__ < 7) +#pragma GCC diagnostic pop +#endif + + inline E operator ~() const { + static_assert(sizeof(E) == sizeof(BitmaskEnum)); + return static_cast ( + ~static_cast(value) + ); + } +#undef FOREACH_TYPE +}; +#define BITMASK_ENUM(E) BitmaskEnum #else -#define or_mask(d, mask) \ - do { \ - d |= (mask); \ - } while (0) +#define BITMASK_ENUM(E) enum E #endif /* diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h b/src/gallium/drivers/freedreno/freedreno_batch.h index 57e24cb..9d19e7d 100644 --- a/src/gallium/drivers/freedreno/freedreno_batch.h +++ b/src/gallium/drivers/freedreno/freedreno_batch.h @@ -102,7 +102,7 @@ struct fd_batch { * color_logic_Op (since those functions are disabled when by- * passing GMEM. */ - enum fd_gmem_reason gmem_reason; + BITMASK_ENUM(fd_gmem_reason) gmem_reason; /* At submit time, once we've decided that this batch will use GMEM * rendering, the appropriate gmem state is looked up: diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index b00010c..14792be 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -385,10 +385,10 @@ struct fd_context { uint32_t gen_dirty; /* which state objects need to be re-emit'd: */ - enum fd_dirty_3d_state dirty dt; + BITMASK_ENUM(fd_dirty_3d_state) dirty dt; /* per shader-stage dirty status: */ - enum fd_dirty_shader_state dirty_shader[PIPE_SHADER_TYPES] dt; + BITMASK_ENUM(fd_dirty_shader_state) dirty_shader[PIPE_SHADER_TYPES] dt; void *compute dt; struct pipe_blend_state *blend dt; @@ -608,7 +608,8 @@ fd_context_dirty_resource(enum fd_dirty_3d_state dirty) /* Mark specified non-shader-stage related state as dirty: */ static inline void -fd_context_dirty(struct fd_context *ctx, enum fd_dirty_3d_state dirty) assert_dt +fd_context_dirty(struct fd_context *ctx, BITMASK_ENUM(fd_dirty_3d_state) dirty) + assert_dt { assert(util_is_power_of_two_nonzero(dirty)); assert(ffs(dirty) <= ARRAY_SIZE(ctx->gen_dirty_map)); @@ -616,14 +617,15 @@ fd_context_dirty(struct fd_context *ctx, enum fd_dirty_3d_state dirty) assert_dt ctx->gen_dirty |= ctx->gen_dirty_map[ffs(dirty) - 1]; if (fd_context_dirty_resource(dirty)) - or_mask(dirty, FD_DIRTY_RESOURCE); + dirty |= FD_DIRTY_RESOURCE; - or_mask(ctx->dirty, dirty); + ctx->dirty |= dirty; } static inline void fd_context_dirty_shader(struct fd_context *ctx, enum pipe_shader_type shader, - enum fd_dirty_shader_state dirty) assert_dt + BITMASK_ENUM(fd_dirty_shader_state) dirty) + assert_dt { const enum fd_dirty_3d_state map[] = { FD_DIRTY_PROG, FD_DIRTY_CONST, FD_DIRTY_TEX, @@ -642,7 +644,7 @@ fd_context_dirty_shader(struct fd_context *ctx, enum pipe_shader_type shader, ctx->gen_dirty |= ctx->gen_dirty_shader_map[shader][ffs(dirty) - 1]; - or_mask(ctx->dirty_shader[shader], dirty); + ctx->dirty_shader[shader] |= dirty; fd_context_dirty(ctx, map[ffs(dirty) - 1]); } @@ -693,7 +695,7 @@ fd_context_add_map(struct fd_context *ctx, enum fd_dirty_3d_state dirty, */ static inline void fd_context_add_shader_map(struct fd_context *ctx, enum pipe_shader_type shader, - enum fd_dirty_shader_state dirty, uint32_t gen_dirty) + BITMASK_ENUM(fd_dirty_shader_state) dirty, uint32_t gen_dirty) { u_foreach_bit (b, dirty) { ctx->gen_dirty_shader_map[shader][b] |= gen_dirty; diff --git a/src/gallium/drivers/freedreno/freedreno_resource.h b/src/gallium/drivers/freedreno/freedreno_resource.h index 0d95f7c..0efa380 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.h +++ b/src/gallium/drivers/freedreno/freedreno_resource.h @@ -137,7 +137,7 @@ struct fd_resource { /* bitmask of state this resource could potentially dirty when rebound, * see rebind_resource() */ - enum fd_dirty_3d_state dirty; + BITMASK_ENUM(fd_dirty_3d_state) dirty; /* Sequence # incremented each time bo changes: */ uint16_t seqno; @@ -240,7 +240,7 @@ fd_resource_set_usage(struct pipe_resource *prsc, enum fd_dirty_3d_state usage) if (likely(rsc->dirty & usage)) return; fd_resource_lock(rsc); - or_mask(rsc->dirty, usage); + rsc->dirty |= usage; fd_resource_unlock(rsc); } -- 2.7.4