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:
Ian Romanick 2018-05-22 18:18:07 -07:00
parent be1cc3552b
commit c6ee46a753
3 changed files with 192 additions and 0 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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)
{