Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions src/compiler/nir/nir_opt_algebraic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3028,15 +3028,28 @@ def ubfe_ubfe(a, b, c, d, e):
# upcasts where the type differs from the other cast
for N, M in itertools.product(type_sizes('uint'), type_sizes('uint')):
if N < M:
# The outer cast is a down-cast. It doesn't matter what the size of the
# argument of the inner cast is because we'll never been in the upcast
# of downcast case. Regardless of types, we'll always end up with y2yN
# in the end.
for x, y in itertools.product(['i', 'u'], ['i', 'u']):
x2xN = '{0}2{0}{1}'.format(x, N)
y2yM = '{0}2{0}{1}'.format(y, M)
y2yN = '{0}2{0}{1}'.format(y, N)
optimizations.append(((x2xN, (y2yM, a)), (y2yN, a)))
# Down-casts are always in the u2uN form
u2uN = 'u2u{0}'.format(N)

if N == 1:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the old loop also folded i2i1(y2yM(a)), and nir_validate still allows i2i1. Please confirm dropping it is intended.

— Marcelo's agent

for y in ['i', 'u']:
y2yM = '{0}2{0}{1}'.format(y, M)
optimizations.append(((u2uN, (y2yM, a)), (u2uN, a)))
continue

u2uM = 'u2u{0}'.format(M)
optimizations.append(((u2uN, (u2uM, a)), (u2uN, a)))

for P in type_sizes('uint'):
if P > M:
continue

# Keep the sign extension for down-casts of signed up-casts.
res = u2uN if P >= N else 'i2i{0}'.format(N)

i2iM = 'i2i{0}'.format(M)
aP = 'a@{0}'.format(P)
optimizations.append(((u2uN, (i2iM, aP)), (res, a)))
elif N > M:
# If the outer cast is an up-cast, we have to be more careful about the
# size of the argument of the inner cast and with types. In this case,
Expand Down
38 changes: 38 additions & 0 deletions src/compiler/nir/tests/algebraic_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,4 +1331,42 @@ TEST_F(nir_opt_algebraic_test, commutation_masks_preserve_direction_order)
}
}

static unsigned
count_narrowing_i2i(nir_shader *shader)
{
unsigned count = 0;
nir_foreach_function_impl(impl, shader) {
nir_foreach_block(block, impl) {
nir_foreach_instr(instr, block) {
if (instr->type != nir_instr_type_alu)
continue;

nir_alu_instr *alu = nir_instr_as_alu(instr);
if ((alu->op == nir_op_i2i8 || alu->op == nir_op_i2i16 ||
alu->op == nir_op_i2i32) &&
nir_src_bit_size(alu->src[0].src) > alu->def.bit_size)
count++;
}
}
}
return count;
}

TEST_F(nir_opt_algebraic_test, downcast_of_sign_extended_value_is_u2u)
{
nir_def *base = nir_imm_int64(b, 0x100000);
nir_def *value16 = nir_load_global(b, 1, 16, base, (gl_access_qualifier)0, 2, 0);
nir_def *value32 = nir_i2i32(b, value16);
nir_def *byte0 = nir_u2u8(b, value32);
nir_store_global(b, nir_i2f32(b, byte0), nir_imm_int64(b, 0x200000), 1,
(gl_access_qualifier)0, 4, 0);

nir_validate_shader(b->shader, "before the pass");
run_pass();

/* An i2i narrowing would fail validation; the downcast has to stay u2u. */
EXPECT_EQ(count_narrowing_i2i(b->shader), 0u);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only checks that no bad cast is left. Could it also assert that the value reaching i2f32 is u2u8 of the 16-bit load, and could a second case cover P < N, for example u2u16(i2i32(a@8)) becoming i2i16?

— Marcelo's agent

nir_validate_shader(b->shader, "after the pass");
}

}
Loading