Mesa (staging/21.2): util: Add and use functions to calculate min and max int for a size
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Thu Aug 26 19:11:37 UTC 2021
Module: Mesa
Branch: staging/21.2
Commit: b44451ad2039b1191ab70617638a79fac2067aee
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=b44451ad2039b1191ab70617638a79fac2067aee
Author: Ian Romanick <ian.d.romanick at intel.com>
Date: Mon Aug 2 16:43:52 2021 -0700
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 at jlekstrand.net>
Suggested-by: Jason Ekstrand <jason at jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12177>
(cherry picked from commit 72259a870f6047c83b3f95ac205aca7ed5bdc049)
---
.pick_status.json | 2 +-
src/compiler/nir/nir_constant_expressions.py | 2 -
src/compiler/nir/nir_opcodes.py | 2 +-
src/compiler/nir/nir_search.c | 2 +-
src/gallium/drivers/iris/iris_clear.c | 4 +-
src/intel/isl/isl_format.c | 10 +--
src/util/fast_idiv_by_const.c | 4 +-
src/util/format/format_utils.h | 53 +++++++---------
src/util/macros.h | 26 ++++++++
src/util/meson.build | 9 +++
.../fast_idiv_by_const/fast_idiv_by_const_test.cpp | 9 +--
src/util/tests/int_min_max.cpp | 73 ++++++++++++++++++++++
12 files changed, 147 insertions(+), 49 deletions(-)
diff --git a/.pick_status.json b/.pick_status.json
index b5226fd6a8b..c7dd303cfc2 100644
--- a/.pick_status.json
+++ b/.pick_status.json
@@ -7627,7 +7627,7 @@
"description": "util: Add and use functions to calculate min and max int for a size",
"nominated": false,
"nomination_type": null,
- "resolution": 4,
+ "resolution": 1,
"main_sha": null,
"because_sha": null
},
diff --git a/src/compiler/nir/nir_constant_expressions.py b/src/compiler/nir/nir_constant_expressions.py
index 606e974353f..c1097de7c67 100644
--- a/src/compiler/nir/nir_constant_expressions.py
+++ b/src/compiler/nir/nir_constant_expressions.py
@@ -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.
*/
diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py
index f9330c0af2c..e2172d7a26e 100644
--- a/src/compiler/nir/nir_opcodes.py
+++ b/src/compiler/nir/nir_opcodes.py
@@ -634,7 +634,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) :
diff --git a/src/compiler/nir/nir_search.c b/src/compiler/nir/nir_search.c
index 272a3f6444a..437a24b9b02 100644
--- a/src/compiler/nir/nir_search.c
+++ b/src/compiler/nir/nir_search.c
@@ -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]);
diff --git a/src/gallium/drivers/iris/iris_clear.c b/src/gallium/drivers/iris/iris_clear.c
index cc619b46a0c..a59ba735cbc 100644
--- a/src/gallium/drivers/iris/iris_clear.c
+++ b/src/gallium/drivers/iris/iris_clear.c
@@ -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);
}
}
diff --git a/src/intel/isl/isl_format.c b/src/intel/isl/isl_format.c
index 60f4409e2b0..bd9c63d140c 100644
--- a/src/intel/isl/isl_format.c
+++ b/src/intel/isl/isl_format.c
@@ -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;
diff --git a/src/util/fast_idiv_by_const.c b/src/util/fast_idiv_by_const.c
index 4f0f6b769b8..b9f0b9cb760 100644
--- a/src/util/fast_idiv_by_const.c
+++ b/src/util/fast_idiv_by_const.c
@@ -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;
diff --git a/src/util/format/format_utils.h b/src/util/format/format_utils.h
index fa1d30060d9..0768a26ecce 100644
--- a/src/util/format/format_utils.h
+++ b/src/util/format/format_utils.h
@@ -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);
}
diff --git a/src/util/macros.h b/src/util/macros.h
index 1fc9e23355b..4bd18f55ec0 100644
--- a/src/util/macros.h
+++ b/src/util/macros.h
@@ -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.
*/
diff --git a/src/util/meson.build b/src/util/meson.build
index aa5bfef5dbc..319b22d9bf7 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -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')
diff --git a/src/util/tests/fast_idiv_by_const/fast_idiv_by_const_test.cpp b/src/util/tests/fast_idiv_by_const/fast_idiv_by_const_test.cpp
index 330f90fa464..abf6079944f 100644
--- a/src/util/tests/fast_idiv_by_const/fast_idiv_by_const_test.cpp
+++ b/src/util/tests/fast_idiv_by_const/fast_idiv_by_const_test.cpp
@@ -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;
diff --git a/src/util/tests/int_min_max.cpp b/src/util/tests/int_min_max.cpp
new file mode 100644
index 00000000000..8d74ecb7d33
--- /dev/null
+++ b/src/util/tests/int_min_max.cpp
@@ -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));
+}
More information about the mesa-commit
mailing list