From 2b1396e7e45f81d31f05d4a73a51eacac6673810 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B3zef=20Kucia?= <jkucia@codeweavers.com>
Date: Tue, 20 Jun 2017 13:34:44 +0200
Subject: [PATCH] libs/vkd3d-shader: Translate mov instruction.

---
 libs/vkd3d-shader/spirv.c                | 473 +++++++++++++++++++++++
 libs/vkd3d-shader/vkd3d_shader_private.h |  51 +++
 2 files changed, 524 insertions(+)

diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index 34e5937494..bb467ce11b 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -282,6 +282,12 @@ static void vkd3d_spirv_build_op2(struct vkd3d_spirv_stream *stream,
     return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, NULL, 0);
 }
 
+static void vkd3d_spirv_build_op3(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, uint32_t operand1, uint32_t operand2)
+{
+    return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, &operand2, 1);
+}
+
 static uint32_t vkd3d_spirv_build_op_rv(struct vkd3d_spirv_builder *builder,
         struct vkd3d_spirv_stream *stream, SpvOp op,
         const uint32_t *operands, unsigned int operand_count)
@@ -328,6 +334,12 @@ static uint32_t vkd3d_spirv_build_op_trv(struct vkd3d_spirv_builder *builder,
     return result_id;
 }
 
+static uint32_t vkd3d_spirv_build_op_tr(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type)
+{
+    return vkd3d_spirv_build_op_trv(builder, stream, op, result_type, NULL, 0);
+}
+
 static uint32_t vkd3d_spirv_build_op_tr1(struct vkd3d_spirv_builder *builder,
         struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
         uint32_t operand0)
@@ -344,6 +356,37 @@ static uint32_t vkd3d_spirv_build_op_tr2(struct vkd3d_spirv_builder *builder,
             operands, ARRAY_SIZE(operands));
 }
 
+static uint32_t vkd3d_spirv_build_op_tr1v(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = builder->current_id++;
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 4 + operand_count));
+    vkd3d_spirv_build_word(stream, result_type);
+    vkd3d_spirv_build_word(stream, result_id);
+    vkd3d_spirv_build_word(stream, operand0);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_tr2v(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, uint32_t operand1, const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = builder->current_id++;
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 5 + operand_count));
+    vkd3d_spirv_build_word(stream, result_type);
+    vkd3d_spirv_build_word(stream, result_id);
+    vkd3d_spirv_build_word(stream, operand0);
+    vkd3d_spirv_build_word(stream, operand1);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+    return result_id;
+}
+
 static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream,
         SpvCapability cap)
 {
@@ -437,6 +480,21 @@ static uint32_t vkd3d_spirv_build_op_type_pointer(struct vkd3d_spirv_builder *bu
             SpvOpTypePointer, storage_class, type_id);
 }
 
+/* Types larger than 32-bits are not supported. */
+static uint32_t vkd3d_spirv_build_op_constant(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, const uint32_t value)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->global_stream,
+            SpvOpConstant, result_type, value);
+}
+
+static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, const uint32_t* constituents, unsigned int constituent_count)
+{
+    return vkd3d_spirv_build_op_trv(builder, &builder->global_stream,
+            SpvOpConstantComposite, result_type, constituents, constituent_count);
+}
+
 /* Initializers are not supported. */
 static uint32_t vkd3d_spirv_build_op_variable(struct vkd3d_spirv_builder *builder,
         struct vkd3d_spirv_stream *stream, uint32_t type_id, uint32_t storage_class)
@@ -461,11 +519,68 @@ static uint32_t vkd3d_spirv_build_op_label(struct vkd3d_spirv_builder *builder)
     return vkd3d_spirv_build_op_r(builder, &builder->function_stream, SpvOpLabel);
 }
 
+static uint32_t vkd3d_spirv_build_op_undef(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, uint32_t type_id)
+{
+    return vkd3d_spirv_build_op_tr(builder, stream, SpvOpUndef, type_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_access_chain(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
+            SpvOpAccessChain, result_type, base_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_in_bounds_access_chain(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
+            SpvOpInBoundsAccessChain, result_type, base_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_vector_shuffle(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t vector1_id, uint32_t vector2_id,
+        uint32_t *components, uint32_t component_count)
+{
+    return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream, SpvOpVectorShuffle,
+            result_type, vector1_id, vector2_id, components, component_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_load(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t pointer_id, uint32_t memory_access)
+{
+    if (!memory_access)
+        return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpLoad,
+                result_type, pointer_id);
+    else
+        return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpLoad,
+                result_type, pointer_id, memory_access);
+}
+
+static void vkd3d_spirv_build_op_store(struct vkd3d_spirv_builder *builder,
+        uint32_t pointer_id, uint32_t object_id, uint32_t memory_access)
+{
+    if (!memory_access)
+        return vkd3d_spirv_build_op2(&builder->function_stream, SpvOpStore,
+                pointer_id, object_id);
+    else
+        return vkd3d_spirv_build_op3(&builder->function_stream, SpvOpStore,
+                pointer_id, object_id, memory_access);
+}
+
 static void vkd3d_spirv_build_op_return(struct vkd3d_spirv_builder *builder)
 {
     vkd3d_spirv_build_op(&builder->function_stream, SpvOpReturn);
 }
 
+static uint32_t vkd3d_spirv_build_op_bitcast(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpBitcast, result_type, operand);
+}
+
 static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder,
         enum vkd3d_component_type component_type, unsigned int component_count)
 {
@@ -604,6 +719,17 @@ struct vkd3d_symbol_pointer_type
     SpvStorageClass storage_class;
 };
 
+struct vkd3d_symbol_constant
+{
+    unsigned int component_count;
+    enum vkd3d_component_type component_type;
+    union
+    {
+        float f[VKD3D_VEC4_SIZE];
+        uint32_t u[VKD3D_VEC4_SIZE];
+    } value;
+};
+
 struct vkd3d_symbol_register
 {
     enum vkd3d_shader_register_type type;
@@ -617,12 +743,14 @@ struct vkd3d_symbol
     enum
     {
         VKD3D_SYMBOL_POINTER_TYPE,
+        VKD3D_SYMBOL_CONSTANT,
         VKD3D_SYMBOL_REGISTER,
     } type;
 
     union
     {
         struct vkd3d_symbol_pointer_type pointer_type;
+        struct vkd3d_symbol_constant constant;
         struct vkd3d_symbol_register reg;
     } key;
 
@@ -659,6 +787,16 @@ static void vkd3d_symbol_make_pointer_type(struct vkd3d_symbol *symbol,
     symbol->key.pointer_type.storage_class = storage_class;
 }
 
+static void vkd3d_symbol_make_constant(struct vkd3d_symbol *symbol,
+        enum vkd3d_component_type component_type, unsigned int component_count, const uint32_t *values)
+{
+    symbol->type = VKD3D_SYMBOL_CONSTANT;
+    memset(&symbol->key, 0, sizeof(symbol->key));
+    symbol->key.constant.component_type = component_type;
+    symbol->key.constant.component_count = component_count;
+    memcpy(symbol->key.constant.value.u, values, sizeof(*values) * component_count);
+}
+
 static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
         const struct vkd3d_shader_register *reg)
 {
@@ -758,6 +896,55 @@ static uint32_t vkd3d_dxbc_compiler_get_pointer_type(struct vkd3d_dxbc_compiler
     return pointer_type.id;
 }
 
+static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_component_type component_type, unsigned int component_count, const uint32_t *values)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+    uint32_t component_ids[VKD3D_VEC4_SIZE];
+    struct vkd3d_symbol constant;
+    struct rb_entry *entry;
+    unsigned int i;
+
+    assert(0 < component_count && component_count <= VKD3D_VEC4_SIZE);
+
+    vkd3d_symbol_make_constant(&constant, component_type, component_count, values);
+    if ((entry = rb_get(&compiler->symbol_table, &constant)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry)->id;
+
+    switch (component_type)
+    {
+        case VKD3D_TYPE_UINT:
+        case VKD3D_TYPE_INT:
+        case VKD3D_TYPE_FLOAT:
+            break;
+        default:
+            FIXME("Unhandled component_type %#x.\n", component_type);
+            return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
+    }
+
+    if (component_count == 1)
+    {
+        constant.id = vkd3d_spirv_build_op_constant(builder, type_id, *values);
+    }
+    else
+    {
+        for (i = 0; i < component_count; ++i)
+            component_ids[i] = vkd3d_dxbc_compiler_get_constant(compiler, component_type, 1, &values[i]);
+        constant.id = vkd3d_spirv_build_op_constant_composite(builder, type_id, component_ids, component_count);
+    }
+
+    vkd3d_dxbc_compiler_put_symbol(compiler, &constant);
+
+    return constant.id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_uint(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t value)
+{
+    return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_TYPE_UINT, 1, &value);
+}
+
 static bool vkd3d_dxbc_compiler_get_register_name(char *buffer,const struct vkd3d_shader_register *reg)
 {
     switch (reg->type)
@@ -801,6 +988,278 @@ static uint32_t vkd3d_dxbc_compiler_emit_variable(struct vkd3d_dxbc_compiler *co
     return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class);
 }
 
+static uint32_t vkd3d_dxbc_compiler_emit_undef(struct vkd3d_dxbc_compiler *compiler,
+        struct vkd3d_spirv_stream *stream, const struct vkd3d_shader_register *reg)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
+    ptr_type_id = vkd3d_dxbc_compiler_get_pointer_type(compiler, type_id, SpvStorageClassPrivate);
+    return vkd3d_spirv_build_op_undef(builder, stream, ptr_type_id);
+}
+
+struct vkd3d_dxbc_register_info
+{
+    uint32_t id;
+    SpvStorageClass storage_class;
+};
+
+static void vkd3d_dxbc_compiler_get_register_info(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, struct vkd3d_dxbc_register_info *register_info)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_symbol reg_symbol, *symbol;
+    struct rb_entry *entry;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+
+    if (reg->idx[0].rel_addr || reg->idx[1].rel_addr)
+        FIXME("Relative indexing not implemented.\n");
+
+    if (reg->type == VKD3DSPR_TEMP)
+    {
+        assert(reg->idx[0].offset < compiler->temp_count);
+        register_info->id = compiler->temp_id + reg->idx[0].offset;
+        register_info->storage_class = SpvStorageClassFunction;
+        return;
+    }
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    entry = rb_get(&compiler->symbol_table, &reg_symbol);
+    assert(entry);
+    symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+    register_info->id = symbol->id;
+    register_info->storage_class = symbol->info.storage_class;
+
+    if (reg->type == VKD3DSPR_CONSTBUFFER)
+    {
+        uint32_t type_id, ptr_type_id;
+        uint32_t indexes[] =
+        {
+            vkd3d_dxbc_compiler_get_constant_uint(compiler, 0),
+            vkd3d_dxbc_compiler_get_constant_uint(compiler, reg->idx[1].offset),
+        };
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
+        ptr_type_id = vkd3d_dxbc_compiler_get_pointer_type(compiler,
+                type_id, register_info->storage_class);
+        register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
+                register_info->id, indexes, ARRAY_SIZE(indexes));
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_register_id(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_dxbc_register_info register_info;
+    unsigned int component_count;
+
+    switch (reg->type)
+    {
+        case VKD3DSPR_TEMP:
+        case VKD3DSPR_INPUT:
+        case VKD3DSPR_OUTPUT:
+        case VKD3DSPR_COLOROUT:
+        case VKD3DSPR_CONSTBUFFER:
+            vkd3d_dxbc_compiler_get_register_info(compiler, reg, &register_info);
+            return register_info.id;
+        case VKD3DSPR_IMMCONST:
+            if (reg->immconst_type == VKD3D_IMMCONST_SCALAR)
+            {
+                component_count = 1;
+            }
+            else if (reg->immconst_type == VKD3D_IMMCONST_VEC4)
+            {
+                component_count = VKD3D_VEC4_SIZE;
+            }
+            else
+            {
+                FIXME("Unhandled immconst type %#x.\n", reg->immconst_type);
+                component_count = 1;
+            }
+            return vkd3d_dxbc_compiler_get_constant(compiler,
+                    vkd3d_component_type_from_data_type(reg->data_type),
+                    component_count, reg->u.immconst_data);
+        default:
+            FIXME("Unhandled register type %#x.\n", reg->type);
+            return vkd3d_dxbc_compiler_emit_undef(compiler, &builder->global_stream, reg);
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_constant(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+    uint32_t values[VKD3D_VEC4_SIZE];
+    unsigned int i, j;
+
+    assert(reg->type == VKD3DSPR_IMMCONST);
+
+    if (component_count == 1 || component_count == VKD3D_VEC4_SIZE)
+    {
+        assert(component_count != 1 || reg->immconst_type == VKD3D_IMMCONST_SCALAR);
+        return vkd3d_dxbc_compiler_get_register_id(compiler, reg);
+    }
+
+    assert(reg->immconst_type == VKD3D_IMMCONST_VEC4);
+
+    for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            values[j++] = reg->u.immconst_data[vkd3d_swizzle_get_component(swizzle, i)];
+    }
+
+    return vkd3d_dxbc_compiler_get_constant(compiler,
+            vkd3d_component_type_from_data_type(reg->data_type), component_count, values);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_scalar(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id, indexes[1], chain_id, val_id;
+    struct vkd3d_dxbc_register_info reg_info;
+    unsigned int component_idx;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+    assert(vkd3d_write_mask_component_count(write_mask) == 1);
+
+    component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+    component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
+
+    vkd3d_dxbc_compiler_get_register_info(compiler, reg, &reg_info);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
+    ptr_type_id = vkd3d_dxbc_compiler_get_pointer_type(compiler, type_id, reg_info.storage_class);
+    indexes[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
+    chain_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder,
+            ptr_type_id, reg_info.id, indexes, ARRAY_SIZE(indexes));
+
+    val_id = vkd3d_spirv_build_op_load(builder, type_id, chain_id, SpvMemoryAccessMaskNone);
+
+    if (reg->data_type != VKD3D_DATA_FLOAT)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder,
+                vkd3d_component_type_from_data_type(reg->data_type), 1);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    return val_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_reg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t src_id, type_id, val_id, components[VKD3D_VEC4_SIZE];
+    unsigned int i, component_idx, component_count;
+
+    if (reg->type == VKD3DSPR_IMMCONST)
+        return vkd3d_dxbc_compiler_emit_load_constant(compiler, reg, swizzle, write_mask);
+
+    component_count = vkd3d_write_mask_component_count(write_mask);
+    if (component_count == 1)
+        return vkd3d_dxbc_compiler_emit_load_scalar(compiler, reg, swizzle, write_mask);
+
+    src_id = vkd3d_dxbc_compiler_get_register_id(compiler, reg);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
+    val_id = vkd3d_spirv_build_op_load(builder, type_id, src_id, SpvMemoryAccessMaskNone);
+
+    if (component_count != VKD3D_VEC4_SIZE || swizzle != VKD3DSP_NOSWIZZLE)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
+
+        for (i = 0, component_idx = 0; i < ARRAY_SIZE(components); ++i)
+        {
+            if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+                components[component_idx++] = vkd3d_swizzle_get_component(swizzle, i);
+        }
+
+        val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
+                type_id, val_id, val_id, components, component_count);
+    }
+
+    if (reg->data_type != VKD3D_DATA_FLOAT)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder,
+                vkd3d_component_type_from_data_type(reg->data_type), component_count);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    return val_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_store_scalar(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id, chain_id, index[1];
+    struct vkd3d_dxbc_register_info reg_info;
+    unsigned int component_idx;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+
+    vkd3d_dxbc_compiler_get_register_info(compiler, reg, &reg_info);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
+    ptr_type_id = vkd3d_dxbc_compiler_get_pointer_type(compiler,
+            type_id, reg_info.storage_class);
+    component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+    index[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
+    chain_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder,
+            ptr_type_id, reg_info.id, index, ARRAY_SIZE(index));
+
+    vkd3d_spirv_build_op_store(builder, chain_id, val_id, SpvMemoryAccessMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_reg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int i, component_idx, component_count;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    uint32_t reg_id;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+
+    component_count = vkd3d_write_mask_component_count(write_mask);
+
+    if (reg->data_type != VKD3D_DATA_FLOAT)
+    {
+        uint32_t type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    if (component_count == 1)
+        return vkd3d_dxbc_compiler_emit_store_scalar(compiler, reg, write_mask, val_id);
+
+    if (component_count != VKD3D_VEC4_SIZE)
+    {
+        uint32_t type_id, reg_val_id;
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
+
+        reg_val_id = vkd3d_dxbc_compiler_emit_load_reg(compiler,
+                reg, VKD3DSP_NOSWIZZLE, VKD3DSP_WRITEMASK_ALL);
+
+        for (i = 0, component_idx = 0; i < ARRAY_SIZE(components); ++i)
+        {
+            if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+                components[i] = VKD3D_VEC4_SIZE + component_idx++;
+            else
+                components[i] = i;
+        }
+
+        val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
+                type_id, reg_val_id, val_id, components, ARRAY_SIZE(components));
+    }
+
+    reg_id = vkd3d_dxbc_compiler_get_register_id(compiler, reg);
+    vkd3d_spirv_build_op_store(builder, reg_id, val_id, SpvMemoryAccessMaskNone);
+}
+
 static void vkd3d_dxbc_compiler_decorate_sysval(struct vkd3d_spirv_builder *builder,
         uint32_t target_id, enum vkd3d_shader_input_sysval_semantic sysval)
 {
@@ -899,6 +1358,17 @@ static void vkd3d_dxbc_compiler_emit_dcl_thread_group(struct vkd3d_dxbc_compiler
     vkd3d_spirv_set_local_size(builder, group_size->x, group_size->y, group_size->z);
 }
 
+static void vkd3d_dxbc_compiler_emit_mov(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_dst_param *dst = &instruction->dst[0];
+    const struct vkd3d_shader_src_param *src = &instruction->src[0];
+    uint32_t val_id;
+
+    val_id = vkd3d_dxbc_compiler_emit_load_reg(compiler, &src->reg, src->swizzle, dst->write_mask);
+    vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id);
+}
+
 static void vkd3d_dxbc_compiler_emit_return(struct vkd3d_dxbc_compiler *compiler,
         const struct vkd3d_shader_instruction *instruction)
 {
@@ -922,6 +1392,9 @@ void vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler
         case VKD3DSIH_DCL_THREAD_GROUP:
             vkd3d_dxbc_compiler_emit_dcl_thread_group(compiler, instruction);
             break;
+        case VKD3DSIH_MOV:
+            vkd3d_dxbc_compiler_emit_mov(compiler, instruction);
+            break;
         case VKD3DSIH_RET:
             vkd3d_dxbc_compiler_emit_return(compiler, instruction);
             break;
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index c4ebeb1674..050b57e6c0 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -827,4 +827,55 @@ bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
         struct vkd3d_shader_code *spirv) DECLSPEC_HIDDEN;
 void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler) DECLSPEC_HIDDEN;
 
+static inline enum vkd3d_component_type vkd3d_component_type_from_data_type(
+        enum vkd3d_data_type data_type)
+{
+    switch (data_type)
+    {
+        case VKD3D_DATA_FLOAT:
+            return VKD3D_TYPE_FLOAT;
+        case VKD3D_DATA_UINT:
+            return VKD3D_TYPE_UINT;
+        case VKD3D_DATA_INT:
+            return VKD3D_TYPE_INT;
+        default:
+            FIXME("Unhandled data type %#x.\n", data_type);
+            return VKD3D_TYPE_UINT;
+    }
+}
+
+static inline unsigned int vkd3d_write_mask_get_component_idx(DWORD write_mask)
+{
+    unsigned int i;
+
+    for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            return i;
+    }
+
+    FIXME("Invalid write mask %#x.\n", write_mask);
+    return 0;
+}
+
+static inline unsigned int vkd3d_write_mask_component_count(DWORD write_mask)
+{
+    unsigned int i, count = 0;
+
+    for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            ++count;
+    }
+
+    return count;
+}
+
+static inline unsigned int vkd3d_swizzle_get_component(DWORD swizzle,
+        unsigned int idx)
+{
+    /* swizzle bits fields: wwzzyyxx */
+    return (swizzle >> (2 * idx)) & 0x3;
+}
+
 #endif  /* __VKD3D_SHADER_PRIVATE_H */
-- 
GitLab