Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl_codegen.c | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 5b68a460..2382ffe9 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -84,6 +84,86 @@ static bool fold_redundant_casts(struct hlsl_ctx *ctx, struct hlsl_ir_node *inst return false; }
+static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + const struct hlsl_struct_field *field; + const struct hlsl_ir_load *rhs_load; + struct hlsl_ir_assignment *assign; + const struct hlsl_ir_node *rhs; + const struct hlsl_type *type; + + if (instr->type != HLSL_IR_ASSIGNMENT) + return false; + + assign = hlsl_ir_assignment(instr); + rhs = assign->rhs.node; + type = rhs->data_type; + if (type->type != HLSL_CLASS_STRUCT) + return false; + + rhs_load = hlsl_ir_load(rhs); + + LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + { + struct hlsl_ir_node *offset, *add; + struct hlsl_ir_assignment *store; + struct hlsl_ir_load *field_load; + struct hlsl_ir_constant *c; + + if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset * 4, instr->loc))) + { + ctx->failed = true; + return false; + } + list_add_before(&instr->entry, &c->node.entry); + + offset = &c->node; + if (rhs_load->src.offset.node) + { + if (!(add = hlsl_new_binary_expr(HLSL_IR_BINOP_ADD, rhs_load->src.offset.node, &c->node))) + { + ctx->failed = true; + return false; + } + list_add_before(&instr->entry, &add->entry); + offset = add; + } + if (!(field_load = hlsl_new_load(rhs_load->src.var, offset, field->type, instr->loc))) + { + ctx->failed = true; + return false; + } + list_add_before(&instr->entry, &field_load->node.entry); + + offset = &c->node; + if (assign->lhs.offset.node) + { + if (!(add = hlsl_new_binary_expr(HLSL_IR_BINOP_ADD, assign->lhs.offset.node, &c->node))) + { + ctx->failed = true; + return false; + } + list_add_before(&instr->entry, &add->entry); + offset = add; + } + + if (!(store = hlsl_new_assignment(assign->lhs.var, offset, &field_load->node, 0, instr->loc))) + { + ctx->failed = true; + return false; + } + list_add_before(&instr->entry, &store->node.entry); + } + + /* Remove the assignment instruction, so that we can split structs + * which contain other structs. Although assignment instructions + * produce a value, we don't allow HLSL_IR_ASSIGNMENT to be used as + * a source. */ + list_remove(&assign->node.entry); + hlsl_free_instr(&assign->node); + return true; +} + static bool fold_constants(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_ir_constant *arg1, *arg2 = NULL, *res; @@ -317,6 +397,7 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun list_move_head(entry_func->body, &ctx->static_initializers);
while (transform_ir(ctx, fold_redundant_casts, entry_func->body, NULL)); + while (transform_ir(ctx, split_struct_copies, entry_func->body, NULL)); while (transform_ir(ctx, fold_constants, entry_func->body, NULL)); while (transform_ir(ctx, dce, entry_func->body, NULL));