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:
Connor Abbott
2017-06-07 14:12:05 -07:00
parent 6158c0b5d8
commit 196e6b60b1

View File

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