summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConnor Abbott <cwabbott0@gmail.com>2017-06-07 14:12:05 -0700
committerConnor Abbott <cwabbott0@gmail.com>2017-07-03 11:58:50 -0700
commit196e6b60b1e392c5e55c07a9f9b4e85dad52fb66 (patch)
treef0eaa840cd4953069bd3a27d71a5796c6ee7980a
parent6158c0b5d8b6367a46acbe2fe20357210422c96f (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.c67
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);