Mesa (master): nir/range_analysis: Handle vectors better in ssa_def_bits_used
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Mon Feb 22 23:01:51 UTC 2021
Module: Mesa
Branch: master
Commit: f2656569c60e7e77f8a8a2bf5da841ca07576534
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=f2656569c60e7e77f8a8a2bf5da841ca07576534
Author: Ian Romanick <ian.d.romanick at intel.com>
Date: Wed Feb 17 19:40:07 2021 -0800
nir/range_analysis: Handle vectors better in ssa_def_bits_used
If a query is made of a vector ssa_def (possibly from an intermediate
result), return all_bits. If a constant source is a vector, swizzle
the correct component.
Unit tests were added for the constant vector cases. I don't see a
great way to make unit tests for the other cases.
v2: Add a FINIHSME comment about u16vec2 hardware.
Fixes: 96303a59eae ("nir: Add some range analysis for used bits")
Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9123>
---
src/compiler/nir/meson.build | 13 ++
src/compiler/nir/nir_range_analysis.c | 40 +++-
src/compiler/nir/tests/ssa_def_bits_used_tests.cpp | 257 +++++++++++++++++++++
3 files changed, 306 insertions(+), 4 deletions(-)
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
index 8df22adb3f6..66dda5b3337 100644
--- a/src/compiler/nir/meson.build
+++ b/src/compiler/nir/meson.build
@@ -485,4 +485,17 @@ if with_tests
),
suite : ['compiler', 'nir'],
)
+
+ test(
+ 'ssa_def_bits_used',
+ executable(
+ 'ssa_def_bits_used',
+ files('tests/ssa_def_bits_used_tests.cpp'),
+ c_args : [c_msvc_compat_args, no_override_init_args],
+ gnu_symbol_visibility : 'hidden',
+ include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
+ dependencies : [dep_thread, idep_gtest, idep_nir, idep_mesautil],
+ ),
+ suite : ['compiler', 'nir'],
+ )
endif
diff --git a/src/compiler/nir/nir_range_analysis.c b/src/compiler/nir/nir_range_analysis.c
index 4c250206594..b6d2c8767b2 100644
--- a/src/compiler/nir/nir_range_analysis.c
+++ b/src/compiler/nir/nir_range_analysis.c
@@ -1502,6 +1502,18 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
uint64_t bits_used = 0;
uint64_t all_bits = BITFIELD64_MASK(def->bit_size);
+ /* Querying the bits used from a vector is too hard of a question to
+ * answer. Return the conservative answer that all bits are used. To
+ * handle this, the function would need to be extended to be a query of a
+ * single component of the vector. That would also necessary to fully
+ * handle the 'num_components > 1' inside the loop below.
+ *
+ * FINISHME: This restriction will eventually need to be restricted to be
+ * useful for hardware that uses u16vec2 as the native 16-bit integer type.
+ */
+ if (def->num_components > 1)
+ return all_bits;
+
/* Limit recursion */
if (recur-- <= 0)
return all_bits;
@@ -1512,6 +1524,22 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
nir_alu_instr *use_alu = nir_instr_as_alu(src->parent_instr);
unsigned src_idx = container_of(src, nir_alu_src, src) - use_alu->src;
+ /* If a user of the value produces a vector result, return the
+ * conservative answer that all bits are used. It is possible to
+ * answer this query by looping over the components used. For example,
+ *
+ * vec4 32 ssa_5 = load_const(0x0000f000, 0x00000f00, 0x000000f0, 0x0000000f)
+ * ...
+ * vec4 32 ssa_8 = iand ssa_7.xxxx, ssa_5
+ *
+ * could conceivably return 0x0000ffff when queyring the bits used of
+ * ssa_7. This is unlikely to be worth the effort because the
+ * question can eventually answered after the shader has been
+ * scalarized.
+ */
+ if (use_alu->dest.dest.ssa.num_components > 1)
+ return all_bits;
+
switch (use_alu->op) {
case nir_op_u2u8:
case nir_op_i2i8:
@@ -1531,7 +1559,8 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
case nir_op_extract_u8:
case nir_op_extract_i8:
if (src_idx == 0 && nir_src_is_const(use_alu->src[1].src)) {
- unsigned chunk = nir_src_as_uint(use_alu->src[1].src);
+ unsigned chunk = nir_src_comp_as_uint(use_alu->src[1].src,
+ use_alu->src[1].swizzle[0]);
bits_used |= 0xffull << (chunk * 8);
break;
} else {
@@ -1541,7 +1570,8 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
case nir_op_extract_u16:
case nir_op_extract_i16:
if (src_idx == 0 && nir_src_is_const(use_alu->src[1].src)) {
- unsigned chunk = nir_src_as_uint(use_alu->src[1].src);
+ unsigned chunk = nir_src_comp_as_uint(use_alu->src[1].src,
+ use_alu->src[1].swizzle[0]);
bits_used |= 0xffffull << (chunk * 16);
break;
} else {
@@ -1561,7 +1591,8 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
case nir_op_iand:
assert(src_idx < 2);
if (nir_src_is_const(use_alu->src[1 - src_idx].src)) {
- uint64_t u64 = nir_src_as_uint(use_alu->src[1 - src_idx].src);
+ uint64_t u64 = nir_src_comp_as_uint(use_alu->src[1 - src_idx].src,
+ use_alu->src[1 - src_idx].swizzle[0]);
bits_used |= u64;
break;
} else {
@@ -1571,7 +1602,8 @@ ssa_def_bits_used(nir_ssa_def *def, int recur)
case nir_op_ior:
assert(src_idx < 2);
if (nir_src_is_const(use_alu->src[1 - src_idx].src)) {
- uint64_t u64 = nir_src_as_uint(use_alu->src[1 - src_idx].src);
+ uint64_t u64 = nir_src_comp_as_uint(use_alu->src[1 - src_idx].src,
+ use_alu->src[1 - src_idx].swizzle[0]);
bits_used |= all_bits & ~u64;
break;
} else {
diff --git a/src/compiler/nir/tests/ssa_def_bits_used_tests.cpp b/src/compiler/nir/tests/ssa_def_bits_used_tests.cpp
new file mode 100644
index 00000000000..b38eef0d2a0
--- /dev/null
+++ b/src/compiler/nir/tests/ssa_def_bits_used_tests.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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 "nir.h"
+#include "nir_builder.h"
+#include "nir_range_analysis.h"
+
+class ssa_def_bits_used_test : public ::testing::Test {
+protected:
+ ssa_def_bits_used_test()
+ {
+ glsl_type_singleton_init_or_ref();
+
+ static const nir_shader_compiler_options options = { };
+ bld = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, &options,
+ "ssa_def_bits_used test");
+ }
+
+ ~ssa_def_bits_used_test()
+ {
+ ralloc_free(bld.shader);
+ glsl_type_singleton_decref();
+ }
+
+ nir_alu_instr *build_alu_instr(nir_op op, nir_ssa_def *, nir_ssa_def *);
+
+ struct nir_builder bld;
+};
+
+static bool
+is_used_once(const nir_ssa_def *def)
+{
+ return list_is_singular(&def->uses) &&
+ list_is_empty(&def->if_uses);
+}
+
+nir_alu_instr *
+ssa_def_bits_used_test::build_alu_instr(nir_op op,
+ nir_ssa_def *src0, nir_ssa_def *src1)
+{
+ nir_ssa_def *def = nir_build_alu(&bld, op, src0, src1, NULL, NULL);
+
+ if (def == NULL)
+ return NULL;
+
+ nir_alu_instr *alu = nir_instr_as_alu(def->parent_instr);
+
+ if (alu == NULL)
+ return NULL;
+
+ alu->dest.write_mask = 1;
+ alu->dest.dest.ssa.num_components = 1;
+
+ return alu;
+}
+
+TEST_F(ssa_def_bits_used_test, iand_with_const_vector)
+{
+ static const unsigned src0_imm[4] = { 255u << 24, 255u << 16, 255u << 8, 255u };
+
+ nir_ssa_def *src0 = nir_imm_ivec4(&bld,
+ src0_imm[0], src0_imm[1],
+ src0_imm[2], src0_imm[3]);
+ nir_ssa_def *src1 = nir_imm_int(&bld, 0xffffffff);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_iand, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 0; i < 4; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[0].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[1].src.ssa);
+
+ /* The answer should be the value swizzled from src0. */
+ EXPECT_EQ(src0_imm[i], bits_used);
+ }
+}
+
+TEST_F(ssa_def_bits_used_test, ior_with_const_vector)
+{
+ static const unsigned src0_imm[4] = { 255u << 24, 255u << 16, 255u << 8, 255u };
+
+ nir_ssa_def *src0 = nir_imm_ivec4(&bld,
+ src0_imm[0], src0_imm[1],
+ src0_imm[2], src0_imm[3]);
+ nir_ssa_def *src1 = nir_imm_int(&bld, 0xffffffff);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_ior, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 0; i < 4; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[0].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[1].src.ssa);
+
+ /* The answer should be the value swizzled from ~src0. */
+ EXPECT_EQ(~src0_imm[i], bits_used);
+ }
+}
+
+TEST_F(ssa_def_bits_used_test, extract_i16_with_const_index)
+{
+ nir_ssa_def *src0 = nir_imm_int(&bld, 0xffffffff);
+
+ static const unsigned src1_imm[4] = { 9, 1, 0, 9 };
+
+ nir_ssa_def *src1 = nir_imm_ivec4(&bld,
+ src1_imm[0],
+ src1_imm[1],
+ src1_imm[2],
+ src1_imm[3]);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_extract_i16, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 1; i < 3; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[1].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[0].src.ssa);
+
+ EXPECT_EQ(0xffffu << (16 * src1_imm[i]), bits_used);
+ }
+}
+
+TEST_F(ssa_def_bits_used_test, extract_u16_with_const_index)
+{
+ nir_ssa_def *src0 = nir_imm_int(&bld, 0xffffffff);
+
+ static const unsigned src1_imm[4] = { 9, 1, 0, 9 };
+
+ nir_ssa_def *src1 = nir_imm_ivec4(&bld,
+ src1_imm[0],
+ src1_imm[1],
+ src1_imm[2],
+ src1_imm[3]);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_extract_u16, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 1; i < 3; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[1].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[0].src.ssa);
+
+ EXPECT_EQ(0xffffu << (16 * src1_imm[i]), bits_used);
+ }
+}
+
+TEST_F(ssa_def_bits_used_test, extract_i8_with_const_index)
+{
+ nir_ssa_def *src0 = nir_imm_int(&bld, 0xffffffff);
+
+ static const unsigned src1_imm[4] = { 3, 2, 1, 0 };
+
+ nir_ssa_def *src1 = nir_imm_ivec4(&bld,
+ src1_imm[0],
+ src1_imm[1],
+ src1_imm[2],
+ src1_imm[3]);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_extract_i8, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 0; i < 4; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[1].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[0].src.ssa);
+
+ EXPECT_EQ(0xffu << (8 * src1_imm[i]), bits_used);
+ }
+}
+
+TEST_F(ssa_def_bits_used_test, extract_u8_with_const_index)
+{
+ nir_ssa_def *src0 = nir_imm_int(&bld, 0xffffffff);
+
+ static const unsigned src1_imm[4] = { 3, 2, 1, 0 };
+
+ nir_ssa_def *src1 = nir_imm_ivec4(&bld,
+ src1_imm[0],
+ src1_imm[1],
+ src1_imm[2],
+ src1_imm[3]);
+
+ nir_alu_instr *alu = build_alu_instr(nir_op_extract_u8, src0, src1);
+
+ ASSERT_NE((void *) 0, alu);
+
+ for (unsigned i = 0; i < 4; i++) {
+ /* If the test is changed, and somehow src1 is used multiple times,
+ * nir_ssa_def_bits_used will accumulate *all* the uses (as it should).
+ * This isn't what we're trying to test here.
+ */
+ ASSERT_TRUE(is_used_once(src1));
+
+ alu->src[1].swizzle[0] = i;
+
+ const uint64_t bits_used = nir_ssa_def_bits_used(alu->src[0].src.ssa);
+
+ EXPECT_EQ(0xffu << (8 * src1_imm[i]), bits_used);
+ }
+}
More information about the mesa-commit
mailing list