[Mesa-dev] [PATCH 1/4] spirv: fix OpBitcast when the src and dst bitsize are different (v2)

Jason Ekstrand jason at jlekstrand.net
Sat Jul 1 15:13:26 UTC 2017


On June 30, 2017 19:57:01 Connor Abbott <connora at valvesoftware.com> wrote:

> From: Connor Abbott <cwabbott0 at gmail.com>
>
> 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)
>
> Fixes: b3135c3c ("anv: Advertise shaderInt64 on Broadwell and above")
> Signed-off-by: Connor Abbott <cwabbott0 at gmail.com>
> ---
>  src/compiler/spirv/vtn_alu.c | 65 +++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
>
> diff --git a/src/compiler/spirv/vtn_alu.c b/src/compiler/spirv/vtn_alu.c
> index 9e4beed..e607825 100644
> --- a/src/compiler/spirv/vtn_alu.c
> +++ b/src/compiler/spirv/vtn_alu.c
> @@ -210,6 +210,66 @@ 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);

With that,

Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>

> +   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 +345,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 +562,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);
> --
> 2.9.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev




More information about the mesa-dev mailing list