nir: Add nir_alu_srcs_negative_equal
v2: Move bug fix in get_neg_instr from the next patch to this patch (where it was intended to be in the first place). Noticed by Caio. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
parent
be1cc3552b
commit
c6ee46a753
|
@ -997,6 +997,10 @@ bool nir_const_value_negative_equal(const nir_const_value *c1,
|
|||
bool nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2,
|
||||
unsigned src1, unsigned src2);
|
||||
|
||||
bool nir_alu_srcs_negative_equal(const nir_alu_instr *alu1,
|
||||
const nir_alu_instr *alu2,
|
||||
unsigned src1, unsigned src2);
|
||||
|
||||
typedef enum {
|
||||
nir_deref_type_var,
|
||||
nir_deref_type_array,
|
||||
|
|
|
@ -276,6 +276,20 @@ nir_srcs_equal(nir_src src1, nir_src src2)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the \p s is an SSA value that was generated by a negation instruction,
|
||||
* that instruction is returned as a \c nir_alu_instr. Otherwise \c NULL is
|
||||
* returned.
|
||||
*/
|
||||
static const struct nir_alu_instr *
|
||||
get_neg_instr(const nir_src *s)
|
||||
{
|
||||
const struct nir_alu_instr *const alu = nir_src_as_alu_instr_const(s);
|
||||
|
||||
return alu != NULL && (alu->op == nir_op_fneg || alu->op == nir_op_ineg)
|
||||
? alu : NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
nir_const_value_negative_equal(const nir_const_value *c1,
|
||||
const nir_const_value *c2,
|
||||
|
@ -377,6 +391,96 @@ nir_const_value_negative_equal(const nir_const_value *c1,
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shallow compare of ALU srcs to determine if one is the negation of the other
|
||||
*
|
||||
* This function detects cases where \p alu1 is a constant and \p alu2 is a
|
||||
* constant that is its negation. It will also detect cases where \p alu2 is
|
||||
* an SSA value that is a \c nir_op_fneg applied to \p alu1 (and vice versa).
|
||||
*
|
||||
* This function does not detect the general case when \p alu1 and \p alu2 are
|
||||
* SSA values that are the negations of each other (e.g., \p alu1 represents
|
||||
* (a * b) and \p alu2 represents (-a * b)).
|
||||
*/
|
||||
bool
|
||||
nir_alu_srcs_negative_equal(const nir_alu_instr *alu1,
|
||||
const nir_alu_instr *alu2,
|
||||
unsigned src1, unsigned src2)
|
||||
{
|
||||
if (alu1->src[src1].abs != alu2->src[src2].abs)
|
||||
return false;
|
||||
|
||||
bool parity = alu1->src[src1].negate != alu2->src[src2].negate;
|
||||
|
||||
/* Handling load_const instructions is tricky. */
|
||||
|
||||
const nir_const_value *const const1 =
|
||||
nir_src_as_const_value(alu1->src[src1].src);
|
||||
|
||||
if (const1 != NULL) {
|
||||
/* Assume that constant folding will eliminate source mods and unary
|
||||
* ops.
|
||||
*/
|
||||
if (parity)
|
||||
return false;
|
||||
|
||||
const nir_const_value *const const2 =
|
||||
nir_src_as_const_value(alu2->src[src2].src);
|
||||
|
||||
if (const2 == NULL)
|
||||
return false;
|
||||
|
||||
/* FINISHME: Apply the swizzle? */
|
||||
return nir_const_value_negative_equal(const1,
|
||||
const2,
|
||||
nir_ssa_alu_instr_src_components(alu1, src1),
|
||||
nir_op_infos[alu1->op].input_types[src1],
|
||||
alu1->dest.dest.ssa.bit_size);
|
||||
}
|
||||
|
||||
uint8_t alu1_swizzle[4] = {};
|
||||
nir_src alu1_actual_src;
|
||||
const struct nir_alu_instr *const neg1 = get_neg_instr(&alu1->src[src1].src);
|
||||
|
||||
if (neg1) {
|
||||
parity = !parity;
|
||||
alu1_actual_src = neg1->src[0].src;
|
||||
|
||||
for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(neg1, 0); i++)
|
||||
alu1_swizzle[i] = neg1->src[0].swizzle[i];
|
||||
} else {
|
||||
alu1_actual_src = alu1->src[src1].src;
|
||||
|
||||
for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(alu1, src1); i++)
|
||||
alu1_swizzle[i] = i;
|
||||
}
|
||||
|
||||
uint8_t alu2_swizzle[4] = {};
|
||||
nir_src alu2_actual_src;
|
||||
const struct nir_alu_instr *const neg2 = get_neg_instr(&alu2->src[src2].src);
|
||||
|
||||
if (neg2) {
|
||||
parity = !parity;
|
||||
alu2_actual_src = neg2->src[0].src;
|
||||
|
||||
for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(neg2, 0); i++)
|
||||
alu2_swizzle[i] = neg2->src[0].swizzle[i];
|
||||
} else {
|
||||
alu2_actual_src = alu2->src[src2].src;
|
||||
|
||||
for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(alu2, src2); i++)
|
||||
alu2_swizzle[i] = i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(alu1, src1); i++) {
|
||||
if (alu1_swizzle[alu1->src[src1].swizzle[i]] !=
|
||||
alu2_swizzle[alu2->src[src2].swizzle[i]])
|
||||
return false;
|
||||
}
|
||||
|
||||
return parity && nir_srcs_equal(alu1_actual_src, alu2_actual_src);
|
||||
}
|
||||
|
||||
bool
|
||||
nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2,
|
||||
unsigned src1, unsigned src2)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include "nir.h"
|
||||
#include "nir_builder.h"
|
||||
#include "util/half_float.h"
|
||||
|
||||
static nir_const_value count_sequence(nir_alu_type base_type, unsigned bits,
|
||||
|
@ -47,6 +48,21 @@ protected:
|
|||
nir_const_value c2;
|
||||
};
|
||||
|
||||
class alu_srcs_negative_equal_test : public ::testing::Test {
|
||||
protected:
|
||||
alu_srcs_negative_equal_test()
|
||||
{
|
||||
static const nir_shader_compiler_options options = { };
|
||||
nir_builder_init_simple_shader(&bld, NULL, MESA_SHADER_VERTEX, &options);
|
||||
}
|
||||
|
||||
~alu_srcs_negative_equal_test()
|
||||
{
|
||||
ralloc_free(bld.shader);
|
||||
}
|
||||
|
||||
struct nir_builder bld;
|
||||
};
|
||||
|
||||
TEST_F(const_value_negative_equal_test, float32_zero)
|
||||
{
|
||||
|
@ -130,6 +146,74 @@ compare_fewer_components(nir_type_uint, 32)
|
|||
compare_fewer_components(nir_type_int, 64)
|
||||
compare_fewer_components(nir_type_uint, 64)
|
||||
|
||||
TEST_F(alu_srcs_negative_equal_test, trivial_float)
|
||||
{
|
||||
nir_ssa_def *two = nir_imm_float(&bld, 2.0f);
|
||||
nir_ssa_def *negative_two = nir_imm_float(&bld, -2.0f);
|
||||
|
||||
nir_ssa_def *result = nir_fadd(&bld, two, negative_two);
|
||||
nir_alu_instr *instr = nir_instr_as_alu(result->parent_instr);
|
||||
|
||||
ASSERT_NE((void *) 0, instr);
|
||||
EXPECT_TRUE(nir_alu_srcs_negative_equal(instr, instr, 0, 1));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 0, 0));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 1, 1));
|
||||
}
|
||||
|
||||
TEST_F(alu_srcs_negative_equal_test, trivial_int)
|
||||
{
|
||||
nir_ssa_def *two = nir_imm_int(&bld, 2);
|
||||
nir_ssa_def *negative_two = nir_imm_int(&bld, -2);
|
||||
|
||||
nir_ssa_def *result = nir_iadd(&bld, two, negative_two);
|
||||
nir_alu_instr *instr = nir_instr_as_alu(result->parent_instr);
|
||||
|
||||
ASSERT_NE((void *) 0, instr);
|
||||
EXPECT_TRUE(nir_alu_srcs_negative_equal(instr, instr, 0, 1));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 0, 0));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 1, 1));
|
||||
}
|
||||
|
||||
TEST_F(alu_srcs_negative_equal_test, trivial_negation_float)
|
||||
{
|
||||
/* Cannot just do the negation of a nir_load_const_instr because
|
||||
* nir_alu_srcs_negative_equal expects that constant folding will convert
|
||||
* fneg(2.0) to just -2.0.
|
||||
*/
|
||||
nir_ssa_def *two = nir_imm_float(&bld, 2.0f);
|
||||
nir_ssa_def *two_plus_two = nir_fadd(&bld, two, two);
|
||||
nir_ssa_def *negation = nir_fneg(&bld, two_plus_two);
|
||||
|
||||
nir_ssa_def *result = nir_fadd(&bld, two_plus_two, negation);
|
||||
|
||||
nir_alu_instr *instr = nir_instr_as_alu(result->parent_instr);
|
||||
|
||||
ASSERT_NE((void *) 0, instr);
|
||||
EXPECT_TRUE(nir_alu_srcs_negative_equal(instr, instr, 0, 1));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 0, 0));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 1, 1));
|
||||
}
|
||||
|
||||
TEST_F(alu_srcs_negative_equal_test, trivial_negation_int)
|
||||
{
|
||||
/* Cannot just do the negation of a nir_load_const_instr because
|
||||
* nir_alu_srcs_negative_equal expects that constant folding will convert
|
||||
* ineg(2) to just -2.
|
||||
*/
|
||||
nir_ssa_def *two = nir_imm_int(&bld, 2);
|
||||
nir_ssa_def *two_plus_two = nir_iadd(&bld, two, two);
|
||||
nir_ssa_def *negation = nir_ineg(&bld, two_plus_two);
|
||||
|
||||
nir_ssa_def *result = nir_iadd(&bld, two_plus_two, negation);
|
||||
|
||||
nir_alu_instr *instr = nir_instr_as_alu(result->parent_instr);
|
||||
|
||||
ASSERT_NE((void *) 0, instr);
|
||||
EXPECT_TRUE(nir_alu_srcs_negative_equal(instr, instr, 0, 1));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 0, 0));
|
||||
EXPECT_FALSE(nir_alu_srcs_negative_equal(instr, instr, 1, 1));
|
||||
}
|
||||
|
||||
static nir_const_value
|
||||
count_sequence(nir_alu_type base_type, unsigned bits, int first)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue