vkd3d-shader/hlsl: Implement the InterlockedAdd() intrinsic.

This commit is contained in:
Shaun Ren
2024-12-12 17:59:15 -05:00
committed by Henri Verbeet
parent 5f943e9110
commit 660a71ef22
Notes: Henri Verbeet 2025-01-20 16:18:51 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Elizabeth Figura (@zfigura)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1330
5 changed files with 309 additions and 0 deletions

View File

@@ -739,6 +739,10 @@ static bool transform_instr_derefs(struct hlsl_ctx *ctx, struct hlsl_ir_node *in
res = func(ctx, &hlsl_ir_resource_store(instr)->resource, instr);
return res;
case HLSL_IR_INTERLOCKED:
res = func(ctx, &hlsl_ir_interlocked(instr)->dst, instr);
return res;
default:
return false;
}
@@ -1836,6 +1840,15 @@ static bool copy_propagation_transform_resource_store(struct hlsl_ctx *ctx,
return progress;
}
static bool copy_propagation_transform_interlocked(struct hlsl_ctx *ctx,
struct hlsl_ir_interlocked *interlocked, struct copy_propagation_state *state)
{
bool progress = false;
progress |= copy_propagation_transform_object_load(ctx, &interlocked->dst, state, interlocked->node.index);
return progress;
}
static void copy_propagation_record_store(struct hlsl_ctx *ctx, struct hlsl_ir_store *store,
struct copy_propagation_state *state)
{
@@ -2042,6 +2055,9 @@ static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_b
progress |= copy_propagation_process_switch(ctx, hlsl_ir_switch(instr), state);
break;
case HLSL_IR_INTERLOCKED:
progress |= copy_propagation_transform_interlocked(ctx, hlsl_ir_interlocked(instr), state);
default:
break;
}
@@ -2225,6 +2241,24 @@ static bool validate_dereferences(struct hlsl_ctx *ctx, struct hlsl_ir_node *ins
validate_component_index_range_from_deref(ctx, &store->lhs);
break;
}
case HLSL_IR_INTERLOCKED:
{
struct hlsl_ir_interlocked *interlocked = hlsl_ir_interlocked(instr);
if (!interlocked->dst.var->is_uniform)
{
hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF,
"Accessed resource must have a single uniform source.");
}
else if (validate_component_index_range_from_deref(ctx, &interlocked->dst) == DEREF_VALIDATION_NOT_CONSTANT)
{
hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF,
"Accessed resource from \"%s\" must be determinable at compile time.",
interlocked->dst.var->name);
note_non_static_deref_expressions(ctx, &interlocked->dst, "accessed resource");
}
break;
}
default:
break;
}
@@ -4478,6 +4512,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
case HLSL_IR_LOOP:
case HLSL_IR_RESOURCE_STORE:
case HLSL_IR_SWITCH:
case HLSL_IR_INTERLOCKED:
break;
case HLSL_IR_STATEBLOCK_CONSTANT:
/* Stateblock constants should not appear in the shader program. */
@@ -4724,6 +4759,19 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop
index->idx.node->last_read = last_read;
break;
}
case HLSL_IR_INTERLOCKED:
{
struct hlsl_ir_interlocked *interlocked = hlsl_ir_interlocked(instr);
var = interlocked->dst.var;
var->last_read = max(var->last_read, last_read);
deref_mark_last_read(&interlocked->dst, last_read);
interlocked->coords.node->last_read = last_read;
interlocked->value.node->last_read = last_read;
if (interlocked->cmp_value.node)
interlocked->cmp_value.node->last_read = last_read;
break;
}
case HLSL_IR_JUMP:
{
struct hlsl_ir_jump *jump = hlsl_ir_jump(instr);
@@ -5135,6 +5183,10 @@ static bool track_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *in
register_deref_usage(ctx, &hlsl_ir_resource_store(instr)->resource);
break;
case HLSL_IR_INTERLOCKED:
register_deref_usage(ctx, &hlsl_ir_interlocked(instr)->dst);
break;
default:
break;
}
@@ -9942,6 +9994,45 @@ static bool sm4_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx,
}
}
static bool sm4_generate_vsir_instr_interlocked(struct hlsl_ctx *ctx,
struct vsir_program *program, struct hlsl_ir_interlocked *interlocked)
{
static const enum vkd3d_shader_opcode opcodes[] =
{
[HLSL_INTERLOCKED_ADD] = VKD3DSIH_ATOMIC_IADD,
};
static const enum vkd3d_shader_opcode imm_opcodes[] =
{
[HLSL_INTERLOCKED_ADD] = VKD3DSIH_IMM_ATOMIC_IADD,
};
struct hlsl_ir_node *coords = interlocked->coords.node, *value = interlocked->value.node;
struct hlsl_ir_node *instr = &interlocked->node;
bool is_imm = interlocked->node.reg.allocated;
struct vkd3d_shader_dst_param *dst_param;
struct vkd3d_shader_instruction *ins;
enum vkd3d_shader_opcode opcode;
opcode = is_imm ? imm_opcodes[interlocked->op] : opcodes[interlocked->op];
if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, is_imm ? 2 : 1, 2)))
return false;
if (is_imm)
vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr);
dst_param = is_imm ? &ins->dst[1] : &ins->dst[0];
if (!sm4_generate_vsir_init_dst_param_from_deref(ctx, program, dst_param, &interlocked->dst, &instr->loc, 0))
return false;
dst_param->reg.dimension = VSIR_DIMENSION_NONE;
vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, VKD3DSP_WRITEMASK_ALL);
vsir_src_from_hlsl_node(&ins->src[1], ctx, value, VKD3DSP_WRITEMASK_ALL);
return true;
}
static bool sm4_generate_vsir_instr_jump(struct hlsl_ctx *ctx,
struct vsir_program *program, const struct hlsl_ir_jump *jump)
{
@@ -10119,6 +10210,10 @@ static void sm4_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *blo
generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr));
break;
case HLSL_IR_INTERLOCKED:
sm4_generate_vsir_instr_interlocked(ctx, program, hlsl_ir_interlocked(instr));
break;
default:
break;
}