diff options
author | Connor Abbott <cwabbott0@gmail.com> | 2017-06-07 14:12:05 -0700 |
---|---|---|
committer | Connor Abbott <cwabbott0@gmail.com> | 2017-07-03 11:58:50 -0700 |
commit | 196e6b60b1e392c5e55c07a9f9b4e85dad52fb66 (patch) | |
tree | f0eaa840cd4953069bd3a27d71a5796c6ee7980a | |
parent | 6158c0b5d8b6367a46acbe2fe20357210422c96f (diff) |
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>
-rw-r--r-- | src/compiler/spirv/vtn_alu.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/src/compiler/spirv/vtn_alu.c b/src/compiler/spirv/vtn_alu.c index 9e4beedf92..ecf9cbc34d 100644 --- a/src/compiler/spirv/vtn_alu.c +++ b/src/compiler/spirv/vtn_alu.c @@ -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); |