diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c
index 1145a91f3e66d39d34ceb606b903e0c40899832f..3b9ec98448d1834701cbffe2d31867a6d8472075 100644
--- a/libs/vkd3d-shader/d3dbc.c
+++ b/libs/vkd3d-shader/d3dbc.c
@@ -1468,9 +1468,11 @@ bool hlsl_sm1_usage_from_semantic(const char *semantic_name,
 
 struct d3dbc_compiler
 {
+    const struct vkd3d_sm1_opcode_info *opcode_table;
     struct vsir_program *program;
     struct vkd3d_bytecode_buffer buffer;
     struct vkd3d_shader_message_context *message_context;
+    bool failed;
 
     /* OBJECTIVE: Store all the required information in the other fields so
      * that this hlsl_ctx is no longer necessary. */
@@ -2169,31 +2171,221 @@ static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_
     }
 }
 
-static void d3dbc_write_constant_defs(struct d3dbc_compiler *d3dbc)
+static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir(
+        struct d3dbc_compiler *d3dbc, enum vkd3d_shader_opcode vkd3d_opcode)
+{
+    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
+    const struct vkd3d_sm1_opcode_info *info;
+    unsigned int i = 0;
+
+    for (;;)
+    {
+        info = &d3dbc->opcode_table[i++];
+        if (info->vkd3d_opcode == VKD3DSIH_INVALID)
+            return NULL;
+
+        if (vkd3d_opcode == info->vkd3d_opcode
+                && vkd3d_shader_ver_ge(version, info->min_version.major, info->min_version.minor)
+                && (vkd3d_shader_ver_le(version, info->max_version.major, info->max_version.minor)
+                        || !info->max_version.major))
+            return info;
+    }
+}
+
+static uint32_t swizzle_from_vsir(uint32_t swizzle)
+{
+    uint32_t x = vsir_swizzle_get_component(swizzle, 0);
+    uint32_t y = vsir_swizzle_get_component(swizzle, 1);
+    uint32_t z = vsir_swizzle_get_component(swizzle, 2);
+    uint32_t w = vsir_swizzle_get_component(swizzle, 3);
+
+    if (x & ~0x3u || y & ~0x3u || z & ~0x3u || w & ~0x3u)
+        ERR("Unexpected vsir swizzle: 0x%08x.\n", swizzle);
+
+    return ((x & 0x3u) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(0))
+            | ((y & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(1))
+            | ((z & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(2))
+            | ((w & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(3));
+}
+
+static void sm1_src_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_src_param *param,
+        struct sm1_src_register *src, const struct vkd3d_shader_location *loc)
+{
+    src->mod = (uint32_t)param->modifiers << VKD3D_SM1_SRC_MODIFIER_SHIFT;
+    src->reg = param->reg.idx[0].offset;
+    src->type = param->reg.type;
+    src->swizzle = swizzle_from_vsir(param->swizzle);
+
+    if (param->reg.idx[0].rel_addr)
+    {
+        vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED,
+                "Unhandled relative addressing on source register.");
+        d3dbc->failed = true;
+    }
+}
+
+static void sm1_dst_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_dst_param *param,
+        struct sm1_dst_register *dst, const struct vkd3d_shader_location *loc)
+{
+    dst->mod = (uint32_t)param->modifiers << VKD3D_SM1_DST_MODIFIER_SHIFT;
+    dst->reg = param->reg.idx[0].offset;
+    dst->type = param->reg.type;
+    dst->writemask = param->write_mask;
+
+    if (param->reg.idx[0].rel_addr)
+    {
+        vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED,
+                "Unhandled relative addressing on destination register.");
+        d3dbc->failed = true;
+    }
+}
+
+static void d3dbc_write_vsir_def(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins)
 {
     const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
     struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer;
-    struct hlsl_ctx *ctx = d3dbc->ctx;
-    unsigned int i, x;
+    uint32_t token;
 
-    for (i = 0; i < ctx->constant_defs.count; ++i)
+    const struct sm1_dst_register reg =
     {
-        const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i];
-        uint32_t token = D3DSIO_DEF;
-        const struct sm1_dst_register reg =
-        {
-            .type = VKD3DSPR_CONST,
-            .writemask = VKD3DSP_WRITEMASK_ALL,
-            .reg = constant_reg->index,
-        };
+        .type = VKD3DSPR_CONST,
+        .writemask = VKD3DSP_WRITEMASK_ALL,
+        .reg = ins->dst[0].reg.idx[0].offset,
+    };
+
+    token = VKD3D_SM1_OP_DEF;
+    if (version->major > 1)
+        token |= 5 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT;
+    put_u32(buffer, token);
 
-        if (version->major > 1)
-            token |= 5 << D3DSI_INSTLENGTH_SHIFT;
-        put_u32(buffer, token);
+    write_sm1_dst_register(buffer, &reg);
+    for (unsigned int x = 0; x < 4; ++x)
+        put_f32(buffer, ins->src[0].reg.u.immconst_f32[x]);
+}
+
+static void d3dbc_write_vsir_sampler_dcl(struct d3dbc_compiler *d3dbc,
+        unsigned int reg_id, enum vkd3d_sm1_resource_type res_type)
+{
+    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
+    struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer;
+    struct sm1_dst_register reg = {0};
+    uint32_t token;
+
+    token = VKD3D_SM1_OP_DCL;
+    if (version->major > 1)
+        token |= 2 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT;
+    put_u32(buffer, token);
+
+    token = VKD3D_SM1_INSTRUCTION_PARAMETER;
+    token |= res_type << VKD3D_SM1_RESOURCE_TYPE_SHIFT;
+    put_u32(buffer, token);
+
+    reg.type = VKD3DSPR_COMBINED_SAMPLER;
+    reg.writemask = VKD3DSP_WRITEMASK_ALL;
+    reg.reg = reg_id;
+
+    write_sm1_dst_register(buffer, &reg);
+}
+
+static void d3dbc_write_vsir_dcl(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins)
+{
+    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
+    const struct vkd3d_shader_semantic *semantic = &ins->declaration.semantic;
+    unsigned int reg_id;
 
-        write_sm1_dst_register(buffer, &reg);
-        for (x = 0; x < 4; ++x)
-            put_f32(buffer, constant_reg->value.f[x]);
+    if (version->major < 2)
+        return;
+
+    reg_id = semantic->resource.reg.reg.idx[0].offset;
+
+    if (semantic->resource.reg.reg.type != VKD3DSPR_SAMPLER)
+    {
+        vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE,
+                "dcl instruction with register type %u.", semantic->resource.reg.reg.type);
+        d3dbc->failed = true;
+        return;
+    }
+
+    switch (semantic->resource_type)
+    {
+        case VKD3D_SHADER_RESOURCE_TEXTURE_2D:
+            d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_2D);
+            break;
+
+        case VKD3D_SHADER_RESOURCE_TEXTURE_CUBE:
+            d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_CUBE);
+            break;
+
+        case VKD3D_SHADER_RESOURCE_TEXTURE_3D:
+            d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_3D);
+            break;
+
+        default:
+            vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_RESOURCE_TYPE,
+                   "dcl instruction with resource_type %u.", semantic->resource_type);
+            d3dbc->failed = true;
+            return;
+    }
+}
+
+static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc,
+        const struct vkd3d_shader_instruction *ins)
+{
+    const struct vkd3d_sm1_opcode_info *info;
+    struct sm1_instruction instr = {0};
+
+    info = shader_sm1_get_opcode_info_from_vsir(d3dbc, ins->opcode);
+
+    if (ins->dst_count != info->dst_count)
+    {
+        vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT,
+                "Invalid destination count %u for vsir instruction %#x (expected %u).",
+                ins->dst_count, ins->opcode, info->dst_count);
+        d3dbc->failed = true;
+        return;
+    }
+    if (ins->src_count != info->src_count)
+    {
+        vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT,
+                "Invalid source count %u for vsir instruction %#x (expected %u).",
+                ins->src_count, ins->opcode, info->src_count);
+        d3dbc->failed = true;
+        return;
+    }
+
+    instr.opcode = (D3DSHADER_INSTRUCTION_OPCODE_TYPE)info->sm1_opcode;
+    instr.has_dst = info->dst_count;
+    instr.src_count = info->src_count;
+
+    if (instr.has_dst)
+        sm1_dst_reg_from_vsir(d3dbc, &ins->dst[0], &instr.dst, &ins->location);
+    for (unsigned int i = 0; i < instr.src_count; ++i)
+        sm1_src_reg_from_vsir(d3dbc, &ins->src[i], &instr.srcs[i], &ins->location);
+
+    d3dbc_write_instruction(d3dbc, &instr);
+}
+
+static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins)
+{
+    switch (ins->opcode)
+    {
+        case VKD3DSIH_DEF:
+            d3dbc_write_vsir_def(d3dbc, ins);
+            break;
+
+        case VKD3DSIH_DCL:
+            d3dbc_write_vsir_dcl(d3dbc, ins);
+            break;
+
+        case VKD3DSIH_MOV:
+            d3dbc_write_vsir_simple_instruction(d3dbc, ins);
+            break;
+
+        default:
+            vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE,
+                   "vsir instruction with opcode %#x.", ins->opcode);
+            d3dbc->failed = true;
+            break;
     }
 }
 
@@ -2262,110 +2454,6 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc)
     }
 }
 
-static void d3dbc_write_sampler_dcl(struct d3dbc_compiler *d3dbc,
-        unsigned int reg_id, enum hlsl_sampler_dim sampler_dim)
-{
-    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
-    struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer;
-    struct sm1_dst_register reg = {0};
-    uint32_t token, res_type = 0;
-
-    token = D3DSIO_DCL;
-    if (version->major > 1)
-        token |= 2 << D3DSI_INSTLENGTH_SHIFT;
-    put_u32(buffer, token);
-
-    switch (sampler_dim)
-    {
-        case HLSL_SAMPLER_DIM_2D:
-            res_type = VKD3D_SM1_RESOURCE_TEXTURE_2D;
-            break;
-
-        case HLSL_SAMPLER_DIM_CUBE:
-            res_type = VKD3D_SM1_RESOURCE_TEXTURE_CUBE;
-            break;
-
-        case HLSL_SAMPLER_DIM_3D:
-            res_type = VKD3D_SM1_RESOURCE_TEXTURE_3D;
-            break;
-
-        default:
-            vkd3d_unreachable();
-            break;
-    }
-
-    token = (1u << 31);
-    token |= res_type << VKD3D_SM1_RESOURCE_TYPE_SHIFT;
-    put_u32(buffer, token);
-
-    reg.type = VKD3DSPR_COMBINED_SAMPLER;
-    reg.writemask = VKD3DSP_WRITEMASK_ALL;
-    reg.reg = reg_id;
-
-    write_sm1_dst_register(buffer, &reg);
-}
-
-static void d3dbc_write_sampler_dcls(struct d3dbc_compiler *d3dbc)
-{
-    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
-    struct hlsl_ctx *ctx = d3dbc->ctx;
-    enum hlsl_sampler_dim sampler_dim;
-    unsigned int i, count, reg_id;
-    struct hlsl_ir_var *var;
-
-    if (version->major < 2)
-        return;
-
-    LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
-    {
-        if (!var->regs[HLSL_REGSET_SAMPLERS].allocated)
-            continue;
-
-        count = var->bind_count[HLSL_REGSET_SAMPLERS];
-
-        for (i = 0; i < count; ++i)
-        {
-            if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used)
-            {
-                sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim;
-                if (sampler_dim == HLSL_SAMPLER_DIM_GENERIC)
-                {
-                    /* These can appear in sm4-style combined sample instructions. */
-                    hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered.");
-                    continue;
-                }
-
-                reg_id = var->regs[HLSL_REGSET_SAMPLERS].index + i;
-                d3dbc_write_sampler_dcl(d3dbc, reg_id, sampler_dim);
-            }
-        }
-    }
-}
-
-static void d3dbc_write_constant(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr)
-{
-    const struct hlsl_ir_constant *constant = hlsl_ir_constant(instr);
-    struct sm1_instruction sm1_instr =
-    {
-        .opcode = D3DSIO_MOV,
-
-        .dst.type = VKD3DSPR_TEMP,
-        .dst.reg = instr->reg.id,
-        .dst.writemask = instr->reg.writemask,
-        .has_dst = 1,
-
-        .srcs[0].type = VKD3DSPR_CONST,
-        .srcs[0].reg = constant->reg.id,
-        .srcs[0].swizzle = hlsl_swizzle_from_writemask(constant->reg.writemask),
-        .src_count = 1,
-    };
-
-    VKD3D_ASSERT(instr->reg.allocated);
-    VKD3D_ASSERT(constant->reg.allocated);
-    sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask);
-    d3dbc_write_instruction(d3dbc, &sm1_instr);
-}
-
 static void d3dbc_write_per_component_unary_op(struct d3dbc_compiler *d3dbc,
         const struct hlsl_ir_node *instr, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode)
 {
@@ -2636,50 +2724,6 @@ static void d3dbc_write_jump(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_
     }
 }
 
-static void d3dbc_write_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr)
-{
-    const struct hlsl_ir_load *load = hlsl_ir_load(instr);
-    struct hlsl_ctx *ctx = d3dbc->ctx;
-    const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &load->src);
-    struct sm1_instruction sm1_instr =
-    {
-        .opcode = D3DSIO_MOV,
-
-        .dst.type = VKD3DSPR_TEMP,
-        .dst.reg = instr->reg.id,
-        .dst.writemask = instr->reg.writemask,
-        .has_dst = 1,
-
-        .srcs[0].type = VKD3DSPR_TEMP,
-        .srcs[0].reg = reg.id,
-        .srcs[0].swizzle = hlsl_swizzle_from_writemask(reg.writemask),
-        .src_count = 1,
-    };
-
-    VKD3D_ASSERT(instr->reg.allocated);
-
-    if (load->src.var->is_uniform)
-    {
-        VKD3D_ASSERT(reg.allocated);
-        sm1_instr.srcs[0].type = VKD3DSPR_CONST;
-    }
-    else if (load->src.var->is_input_semantic)
-    {
-        if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, load->src.var->semantic.name,
-                load->src.var->semantic.index, false, &sm1_instr.srcs[0].type, &sm1_instr.srcs[0].reg))
-        {
-            VKD3D_ASSERT(reg.allocated);
-            sm1_instr.srcs[0].type = VKD3DSPR_INPUT;
-            sm1_instr.srcs[0].reg = reg.id;
-        }
-        else
-            sm1_instr.srcs[0].swizzle = hlsl_swizzle_from_writemask((1 << load->src.var->data_type->dimx) - 1);
-    }
-
-    sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask);
-    d3dbc_write_instruction(d3dbc, &sm1_instr);
-}
-
 static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr)
 {
     const struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr);
@@ -2751,82 +2795,12 @@ static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct
     d3dbc_write_instruction(d3dbc, &sm1_instr);
 }
 
-static void d3dbc_write_store(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr)
-{
-    const struct vkd3d_shader_version *version = &d3dbc->program->shader_version;
-    const struct hlsl_ir_store *store = hlsl_ir_store(instr);
-    struct hlsl_ctx *ctx = d3dbc->ctx;
-    const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &store->lhs);
-    const struct hlsl_ir_node *rhs = store->rhs.node;
-    struct sm1_instruction sm1_instr =
-    {
-        .opcode = D3DSIO_MOV,
-
-        .dst.type = VKD3DSPR_TEMP,
-        .dst.reg = reg.id,
-        .dst.writemask = hlsl_combine_writemasks(reg.writemask, store->writemask),
-        .has_dst = 1,
-
-        .srcs[0].type = VKD3DSPR_TEMP,
-        .srcs[0].reg = rhs->reg.id,
-        .srcs[0].swizzle = hlsl_swizzle_from_writemask(rhs->reg.writemask),
-        .src_count = 1,
-    };
-
-    if (store->lhs.var->is_output_semantic)
-    {
-        if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 1)
-        {
-            sm1_instr.dst.type = VKD3DSPR_TEMP;
-            sm1_instr.dst.reg = 0;
-        }
-        else if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, store->lhs.var->semantic.name,
-                store->lhs.var->semantic.index, true, &sm1_instr.dst.type, &sm1_instr.dst.reg))
-        {
-            VKD3D_ASSERT(reg.allocated);
-            sm1_instr.dst.type = VKD3DSPR_OUTPUT;
-            sm1_instr.dst.reg = reg.id;
-        }
-        else
-            sm1_instr.dst.writemask = (1u << store->lhs.var->data_type->dimx) - 1;
-    }
-    else
-        VKD3D_ASSERT(reg.allocated);
-
-    sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask);
-    d3dbc_write_instruction(d3dbc, &sm1_instr);
-}
-
-static void d3dbc_write_swizzle(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr)
-{
-    const struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(instr);
-    const struct hlsl_ir_node *val = swizzle->val.node;
-    struct sm1_instruction sm1_instr =
-    {
-        .opcode = D3DSIO_MOV,
-
-        .dst.type = VKD3DSPR_TEMP,
-        .dst.reg = instr->reg.id,
-        .dst.writemask = instr->reg.writemask,
-        .has_dst = 1,
-
-        .srcs[0].type = VKD3DSPR_TEMP,
-        .srcs[0].reg = val->reg.id,
-        .srcs[0].swizzle = hlsl_combine_swizzles(hlsl_swizzle_from_writemask(val->reg.writemask),
-                swizzle->swizzle, instr->data_type->dimx),
-        .src_count = 1,
-    };
-
-    VKD3D_ASSERT(instr->reg.allocated);
-    VKD3D_ASSERT(val->reg.allocated);
-    sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask);
-    d3dbc_write_instruction(d3dbc, &sm1_instr);
-}
-
 static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block)
 {
+    struct vkd3d_shader_instruction *vsir_instr;
     struct hlsl_ctx *ctx = d3dbc->ctx;
     const struct hlsl_ir_node *instr;
+    unsigned int vsir_instr_idx;
 
     LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry)
     {
@@ -2844,10 +2818,6 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl
             case HLSL_IR_CALL:
                 vkd3d_unreachable();
 
-            case HLSL_IR_CONSTANT:
-                d3dbc_write_constant(d3dbc, instr);
-                break;
-
             case HLSL_IR_EXPR:
                 d3dbc_write_expr(d3dbc, instr);
                 break;
@@ -2863,20 +2833,14 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl
                 d3dbc_write_jump(d3dbc, instr);
                 break;
 
-            case HLSL_IR_LOAD:
-                d3dbc_write_load(d3dbc, instr);
-                break;
-
             case HLSL_IR_RESOURCE_LOAD:
                 d3dbc_write_resource_load(d3dbc, instr);
                 break;
 
-            case HLSL_IR_STORE:
-                d3dbc_write_store(d3dbc, instr);
-                break;
-
-            case HLSL_IR_SWIZZLE:
-                d3dbc_write_swizzle(d3dbc, instr);
+            case HLSL_IR_VSIR_INSTRUCTION_REF:
+                vsir_instr_idx = hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx;
+                vsir_instr = &d3dbc->program->instructions.elements[vsir_instr_idx];
+                d3dbc_write_vsir_instruction(d3dbc, vsir_instr);
                 break;
 
             default:
@@ -2897,26 +2861,43 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags,
     const struct vkd3d_shader_version *version = &program->shader_version;
     struct d3dbc_compiler d3dbc = {0};
     struct vkd3d_bytecode_buffer *buffer = &d3dbc.buffer;
+    int result;
 
     d3dbc.ctx = ctx;
     d3dbc.program = program;
     d3dbc.message_context = message_context;
+    switch (version->type)
+    {
+        case VKD3D_SHADER_TYPE_VERTEX:
+            d3dbc.opcode_table = vs_opcode_table;
+            break;
+
+        case VKD3D_SHADER_TYPE_PIXEL:
+            d3dbc.opcode_table = ps_opcode_table;
+            break;
+
+        default:
+            vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE,
+                    "Invalid shader type %u.", version->type);
+            return VKD3D_ERROR_INVALID_SHADER;
+    }
 
     put_u32(buffer, sm1_version(version->type, version->major, version->minor));
 
     bytecode_put_bytes(buffer, ctab->code, ctab->size);
 
-    d3dbc_write_constant_defs(&d3dbc);
     d3dbc_write_semantic_dcls(&d3dbc);
-    d3dbc_write_sampler_dcls(&d3dbc);
     d3dbc_write_block(&d3dbc, &entry_func->body);
 
     put_u32(buffer, D3DSIO_END);
 
+    result = ctx->result;
     if (buffer->status)
-        ctx->result = buffer->status;
+        result = buffer->status;
+    if (d3dbc.failed)
+        result = VKD3D_ERROR_INVALID_SHADER;
 
-    if (!ctx->result)
+    if (!result)
     {
         out->code = buffer->data;
         out->size = buffer->size;
@@ -2925,5 +2906,5 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags,
     {
         vkd3d_free(buffer->data);
     }
-    return ctx->result;
+    return result;
 }
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index bd5baacd83dc8e9bcae619276e1a4c8f7c7ba811..7a924183207b19b44d856f591cf69c10bb33fccd 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -1640,6 +1640,22 @@ struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *
     return &s->node;
 }
 
+struct hlsl_ir_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx,
+        struct hlsl_type *type, const struct hlsl_reg *reg, const struct vkd3d_shader_location *loc)
+{
+    struct hlsl_ir_vsir_instruction_ref *vsir_instr;
+
+    if (!(vsir_instr = hlsl_alloc(ctx, sizeof(*vsir_instr))))
+        return NULL;
+    init_node(&vsir_instr->node, HLSL_IR_VSIR_INSTRUCTION_REF, type, loc);
+    vsir_instr->vsir_instr_idx = vsir_instr_idx;
+
+    if (reg)
+        vsir_instr->node.reg = *reg;
+
+    return &vsir_instr->node;
+}
+
 struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl_deref *deref,
         struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc)
 {
@@ -2286,6 +2302,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx,
 
         case HLSL_IR_STATEBLOCK_CONSTANT:
             return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr));
+
+        case HLSL_IR_VSIR_INSTRUCTION_REF:
+            vkd3d_unreachable();
     }
 
     vkd3d_unreachable();
@@ -2699,6 +2718,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type)
         [HLSL_IR_SWITCH         ] = "HLSL_IR_SWITCH",
         [HLSL_IR_SWIZZLE        ] = "HLSL_IR_SWIZZLE",
         [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT",
+        [HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF",
     };
 
     if (type >= ARRAY_SIZE(names))
@@ -3248,6 +3268,11 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer,
         case HLSL_IR_STATEBLOCK_CONSTANT:
             dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr));
             break;
+
+        case HLSL_IR_VSIR_INSTRUCTION_REF:
+            vkd3d_string_buffer_printf(buffer, "vsir_program instruction %u",
+                    hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx);
+            break;
     }
 }
 
@@ -3308,8 +3333,8 @@ void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new)
 {
     struct hlsl_src *src, *next;
 
-    VKD3D_ASSERT(old->data_type->dimx == new->data_type->dimx);
-    VKD3D_ASSERT(old->data_type->dimy == new->data_type->dimy);
+    VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimx == new->data_type->dimx);
+    VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimy == new->data_type->dimy);
 
     LIST_FOR_EACH_ENTRY_SAFE(src, next, &old->uses, struct hlsl_src, entry)
     {
@@ -3530,6 +3555,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node)
         case HLSL_IR_STATEBLOCK_CONSTANT:
             free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node));
             break;
+
+        case HLSL_IR_VSIR_INSTRUCTION_REF:
+            vkd3d_free(hlsl_ir_vsir_instruction_ref(node));
+            break;
     }
 }
 
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index d03a70f512588c68a9ab1da2d48a8e527997646d..a4f8450678e6a93e5691a1c4069aef024ce3f58b 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -70,6 +70,14 @@ static inline unsigned int hlsl_swizzle_get_component(uint32_t swizzle, unsigned
     return (swizzle >> HLSL_SWIZZLE_SHIFT(idx)) & HLSL_SWIZZLE_MASK;
 }
 
+static inline uint32_t vsir_swizzle_from_hlsl(uint32_t swizzle)
+{
+    return vkd3d_shader_create_swizzle(hlsl_swizzle_get_component(swizzle, 0),
+            hlsl_swizzle_get_component(swizzle, 1),
+            hlsl_swizzle_get_component(swizzle, 2),
+            hlsl_swizzle_get_component(swizzle, 3));
+}
+
 enum hlsl_type_class
 {
     HLSL_CLASS_SCALAR,
@@ -317,6 +325,8 @@ enum hlsl_ir_node_type
     HLSL_IR_SWIZZLE,
     HLSL_IR_SWITCH,
     HLSL_IR_STATEBLOCK_CONSTANT,
+
+    HLSL_IR_VSIR_INSTRUCTION_REF,
 };
 
 /* Common data for every type of IR instruction node. */
@@ -862,6 +872,16 @@ struct hlsl_ir_stateblock_constant
     char *name;
 };
 
+/* A vkd3d_shader_instruction that can be inserted in a hlsl_block.
+ * Only used for the HLSL IR to vsir translation, might be removed once this translation is complete. */
+struct hlsl_ir_vsir_instruction_ref
+{
+    struct hlsl_ir_node node;
+
+    /* Index to a vkd3d_shader_instruction within a vkd3d_shader_instruction_array in a vsir_program. */
+    unsigned int vsir_instr_idx;
+};
+
 struct hlsl_scope
 {
     /* Item entry for hlsl_ctx.scopes. */
@@ -1016,6 +1036,7 @@ struct hlsl_ctx
         {
             uint32_t index;
             struct hlsl_vec4 value;
+            struct vkd3d_shader_location loc;
         } *regs;
         size_t count, size;
     } constant_defs;
@@ -1155,6 +1176,12 @@ static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(co
     return CONTAINING_RECORD(node, struct hlsl_ir_stateblock_constant, node);
 }
 
+static inline struct hlsl_ir_vsir_instruction_ref *hlsl_ir_vsir_instruction_ref(const struct hlsl_ir_node *node)
+{
+    VKD3D_ASSERT(node->type == HLSL_IR_VSIR_INSTRUCTION_REF);
+    return CONTAINING_RECORD(node, struct hlsl_ir_vsir_instruction_ref, node);
+}
+
 static inline void hlsl_block_init(struct hlsl_block *block)
 {
     list_init(&block->instrs);
@@ -1466,6 +1493,9 @@ struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned
 struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector,
         struct list *cases, const struct vkd3d_shader_location *loc);
 
+struct hlsl_ir_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx,
+        struct hlsl_type *type, const struct hlsl_reg *reg, const struct vkd3d_shader_location *loc);
+
 void hlsl_error(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc,
         enum vkd3d_shader_error error, const char *fmt, ...) VKD3D_PRINTF_FUNC(4, 5);
 void hlsl_fixme(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc,
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index 3f319dea0d84a214c5968e2d3c81a8171948a306..3bc2f0846c6959b3d79e48d5ea18a46de4441798 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -632,6 +632,8 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx
                 hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
                         "Expected literal expression.");
                 break;
+            case HLSL_IR_VSIR_INSTRUCTION_REF:
+                vkd3d_unreachable();
         }
     }
 
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 154328a64c3c92bc0b4f4845594160f7a04d63de..30694d9856cc82d7ef06e836ed47ad7a81554c29 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -4088,6 +4088,9 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
         case HLSL_IR_STATEBLOCK_CONSTANT:
             /* Stateblock constants should not appear in the shader program. */
             vkd3d_unreachable();
+        case HLSL_IR_VSIR_INSTRUCTION_REF:
+            /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */
+            vkd3d_unreachable();
     }
 
     return false;
@@ -4213,6 +4216,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop
         case HLSL_IR_STATEBLOCK_CONSTANT:
             /* Stateblock constants should not appear in the shader program. */
             vkd3d_unreachable();
+        case HLSL_IR_VSIR_INSTRUCTION_REF:
+            /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */
+            vkd3d_unreachable();
 
         case HLSL_IR_STORE:
         {
@@ -4816,7 +4822,8 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx,
     }
 }
 
-static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f)
+static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f,
+        const struct vkd3d_shader_location *loc)
 {
     struct hlsl_constant_defs *defs = &ctx->constant_defs;
     struct hlsl_constant_register *reg;
@@ -4838,6 +4845,7 @@ static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index,
     memset(reg, 0, sizeof(*reg));
     reg->index = component_index / 4;
     reg->value.f[component_index % 4] = f;
+    reg->loc = *loc;
 }
 
 static void allocate_const_registers_recurse(struct hlsl_ctx *ctx,
@@ -4898,7 +4906,7 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx,
                             vkd3d_unreachable();
                     }
 
-                    record_constant(ctx, constant->reg.id * 4 + x, f);
+                    record_constant(ctx, constant->reg.id * 4 + x, f, &constant->node.loc);
                 }
 
                 break;
@@ -4991,17 +4999,17 @@ static void allocate_sincos_const_registers(struct hlsl_ctx *ctx, struct hlsl_bl
 
             ctx->d3dsincosconst1 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type);
             TRACE("Allocated D3DSINCOSCONST1 to %s.\n", debug_register('c', ctx->d3dsincosconst1, type));
-            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f);
-            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f);
-            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2,  2.60416674e-03f);
-            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3,  2.60416680e-04f);
+            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2,  2.60416674e-03f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3,  2.60416680e-04f, &instr->loc);
 
             ctx->d3dsincosconst2 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type);
             TRACE("Allocated D3DSINCOSCONST2 to %s.\n", debug_register('c', ctx->d3dsincosconst2, type));
-            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f);
-            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f);
-            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2,  1.00000000e+00f);
-            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3,  5.00000000e-01f);
+            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2,  1.00000000e+00f, &instr->loc);
+            record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3,  5.00000000e-01f, &instr->loc);
 
             return;
         }
@@ -6006,6 +6014,441 @@ static void sm1_generate_vsir_signature(struct hlsl_ctx *ctx, struct vsir_progra
     }
 }
 
+static uint32_t sm1_generate_vsir_get_src_swizzle(uint32_t src_writemask, uint32_t dst_writemask)
+{
+    uint32_t swizzle;
+
+    swizzle = hlsl_swizzle_from_writemask(src_writemask);
+    swizzle = hlsl_map_swizzle(swizzle, dst_writemask);
+    swizzle = vsir_swizzle_from_hlsl(swizzle);
+    return swizzle;
+}
+
+static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_program *program,
+        struct hlsl_block *block)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct vkd3d_shader_dst_param *dst_param;
+    struct vkd3d_shader_src_param *src_param;
+    struct vkd3d_shader_instruction *ins;
+    struct hlsl_ir_node *vsir_instr;
+    unsigned int i, x;
+
+    for (i = 0; i < ctx->constant_defs.count; ++i)
+    {
+        const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i];
+
+        if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
+        {
+            ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+            return;
+        }
+
+        ins = &instructions->elements[instructions->count];
+        if (!vsir_instruction_init_with_params(program, ins, &constant_reg->loc, VKD3DSIH_DEF, 1, 1))
+        {
+            ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+            return;
+        }
+        ++instructions->count;
+
+        dst_param = &ins->dst[0];
+        vsir_register_init(&dst_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1);
+        ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4;
+        ins->dst[0].reg.idx[0].offset = constant_reg->index;
+        ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL;
+
+        src_param = &ins->src[0];
+        vsir_register_init(&src_param->reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0);
+        src_param->reg.type = VKD3DSPR_IMMCONST;
+        src_param->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT;
+        src_param->reg.non_uniform = false;
+        src_param->reg.data_type = VKD3D_DATA_FLOAT;
+        src_param->reg.dimension = VSIR_DIMENSION_VEC4;
+        for (x = 0; x < 4; ++x)
+            src_param->reg.u.immconst_f32[x] = constant_reg->value.f[x];
+        src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE;
+
+        if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL,
+                &constant_reg->loc)))
+        {
+            ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+            return;
+        }
+        hlsl_block_add_instr(block, vsir_instr);
+    }
+}
+
+static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx,
+        struct vsir_program *program, struct hlsl_block *block)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    enum vkd3d_shader_resource_type resource_type;
+    struct vkd3d_shader_register_range *range;
+    struct vkd3d_shader_dst_param *dst_param;
+    struct vkd3d_shader_semantic *semantic;
+    struct vkd3d_shader_instruction *ins;
+    enum hlsl_sampler_dim sampler_dim;
+    struct hlsl_ir_node *vsir_instr;
+    struct hlsl_ir_var *var;
+    unsigned int i, count;
+
+    LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+    {
+        if (!var->regs[HLSL_REGSET_SAMPLERS].allocated)
+            continue;
+
+        count = var->bind_count[HLSL_REGSET_SAMPLERS];
+        for (i = 0; i < count; ++i)
+        {
+            if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used)
+            {
+                sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim;
+
+                switch (sampler_dim)
+                {
+                    case HLSL_SAMPLER_DIM_2D:
+                        resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
+                        break;
+
+                    case HLSL_SAMPLER_DIM_CUBE:
+                        resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_CUBE;
+                        break;
+
+                    case HLSL_SAMPLER_DIM_3D:
+                        resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_3D;
+                        break;
+
+                    case HLSL_SAMPLER_DIM_GENERIC:
+                        /* These can appear in sm4-style combined sample instructions. */
+                        hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered.");
+                        continue;
+
+                    default:
+                        vkd3d_unreachable();
+                        break;
+                }
+
+                if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
+                {
+                    ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+                    return;
+                }
+
+                ins = &instructions->elements[instructions->count];
+                if (!vsir_instruction_init_with_params(program, ins, &var->loc, VKD3DSIH_DCL, 0, 0))
+                {
+                    ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+                    return;
+                }
+                ++instructions->count;
+
+                semantic = &ins->declaration.semantic;
+                semantic->resource_type = resource_type;
+
+                dst_param = &semantic->resource.reg;
+                vsir_register_init(&dst_param->reg, VKD3DSPR_SAMPLER, VKD3D_DATA_FLOAT, 1);
+                dst_param->reg.dimension = VSIR_DIMENSION_NONE;
+                dst_param->reg.idx[0].offset = var->regs[HLSL_REGSET_SAMPLERS].index + i;
+                dst_param->write_mask = 0;
+                range = &semantic->resource.range;
+                range->space = 0;
+                range->first = range->last = dst_param->reg.idx[0].offset;
+
+                if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL,
+                        NULL, &var->loc)))
+                {
+                    ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+                    return;
+                }
+                hlsl_block_add_instr(block, vsir_instr);
+            }
+        }
+    }
+}
+
+static struct vkd3d_shader_instruction *generate_vsir_add_program_instruction(
+        struct hlsl_ctx *ctx, struct vsir_program *program,
+        const struct vkd3d_shader_location *loc, enum vkd3d_shader_opcode opcode,
+        unsigned int dst_count, unsigned int src_count)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct vkd3d_shader_instruction *ins;
+
+    if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return NULL;
+    }
+    ins = &instructions->elements[instructions->count];
+    if (!vsir_instruction_init_with_params(program, ins, loc, opcode, dst_count, src_count))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return NULL;
+    }
+    ++instructions->count;
+    return ins;
+}
+
+static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx,
+        struct vsir_program *program, struct hlsl_ir_constant *constant)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct hlsl_ir_node *instr = &constant->node;
+    struct vkd3d_shader_dst_param *dst_param;
+    struct vkd3d_shader_src_param *src_param;
+    struct vkd3d_shader_instruction *ins;
+    struct hlsl_ir_node *vsir_instr;
+
+    VKD3D_ASSERT(instr->reg.allocated);
+    VKD3D_ASSERT(constant->reg.allocated);
+
+    if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1)))
+        return;
+
+    src_param = &ins->src[0];
+    vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1);
+    src_param->reg.idx[0].offset = constant->reg.id;
+    src_param->swizzle = sm1_generate_vsir_get_src_swizzle(constant->reg.writemask, instr->reg.writemask);
+
+    dst_param = &ins->dst[0];
+    vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    dst_param->reg.idx[0].offset = instr->reg.id;
+    dst_param->write_mask = instr->reg.writemask;
+
+    if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1,
+            instr->data_type, &instr->reg, &instr->loc)))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return;
+    }
+
+    list_add_before(&instr->entry, &vsir_instr->entry);
+    hlsl_replace_node(instr, vsir_instr);
+}
+
+static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx,
+        struct vkd3d_shader_dst_param *dst_param, struct hlsl_deref *deref,
+        const struct vkd3d_shader_location *loc, unsigned int writemask)
+{
+    enum vkd3d_shader_register_type type = VKD3DSPR_TEMP;
+    struct vkd3d_shader_version version;
+    uint32_t register_index;
+    struct hlsl_reg reg;
+
+    reg = hlsl_reg_from_deref(ctx, deref);
+    register_index = reg.id;
+    writemask = hlsl_combine_writemasks(reg.writemask, writemask);
+
+    if (deref->var->is_output_semantic)
+    {
+        version.major = ctx->profile->major_version;
+        version.minor = ctx->profile->minor_version;
+        version.type = ctx->profile->type;
+
+        if (version.type == VKD3D_SHADER_TYPE_PIXEL && version.major == 1)
+        {
+            type = VKD3DSPR_TEMP;
+            register_index = 0;
+        }
+        else if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name,
+                deref->var->semantic.index, true, &type, &register_index))
+        {
+            VKD3D_ASSERT(reg.allocated);
+            type = VKD3DSPR_OUTPUT;
+            register_index = reg.id;
+        }
+        else
+            writemask = (1u << deref->var->data_type->dimx) - 1;
+    }
+    else
+        VKD3D_ASSERT(reg.allocated);
+
+    vsir_register_init(&dst_param->reg, type, VKD3D_DATA_FLOAT, 1);
+    dst_param->write_mask = writemask;
+    dst_param->reg.idx[0].offset = register_index;
+
+    if (deref->rel_offset.node)
+        hlsl_fixme(ctx, loc, "Translate relative addressing on dst register for vsir.");
+}
+
+static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx,
+        struct vkd3d_shader_src_param *src_param, struct hlsl_deref *deref,
+        unsigned int dst_writemask, const struct vkd3d_shader_location *loc)
+{
+    enum vkd3d_shader_register_type type = VKD3DSPR_TEMP;
+    struct vkd3d_shader_version version;
+    uint32_t register_index;
+    unsigned int writemask;
+    struct hlsl_reg reg;
+
+    reg = hlsl_reg_from_deref(ctx, deref);
+    register_index = reg.id;
+    writemask = reg.writemask;
+
+    if (deref->var->is_uniform)
+    {
+        VKD3D_ASSERT(reg.allocated);
+        type = VKD3DSPR_CONST;
+    }
+    else if (deref->var->is_input_semantic)
+    {
+        version.major = ctx->profile->major_version;
+        version.minor = ctx->profile->minor_version;
+        version.type = ctx->profile->type;
+        if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name,
+                deref->var->semantic.index, false, &type, &register_index))
+        {
+            VKD3D_ASSERT(reg.allocated);
+            type = VKD3DSPR_INPUT;
+            register_index = reg.id;
+        }
+        else
+            writemask = (1 << deref->var->data_type->dimx) - 1;
+    }
+
+    vsir_register_init(&src_param->reg, type, VKD3D_DATA_FLOAT, 1);
+    src_param->reg.idx[0].offset = register_index;
+    src_param->swizzle = sm1_generate_vsir_get_src_swizzle(writemask, dst_writemask);
+
+    if (deref->rel_offset.node)
+        hlsl_fixme(ctx, loc, "Translate relative addressing on src register for vsir.");
+}
+
+static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_program *program,
+        struct hlsl_ir_load *load)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct hlsl_ir_node *instr = &load->node;
+    struct vkd3d_shader_dst_param *dst_param;
+    struct vkd3d_shader_instruction *ins;
+    struct hlsl_ir_node *vsir_instr;
+
+    VKD3D_ASSERT(instr->reg.allocated);
+
+    if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1)))
+        return;
+
+    dst_param = &ins->dst[0];
+    vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    dst_param->reg.idx[0].offset = instr->reg.id;
+    dst_param->write_mask = instr->reg.writemask;
+
+    sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[0], &load->src, dst_param->write_mask,
+            &ins->location);
+
+    if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type,
+            &instr->reg, &instr->loc)))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return;
+    }
+
+    list_add_before(&instr->entry, &vsir_instr->entry);
+    hlsl_replace_node(instr, vsir_instr);
+}
+
+static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program,
+        struct hlsl_ir_swizzle *swizzle_instr)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct hlsl_ir_node *instr = &swizzle_instr->node, *val = swizzle_instr->val.node;
+    struct vkd3d_shader_dst_param *dst_param;
+    struct vkd3d_shader_src_param *src_param;
+    struct vkd3d_shader_instruction *ins;
+    struct hlsl_ir_node *vsir_instr;
+    uint32_t swizzle;
+
+    VKD3D_ASSERT(instr->reg.allocated);
+
+    if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1)))
+        return;
+
+    dst_param = &ins->dst[0];
+    vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    dst_param->reg.idx[0].offset = instr->reg.id;
+    dst_param->write_mask = instr->reg.writemask;
+
+    swizzle = hlsl_swizzle_from_writemask(val->reg.writemask);
+    swizzle = hlsl_combine_swizzles(swizzle, swizzle_instr->swizzle, instr->data_type->dimx);
+    swizzle = hlsl_map_swizzle(swizzle, ins->dst[0].write_mask);
+    swizzle = vsir_swizzle_from_hlsl(swizzle);
+
+    src_param = &ins->src[0];
+    vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    src_param->reg.idx[0].offset = val->reg.id;
+    src_param->swizzle = swizzle;
+
+    if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type,
+            &instr->reg, &instr->loc)))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return;
+    }
+
+    list_add_before(&instr->entry, &vsir_instr->entry);
+    hlsl_replace_node(instr, vsir_instr);
+}
+
+static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program,
+        struct hlsl_ir_store *store)
+{
+    struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+    struct hlsl_ir_node *rhs = store->rhs.node;
+    struct hlsl_ir_node *instr = &store->node;
+    struct vkd3d_shader_instruction *ins;
+    struct vkd3d_shader_src_param *src_param;
+    struct hlsl_ir_node *vsir_instr;
+
+    if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1)))
+        return;
+
+    sm1_generate_vsir_init_dst_param_from_deref(ctx, &ins->dst[0], &store->lhs, &ins->location, store->writemask);
+
+    src_param = &ins->src[0];
+    vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    src_param->reg.idx[0].offset = rhs->reg.id;
+    src_param->swizzle = sm1_generate_vsir_get_src_swizzle(rhs->reg.writemask, ins->dst[0].write_mask);
+
+    if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL, &instr->loc)))
+    {
+        ctx->result = VKD3D_ERROR_OUT_OF_MEMORY;
+        return;
+    }
+
+    list_add_before(&instr->entry, &vsir_instr->entry);
+    hlsl_replace_node(instr, vsir_instr);
+}
+
+static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
+{
+    struct vsir_program *program = context;
+
+    switch (instr->type)
+    {
+        case HLSL_IR_CONSTANT:
+            sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr));
+            return true;
+
+        case HLSL_IR_LOAD:
+            sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr));
+            return true;
+
+        case HLSL_IR_STORE:
+            sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr));
+            return true;
+
+        case HLSL_IR_SWIZZLE:
+            sm1_generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr));
+            return true;
+
+        default:
+            break;
+    }
+
+    return false;
+}
+
 /* OBJECTIVE: Translate all the information from ctx and entry_func to the
  * vsir_program and ctab blob, so they can be used as input to d3dbc_compile()
  * without relying on ctx and entry_func. */
@@ -6014,6 +6457,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
 {
     struct vkd3d_shader_version version = {0};
     struct vkd3d_bytecode_buffer buffer = {0};
+    struct hlsl_block block;
 
     version.major = ctx->profile->major_version;
     version.minor = ctx->profile->minor_version;
@@ -6035,6 +6479,13 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
     ctab->size = buffer.size;
 
     sm1_generate_vsir_signature(ctx, program);
+
+    hlsl_block_init(&block);
+    sm1_generate_vsir_constant_defs(ctx, program, &block);
+    sm1_generate_vsir_sampler_dcls(ctx, program, &block);
+    list_move_head(&entry_func->body.instrs, &block.instrs);
+
+    hlsl_transform_ir(ctx, sm1_generate_vsir_instr, &entry_func->body, program);
 }
 
 static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point,
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c
index 747238e2feecd77fbe8fe5b1cbe07202b24a03d4..d765abc938b02e9d8e8af6770e69358be2b2a190 100644
--- a/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d-shader/ir.c
@@ -136,7 +136,7 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i
     vsir_instruction_init(ins, &location, VKD3DSIH_NOP);
 }
 
-static bool vsir_instruction_init_with_params(struct vsir_program *program,
+bool vsir_instruction_init_with_params(struct vsir_program *program,
         struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
         enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count)
 {
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index c6ad5857711409b7814fc57a1d87272da618596f..93dff4e86721d759e4f14664e46d31939ac1674f 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -169,6 +169,10 @@ enum vkd3d_shader_error
     VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY              = 7004,
     VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX     = 7005,
     VKD3D_SHADER_ERROR_D3DBC_UNDECLARED_SEMANTIC        = 7006,
+    VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE      = 7007,
+    VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT     = 7008,
+    VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED            = 7009,
+    VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE            = 7010,
 
     VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300,
 
@@ -1389,6 +1393,9 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t
         const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context);
 enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags,
         const char *source_name, struct vkd3d_shader_message_context *message_context);
+bool vsir_instruction_init_with_params(struct vsir_program *program,
+        struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
+        enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count);
 
 static inline struct vkd3d_shader_dst_param *vsir_program_get_dst_params(
         struct vsir_program *program, unsigned int count)