Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 76 ++++++++++++++++---------------- libs/vkd3d-shader/hlsl.h | 22 ++++----- libs/vkd3d-shader/hlsl.y | 50 ++++++++++----------- libs/vkd3d-shader/hlsl_codegen.c | 59 ++++++++++++------------- 4 files changed, 103 insertions(+), 104 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 53b9db36..23003f44 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -418,28 +418,28 @@ static bool type_is_single_reg(const struct hlsl_type *type) return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR; }
-struct hlsl_ir_assignment *hlsl_new_assignment(struct hlsl_ir_var *var, struct hlsl_ir_node *offset, +struct hlsl_ir_store *hlsl_new_store(struct hlsl_ir_var *var, struct hlsl_ir_node *offset, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) { - struct hlsl_ir_assignment *assign; + struct hlsl_ir_store *store;
if (!writemask && type_is_single_reg(rhs->data_type)) writemask = (1 << rhs->data_type->dimx) - 1;
- if (!(assign = vkd3d_malloc(sizeof(*assign)))) + if (!(store = vkd3d_malloc(sizeof(*store)))) return NULL;
- init_node(&assign->node, HLSL_IR_ASSIGNMENT, NULL, loc); - assign->lhs.var = var; - hlsl_src_from_node(&assign->lhs.offset, offset); - hlsl_src_from_node(&assign->rhs, rhs); - assign->writemask = writemask; - return assign; + init_node(&store->node, HLSL_IR_STORE, NULL, loc); + store->lhs.var = var; + hlsl_src_from_node(&store->lhs.offset, offset); + hlsl_src_from_node(&store->rhs, rhs); + store->writemask = writemask; + return store; }
-struct hlsl_ir_assignment *hlsl_new_simple_assignment(struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs) +struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs) { - return hlsl_new_assignment(lhs, NULL, rhs, 0, rhs->loc); + return hlsl_new_store(lhs, NULL, rhs, 0, rhs->loc); }
struct hlsl_ir_constant *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned int n, @@ -830,13 +830,13 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) { static const char * const names[] = { - "HLSL_IR_ASSIGNMENT", "HLSL_IR_CONSTANT", "HLSL_IR_EXPR", "HLSL_IR_IF", "HLSL_IR_LOAD", "HLSL_IR_LOOP", "HLSL_IR_JUMP", + "HLSL_IR_STORE", "HLSL_IR_SWIZZLE", };
@@ -909,17 +909,6 @@ static const char *debug_writemask(DWORD writemask) return vkd3d_dbg_sprintf(".%s", string); }
-static void dump_ir_assignment(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_assignment *assign) -{ - vkd3d_string_buffer_printf(buffer, "= ("); - dump_deref(buffer, &assign->lhs); - if (assign->writemask != VKD3DSP_WRITEMASK_ALL) - vkd3d_string_buffer_printf(buffer, "%s", debug_writemask(assign->writemask)); - vkd3d_string_buffer_printf(buffer, " "); - dump_src(buffer, &assign->rhs); - vkd3d_string_buffer_printf(buffer, ")"); -} - static void dump_ir_constant(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_constant *constant) { struct hlsl_type *type = constant->node.data_type; @@ -1080,6 +1069,17 @@ static void dump_ir_loop(struct vkd3d_string_buffer *buffer, const struct hlsl_i vkd3d_string_buffer_printf(buffer, "}\n"); }
+static void dump_ir_store(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_store *store) +{ + vkd3d_string_buffer_printf(buffer, "= ("); + dump_deref(buffer, &store->lhs); + if (store->writemask != VKD3DSP_WRITEMASK_ALL) + vkd3d_string_buffer_printf(buffer, "%s", debug_writemask(store->writemask)); + vkd3d_string_buffer_printf(buffer, " "); + dump_src(buffer, &store->rhs); + vkd3d_string_buffer_printf(buffer, ")"); +} + static void dump_ir_swizzle(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_swizzle *swizzle) { unsigned int i; @@ -1111,10 +1111,6 @@ static void dump_instr(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_
switch (instr->type) { - case HLSL_IR_ASSIGNMENT: - dump_ir_assignment(buffer, hlsl_ir_assignment(instr)); - break; - case HLSL_IR_CONSTANT: dump_ir_constant(buffer, hlsl_ir_constant(instr)); break; @@ -1139,6 +1135,10 @@ static void dump_instr(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_ dump_ir_loop(buffer, hlsl_ir_loop(instr)); break;
+ case HLSL_IR_STORE: + dump_ir_store(buffer, hlsl_ir_store(instr)); + break; + case HLSL_IR_SWIZZLE: dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); break; @@ -1198,13 +1198,6 @@ void hlsl_free_instr_list(struct list *list) vkd3d_free(list); }
-static void free_ir_assignment(struct hlsl_ir_assignment *assignment) -{ - hlsl_src_remove(&assignment->rhs); - hlsl_src_remove(&assignment->lhs.offset); - vkd3d_free(assignment); -} - static void free_ir_constant(struct hlsl_ir_constant *constant) { vkd3d_free(constant); @@ -1251,6 +1244,13 @@ static void free_ir_loop(struct hlsl_ir_loop *loop) vkd3d_free(loop); }
+static void free_ir_store(struct hlsl_ir_store *store) +{ + hlsl_src_remove(&store->rhs); + hlsl_src_remove(&store->lhs.offset); + vkd3d_free(store); +} + static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle) { hlsl_src_remove(&swizzle->val); @@ -1261,10 +1261,6 @@ void hlsl_free_instr(struct hlsl_ir_node *node) { switch (node->type) { - case HLSL_IR_ASSIGNMENT: - free_ir_assignment(hlsl_ir_assignment(node)); - break; - case HLSL_IR_CONSTANT: free_ir_constant(hlsl_ir_constant(node)); break; @@ -1289,6 +1285,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) free_ir_loop(hlsl_ir_loop(node)); break;
+ case HLSL_IR_STORE: + free_ir_store(hlsl_ir_store(node)); + break; + case HLSL_IR_SWIZZLE: free_ir_swizzle(hlsl_ir_swizzle(node)); break; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index cf12f63f..c82cd4f5 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -139,13 +139,13 @@ struct hlsl_struct_field
enum hlsl_ir_node_type { - HLSL_IR_ASSIGNMENT = 0, HLSL_IR_CONSTANT, HLSL_IR_EXPR, HLSL_IR_IF, HLSL_IR_LOAD, HLSL_IR_LOOP, HLSL_IR_JUMP, + HLSL_IR_STORE, HLSL_IR_SWIZZLE, };
@@ -352,7 +352,7 @@ struct hlsl_ir_load struct hlsl_deref src; };
-struct hlsl_ir_assignment +struct hlsl_ir_store { struct hlsl_ir_node node; struct hlsl_deref lhs; @@ -420,12 +420,6 @@ enum hlsl_error_level HLSL_LEVEL_NOTE, };
-static inline struct hlsl_ir_assignment *hlsl_ir_assignment(const struct hlsl_ir_node *node) -{ - assert(node->type == HLSL_IR_ASSIGNMENT); - return CONTAINING_RECORD(node, struct hlsl_ir_assignment, node); -} - static inline struct hlsl_ir_constant *hlsl_ir_constant(const struct hlsl_ir_node *node) { assert(node->type == HLSL_IR_CONSTANT); @@ -462,6 +456,12 @@ static inline struct hlsl_ir_loop *hlsl_ir_loop(const struct hlsl_ir_node *node) return CONTAINING_RECORD(node, struct hlsl_ir_loop, node); }
+static inline struct hlsl_ir_store *hlsl_ir_store(const struct hlsl_ir_node *node) +{ + assert(node->type == HLSL_IR_STORE); + return CONTAINING_RECORD(node, struct hlsl_ir_store, node); +} + static inline struct hlsl_ir_swizzle *hlsl_ir_swizzle(const struct hlsl_ir_node *node) { assert(node->type == HLSL_IR_SWIZZLE); @@ -520,8 +520,6 @@ struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name) DEC
struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *basic_type, unsigned int array_size) DECLSPEC_HIDDEN; -struct hlsl_ir_assignment *hlsl_new_assignment(struct hlsl_ir_var *var, struct hlsl_ir_node *offset, - struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) DECLSPEC_HIDDEN; struct hlsl_ir_node *hlsl_new_binary_expr(enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2) DECLSPEC_HIDDEN; struct hlsl_ir_expr *hlsl_new_cast(struct hlsl_ir_node *node, struct hlsl_type *type, @@ -534,8 +532,10 @@ struct hlsl_ir_jump *hlsl_new_jump(enum hlsl_ir_jump_type type, struct vkd3d_sha struct hlsl_ir_load *hlsl_new_load(struct hlsl_ir_var *var, struct hlsl_ir_node *offset, struct hlsl_type *type, struct vkd3d_shader_location loc) DECLSPEC_HIDDEN; struct hlsl_ir_loop *hlsl_new_loop(struct vkd3d_shader_location loc) DECLSPEC_HIDDEN; -struct hlsl_ir_assignment *hlsl_new_simple_assignment(struct hlsl_ir_var *lhs, +struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs) DECLSPEC_HIDDEN; +struct hlsl_ir_store *hlsl_new_store(struct hlsl_ir_var *var, struct hlsl_ir_node *offset, + struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) DECLSPEC_HIDDEN; struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct list *fields) DECLSPEC_HIDDEN; struct hlsl_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components, struct hlsl_ir_node *val, struct vkd3d_shader_location *loc) DECLSPEC_HIDDEN; diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ab7059d3..6216b100 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -499,14 +499,14 @@ static struct hlsl_ir_jump *add_return(struct hlsl_ctx *ctx, struct list *instrs
if (return_value) { - struct hlsl_ir_assignment *assignment; + struct hlsl_ir_store *store;
if (!(return_value = add_implicit_conversion(ctx, instrs, return_value, return_type, &loc))) return NULL;
- if (!(assignment = hlsl_new_simple_assignment(ctx->cur_function->return_var, return_value))) + if (!(store = hlsl_new_simple_store(ctx->cur_function->return_var, return_value))) return NULL; - list_add_after(&return_value->entry, &assignment->node.entry); + list_add_after(&return_value->entry, &store->node.entry); } else if (!hlsl_type_is_void(return_type)) { @@ -543,17 +543,17 @@ static struct hlsl_ir_load *add_load(struct hlsl_ctx *ctx, struct list *instrs, } else { - struct hlsl_ir_assignment *assign; + struct hlsl_ir_store *store; char name[27];
sprintf(name, "<deref-%p>", var_node); if (!(var = hlsl_new_synthetic_var(ctx, name, var_node->data_type, var_node->loc))) return NULL;
- if (!(assign = hlsl_new_simple_assignment(var, var_node))) + if (!(store = hlsl_new_simple_store(var, var_node))) return NULL;
- list_add_tail(instrs, &assign->node.entry); + list_add_tail(instrs, &store->node.entry); }
if (!(load = hlsl_new_load(var, offset, data_type, loc))) @@ -900,7 +900,7 @@ static unsigned int evaluate_array_dimension(struct hlsl_ir_node *node) FIXME("Unhandled type %s.\n", hlsl_node_type_to_string(node->type)); return 0;
- case HLSL_IR_ASSIGNMENT: + case HLSL_IR_STORE: default: WARN("Invalid node type %s.\n", hlsl_node_type_to_string(node->type)); return 0; @@ -1216,7 +1216,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in enum parse_assign_op assign_op, struct hlsl_ir_node *rhs) { struct hlsl_type *lhs_type = lhs->data_type; - struct hlsl_ir_assignment *assign; + struct hlsl_ir_store *store; struct hlsl_ir_expr *copy; DWORD writemask = 0;
@@ -1239,7 +1239,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in return NULL; }
- if (!(assign = vkd3d_malloc(sizeof(*assign)))) + if (!(store = vkd3d_malloc(sizeof(*store)))) return NULL;
while (lhs->type != HLSL_IR_LOAD) @@ -1247,7 +1247,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in if (lhs->type == HLSL_IR_EXPR && hlsl_ir_expr(lhs)->op == HLSL_IR_UNOP_CAST) { FIXME("Cast on the lhs.\n"); - vkd3d_free(assign); + vkd3d_free(store); return NULL; } else if (lhs->type == HLSL_IR_SWIZZLE) @@ -1261,13 +1261,13 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in if (!invert_swizzle(&s, &writemask, &width)) { hlsl_error(ctx, lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, "Invalid writemask."); - vkd3d_free(assign); + vkd3d_free(store); return NULL; }
if (!(new_swizzle = hlsl_new_swizzle(ctx, s, width, rhs, &swizzle->node.loc))) { - vkd3d_free(assign); + vkd3d_free(store); return NULL; } list_add_tail(instrs, &new_swizzle->node.entry); @@ -1278,17 +1278,17 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in else { hlsl_error(ctx, lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, "Invalid lvalue."); - vkd3d_free(assign); + vkd3d_free(store); return NULL; } }
- init_node(&assign->node, HLSL_IR_ASSIGNMENT, NULL, lhs->loc); - assign->writemask = writemask; - assign->lhs.var = hlsl_ir_load(lhs)->src.var; - hlsl_src_from_node(&assign->lhs.offset, hlsl_ir_load(lhs)->src.offset.node); - hlsl_src_from_node(&assign->rhs, rhs); - list_add_tail(instrs, &assign->node.entry); + init_node(&store->node, HLSL_IR_STORE, NULL, lhs->loc); + store->writemask = writemask; + store->lhs.var = hlsl_ir_load(lhs)->src.var; + hlsl_src_from_node(&store->lhs.offset, hlsl_ir_load(lhs)->src.offset.node); + hlsl_src_from_node(&store->rhs, rhs); + list_add_tail(instrs, &store->node.entry);
/* Don't use the instruction itself as a source, as this makes structure * splitting easier. Instead copy it here. Since we retrieve sources from @@ -1355,7 +1355,7 @@ static void struct_var_initializer(struct hlsl_ctx *ctx, struct list *list, stru LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { struct hlsl_ir_node *node = initializer->args[i]; - struct hlsl_ir_assignment *assign; + struct hlsl_ir_store *store; struct hlsl_ir_constant *c;
if (i++ >= initializer->args_count) @@ -1367,9 +1367,9 @@ static void struct_var_initializer(struct hlsl_ctx *ctx, struct list *list, stru break; list_add_tail(list, &c->node.entry);
- if (!(assign = hlsl_new_assignment(var, &c->node, node, 0, node->loc))) + if (!(store = hlsl_new_store(var, &c->node, node, 0, node->loc))) break; - list_add_tail(list, &assign->node.entry); + list_add_tail(list, &store->node.entry); } else FIXME("Initializing with "mismatched" fields is not supported yet.\n"); @@ -2724,8 +2724,8 @@ postfix_expr: /* var_modifiers is necessary to avoid shift/reduce conflicts. */ | var_modifiers type '(' initializer_expr_list ')' { - struct hlsl_ir_assignment *assignment; unsigned int i, writemask_offset = 0; + struct hlsl_ir_store *store; static unsigned int counter; struct hlsl_ir_load *load; struct hlsl_ir_var *var; @@ -2788,11 +2788,11 @@ postfix_expr: ctx->builtin_types.vector[$2->base_type][width - 1], &arg->loc))) continue;
- if (!(assignment = hlsl_new_assignment(var, NULL, arg, + if (!(store = hlsl_new_store(var, NULL, arg, ((1 << width) - 1) << writemask_offset, arg->loc))) YYABORT; writemask_offset += width; - list_add_tail($4.instrs, &assignment->node.entry); + list_add_tail($4.instrs, &store->node.entry); } vkd3d_free($4.args); if (!(load = hlsl_new_var_load(var, @2))) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index dbd591af..0641aa0f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -27,8 +27,8 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { struct vkd3d_string_buffer *name; - struct hlsl_ir_assignment *store; struct hlsl_ir_var *const_var; + struct hlsl_ir_store *store; struct hlsl_ir_load *load;
if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) @@ -55,7 +55,7 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, stru } list_add_head(instrs, &load->node.entry);
- if (!(store = hlsl_new_simple_assignment(var, &load->node))) + if (!(store = hlsl_new_simple_store(var, &load->node))) { ctx->failed = true; return; @@ -67,8 +67,8 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_type *type, unsigned int field_offset, const char *semantic) { struct vkd3d_string_buffer *name; - struct hlsl_ir_assignment *store; struct hlsl_ir_constant *offset; + struct hlsl_ir_store *store; struct hlsl_ir_var *varying; struct hlsl_ir_load *load;
@@ -102,7 +102,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } list_add_after(&load->node.entry, &offset->node.entry);
- if (!(store = hlsl_new_assignment(var, &offset->node, &load->node, 0, var->loc))) + if (!(store = hlsl_new_store(var, &offset->node, &load->node, 0, var->loc))) { ctx->failed = true; return; @@ -144,8 +144,8 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_type *type, unsigned int field_offset, const char *semantic) { struct vkd3d_string_buffer *name; - struct hlsl_ir_assignment *store; struct hlsl_ir_constant *offset; + struct hlsl_ir_store *store; struct hlsl_ir_var *varying; struct hlsl_ir_load *load;
@@ -179,7 +179,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } list_add_after(&offset->node.entry, &load->node.entry);
- if (!(store = hlsl_new_assignment(varying, NULL, &load->node, 0, var->loc))) + if (!(store = hlsl_new_store(varying, NULL, &load->node, 0, var->loc))) { ctx->failed = true; return; @@ -285,15 +285,15 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr { 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; + struct hlsl_ir_store *store;
- if (instr->type != HLSL_IR_ASSIGNMENT) + if (instr->type != HLSL_IR_STORE) return false;
- assign = hlsl_ir_assignment(instr); - rhs = assign->rhs.node; + store = hlsl_ir_store(instr); + rhs = store->rhs.node; type = rhs->data_type; if (type->type != HLSL_CLASS_STRUCT) return false; @@ -302,8 +302,8 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr
LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { + struct hlsl_ir_store *field_store; struct hlsl_ir_node *offset, *add; - struct hlsl_ir_assignment *store; struct hlsl_ir_load *field_load; struct hlsl_ir_constant *c;
@@ -333,9 +333,9 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr list_add_before(&instr->entry, &field_load->node.entry);
offset = &c->node; - if (assign->lhs.offset.node) + if (store->lhs.offset.node) { - if (!(add = hlsl_new_binary_expr(HLSL_IR_BINOP_ADD, assign->lhs.offset.node, &c->node))) + if (!(add = hlsl_new_binary_expr(HLSL_IR_BINOP_ADD, store->lhs.offset.node, &c->node))) { ctx->failed = true; return false; @@ -344,20 +344,19 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr offset = add; }
- if (!(store = hlsl_new_assignment(assign->lhs.var, offset, &field_load->node, 0, instr->loc))) + if (!(field_store = hlsl_new_store(store->lhs.var, offset, &field_load->node, 0, instr->loc))) { ctx->failed = true; return false; } - list_add_before(&instr->entry, &store->node.entry); + list_add_before(&instr->entry, &field_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); + /* Remove the store instruction, so that we can split structs which contain + * other structs. Although assignments produce a value, we don't allow + * HLSL_IR_STORE to be used as a source. */ + list_remove(&store->node.entry); + hlsl_free_instr(&store->node); return true; }
@@ -440,10 +439,10 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) } break;
- case HLSL_IR_ASSIGNMENT: + case HLSL_IR_STORE: { - struct hlsl_ir_assignment *assignment = hlsl_ir_assignment(instr); - struct hlsl_ir_var *var = assignment->lhs.var; + struct hlsl_ir_store *store = hlsl_ir_store(instr); + struct hlsl_ir_var *var = store->lhs.var;
if (var->last_read < instr->index) { @@ -517,16 +516,16 @@ static void compute_liveness_recurse(struct list *instrs, unsigned int loop_firs { switch (instr->type) { - case HLSL_IR_ASSIGNMENT: + case HLSL_IR_STORE: { - struct hlsl_ir_assignment *assignment = hlsl_ir_assignment(instr); + struct hlsl_ir_store *store = hlsl_ir_store(instr);
- var = assignment->lhs.var; + var = store->lhs.var; if (!var->first_write) var->first_write = loop_first ? min(instr->index, loop_first) : instr->index; - assignment->rhs.node->last_read = instr->index; - if (assignment->lhs.offset.node) - assignment->lhs.offset.node->last_read = instr->index; + store->rhs.node->last_read = instr->index; + if (store->lhs.offset.node) + store->lhs.offset.node->last_read = instr->index; break; } case HLSL_IR_EXPR:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 4 +- libs/vkd3d-shader/hlsl.h | 9 ++ libs/vkd3d-shader/hlsl_codegen.c | 187 +++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 23003f44..f1db47cf 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -890,7 +890,7 @@ static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_der } }
-static const char *debug_writemask(DWORD writemask) +const char *debug_hlsl_writemask(unsigned int writemask) { static const char components[] = {'x', 'y', 'z', 'w'}; char string[5]; @@ -1074,7 +1074,7 @@ static void dump_ir_store(struct vkd3d_string_buffer *buffer, const struct hlsl_ vkd3d_string_buffer_printf(buffer, "= ("); dump_deref(buffer, &store->lhs); if (store->writemask != VKD3DSP_WRITEMASK_ALL) - vkd3d_string_buffer_printf(buffer, "%s", debug_writemask(store->writemask)); + vkd3d_string_buffer_printf(buffer, "%s", debug_hlsl_writemask(store->writemask)); vkd3d_string_buffer_printf(buffer, " "); dump_src(buffer, &store->rhs); vkd3d_string_buffer_printf(buffer, ")"); diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index c82cd4f5..c5a611d9 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -137,6 +137,13 @@ struct hlsl_struct_field unsigned int reg_offset; };
+struct hlsl_reg +{ + uint32_t id; + unsigned int writemask; + bool allocated; +}; + enum hlsl_ir_node_type { HLSL_IR_CONSTANT, @@ -208,6 +215,7 @@ struct hlsl_ir_var struct list scope_entry, param_entry;
unsigned int first_write, last_read; + struct hlsl_reg reg;
uint32_t is_input_varying : 1; uint32_t is_output_varying : 1; @@ -493,6 +501,7 @@ static inline void hlsl_src_remove(struct hlsl_src *src) }
const char *debug_hlsl_type(const struct hlsl_type *type) DECLSPEC_HIDDEN; +const char *debug_hlsl_writemask(unsigned int writemask) DECLSPEC_HIDDEN;
struct vkd3d_string_buffer *hlsl_type_to_string(struct vkd3d_string_buffer_cache *string_buffers, const struct hlsl_type *type) DECLSPEC_HIDDEN; diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 0641aa0f..c8d3ed4b 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -611,6 +611,191 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl compute_liveness_recurse(entry_func->body, 0, 0); }
+struct liveness +{ + size_t size; + struct + { + /* 0 if not live yet. */ + unsigned int last_read; + } *regs; +}; + +static unsigned int get_available_writemask(struct liveness *liveness, + unsigned int first_write, unsigned int component_idx, unsigned int component_count) +{ + unsigned int i, writemask = 0, count = 0; + + for (i = 0; i < 4; ++i) + { + if (liveness->regs[component_idx + i].last_read <= first_write) + { + writemask |= 1u << i; + if (++count == component_count) + return writemask; + } + } + + return 0; +} + +static bool resize_liveness(struct liveness *liveness, size_t new_count) +{ + size_t old_capacity = liveness->size; + + if (!vkd3d_array_reserve((void **)&liveness->regs, &liveness->size, new_count, sizeof(*liveness->regs))) + return false; + + if (liveness->size > old_capacity) + memset(liveness->regs + old_capacity, 0, (liveness->size - old_capacity) * sizeof(*liveness->regs)); + return true; +} + +static struct hlsl_reg allocate_register(struct liveness *liveness, + unsigned int first_write, unsigned int last_read, unsigned int component_count) +{ + unsigned int component_idx, writemask, i; + struct hlsl_reg ret = {0}; + + for (component_idx = 0; component_idx < liveness->size; component_idx += 4) + { + if ((writemask = get_available_writemask(liveness, first_write, component_idx, component_count))) + break; + } + if (component_idx == liveness->size) + { + if (!resize_liveness(liveness, component_idx + 4)) + return ret; + writemask = (1u << component_count) - 1; + } + for (i = 0; i < 4; ++i) + { + if (writemask & (1u << i)) + liveness->regs[component_idx + i].last_read = last_read; + } + ret.id = component_idx / 4; + ret.writemask = writemask; + ret.allocated = true; + return ret; +} + +static bool is_range_available(struct liveness *liveness, unsigned int first_write, + unsigned int component_idx, unsigned int component_count) +{ + unsigned int i; + + for (i = 0; i < component_count; i += 4) + { + if (!get_available_writemask(liveness, first_write, component_idx + i, 4)) + return false; + } + return true; +} + +static struct hlsl_reg allocate_range(struct liveness *liveness, + unsigned int first_write, unsigned int last_read, unsigned int reg_count) +{ + const unsigned int component_count = reg_count * 4; + unsigned int i, component_idx; + struct hlsl_reg ret = {0}; + + for (component_idx = 0; component_idx < liveness->size; component_idx += 4) + { + if (is_range_available(liveness, first_write, component_idx, + min(component_count, liveness->size - component_idx))) + break; + } + if (!resize_liveness(liveness, component_idx + component_count)) + return ret; + + for (i = 0; i < component_count; ++i) + liveness->regs[component_idx + i].last_read = last_read; + ret.id = component_idx / 4; + ret.allocated = true; + return ret; +} + +static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type) +{ + if (type->reg_size > 4) + return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class, + reg.id + type->reg_size - 1); + return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask)); +} + +static void allocate_variable_temp_register(struct hlsl_ir_var *var, struct liveness *liveness) +{ + if (var->is_input_varying || var->is_output_varying || var->is_uniform) + return; + + if (!var->reg.allocated && var->last_read) + { + if (var->data_type->reg_size > 1) + var->reg = allocate_range(liveness, var->first_write, + var->last_read, var->data_type->reg_size); + else + var->reg = allocate_register(liveness, var->first_write, + var->last_read, var->data_type->dimx); + TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name, + debug_register('r', var->reg, var->data_type), var->first_write, var->last_read); + } +} + +static void allocate_temp_registers_recurse(struct list *instrs, struct liveness *liveness) +{ + struct hlsl_ir_node *instr; + + LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) + { + switch (instr->type) + { + case HLSL_IR_IF: + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + allocate_temp_registers_recurse(&iff->then_instrs, liveness); + allocate_temp_registers_recurse(&iff->else_instrs, liveness); + break; + } + + case HLSL_IR_LOAD: + { + struct hlsl_ir_load *load = hlsl_ir_load(instr); + /* We need to at least allocate a variable for undefs. + * FIXME: We should probably find a way to remove them instead. */ + allocate_variable_temp_register(load->src.var, liveness); + break; + } + + case HLSL_IR_LOOP: + { + struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); + allocate_temp_registers_recurse(&loop->body, liveness); + break; + } + + case HLSL_IR_STORE: + { + struct hlsl_ir_store *store = hlsl_ir_store(instr); + allocate_variable_temp_register(store->lhs.var, liveness); + break; + } + + default: + break; + } + } +} + +/* Simple greedy temporary register allocation pass that just assigns a unique + * index to all (simultaneously live) variables or intermediate values. Agnostic + * as to how many registers are actually available for the current backend, and + * does not handle constants. */ +static void allocate_temp_registers(struct hlsl_ir_function_decl *entry_func) +{ + struct liveness liveness = {0}; + allocate_temp_registers_recurse(entry_func->body, &liveness); +} + int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) { struct hlsl_ir_var *var; @@ -648,6 +833,8 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun if (TRACE_ON()) rb_for_each_entry(&ctx->functions, dump_function, NULL);
+ allocate_temp_registers(entry_func); + if (ctx->failed) return VKD3D_ERROR_INVALID_SHADER; return VKD3D_ERROR_NOT_IMPLEMENTED;
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Fri, Apr 9, 2021 at 6:38 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.c | 4 +- libs/vkd3d-shader/hlsl.h | 9 ++ libs/vkd3d-shader/hlsl_codegen.c | 187 +++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-)
I keep finding nitpicks one at a time...
+static struct hlsl_reg allocate_range(struct liveness *liveness,
unsigned int first_write, unsigned int last_read, unsigned int reg_count)
+{
- const unsigned int component_count = reg_count * 4;
- unsigned int i, component_idx;
- struct hlsl_reg ret = {0};
- for (component_idx = 0; component_idx < liveness->size; component_idx += 4)
- {
if (is_range_available(liveness, first_write, component_idx,
min(component_count, liveness->size - component_idx)))
break;
- }
- if (!resize_liveness(liveness, component_idx + component_count))
return ret;
- for (i = 0; i < component_count; ++i)
liveness->regs[component_idx + i].last_read = last_read;
- ret.id = component_idx / 4;
- ret.allocated = true;
- return ret;
+}
This is slightly awkward in that it sets writemask to 0. That is arguably correct (more than 1 full register is allocated, in which case there is no partial register allocation) but we have to be careful with the users of struct hlsl_reg. At the moment there is not much of that, just the TRACE() in allocate_variable_temp_register() that prints something like "r0.". Speaking of which...
+static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type) +{
- if (type->reg_size > 4)
return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class,
reg.id + type->reg_size - 1);
- return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask));
+}
+static void allocate_variable_temp_register(struct hlsl_ir_var *var, struct liveness *liveness) +{
- if (var->is_input_varying || var->is_output_varying || var->is_uniform)
return;
- if (!var->reg.allocated && var->last_read)
- {
if (var->data_type->reg_size > 1)
var->reg = allocate_range(liveness, var->first_write,
var->last_read, var->data_type->reg_size);
else
var->reg = allocate_register(liveness, var->first_write,
var->last_read, var->data_type->dimx);
TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name,
debug_register('r', var->reg, var->data_type), var->first_write, var->last_read);
This doesn't tell the whole story for register ranges, maybe we could print more info in that case.
On 4/9/21 1:31 PM, Matteo Bruni wrote:
On Fri, Apr 9, 2021 at 6:38 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.c | 4 +- libs/vkd3d-shader/hlsl.h | 9 ++ libs/vkd3d-shader/hlsl_codegen.c | 187 +++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-)
I keep finding nitpicks one at a time...
+static struct hlsl_reg allocate_range(struct liveness *liveness,
unsigned int first_write, unsigned int last_read, unsigned int reg_count)
+{
- const unsigned int component_count = reg_count * 4;
- unsigned int i, component_idx;
- struct hlsl_reg ret = {0};
- for (component_idx = 0; component_idx < liveness->size; component_idx += 4)
- {
if (is_range_available(liveness, first_write, component_idx,
min(component_count, liveness->size - component_idx)))
break;
- }
- if (!resize_liveness(liveness, component_idx + component_count))
return ret;
- for (i = 0; i < component_count; ++i)
liveness->regs[component_idx + i].last_read = last_read;
- ret.id = component_idx / 4;
- ret.allocated = true;
- return ret;
+}
This is slightly awkward in that it sets writemask to 0. That is arguably correct (more than 1 full register is allocated, in which case there is no partial register allocation) but we have to be careful with the users of struct hlsl_reg. At the moment there is not much of that, just the TRACE() in allocate_variable_temp_register() that prints something like "r0.". Speaking of which...
I think I designed it this way on purpose. In a sense it allows us to be more careful; I believe I've caught a few errors this way when a register had an empty writemask.
I could have sworn I had fixed those traces, but oh well, I'll add an extra patch for those...
+static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type) +{
- if (type->reg_size > 4)
return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class,
reg.id + type->reg_size - 1);
- return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask));
+}
+static void allocate_variable_temp_register(struct hlsl_ir_var *var, struct liveness *liveness) +{
- if (var->is_input_varying || var->is_output_varying || var->is_uniform)
return;
- if (!var->reg.allocated && var->last_read)
- {
if (var->data_type->reg_size > 1)
var->reg = allocate_range(liveness, var->first_write,
var->last_read, var->data_type->reg_size);
else
var->reg = allocate_register(liveness, var->first_write,
var->last_read, var->data_type->dimx);
TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name,
debug_register('r', var->reg, var->data_type), var->first_write, var->last_read);
This doesn't tell the whole story for register ranges, maybe we could print more info in that case.
On 4/13/21 11:18 PM, Zebediah Figura (she/her) wrote:
On 4/9/21 1:31 PM, Matteo Bruni wrote:
On Fri, Apr 9, 2021 at 6:38 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.c | 4 +- libs/vkd3d-shader/hlsl.h | 9 ++ libs/vkd3d-shader/hlsl_codegen.c | 187 +++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-)
I keep finding nitpicks one at a time...
+static struct hlsl_reg allocate_range(struct liveness *liveness,
unsigned int first_write, unsigned int last_read, unsigned int reg_count)
+{
- const unsigned int component_count = reg_count * 4;
- unsigned int i, component_idx;
- struct hlsl_reg ret = {0};
- for (component_idx = 0; component_idx < liveness->size; component_idx += 4)
- {
if (is_range_available(liveness, first_write, component_idx,
min(component_count, liveness->size - component_idx)))
break;
- }
- if (!resize_liveness(liveness, component_idx + component_count))
return ret;
- for (i = 0; i < component_count; ++i)
liveness->regs[component_idx + i].last_read = last_read;
- ret.id = component_idx / 4;
- ret.allocated = true;
- return ret;
+}
This is slightly awkward in that it sets writemask to 0. That is arguably correct (more than 1 full register is allocated, in which case there is no partial register allocation) but we have to be careful with the users of struct hlsl_reg. At the moment there is not much of that, just the TRACE() in allocate_variable_temp_register() that prints something like "r0.". Speaking of which...
I think I designed it this way on purpose. In a sense it allows us to be more careful; I believe I've caught a few errors this way when a register had an empty writemask.
I could have sworn I had fixed those traces, but oh well, I'll add an extra patch for those...
Ah, never mind, it seems I had a bad rebase, and confused how I was keeping track of register size.
+static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type) +{
- if (type->reg_size > 4)
return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class,
reg.id + type->reg_size - 1);
- return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask));
+}
+static void allocate_variable_temp_register(struct hlsl_ir_var *var,
struct liveness *liveness)
+{
- if (var->is_input_varying || var->is_output_varying || var->is_uniform)
return;
- if (!var->reg.allocated && var->last_read)
- {
if (var->data_type->reg_size > 1)
var->reg = allocate_range(liveness, var->first_write,
var->last_read, var->data_type->reg_size);
else
var->reg = allocate_register(liveness, var->first_write,
var->last_read, var->data_type->dimx);
TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name,
debug_register('r', var->reg, var->data_type), var->first_write, var->last_read);
This doesn't tell the whole story for register ranges, maybe we could print more info in that case.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 12 ++++++++++++ 2 files changed, 13 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index c5a611d9..4122711b 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -171,6 +171,7 @@ struct hlsl_ir_node * true even for loops, since currently we can't have a reference to a * value generated in an earlier iteration of the loop. */ unsigned int index, last_read; + struct hlsl_reg reg; };
struct hlsl_src diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index c8d3ed4b..cfa021bc 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -747,6 +747,18 @@ static void allocate_temp_registers_recurse(struct list *instrs, struct liveness
LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) { + if (!instr->reg.allocated && instr->last_read) + { + if (instr->data_type->reg_size > 1) + instr->reg = allocate_range(liveness, instr->index, + instr->last_read, instr->data_type->reg_size); + else + instr->reg = allocate_register(liveness, instr->index, + instr->last_read, instr->data_type->dimx); + TRACE("Allocated anonymous expression @%u to %s (liveness %u-%u).\n", instr->index, + debug_register('r', instr->reg, instr->data_type), instr->index, instr->last_read); + } + switch (instr->type) { case HLSL_IR_IF:
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 18 +++++------------- libs/vkd3d-shader/hlsl.h | 13 +++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index f1db47cf..d797aa10 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1370,17 +1370,6 @@ void hlsl_add_function(struct rb_tree *funcs, char *name, struct hlsl_ir_functio rb_put(funcs, func->name, &func->entry); }
-struct hlsl_profile_info -{ - const char *name; - enum vkd3d_shader_type type; - DWORD sm_major; - DWORD sm_minor; - DWORD level_major; - DWORD level_minor; - bool sw; -}; - static const struct hlsl_profile_info *get_target_info(const char *target) { unsigned int i; @@ -1556,10 +1545,13 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) } }
-static bool hlsl_ctx_init(struct hlsl_ctx *ctx, struct vkd3d_shader_message_context *message_context) +static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct hlsl_profile_info *profile, + struct vkd3d_shader_message_context *message_context) { memset(ctx, 0, sizeof(*ctx));
+ ctx->profile = profile; + ctx->message_context = message_context;
if (!(ctx->source_files = vkd3d_malloc(sizeof(*ctx->source_files)))) @@ -1642,7 +1634,7 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
vkd3d_shader_dump_shader(profile->type, &compile_info->source);
- if (!hlsl_ctx_init(&ctx, message_context)) + if (!hlsl_ctx_init(&ctx, profile, message_context)) return VKD3D_ERROR_OUT_OF_MEMORY;
if (hlsl_lexer_compile(&ctx, hlsl) == 2) diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 4122711b..3f6abdc7 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -390,8 +390,21 @@ struct hlsl_scope struct hlsl_scope *upper; };
+struct hlsl_profile_info +{ + const char *name; + enum vkd3d_shader_type type; + unsigned int major_version; + unsigned int minor_version; + unsigned int major_level; + unsigned int minor_level; + bool software; +}; + struct hlsl_ctx { + const struct hlsl_profile_info *profile; + const char **source_files; unsigned int source_files_count; struct vkd3d_shader_location location;
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 3f6abdc7..923eff55 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -380,6 +380,7 @@ struct hlsl_ir_constant double d[4]; bool b[4]; } value; + struct hlsl_reg reg; };
struct hlsl_scope diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index cfa021bc..f7e11565 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -798,6 +798,55 @@ static void allocate_temp_registers_recurse(struct list *instrs, struct liveness } }
+static void allocate_const_registers_recurse(struct list *instrs, struct liveness *liveness) +{ + struct hlsl_ir_node *instr; + + LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) + { + switch (instr->type) + { + case HLSL_IR_CONSTANT: + { + struct hlsl_ir_constant *constant = hlsl_ir_constant(instr); + + if (instr->data_type->reg_size > 1) + constant->reg = allocate_range(liveness, 1, UINT_MAX, instr->data_type->reg_size); + else + constant->reg = allocate_register(liveness, 1, UINT_MAX, instr->data_type->dimx); + TRACE("Allocated constant @%u to %s.\n", instr->index, + debug_register('c', constant->reg, instr->data_type)); + break; + } + + case HLSL_IR_IF: + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + allocate_const_registers_recurse(&iff->then_instrs, liveness); + allocate_const_registers_recurse(&iff->else_instrs, liveness); + break; + } + + case HLSL_IR_LOOP: + { + struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); + allocate_const_registers_recurse(&loop->body, liveness); + break; + } + + default: + break; + } + } +} + +static void allocate_const_registers(struct hlsl_ir_function_decl *entry_func) +{ + struct liveness liveness = {0}; + + allocate_const_registers_recurse(entry_func->body, &liveness); +} + /* Simple greedy temporary register allocation pass that just assigns a unique * index to all (simultaneously live) variables or intermediate values. Agnostic * as to how many registers are actually available for the current backend, and @@ -846,6 +895,8 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun rb_for_each_entry(&ctx->functions, dump_function, NULL);
allocate_temp_registers(entry_func); + if (ctx->profile->major_version < 4) + allocate_const_registers(entry_func);
if (ctx->failed) return VKD3D_ERROR_INVALID_SHADER;
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- An obvious future optimization would be to deduplicate constants, e.g. mapping all the "uint 0" constants to the same register + component.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl_codegen.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index f7e11565..e254cede 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -840,9 +840,25 @@ static void allocate_const_registers_recurse(struct list *instrs, struct livenes } }
-static void allocate_const_registers(struct hlsl_ir_function_decl *entry_func) +static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) { struct liveness liveness = {0}; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + if (var->is_uniform && var->last_read) + { + if (var->data_type->reg_size > 1) + var->reg = allocate_range(&liveness, 1, UINT_MAX, var->data_type->reg_size); + else + { + var->reg = allocate_register(&liveness, 1, UINT_MAX, 4); + var->reg.writemask = (1u << var->data_type->dimx) - 1; + } + TRACE("Allocated %s to %s.\n", var->name, debug_register('c', var->reg, var->data_type)); + } + }
allocate_const_registers_recurse(entry_func->body, &liveness); } @@ -896,7 +912,7 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun
allocate_temp_registers(entry_func); if (ctx->profile->major_version < 4) - allocate_const_registers(entry_func); + allocate_const_registers(ctx, entry_func);
if (ctx->failed) return VKD3D_ERROR_INVALID_SHADER;
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com