util: Add and use functions to calculate min and max int for a size
Many places need to know the maximum or minimum possible value for a given size integer... so everyone just open-codes their favorite version. There is some potential to hit either undefined or implementation-defined behavior, so having one version that Just Works seems beneficial. v2: Fix copy-and-pasted bug (INT64_MAX instead of INT64_MIN) in u_intmin. Noticed by CI. Lol. Rename functions `s/u_(uint|int)(min|max)/u_\1N_\2/g`. Suggested by Jason. Add some unit tests that would have caught the copy-and-paste bug before wasting CI time. Change the implementation of u_intN_min to use the same pattern as stdint.h. This avoids the integer division. Noticed by Jason. v3: Add changes to convert_clear_color (src/gallium/drivers/iris/iris_clear.c). Suggested by Nanley. Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> Suggested-by: Jason Ekstrand <jason@jlekstrand.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12177>
This commit is contained in:
parent
08d6361591
commit
72259a870f
|
@ -68,8 +68,6 @@ template = """\
|
|||
#include "util/bigmath.h"
|
||||
#include "nir_constant_expressions.h"
|
||||
|
||||
#define MAX_UINT_FOR_SIZE(bits) (UINT64_MAX >> (64 - (bits)))
|
||||
|
||||
/**
|
||||
* \brief Checks if the provided value is a denorm and flushes it to zero.
|
||||
*/
|
||||
|
|
|
@ -633,7 +633,7 @@ binop("iadd_sat", tint, _2src_commutative, """
|
|||
(src0 < src0 + src1 ? (1ull << (bit_size - 1)) : src0 + src1)
|
||||
""")
|
||||
binop("uadd_sat", tuint, _2src_commutative,
|
||||
"(src0 + src1) < src0 ? MAX_UINT_FOR_SIZE(sizeof(src0) * 8) : (src0 + src1)")
|
||||
"(src0 + src1) < src0 ? u_uintN_max(sizeof(src0) * 8) : (src0 + src1)")
|
||||
binop("isub_sat", tint, "", """
|
||||
src1 < 0 ?
|
||||
(src0 - src1 < src0 ? (1ull << (bit_size - 1)) - 1 : src0 - src1) :
|
||||
|
|
|
@ -368,7 +368,7 @@ match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src,
|
|||
case nir_type_uint:
|
||||
case nir_type_bool: {
|
||||
unsigned bit_size = nir_src_bit_size(instr->src[src].src);
|
||||
uint64_t mask = bit_size == 64 ? UINT64_MAX : (1ull << bit_size) - 1;
|
||||
uint64_t mask = u_uintN_max(bit_size);
|
||||
for (unsigned i = 0; i < num_components; ++i) {
|
||||
uint64_t val = nir_src_comp_as_uint(instr->src[src].src,
|
||||
new_swizzle[i]);
|
||||
|
|
|
@ -185,8 +185,8 @@ convert_clear_color(enum pipe_format format,
|
|||
unsigned bits = util_format_get_component_bits(
|
||||
format, UTIL_FORMAT_COLORSPACE_RGB, i);
|
||||
if (bits > 0 && bits < 32) {
|
||||
int32_t max = (1 << (bits - 1)) - 1;
|
||||
int32_t min = -(1 << (bits - 1));
|
||||
int32_t max = u_intN_max(bits);
|
||||
int32_t min = u_intN_min(bits);
|
||||
override_color.i32[i] = CLAMP(override_color.i32[i], min, max);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1188,11 +1188,11 @@ pack_channel(const union isl_color_value *value, unsigned i,
|
|||
}
|
||||
break;
|
||||
case ISL_UINT:
|
||||
packed = MIN(value->u32[i], MAX_UINT(layout->bits));
|
||||
packed = MIN(value->u32[i], u_uintN_max(layout->bits));
|
||||
break;
|
||||
case ISL_SINT:
|
||||
packed = MIN(MAX(value->u32[i], MIN_INT(layout->bits)),
|
||||
MAX_INT(layout->bits));
|
||||
packed = MIN(MAX(value->u32[i], u_intN_min(layout->bits)),
|
||||
u_intN_max(layout->bits));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1202,7 +1202,7 @@ pack_channel(const union isl_color_value *value, unsigned i,
|
|||
unsigned dword = layout->start_bit / 32;
|
||||
unsigned bit = layout->start_bit % 32;
|
||||
assert(bit + layout->bits <= 32);
|
||||
data_out[dword] |= (packed & MAX_UINT(layout->bits)) << bit;
|
||||
data_out[dword] |= (packed & u_uintN_max(layout->bits)) << bit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1264,7 +1264,7 @@ unpack_channel(union isl_color_value *value,
|
|||
unsigned dword = layout->start_bit / 32;
|
||||
unsigned bit = layout->start_bit % 32;
|
||||
assert(bit + layout->bits <= 32);
|
||||
uint32_t packed = (data_in[dword] >> bit) & MAX_UINT(layout->bits);
|
||||
uint32_t packed = (data_in[dword] >> bit) & u_uintN_max(layout->bits);
|
||||
|
||||
union {
|
||||
uint32_t u32;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "fast_idiv_by_const.h"
|
||||
#include "u_math.h"
|
||||
#include "util/macros.h"
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -65,8 +66,7 @@ util_compute_fast_udiv_info(uint64_t D, unsigned num_bits, unsigned UINT_BITS)
|
|||
} else {
|
||||
/* Dividing by 1. */
|
||||
/* Assuming: floor((num + 1) * (2^32 - 1) / 2^32) = num */
|
||||
result.multiplier = UINT_BITS == 64 ? UINT64_MAX :
|
||||
(1ull << UINT_BITS) - 1;
|
||||
result.multiplier = u_uintN_max(UINT_BITS);
|
||||
result.pre_shift = 0;
|
||||
result.post_shift = 0;
|
||||
result.increment = 1;
|
||||
|
|
|
@ -34,29 +34,24 @@
|
|||
#include "util/half_float.h"
|
||||
#include "util/rounding.h"
|
||||
|
||||
/* Only guaranteed to work for BITS <= 32 */
|
||||
#define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << (BITS)) - 1))
|
||||
#define MAX_INT(BITS) ((int)MAX_UINT((BITS) - 1))
|
||||
#define MIN_INT(BITS) ((BITS) == 32 ? INT32_MIN : (-(1 << (BITS - 1))))
|
||||
|
||||
/* Extends an integer of size SRC_BITS to one of size DST_BITS linearly */
|
||||
#define EXTEND_NORMALIZED_INT(X, SRC_BITS, DST_BITS) \
|
||||
(((X) * (int)(MAX_UINT(DST_BITS) / MAX_UINT(SRC_BITS))) + \
|
||||
(((X) * (int)(u_uintN_max(DST_BITS) / u_uintN_max(SRC_BITS))) + \
|
||||
((DST_BITS % SRC_BITS) ? ((X) >> (SRC_BITS - DST_BITS % SRC_BITS)) : 0))
|
||||
|
||||
static inline float
|
||||
_mesa_unorm_to_float(unsigned x, unsigned src_bits)
|
||||
{
|
||||
return x * (1.0f / (float)MAX_UINT(src_bits));
|
||||
return x * (1.0f / (float)u_uintN_max(src_bits));
|
||||
}
|
||||
|
||||
static inline float
|
||||
_mesa_snorm_to_float(int x, unsigned src_bits)
|
||||
{
|
||||
if (x <= -MAX_INT(src_bits))
|
||||
if (x <= -u_intN_max(src_bits))
|
||||
return -1.0f;
|
||||
else
|
||||
return x * (1.0f / (float)MAX_INT(src_bits));
|
||||
return x * (1.0f / (float)u_intN_max(src_bits));
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
|
@ -77,9 +72,9 @@ _mesa_float_to_unorm(float x, unsigned dst_bits)
|
|||
if (x < 0.0f)
|
||||
return 0;
|
||||
else if (x > 1.0f)
|
||||
return MAX_UINT(dst_bits);
|
||||
return u_uintN_max(dst_bits);
|
||||
else
|
||||
return _mesa_i64roundevenf(x * MAX_UINT(dst_bits));
|
||||
return _mesa_i64roundevenf(x * u_uintN_max(dst_bits));
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
|
@ -98,10 +93,10 @@ _mesa_unorm_to_unorm(unsigned x, unsigned src_bits, unsigned dst_bits)
|
|||
|
||||
if (src_bits + dst_bits > sizeof(x) * 8) {
|
||||
assert(src_bits + dst_bits <= sizeof(uint64_t) * 8);
|
||||
return (((uint64_t) x * MAX_UINT(dst_bits) + src_half) /
|
||||
MAX_UINT(src_bits));
|
||||
return (((uint64_t) x * u_uintN_max(dst_bits) + src_half) /
|
||||
u_uintN_max(src_bits));
|
||||
} else {
|
||||
return (x * MAX_UINT(dst_bits) + src_half) / MAX_UINT(src_bits);
|
||||
return (x * u_uintN_max(dst_bits) + src_half) / u_uintN_max(src_bits);
|
||||
}
|
||||
} else {
|
||||
return x;
|
||||
|
@ -121,11 +116,11 @@ static inline int
|
|||
_mesa_float_to_snorm(float x, unsigned dst_bits)
|
||||
{
|
||||
if (x < -1.0f)
|
||||
return -MAX_INT(dst_bits);
|
||||
return -u_intN_max(dst_bits);
|
||||
else if (x > 1.0f)
|
||||
return MAX_INT(dst_bits);
|
||||
return u_intN_max(dst_bits);
|
||||
else
|
||||
return _mesa_lroundevenf(x * MAX_INT(dst_bits));
|
||||
return _mesa_lroundevenf(x * u_intN_max(dst_bits));
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -143,8 +138,8 @@ _mesa_unorm_to_snorm(unsigned x, unsigned src_bits, unsigned dst_bits)
|
|||
static inline int
|
||||
_mesa_snorm_to_snorm(int x, unsigned src_bits, unsigned dst_bits)
|
||||
{
|
||||
if (x < -MAX_INT(src_bits))
|
||||
return -MAX_INT(dst_bits);
|
||||
if (x < -u_intN_max(src_bits))
|
||||
return -u_intN_max(dst_bits);
|
||||
else if (src_bits < dst_bits)
|
||||
return EXTEND_NORMALIZED_INT(x, src_bits - 1, dst_bits - 1);
|
||||
else
|
||||
|
@ -154,25 +149,25 @@ _mesa_snorm_to_snorm(int x, unsigned src_bits, unsigned dst_bits)
|
|||
static inline unsigned
|
||||
_mesa_unsigned_to_unsigned(unsigned src, unsigned dst_size)
|
||||
{
|
||||
return MIN2(src, MAX_UINT(dst_size));
|
||||
return MIN2(src, u_uintN_max(dst_size));
|
||||
}
|
||||
|
||||
static inline int
|
||||
_mesa_unsigned_to_signed(unsigned src, unsigned dst_size)
|
||||
{
|
||||
return MIN2(src, (unsigned)MAX_INT(dst_size));
|
||||
return MIN2(src, (unsigned)u_intN_max(dst_size));
|
||||
}
|
||||
|
||||
static inline int
|
||||
_mesa_signed_to_signed(int src, unsigned dst_size)
|
||||
{
|
||||
return CLAMP(src, MIN_INT(dst_size), MAX_INT(dst_size));
|
||||
return CLAMP(src, u_intN_min(dst_size), u_intN_max(dst_size));
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
_mesa_signed_to_unsigned(int src, unsigned dst_size)
|
||||
{
|
||||
return CLAMP(src, 0, MAX_UINT(dst_size));
|
||||
return CLAMP(src, 0, u_uintN_max(dst_size));
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
|
@ -180,18 +175,18 @@ _mesa_float_to_unsigned(float src, unsigned dst_bits)
|
|||
{
|
||||
if (src < 0.0f)
|
||||
return 0;
|
||||
if (src > (float)MAX_UINT(dst_bits))
|
||||
return MAX_UINT(dst_bits);
|
||||
if (src > (float)u_uintN_max(dst_bits))
|
||||
return u_uintN_max(dst_bits);
|
||||
return _mesa_signed_to_unsigned(src, dst_bits);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
_mesa_float_to_signed(float src, unsigned dst_bits)
|
||||
{
|
||||
if (src < (float)(-MAX_INT(dst_bits)))
|
||||
return -MAX_INT(dst_bits);
|
||||
if (src > (float)MAX_INT(dst_bits))
|
||||
return MAX_INT(dst_bits);
|
||||
if (src < (float)(-u_intN_max(dst_bits)))
|
||||
return -u_intN_max(dst_bits);
|
||||
if (src > (float)u_intN_max(dst_bits))
|
||||
return u_intN_max(dst_bits);
|
||||
return _mesa_signed_to_signed(src, dst_bits);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "c99_compat.h"
|
||||
#include "c11_compat.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Compute the size of an array */
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
@ -392,6 +394,30 @@ do { \
|
|||
#define BITFIELD64_RANGE(b, count) \
|
||||
(BITFIELD64_MASK((b) + (count)) & ~BITFIELD64_MASK(b))
|
||||
|
||||
static inline int64_t
|
||||
u_intN_max(unsigned bit_size)
|
||||
{
|
||||
assert(bit_size <= 64 && bit_size > 0);
|
||||
return INT64_MAX >> (64 - bit_size);
|
||||
}
|
||||
|
||||
static inline int64_t
|
||||
u_intN_min(unsigned bit_size)
|
||||
{
|
||||
/* On 2's compliment platforms, which is every platform Mesa is likely to
|
||||
* every worry about, stdint.h generally calculated INT##_MIN in this
|
||||
* manner.
|
||||
*/
|
||||
return (-u_intN_max(bit_size)) - 1;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
u_uintN_max(unsigned bit_size)
|
||||
{
|
||||
assert(bit_size <= 64 && bit_size > 0);
|
||||
return UINT64_MAX >> (64 - bit_size);
|
||||
}
|
||||
|
||||
/* TODO: In future we should try to move this to u_debug.h once header
|
||||
* dependencies are reorganised to allow this.
|
||||
*/
|
||||
|
|
|
@ -383,6 +383,15 @@ if with_tests
|
|||
env: ['BUILD_FULL_PATH='+process_test_exe_full_path]
|
||||
)
|
||||
|
||||
test('int_min_max',
|
||||
executable('int_min_max_test',
|
||||
files('tests/int_min_max.cpp'),
|
||||
include_directories : [inc_include, inc_src],
|
||||
dependencies : [idep_mesautil, idep_gtest],
|
||||
),
|
||||
suite : ['util'],
|
||||
)
|
||||
|
||||
subdir('tests/cache')
|
||||
subdir('tests/fast_idiv_by_const')
|
||||
subdir('tests/fast_urem_by_const')
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
|
||||
#define RAND_TEST_ITERATIONS 100000
|
||||
|
||||
#define MAX_UINT(bits) \
|
||||
(((bits) == 64) ? UINT64_MAX : ((1ull << (bits)) - 1))
|
||||
|
||||
static inline uint64_t
|
||||
utrunc(uint64_t x, unsigned num_bits)
|
||||
{
|
||||
|
@ -82,7 +79,7 @@ uadd_sat(uint64_t a, uint64_t b, unsigned num_bits)
|
|||
return sum < a ? UINT64_MAX : sum;
|
||||
} else {
|
||||
/* Check if sum is more than num_bits */
|
||||
return (sum >> num_bits) ? MAX_UINT(num_bits) : sum;
|
||||
return (sum >> num_bits) ? u_uintN_max(num_bits) : sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +198,7 @@ rand_uint(unsigned bits, unsigned min)
|
|||
if (k == 17) {
|
||||
return min + (rand() % 16);
|
||||
} else if (k == 42) {
|
||||
return MAX_UINT(bits) - (rand() % 16);
|
||||
return u_uintN_max(bits) - (rand() % 16);
|
||||
} else if (k == 9) {
|
||||
uint64_t r;
|
||||
do {
|
||||
|
@ -230,7 +227,7 @@ rand_sint(unsigned bits, unsigned min_abs)
|
|||
{
|
||||
/* Make sure we hit MIN_INT every once in a while */
|
||||
if (rand() % 64 == 37)
|
||||
return INT64_MIN >> (64 - bits);
|
||||
return u_intN_min(bits);
|
||||
|
||||
int64_t s = rand_uint(bits - 1, min_abs);
|
||||
return rand() & 1 ? s : -s;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright © 2021 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "util/macros.h"
|
||||
|
||||
#define MESA_UINT24_MAX 16777215
|
||||
#define MESA_INT24_MAX 8388607
|
||||
#define MESA_INT24_MIN (-8388607-1)
|
||||
|
||||
#define MESA_UINT12_MAX 4095
|
||||
#define MESA_INT12_MAX 2047
|
||||
#define MESA_INT12_MIN (-2047-1)
|
||||
|
||||
#define MESA_UINT10_MAX 1023
|
||||
#define MESA_INT10_MAX 511
|
||||
#define MESA_INT10_MIN (-511-1)
|
||||
|
||||
TEST(int_min_max, u_intN_min)
|
||||
{
|
||||
EXPECT_EQ(INT64_MIN, u_intN_min(64));
|
||||
EXPECT_EQ(INT32_MIN, u_intN_min(32));
|
||||
EXPECT_EQ(INT16_MIN, u_intN_min(16));
|
||||
EXPECT_EQ(INT8_MIN, u_intN_min(8));
|
||||
|
||||
EXPECT_EQ(MESA_INT24_MIN, u_intN_min(24));
|
||||
EXPECT_EQ(MESA_INT12_MIN, u_intN_min(12));
|
||||
EXPECT_EQ(MESA_INT10_MIN, u_intN_min(10));
|
||||
}
|
||||
|
||||
TEST(int_min_max, u_intN_max)
|
||||
{
|
||||
EXPECT_EQ(INT64_MAX, u_intN_max(64));
|
||||
EXPECT_EQ(INT32_MAX, u_intN_max(32));
|
||||
EXPECT_EQ(INT16_MAX, u_intN_max(16));
|
||||
EXPECT_EQ(INT8_MAX, u_intN_max(8));
|
||||
|
||||
EXPECT_EQ(MESA_INT24_MAX, u_intN_max(24));
|
||||
EXPECT_EQ(MESA_INT12_MAX, u_intN_max(12));
|
||||
EXPECT_EQ(MESA_INT10_MAX, u_intN_max(10));
|
||||
}
|
||||
|
||||
TEST(int_min_max, u_uintN_max)
|
||||
{
|
||||
EXPECT_EQ(UINT64_MAX, u_uintN_max(64));
|
||||
EXPECT_EQ(UINT32_MAX, u_uintN_max(32));
|
||||
EXPECT_EQ(UINT16_MAX, u_uintN_max(16));
|
||||
EXPECT_EQ(UINT8_MAX, u_uintN_max(8));
|
||||
|
||||
EXPECT_EQ(MESA_UINT24_MAX, u_uintN_max(24));
|
||||
EXPECT_EQ(MESA_UINT12_MAX, u_uintN_max(12));
|
||||
EXPECT_EQ(MESA_UINT10_MAX, u_uintN_max(10));
|
||||
}
|
Loading…
Reference in New Issue