spirv: fix OpBitcast when the src and dst bitsize are different (v3)
Before, we were just implementing it with a move, which is incorrect
when the source and destination have different bitsizes. To implement
it properly, we need to use the 64-bit pack/unpack opcodes. Since
glslang uses OpBitcast to implement packInt2x32 and unpackInt2x32, this
should fix them on anv (and radv once we enable the int64 capability).
v2: make supporting non-32/64 bit easier (Jason)
v3: add another assert (Jason)
Fixes: b3135c3c
("anv: Advertise shaderInt64 on Broadwell and above")
Signed-off-by: Connor Abbott <cwabbott0@gmail.com>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
This commit is contained in:
@@ -210,6 +210,68 @@ vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vtn_handle_bitcast(struct vtn_builder *b, struct vtn_ssa_value *dest,
|
||||
struct nir_ssa_def *src)
|
||||
{
|
||||
if (glsl_get_vector_elements(dest->type) == src->num_components) {
|
||||
/* From the definition of OpBitcast in the SPIR-V 1.2 spec:
|
||||
*
|
||||
* "If Result Type has the same number of components as Operand, they
|
||||
* must also have the same component width, and results are computed per
|
||||
* component."
|
||||
*/
|
||||
dest->def = nir_imov(&b->nb, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/* From the definition of OpBitcast in the SPIR-V 1.2 spec:
|
||||
*
|
||||
* "If Result Type has a different number of components than Operand, the
|
||||
* total number of bits in Result Type must equal the total number of bits
|
||||
* in Operand. Let L be the type, either Result Type or Operand’s type, that
|
||||
* has the larger number of components. Let S be the other type, with the
|
||||
* smaller number of components. The number of components in L must be an
|
||||
* integer multiple of the number of components in S. The first component
|
||||
* (that is, the only or lowest-numbered component) of S maps to the first
|
||||
* components of L, and so on, up to the last component of S mapping to the
|
||||
* last components of L. Within this mapping, any single component of S
|
||||
* (mapping to multiple components of L) maps its lower-ordered bits to the
|
||||
* lower-numbered components of L."
|
||||
*/
|
||||
unsigned src_bit_size = src->bit_size;
|
||||
unsigned dest_bit_size = glsl_get_bit_size(dest->type);
|
||||
unsigned src_components = src->num_components;
|
||||
unsigned dest_components = glsl_get_vector_elements(dest->type);
|
||||
assert(src_bit_size * src_components == dest_bit_size * dest_components);
|
||||
|
||||
nir_ssa_def *dest_chan[4];
|
||||
if (src_bit_size > dest_bit_size) {
|
||||
assert(src_bit_size % dest_bit_size == 0);
|
||||
unsigned divisor = src_bit_size / dest_bit_size;
|
||||
for (unsigned comp = 0; comp < src_components; comp++) {
|
||||
assert(src_bit_size == 64);
|
||||
assert(dest_bit_size == 32);
|
||||
nir_ssa_def *split =
|
||||
nir_unpack_64_2x32(&b->nb, nir_channel(&b->nb, src, comp));
|
||||
for (unsigned i = 0; i < divisor; i++)
|
||||
dest_chan[divisor * comp + i] = nir_channel(&b->nb, split, i);
|
||||
}
|
||||
} else {
|
||||
assert(dest_bit_size % src_bit_size == 0);
|
||||
unsigned divisor = dest_bit_size / src_bit_size;
|
||||
for (unsigned comp = 0; comp < dest_components; comp++) {
|
||||
unsigned channels = ((1 << divisor) - 1) << (comp * divisor);
|
||||
nir_ssa_def *src_chan =
|
||||
nir_channels(&b->nb, src, channels);
|
||||
assert(dest_bit_size == 64);
|
||||
assert(src_bit_size == 32);
|
||||
dest_chan[comp] = nir_pack_64_2x32(&b->nb, src_chan);
|
||||
}
|
||||
}
|
||||
dest->def = nir_vec(&b->nb, dest_chan, dest_components);
|
||||
}
|
||||
|
||||
nir_op
|
||||
vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
|
||||
nir_alu_type src, nir_alu_type dst)
|
||||
@@ -285,7 +347,6 @@ vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
|
||||
case SpvOpFUnordGreaterThanEqual: return nir_op_fge;
|
||||
|
||||
/* Conversions: */
|
||||
case SpvOpBitcast: return nir_op_imov;
|
||||
case SpvOpQuantizeToF16: return nir_op_fquantize2f16;
|
||||
case SpvOpUConvert:
|
||||
case SpvOpConvertFToU:
|
||||
@@ -503,6 +564,10 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitcast:
|
||||
vtn_handle_bitcast(b, val->ssa, src[0]);
|
||||
break;
|
||||
|
||||
default: {
|
||||
bool swap;
|
||||
nir_alu_type src_alu_type = nir_get_nir_type_for_glsl_type(vtn_src[0]->type);
|
||||
|
Reference in New Issue
Block a user